Skip to content

Commit

Permalink
refactor(language-service): use compiler for current program instance (
Browse files Browse the repository at this point in the history
…#55097)

Within the language service, the Angular compiler instance can provide
access to the current TypeScript program via `getCurrentProgram`. By
using the compiler, the need to pass around the program driver is no longer
required and can also be removed as an instance field of the Angular language
service class. This change also provides a higher assurance that the correct
program is being used throughout each language service request.

PR Close #55097
  • Loading branch information
clydin authored and atscott committed Apr 8, 2024
1 parent faafadb commit ed6df68
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 30 deletions.
7 changes: 2 additions & 5 deletions packages/language-service/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {AST, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstElement, TmplAstNo
import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
import {isExternalResource} from '@angular/compiler-cli/src/ngtsc/metadata';
import {ProgramDriver} from '@angular/compiler-cli/src/ngtsc/program_driver';
import {DirectiveSymbol, DomBindingSymbol, ElementSymbol, Symbol, SymbolKind, TcbLocation, TemplateSymbol} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import ts from 'typescript';

Expand All @@ -32,9 +31,7 @@ interface HasTcbLocation {
export class DefinitionBuilder {
private readonly ttc = this.compiler.getTemplateTypeChecker();

constructor(
private readonly tsLS: ts.LanguageService, private readonly compiler: NgCompiler,
private readonly driver: ProgramDriver) {}
constructor(private readonly tsLS: ts.LanguageService, private readonly compiler: NgCompiler) {}

getDefinitionAndBoundSpan(fileName: string, position: number): ts.DefinitionInfoAndBoundSpan
|undefined {
Expand Down Expand Up @@ -160,7 +157,7 @@ export class DefinitionBuilder {
for (const info of definitionInfos) {
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(info.fileName))) {
const templateDefinitionInfo =
convertToTemplateDocumentSpan(info, this.ttc, this.driver.getProgram());
convertToTemplateDocumentSpan(info, this.ttc, this.compiler.getCurrentProgram());
if (templateDefinitionInfo === null) {
continue;
}
Expand Down
26 changes: 12 additions & 14 deletions packages/language-service/src/language_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ type LanguageServiceConfig = Omit<PluginConfig, 'angularOnly'>;
export class LanguageService {
private options: CompilerOptions;
readonly compilerFactory: CompilerFactory;
private readonly programDriver: ProgramDriver;
private readonly adapter: LanguageServiceAdapter;
private readonly codeFixes: CodeFixes;

constructor(
Expand All @@ -56,9 +54,9 @@ export class LanguageService {
}
logCompilerOptions(project, this.options);

this.programDriver = createProgramDriver(project);
this.adapter = new LanguageServiceAdapter(project);
this.compilerFactory = new CompilerFactory(this.adapter, this.programDriver, this.options);
const programDriver = createProgramDriver(project);
const adapter = new LanguageServiceAdapter(project);
this.compilerFactory = new CompilerFactory(adapter, programDriver, this.options);
this.codeFixes = new CodeFixes(tsLS, ALL_CODE_FIXES_METAS);
}

Expand Down Expand Up @@ -117,7 +115,7 @@ export class LanguageService {
if (!isInAngularContext(compiler.getCurrentProgram(), fileName, position)) {
return undefined;
}
return new DefinitionBuilder(this.tsLS, compiler, this.programDriver)
return new DefinitionBuilder(this.tsLS, compiler)
.getDefinitionAndBoundSpan(fileName, position);
});
}
Expand All @@ -128,7 +126,7 @@ export class LanguageService {
if (!isTemplateContext(compiler.getCurrentProgram(), fileName, position)) {
return undefined;
}
return new DefinitionBuilder(this.tsLS, compiler, this.programDriver)
return new DefinitionBuilder(this.tsLS, compiler)
.getTypeDefinitionsAtPosition(fileName, position);
});
}
Expand Down Expand Up @@ -169,16 +167,16 @@ export class LanguageService {

getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[]|undefined {
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
const results = new ReferencesBuilder(this.programDriver, this.tsLS, compiler)
.getReferencesAtPosition(fileName, position);
const results =
new ReferencesBuilder(this.tsLS, compiler).getReferencesAtPosition(fileName, position);
return results === undefined ? undefined : getUniqueLocations(results);
});
}

getRenameInfo(fileName: string, position: number): ts.RenameInfo {
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
const renameInfo = new RenameBuilder(this.programDriver, this.tsLS, compiler)
.getRenameInfo(absoluteFrom(fileName), position);
const renameInfo =
new RenameBuilder(this.tsLS, compiler).getRenameInfo(absoluteFrom(fileName), position);
if (!renameInfo.canRename) {
return renameInfo;
}
Expand All @@ -193,8 +191,8 @@ export class LanguageService {

findRenameLocations(fileName: string, position: number): readonly ts.RenameLocation[]|undefined {
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
const results = new RenameBuilder(this.programDriver, this.tsLS, compiler)
.findRenameLocations(fileName, position);
const results =
new RenameBuilder(this.tsLS, compiler).findRenameLocations(fileName, position);
return results === null ? undefined : getUniqueLocations(results);
});
}
Expand Down Expand Up @@ -355,7 +353,7 @@ export class LanguageService {
return this.withCompilerAndPerfTracing<GetTemplateLocationForComponentResponse>(
PerfPhase.LsComponentLocations, (compiler) => {
const nearestNode =
findTightestNodeAtPosition(this.programDriver.getProgram(), fileName, position);
findTightestNodeAtPosition(compiler.getCurrentProgram(), fileName, position);
if (nearestNode === undefined) {
return undefined;
}
Expand Down
18 changes: 7 additions & 11 deletions packages/language-service/src/references_and_rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
import {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
import {MetaKind, PipeMeta} from '@angular/compiler-cli/src/ngtsc/metadata';
import {PerfPhase} from '@angular/compiler-cli/src/ngtsc/perf';
import {ProgramDriver} from '@angular/compiler-cli/src/ngtsc/program_driver';
import {SymbolKind} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import ts from 'typescript';

Expand All @@ -21,9 +20,7 @@ import {getTemplateInfoAtPosition, TemplateInfo} from './utils';
export class ReferencesBuilder {
private readonly ttc = this.compiler.getTemplateTypeChecker();

constructor(
private readonly driver: ProgramDriver, private readonly tsLS: ts.LanguageService,
private readonly compiler: NgCompiler) {}
constructor(private readonly tsLS: ts.LanguageService, private readonly compiler: NgCompiler) {}

getReferencesAtPosition(filePath: string, position: number): ts.ReferenceEntry[]|undefined {
this.ttc.generateAllTypeCheckBlocks();
Expand Down Expand Up @@ -62,7 +59,8 @@ export class ReferencesBuilder {
const entries: ts.ReferenceEntry[] = [];
for (const ref of refs) {
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(ref.fileName))) {
const entry = convertToTemplateDocumentSpan(ref, this.ttc, this.driver.getProgram());
const entry =
convertToTemplateDocumentSpan(ref, this.ttc, this.compiler.getCurrentProgram());
if (entry !== null) {
entries.push(entry);
}
Expand Down Expand Up @@ -143,9 +141,7 @@ function isDirectRenameContext(context: RenameRequest): context is DirectFromTem
export class RenameBuilder {
private readonly ttc = this.compiler.getTemplateTypeChecker();

constructor(
private readonly driver: ProgramDriver, private readonly tsLS: ts.LanguageService,
private readonly compiler: NgCompiler) {}
constructor(private readonly tsLS: ts.LanguageService, private readonly compiler: NgCompiler) {}

getRenameInfo(filePath: string, position: number):
Omit<ts.RenameInfoSuccess, 'kind'|'kindModifiers'>|ts.RenameInfoFailure {
Expand Down Expand Up @@ -265,7 +261,7 @@ export class RenameBuilder {
for (const location of locations) {
if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(location.fileName))) {
const entry = convertToTemplateDocumentSpan(
location, this.ttc, this.driver.getProgram(), expectedRenameText);
location, this.ttc, this.compiler.getCurrentProgram(), expectedRenameText);
// There is no template node whose text matches the original rename request. Bail on
// renaming completely rather than providing incomplete results.
if (entry === null) {
Expand Down Expand Up @@ -293,7 +289,7 @@ export class RenameBuilder {
}

private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null {
const sf = this.driver.getProgram().getSourceFile(filePath);
const sf = this.compiler.getCurrentProgram().getSourceFile(filePath);
if (!sf) {
return null;
}
Expand Down Expand Up @@ -349,7 +345,7 @@ export class RenameBuilder {
!ts.isStringLiteral(meta.nameExpr)) {
return null;
}
const typeChecker = this.driver.getProgram().getTypeChecker();
const typeChecker = this.compiler.getCurrentProgram().getTypeChecker();
const memberMethods = collectMemberMethods(meta.ref.node, typeChecker) ?? [];
const pipeTransformNode: ts.MethodDeclaration|undefined =
memberMethods.find(m => m.name.getText() === 'transform');
Expand Down

0 comments on commit ed6df68

Please sign in to comment.