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
This commit is contained in:
parent
2d44a2ab0d
commit
43e1520260
|
@ -140,7 +140,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnalyzedModules(): NgAnalyzedModules {
|
getAnalyzedModules(): NgAnalyzedModules {
|
||||||
this.validate();
|
this.updateAnalyzedModules();
|
||||||
return this.ensureAnalyzedModules();
|
return this.ensureAnalyzedModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
|
|
||||||
private validate() {
|
private validate() {
|
||||||
const program = this.program;
|
const program = this.program;
|
||||||
if (this._staticSymbolResolver && this.lastProgram != program) {
|
if (this.lastProgram !== program) {
|
||||||
// Invalidate file that have changed in the static symbol resolver
|
// Invalidate file that have changed in the static symbol resolver
|
||||||
const invalidateFile = (fileName: string) =>
|
const invalidateFile = (fileName: string) =>
|
||||||
this._staticSymbolResolver.invalidateFile(fileName);
|
this._staticSymbolResolver.invalidateFile(fileName);
|
||||||
|
@ -253,14 +253,18 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
||||||
const lastVersion = this.fileVersions.get(fileName);
|
const lastVersion = this.fileVersions.get(fileName);
|
||||||
if (version != lastVersion) {
|
if (version != lastVersion) {
|
||||||
this.fileVersions.set(fileName, version);
|
this.fileVersions.set(fileName, version);
|
||||||
invalidateFile(fileName);
|
if (this._staticSymbolResolver) {
|
||||||
|
invalidateFile(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove file versions that are no longer in the file and invalidate them.
|
// Remove file versions that are no longer in the file and invalidate them.
|
||||||
const missing = Array.from(this.fileVersions.keys()).filter(f => !seen.has(f));
|
const missing = Array.from(this.fileVersions.keys()).filter(f => !seen.has(f));
|
||||||
missing.forEach(f => this.fileVersions.delete(f));
|
missing.forEach(f => this.fileVersions.delete(f));
|
||||||
missing.forEach(invalidateFile);
|
if (this._staticSymbolResolver) {
|
||||||
|
missing.forEach(invalidateFile);
|
||||||
|
}
|
||||||
|
|
||||||
this.lastProgram = program;
|
this.lastProgram = program;
|
||||||
}
|
}
|
||||||
|
@ -634,4 +638,4 @@ function convertChain(chain: FormattedMessageChain): DiagnosticMessageChain {
|
||||||
|
|
||||||
function errorToDiagnosticWithChain(error: FormattedError, span: Span): DeclarationError {
|
function errorToDiagnosticWithChain(error: FormattedError, span: Span): DeclarationError {
|
||||||
return {message: error.chain ? convertChain(error.chain) : error.message, span};
|
return {message: error.chain ? convertChain(error.chain) : error.message, span};
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ describe('diagnostics', () => {
|
||||||
template: \`
|
template: \`
|
||||||
<div *ngIf="comps | async; let comps; else loading">
|
<div *ngIf="comps | async; let comps; else loading">
|
||||||
</div>
|
</div>
|
||||||
<ng-template #loading>Loading comps...</ng-template>
|
<ng-template #loading>Loading comps...</ng-template>
|
||||||
\`
|
\`
|
||||||
})
|
})
|
||||||
export class MyComponent {}
|
export class MyComponent {}
|
||||||
|
|
|
@ -46,4 +46,20 @@ describe('completions', () => {
|
||||||
ngHost = new TypeScriptServiceHost(host, service);
|
ngHost = new TypeScriptServiceHost(host, service);
|
||||||
expect(() => ngHost.getAnalyzedModules()).not.toThrow();
|
expect(() => ngHost.getAnalyzedModules()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should clear the caches if program changes', () => {
|
||||||
|
// First create a TypescriptHost with empty script names
|
||||||
|
host = new MockTypescriptHost([], toh);
|
||||||
|
service = ts.createLanguageService(host);
|
||||||
|
ngHost = new TypeScriptServiceHost(host, service);
|
||||||
|
expect(ngHost.getAnalyzedModules().ngModules).toEqual([]);
|
||||||
|
// Now add a script, this would change the program
|
||||||
|
const fileName = '/app/main.ts';
|
||||||
|
const content = (host as MockTypescriptHost).getFileContent(fileName) !;
|
||||||
|
(host as MockTypescriptHost).addScript(fileName, content);
|
||||||
|
// If the caches are not cleared, we would get back an empty array.
|
||||||
|
// But if the caches are cleared then the analyzed modules will be non-empty.
|
||||||
|
expect(ngHost.getAnalyzedModules().ngModules.length).not.toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue