@@ -38,6 +38,10 @@ namespace ts {
38
38
* Already seen affected files
39
39
*/
40
40
seenAffectedFiles : Map < true > | undefined ;
41
+ /**
42
+ * True if the semantic diagnostics were copied from the old state
43
+ */
44
+ semanticDiagnosticsFromOldStateFiles ?: number ;
41
45
/**
42
46
* program corresponding to this state
43
47
*/
@@ -100,6 +104,7 @@ namespace ts {
100
104
const diagnostics = oldState ! . semanticDiagnosticsPerFile ! . get ( sourceFilePath ) ;
101
105
if ( diagnostics ) {
102
106
state . semanticDiagnosticsPerFile ! . set ( sourceFilePath , diagnostics ) ;
107
+ state . semanticDiagnosticsFromOldStateFiles = ( state . semanticDiagnosticsFromOldStateFiles || 0 ) + 1 ;
103
108
}
104
109
}
105
110
} ) ;
@@ -124,19 +129,17 @@ namespace ts {
124
129
while ( true ) {
125
130
const { affectedFiles } = state ;
126
131
if ( affectedFiles ) {
127
- const { seenAffectedFiles, semanticDiagnosticsPerFile } = state ;
132
+ const seenAffectedFiles = state . seenAffectedFiles ! ;
128
133
let affectedFilesIndex = state . affectedFilesIndex ! ; // TODO: GH#18217
129
134
while ( affectedFilesIndex < affectedFiles . length ) {
130
135
const affectedFile = affectedFiles [ affectedFilesIndex ] ;
131
- if ( ! seenAffectedFiles ! . has ( affectedFile . path ) ) {
136
+ if ( ! seenAffectedFiles . has ( affectedFile . path ) ) {
132
137
// Set the next affected file as seen and remove the cached semantic diagnostics
133
138
state . affectedFilesIndex = affectedFilesIndex ;
134
- semanticDiagnosticsPerFile ! . delete ( affectedFile . path ) ;
135
- // Remove semantic diagnostics for files that are affected by using exports of this module
136
- BuilderState . getFilesAffectedByExportedModule ( state , affectedFile . path , state . currentAffectedFilesExportedModulesMap ) . forEach ( path => semanticDiagnosticsPerFile ! . delete ( path ) ) ;
139
+ cleanSemanticDiagnosticsOfAffectedFile ( state , affectedFile ) ;
137
140
return affectedFile ;
138
141
}
139
- seenAffectedFiles ! . set ( affectedFile . path , true ) ;
142
+ seenAffectedFiles . set ( affectedFile . path , true ) ;
140
143
affectedFilesIndex ++ ;
141
144
}
142
145
@@ -172,12 +175,74 @@ namespace ts {
172
175
}
173
176
state . affectedFiles = BuilderState . getFilesAffectedBy ( state , state . program , nextKey . value as Path , cancellationToken , computeHash , state . currentAffectedFilesSignatures , state . currentAffectedFilesExportedModulesMap ) ;
174
177
state . currentChangedFilePath = nextKey . value as Path ;
175
- state . semanticDiagnosticsPerFile ! . delete ( nextKey . value as Path ) ;
176
178
state . affectedFilesIndex = 0 ;
177
179
state . seenAffectedFiles = state . seenAffectedFiles || createMap < true > ( ) ;
178
180
}
179
181
}
180
182
183
+ /**
184
+ * Remove the semantic diagnostics cached from old state for affected File and the files that are referencing modules that export entities from affected file
185
+ */
186
+ function cleanSemanticDiagnosticsOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile ) {
187
+ if ( ! state . semanticDiagnosticsFromOldStateFiles ) {
188
+ Debug . assert ( ! state . semanticDiagnosticsPerFile ! . has ( affectedFile . path ) ) ;
189
+ return ;
190
+ }
191
+
192
+ if ( removeSemanticDiagnosticsOf ( state , affectedFile . path ) ) {
193
+ // If there are no more diagnostics from old cache, remove them
194
+ return ;
195
+ }
196
+
197
+ // If there was change in signature for the changed file,
198
+ // then delete the semantic diagnostics for files that are affected by using exports of this module
199
+
200
+ if ( ! state . exportedModulesMap || state . affectedFiles ! . length === 1 || ! state . changedFilesSet . has ( affectedFile . path ) ) {
201
+ return ;
202
+ }
203
+
204
+ Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
205
+ // Go through exported modules from cache first
206
+ // If exported modules has path, all files referencing file exported from are affected
207
+ if ( forEachEntry ( state . currentAffectedFilesExportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
208
+ exportedModules &&
209
+ exportedModules . has ( affectedFile . path ) &&
210
+ removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path )
211
+ ) ) {
212
+ return ;
213
+ }
214
+
215
+ // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
216
+ forEachEntry ( state . exportedModulesMap , ( exportedModules , exportedFromPath ) =>
217
+ ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
218
+ exportedModules . has ( affectedFile . path ) &&
219
+ removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path )
220
+ ) ;
221
+ }
222
+
223
+ /**
224
+ * removes the semantic diagnostics of files referencing referencedPath and
225
+ * returns true if there are no more semantic diagnostics from old state
226
+ */
227
+ function removeSemanticDiagnosticsOfFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path ) {
228
+ return forEachEntry ( state . referencedMap ! , ( referencesInFile , filePath ) =>
229
+ referencesInFile . has ( referencedPath ) && removeSemanticDiagnosticsOf ( state , filePath as Path )
230
+ ) ;
231
+ }
232
+
233
+ /**
234
+ * Removes semantic diagnostics for path and
235
+ * returns true if there are no more semantic diagnostics from the old state
236
+ */
237
+ function removeSemanticDiagnosticsOf ( state : BuilderProgramState , path : Path ) {
238
+ if ( state . semanticDiagnosticsPerFile ! . delete ( path ) ) {
239
+ Debug . assert ( ( state . semanticDiagnosticsFromOldStateFiles || 0 ) > 0 ) ;
240
+ state . semanticDiagnosticsFromOldStateFiles ! -- ;
241
+ return ! state . semanticDiagnosticsFromOldStateFiles ;
242
+ }
243
+ return false ;
244
+ }
245
+
181
246
/**
182
247
* This is called after completing operation on the next affected file.
183
248
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly
0 commit comments