Skip to content

Commit 50b75e7

Browse files
committed
Optimize the deletion and calculation of bigger set of semantic diagnostics to be calculated
1 parent 585acb1 commit 50b75e7

File tree

2 files changed

+72
-45
lines changed

2 files changed

+72
-45
lines changed

src/compiler/builder.ts

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ namespace ts {
3838
* Already seen affected files
3939
*/
4040
seenAffectedFiles: Map<true> | undefined;
41+
/**
42+
* True if the semantic diagnostics were copied from the old state
43+
*/
44+
semanticDiagnosticsFromOldStateFiles?: number;
4145
/**
4246
* program corresponding to this state
4347
*/
@@ -100,6 +104,7 @@ namespace ts {
100104
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
101105
if (diagnostics) {
102106
state.semanticDiagnosticsPerFile!.set(sourceFilePath, diagnostics);
107+
state.semanticDiagnosticsFromOldStateFiles = (state.semanticDiagnosticsFromOldStateFiles || 0) + 1;
103108
}
104109
}
105110
});
@@ -124,19 +129,17 @@ namespace ts {
124129
while (true) {
125130
const { affectedFiles } = state;
126131
if (affectedFiles) {
127-
const { seenAffectedFiles, semanticDiagnosticsPerFile } = state;
132+
const seenAffectedFiles = state.seenAffectedFiles!;
128133
let affectedFilesIndex = state.affectedFilesIndex!; // TODO: GH#18217
129134
while (affectedFilesIndex < affectedFiles.length) {
130135
const affectedFile = affectedFiles[affectedFilesIndex];
131-
if (!seenAffectedFiles!.has(affectedFile.path)) {
136+
if (!seenAffectedFiles.has(affectedFile.path)) {
132137
// Set the next affected file as seen and remove the cached semantic diagnostics
133138
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);
137140
return affectedFile;
138141
}
139-
seenAffectedFiles!.set(affectedFile.path, true);
142+
seenAffectedFiles.set(affectedFile.path, true);
140143
affectedFilesIndex++;
141144
}
142145

@@ -172,12 +175,74 @@ namespace ts {
172175
}
173176
state.affectedFiles = BuilderState.getFilesAffectedBy(state, state.program, nextKey.value as Path, cancellationToken, computeHash, state.currentAffectedFilesSignatures, state.currentAffectedFilesExportedModulesMap);
174177
state.currentChangedFilePath = nextKey.value as Path;
175-
state.semanticDiagnosticsPerFile!.delete(nextKey.value as Path);
176178
state.affectedFilesIndex = 0;
177179
state.seenAffectedFiles = state.seenAffectedFiles || createMap<true>();
178180
}
179181
}
180182

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+
181246
/**
182247
* This is called after completing operation on the next affected file.
183248
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly

src/compiler/builderState.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -320,44 +320,6 @@ namespace ts.BuilderState {
320320
}
321321
}
322322

323-
/**
324-
* Gets the files affected by exported module
325-
*/
326-
export function getFilesAffectedByExportedModule(state: BuilderState, path: Path, exportedModulesMapCache?: ComputingExportedModulesMap): ReadonlyArray<Path> {
327-
if (!state.exportedModulesMap) {
328-
return emptyArray;
329-
}
330-
331-
Debug.assert(!!exportedModulesMapCache);
332-
let affectedFiles: Map<true> | undefined;
333-
// Go through exported modules from cache first
334-
exportedModulesMapCache!.forEach((exportedModules, exportedFromPath) => {
335-
// If exported modules has path, all files referencing file exported from are affected
336-
if (exportedModules && exportedModules.has(path)) {
337-
addFilesReferencing(exportedFromPath as Path);
338-
}
339-
});
340-
state.exportedModulesMap.forEach((exportedModules, exportedFromPath) => {
341-
// If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
342-
if (!exportedModulesMapCache!.has(exportedFromPath) && exportedModules.has(path)) {
343-
addFilesReferencing(exportedFromPath as Path);
344-
}
345-
});
346-
347-
return affectedFiles ? arrayFrom(affectedFiles.keys()) as Path[] : emptyArray;
348-
349-
function addFilesReferencing(referencingFilePath: Path) {
350-
state.referencedMap!.forEach((referencesInFile, filePath) => {
351-
if (referencesInFile.has(referencingFilePath)) {
352-
if (!affectedFiles) {
353-
affectedFiles = createMap<true>();
354-
}
355-
affectedFiles.set(filePath, true);
356-
}
357-
});
358-
}
359-
}
360-
361323
/**
362324
* Get all the dependencies of the sourceFile
363325
*/

0 commit comments

Comments
 (0)