@@ -30,10 +30,18 @@ namespace ts {
30
30
* These will be commited whenever the iteration through affected files of current changed file is complete
31
31
*/
32
32
currentAffectedFilesSignatures : Map < string > | undefined ;
33
+ /**
34
+ * Newly computed visible to outside referencedSet
35
+ */
36
+ currentAffectedFilesExportedModulesMap : BuilderState . ComputingExportedModulesMap | undefined ;
33
37
/**
34
38
* Already seen affected files
35
39
*/
36
40
seenAffectedFiles : Map < true > | undefined ;
41
+ /**
42
+ * True if the semantic diagnostics were copied from the old state
43
+ */
44
+ semanticDiagnosticsFromOldState ?: Map < true > ;
37
45
/**
38
46
* program corresponding to this state
39
47
*/
@@ -96,6 +104,10 @@ namespace ts {
96
104
const diagnostics = oldState ! . semanticDiagnosticsPerFile ! . get ( sourceFilePath ) ;
97
105
if ( diagnostics ) {
98
106
state . semanticDiagnosticsPerFile ! . set ( sourceFilePath , diagnostics ) ;
107
+ if ( ! state . semanticDiagnosticsFromOldState ) {
108
+ state . semanticDiagnosticsFromOldState = createMap < true > ( ) ;
109
+ }
110
+ state . semanticDiagnosticsFromOldState . set ( sourceFilePath , true ) ;
99
111
}
100
112
}
101
113
} ) ;
@@ -120,17 +132,17 @@ namespace ts {
120
132
while ( true ) {
121
133
const { affectedFiles } = state ;
122
134
if ( affectedFiles ) {
123
- const { seenAffectedFiles, semanticDiagnosticsPerFile } = state ;
135
+ const seenAffectedFiles = state . seenAffectedFiles ! ;
124
136
let affectedFilesIndex = state . affectedFilesIndex ! ; // TODO: GH#18217
125
137
while ( affectedFilesIndex < affectedFiles . length ) {
126
138
const affectedFile = affectedFiles [ affectedFilesIndex ] ;
127
- if ( ! seenAffectedFiles ! . has ( affectedFile . path ) ) {
139
+ if ( ! seenAffectedFiles . has ( affectedFile . path ) ) {
128
140
// Set the next affected file as seen and remove the cached semantic diagnostics
129
141
state . affectedFilesIndex = affectedFilesIndex ;
130
- semanticDiagnosticsPerFile ! . delete ( affectedFile . path ) ;
142
+ cleanSemanticDiagnosticsOfAffectedFile ( state , affectedFile ) ;
131
143
return affectedFile ;
132
144
}
133
- seenAffectedFiles ! . set ( affectedFile . path , true ) ;
145
+ seenAffectedFiles . set ( affectedFile . path , true ) ;
134
146
affectedFilesIndex ++ ;
135
147
}
136
148
@@ -140,6 +152,7 @@ namespace ts {
140
152
// Commit the changes in file signature
141
153
BuilderState . updateSignaturesFromCache ( state , state . currentAffectedFilesSignatures ! ) ;
142
154
state . currentAffectedFilesSignatures ! . clear ( ) ;
155
+ BuilderState . updateExportedFilesMapFromCache ( state , state . currentAffectedFilesExportedModulesMap ) ;
143
156
state . affectedFiles = undefined ;
144
157
}
145
158
@@ -160,14 +173,74 @@ namespace ts {
160
173
161
174
// Get next batch of affected files
162
175
state . currentAffectedFilesSignatures = state . currentAffectedFilesSignatures || createMap ( ) ;
163
- state . affectedFiles = BuilderState . getFilesAffectedBy ( state , state . program , nextKey . value as Path , cancellationToken , computeHash , state . currentAffectedFilesSignatures ) ;
176
+ if ( state . exportedModulesMap ) {
177
+ state . currentAffectedFilesExportedModulesMap = state . currentAffectedFilesExportedModulesMap || createMap < BuilderState . ReferencedSet | false > ( ) ;
178
+ }
179
+ state . affectedFiles = BuilderState . getFilesAffectedBy ( state , state . program , nextKey . value as Path , cancellationToken , computeHash , state . currentAffectedFilesSignatures , state . currentAffectedFilesExportedModulesMap ) ;
164
180
state . currentChangedFilePath = nextKey . value as Path ;
165
- state . semanticDiagnosticsPerFile ! . delete ( nextKey . value as Path ) ;
166
181
state . affectedFilesIndex = 0 ;
167
182
state . seenAffectedFiles = state . seenAffectedFiles || createMap < true > ( ) ;
168
183
}
169
184
}
170
185
186
+ /**
187
+ * Remove the semantic diagnostics cached from old state for affected File and the files that are referencing modules that export entities from affected file
188
+ */
189
+ function cleanSemanticDiagnosticsOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile ) {
190
+ if ( removeSemanticDiagnosticsOf ( state , affectedFile . path ) ) {
191
+ // If there are no more diagnostics from old cache, done
192
+ return ;
193
+ }
194
+
195
+ // If there was change in signature for the changed file,
196
+ // then delete the semantic diagnostics for files that are affected by using exports of this module
197
+
198
+ if ( ! state . exportedModulesMap || state . affectedFiles ! . length === 1 || ! state . changedFilesSet . has ( affectedFile . path ) ) {
199
+ return ;
200
+ }
201
+
202
+ Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
203
+ // Go through exported modules from cache first
204
+ // If exported modules has path, all files referencing file exported from are affected
205
+ if ( forEachEntry ( state . currentAffectedFilesExportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
206
+ exportedModules &&
207
+ exportedModules . has ( affectedFile . path ) &&
208
+ removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path )
209
+ ) ) {
210
+ return ;
211
+ }
212
+
213
+ // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
214
+ forEachEntry ( state . exportedModulesMap , ( exportedModules , exportedFromPath ) =>
215
+ ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
216
+ exportedModules . has ( affectedFile . path ) &&
217
+ removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path )
218
+ ) ;
219
+ }
220
+
221
+ /**
222
+ * removes the semantic diagnostics of files referencing referencedPath and
223
+ * returns true if there are no more semantic diagnostics from old state
224
+ */
225
+ function removeSemanticDiagnosticsOfFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path ) {
226
+ return forEachEntry ( state . referencedMap ! , ( referencesInFile , filePath ) =>
227
+ referencesInFile . has ( referencedPath ) && removeSemanticDiagnosticsOf ( state , filePath as Path )
228
+ ) ;
229
+ }
230
+
231
+ /**
232
+ * Removes semantic diagnostics for path and
233
+ * returns true if there are no more semantic diagnostics from the old state
234
+ */
235
+ function removeSemanticDiagnosticsOf ( state : BuilderProgramState , path : Path ) {
236
+ if ( ! state . semanticDiagnosticsFromOldState ) {
237
+ return false ;
238
+ }
239
+ state . semanticDiagnosticsFromOldState . delete ( path ) ;
240
+ state . semanticDiagnosticsPerFile ! . delete ( path ) ;
241
+ return ! state . semanticDiagnosticsFromOldState . size ;
242
+ }
243
+
171
244
/**
172
245
* This is called after completing operation on the next affected file.
173
246
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly
0 commit comments