Skip to content

Commit fab4ef0

Browse files
authored
cache semantic and declaration diagnostics in program (microsoft#14516)
1 parent 3e5b232 commit fab4ef0

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

src/compiler/program.ts

+43-1
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ namespace ts {
290290
return resolutions;
291291
}
292292

293+
interface DiagnosticCache {
294+
perFile?: FileMap<Diagnostic[]>;
295+
allDiagnostics?: Diagnostic[];
296+
}
297+
293298
export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program {
294299
let program: Program;
295300
let files: SourceFile[] = [];
@@ -298,6 +303,9 @@ namespace ts {
298303
let noDiagnosticsTypeChecker: TypeChecker;
299304
let classifiableNames: Map<string>;
300305

306+
let cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
307+
let cachedDeclarationDiagnosticsForFile: DiagnosticCache = {};
308+
301309
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
302310
let fileProcessingDiagnostics = createDiagnosticCollection();
303311

@@ -899,6 +907,10 @@ namespace ts {
899907
}
900908

901909
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
910+
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedSemanticDiagnosticsForFile, getSemanticDiagnosticsForFileNoCache);
911+
}
912+
913+
function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
902914
return runWithCancellationToken(() => {
903915
const typeChecker = getDiagnosticsProducingTypeChecker();
904916

@@ -1094,14 +1106,44 @@ namespace ts {
10941106
});
10951107
}
10961108

1097-
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
1109+
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken): Diagnostic[] {
1110+
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
1111+
}
1112+
1113+
function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile| undefined, cancellationToken: CancellationToken) {
10981114
return runWithCancellationToken(() => {
10991115
const resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
11001116
// Don't actually write any files since we're just getting diagnostics.
11011117
return ts.getDeclarationDiagnostics(getEmitHost(noop), resolver, sourceFile);
11021118
});
11031119
}
11041120

1121+
function getAndCacheDiagnostics(
1122+
sourceFile: SourceFile | undefined,
1123+
cancellationToken: CancellationToken,
1124+
cache: DiagnosticCache,
1125+
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[]) {
1126+
1127+
const cachedResult = sourceFile
1128+
? cache.perFile && cache.perFile.get(sourceFile.path)
1129+
: cache.allDiagnostics;
1130+
1131+
if (cachedResult) {
1132+
return cachedResult;
1133+
}
1134+
const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
1135+
if (sourceFile) {
1136+
if (!cache.perFile) {
1137+
cache.perFile = createFileMap<Diagnostic[]>();
1138+
}
1139+
cache.perFile.set(sourceFile.path, result);
1140+
}
1141+
else {
1142+
cache.allDiagnostics = result;
1143+
}
1144+
return result;
1145+
}
1146+
11051147
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
11061148
return isDeclarationFile(sourceFile) ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
11071149
}

0 commit comments

Comments
 (0)