Skip to content

Commit 43e1520

Browse files
Keen Yee Liaualexeagle
Keen Yee Liau
authored andcommitted
fix(language-service): Clear caches when program changes (#21337)
This commit fixes a bug whereby the caches are not cleared when the program changes. This subsequently produces the incorrect error of 'Component ... is not included in a module ...'. PR Close #19405 PR Close #21337
1 parent 2d44a2a commit 43e1520

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

packages/language-service/src/typescript_host.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
140140
}
141141

142142
getAnalyzedModules(): NgAnalyzedModules {
143-
this.validate();
143+
this.updateAnalyzedModules();
144144
return this.ensureAnalyzedModules();
145145
}
146146

@@ -240,7 +240,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
240240

241241
private validate() {
242242
const program = this.program;
243-
if (this._staticSymbolResolver && this.lastProgram != program) {
243+
if (this.lastProgram !== program) {
244244
// Invalidate file that have changed in the static symbol resolver
245245
const invalidateFile = (fileName: string) =>
246246
this._staticSymbolResolver.invalidateFile(fileName);
@@ -253,14 +253,18 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
253253
const lastVersion = this.fileVersions.get(fileName);
254254
if (version != lastVersion) {
255255
this.fileVersions.set(fileName, version);
256-
invalidateFile(fileName);
256+
if (this._staticSymbolResolver) {
257+
invalidateFile(fileName);
258+
}
257259
}
258260
}
259261

260262
// Remove file versions that are no longer in the file and invalidate them.
261263
const missing = Array.from(this.fileVersions.keys()).filter(f => !seen.has(f));
262264
missing.forEach(f => this.fileVersions.delete(f));
263-
missing.forEach(invalidateFile);
265+
if (this._staticSymbolResolver) {
266+
missing.forEach(invalidateFile);
267+
}
264268

265269
this.lastProgram = program;
266270
}
@@ -634,4 +638,4 @@ function convertChain(chain: FormattedMessageChain): DiagnosticMessageChain {
634638

635639
function errorToDiagnosticWithChain(error: FormattedError, span: Span): DeclarationError {
636640
return {message: error.chain ? convertChain(error.chain) : error.message, span};
637-
}
641+
}

packages/language-service/test/diagnostics_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ describe('diagnostics', () => {
248248
template: \`
249249
<div *ngIf="comps | async; let comps; else loading">
250250
</div>
251-
<ng-template #loading>Loading comps...</ng-template>
251+
<ng-template #loading>Loading comps...</ng-template>
252252
\`
253253
})
254254
export class MyComponent {}

packages/language-service/test/typescript_host_spec.ts

+16
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@ describe('completions', () => {
4646
ngHost = new TypeScriptServiceHost(host, service);
4747
expect(() => ngHost.getAnalyzedModules()).not.toThrow();
4848
});
49+
50+
it('should clear the caches if program changes', () => {
51+
// First create a TypescriptHost with empty script names
52+
host = new MockTypescriptHost([], toh);
53+
service = ts.createLanguageService(host);
54+
ngHost = new TypeScriptServiceHost(host, service);
55+
expect(ngHost.getAnalyzedModules().ngModules).toEqual([]);
56+
// Now add a script, this would change the program
57+
const fileName = '/app/main.ts';
58+
const content = (host as MockTypescriptHost).getFileContent(fileName) !;
59+
(host as MockTypescriptHost).addScript(fileName, content);
60+
// If the caches are not cleared, we would get back an empty array.
61+
// But if the caches are cleared then the analyzed modules will be non-empty.
62+
expect(ngHost.getAnalyzedModules().ngModules.length).not.toEqual(0);
63+
});
64+
4965
});

0 commit comments

Comments
 (0)