Skip to content

Commit 69193d9

Browse files
committed
Add method to release held Program in BuilderProgram
1 parent 56a76d8 commit 69193d9

File tree

1 file changed

+49
-30
lines changed

1 file changed

+49
-30
lines changed

src/compiler/builder.ts

+49-30
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ namespace ts {
4949
/**
5050
* program corresponding to this state
5151
*/
52-
program: Program;
52+
program: Program | undefined;
53+
/**
54+
* compilerOptions for the program
55+
*/
56+
compilerOptions: CompilerOptions;
5357
}
5458

5559
function hasSameKeys<T, U>(map1: ReadonlyMap<T> | undefined, map2: ReadonlyMap<U> | undefined): boolean {
@@ -64,13 +68,14 @@ namespace ts {
6468
const state = BuilderState.create(newProgram, getCanonicalFileName, oldState) as BuilderProgramState;
6569
state.program = newProgram;
6670
const compilerOptions = newProgram.getCompilerOptions();
71+
state.compilerOptions = compilerOptions;
6772
if (!compilerOptions.outFile && !compilerOptions.out) {
6873
state.semanticDiagnosticsPerFile = createMap<ReadonlyArray<Diagnostic>>();
6974
}
7075
state.changedFilesSet = createMap<true>();
7176

7277
const useOldState = BuilderState.canReuseOldState(state.referencedMap, oldState);
73-
const oldCompilerOptions = useOldState ? oldState!.program.getCompilerOptions() : undefined;
78+
const oldCompilerOptions = useOldState ? oldState!.compilerOptions : undefined;
7479
const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile &&
7580
!compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldCompilerOptions!);
7681
if (useOldState) {
@@ -109,7 +114,7 @@ namespace ts {
109114
state.changedFilesSet.set(sourceFilePath, true);
110115
}
111116
else if (canCopySemanticDiagnostics) {
112-
const sourceFile = state.program.getSourceFileByPath(sourceFilePath as Path)!;
117+
const sourceFile = newProgram.getSourceFileByPath(sourceFilePath as Path)!;
113118

114119
if (sourceFile.isDeclarationFile && !copyDeclarationFileDiagnostics) { return; }
115120
if (sourceFile.hasNoDefaultLib && !copyLibFileDiagnostics) { return; }
@@ -179,18 +184,19 @@ namespace ts {
179184

180185
// With --out or --outFile all outputs go into single file
181186
// so operations are performed directly on program, return program
182-
const compilerOptions = state.program.getCompilerOptions();
187+
const program = Debug.assertDefined(state.program);
188+
const compilerOptions = program.getCompilerOptions();
183189
if (compilerOptions.outFile || compilerOptions.out) {
184190
Debug.assert(!state.semanticDiagnosticsPerFile);
185-
return state.program;
191+
return program;
186192
}
187193

188194
// Get next batch of affected files
189195
state.currentAffectedFilesSignatures = state.currentAffectedFilesSignatures || createMap();
190196
if (state.exportedModulesMap) {
191197
state.currentAffectedFilesExportedModulesMap = state.currentAffectedFilesExportedModulesMap || createMap<BuilderState.ReferencedSet | false>();
192198
}
193-
state.affectedFiles = BuilderState.getFilesAffectedBy(state, state.program, nextKey.value as Path, cancellationToken, computeHash, state.currentAffectedFilesSignatures, state.currentAffectedFilesExportedModulesMap);
199+
state.affectedFiles = BuilderState.getFilesAffectedBy(state, program, nextKey.value as Path, cancellationToken, computeHash, state.currentAffectedFilesSignatures, state.currentAffectedFilesExportedModulesMap);
194200
state.currentChangedFilePath = nextKey.value as Path;
195201
state.affectedFilesIndex = 0;
196202
state.seenAffectedFiles = state.seenAffectedFiles || createMap<true>();
@@ -209,9 +215,10 @@ namespace ts {
209215
// Clean lib file diagnostics if its all files excluding default files to emit
210216
if (state.allFilesExcludingDefaultLibraryFile === state.affectedFiles && !state.cleanedDiagnosticsOfLibFiles) {
211217
state.cleanedDiagnosticsOfLibFiles = true;
212-
const options = state.program.getCompilerOptions();
213-
if (forEach(state.program.getSourceFiles(), f =>
214-
state.program.isSourceFileDefaultLibrary(f) &&
218+
const program = Debug.assertDefined(state.program);
219+
const options = program.getCompilerOptions();
220+
if (forEach(program.getSourceFiles(), f =>
221+
program.isSourceFileDefaultLibrary(f) &&
215222
!skipTypeChecking(f, options) &&
216223
removeSemanticDiagnosticsOf(state, f.path)
217224
)) {
@@ -336,7 +343,7 @@ namespace ts {
336343
}
337344

338345
// Diagnostics werent cached, get them from program, and cache the result
339-
const diagnostics = state.program.getSemanticDiagnostics(sourceFile, cancellationToken);
346+
const diagnostics = Debug.assertDefined(state.program).getSemanticDiagnostics(sourceFile, cancellationToken);
340347
state.semanticDiagnosticsPerFile!.set(path, diagnostics);
341348
return diagnostics;
342349
}
@@ -370,7 +377,7 @@ namespace ts {
370377
rootNames: newProgramOrRootNames,
371378
options: hostOrOptions as CompilerOptions,
372379
host: oldProgramOrHost as CompilerHost,
373-
oldProgram: oldProgram && oldProgram.getProgram(),
380+
oldProgram: oldProgram && oldProgram.getProgramOrUndefined(),
374381
configFileParsingDiagnostics,
375382
projectReferences
376383
});
@@ -413,7 +420,7 @@ namespace ts {
413420

414421
const result = createRedirectedBuilderProgram(state, configFileParsingDiagnostics);
415422
result.getState = () => state;
416-
result.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, state.program, sourceFile);
423+
result.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.assertDefined(state.program), sourceFile);
417424
result.getSemanticDiagnostics = getSemanticDiagnostics;
418425
result.emit = emit;
419426

@@ -445,7 +452,7 @@ namespace ts {
445452
state,
446453
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
447454
// Otherwise just affected file
448-
state.program.emit(affected === state.program ? undefined : affected as SourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers),
455+
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers),
449456
affected
450457
);
451458
}
@@ -486,7 +493,7 @@ namespace ts {
486493
};
487494
}
488495
}
489-
return state.program.emit(targetSourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
496+
return Debug.assertDefined(state.program).emit(targetSourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
490497
}
491498

492499
/**
@@ -534,11 +541,11 @@ namespace ts {
534541
*/
535542
function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
536543
assertSourceFileOkWithoutNextAffectedCall(state, sourceFile);
537-
const compilerOptions = state.program.getCompilerOptions();
544+
const compilerOptions = Debug.assertDefined(state.program).getCompilerOptions();
538545
if (compilerOptions.outFile || compilerOptions.out) {
539546
Debug.assert(!state.semanticDiagnosticsPerFile);
540547
// We dont need to cache the diagnostics just return them from program
541-
return state.program.getSemanticDiagnostics(sourceFile, cancellationToken);
548+
return Debug.assertDefined(state.program).getSemanticDiagnostics(sourceFile, cancellationToken);
542549
}
543550

544551
if (sourceFile) {
@@ -555,29 +562,31 @@ namespace ts {
555562
}
556563

557564
let diagnostics: Diagnostic[] | undefined;
558-
for (const sourceFile of state.program.getSourceFiles()) {
565+
for (const sourceFile of Debug.assertDefined(state.program).getSourceFiles()) {
559566
diagnostics = addRange(diagnostics, getSemanticDiagnosticsOfFile(state, sourceFile, cancellationToken));
560567
}
561568
return diagnostics || emptyArray;
562569
}
563570
}
564571

565-
export function createRedirectedBuilderProgram(state: { program: Program; }, configFileParsingDiagnostics: ReadonlyArray<Diagnostic>): BuilderProgram {
572+
export function createRedirectedBuilderProgram(state: { program: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: ReadonlyArray<Diagnostic>): BuilderProgram {
566573
return {
567574
getState: notImplemented,
568-
getProgram: () => state.program,
569-
getCompilerOptions: () => state.program.getCompilerOptions(),
570-
getSourceFile: fileName => state.program.getSourceFile(fileName),
571-
getSourceFiles: () => state.program.getSourceFiles(),
572-
getOptionsDiagnostics: cancellationToken => state.program.getOptionsDiagnostics(cancellationToken),
573-
getGlobalDiagnostics: cancellationToken => state.program.getGlobalDiagnostics(cancellationToken),
575+
getProgram: () => Debug.assertDefined(state.program),
576+
getProgramOrUndefined: () => state.program,
577+
releaseProgram: () => state.program = undefined,
578+
getCompilerOptions: () => state.compilerOptions,
579+
getSourceFile: fileName => Debug.assertDefined(state.program).getSourceFile(fileName),
580+
getSourceFiles: () => Debug.assertDefined(state.program).getSourceFiles(),
581+
getOptionsDiagnostics: cancellationToken => Debug.assertDefined(state.program).getOptionsDiagnostics(cancellationToken),
582+
getGlobalDiagnostics: cancellationToken => Debug.assertDefined(state.program).getGlobalDiagnostics(cancellationToken),
574583
getConfigFileParsingDiagnostics: () => configFileParsingDiagnostics,
575-
getSyntacticDiagnostics: (sourceFile, cancellationToken) => state.program.getSyntacticDiagnostics(sourceFile, cancellationToken),
576-
getDeclarationDiagnostics: (sourceFile, cancellationToken) => state.program.getDeclarationDiagnostics(sourceFile, cancellationToken),
577-
getSemanticDiagnostics: (sourceFile, cancellationToken) => state.program.getSemanticDiagnostics(sourceFile, cancellationToken),
578-
emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => state.program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers),
584+
getSyntacticDiagnostics: (sourceFile, cancellationToken) => Debug.assertDefined(state.program).getSyntacticDiagnostics(sourceFile, cancellationToken),
585+
getDeclarationDiagnostics: (sourceFile, cancellationToken) => Debug.assertDefined(state.program).getDeclarationDiagnostics(sourceFile, cancellationToken),
586+
getSemanticDiagnostics: (sourceFile, cancellationToken) => Debug.assertDefined(state.program).getSemanticDiagnostics(sourceFile, cancellationToken),
587+
emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => Debug.assertDefined(state.program).emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers),
579588
getAllDependencies: notImplemented,
580-
getCurrentDirectory: () => state.program.getCurrentDirectory()
589+
getCurrentDirectory: () => Debug.assertDefined(state.program).getCurrentDirectory()
581590
};
582591
}
583592
}
@@ -611,6 +620,16 @@ namespace ts {
611620
* Returns current program
612621
*/
613622
getProgram(): Program;
623+
/**
624+
* Returns current program that could be undefined if the program was released
625+
*/
626+
/*@internal*/
627+
getProgramOrUndefined(): Program | undefined;
628+
/**
629+
* Releases reference to the program, making all the other operations that need program to fail.
630+
*/
631+
/*@internal*/
632+
releaseProgram(): void;
614633
/**
615634
* Get compiler options of the program
616635
*/
@@ -725,6 +744,6 @@ namespace ts {
725744
export function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
726745
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram {
727746
const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
728-
return createRedirectedBuilderProgram({ program: newProgram }, newConfigFileParsingDiagnostics);
747+
return createRedirectedBuilderProgram({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }, newConfigFileParsingDiagnostics);
729748
}
730749
}

0 commit comments

Comments
 (0)