diff --git a/packages/language-service/ivy/language_service.ts b/packages/language-service/ivy/language_service.ts index 42bc71cb08..26fa982920 100644 --- a/packages/language-service/ivy/language_service.ts +++ b/packages/language-service/ivy/language_service.ts @@ -26,7 +26,7 @@ import {CompilerFactory} from './compiler_factory'; import {CompletionBuilder, CompletionNodeContext} from './completions'; import {DefinitionBuilder} from './definitions'; import {QuickInfoBuilder} from './quick_info'; -import {ReferencesAndRenameBuilder} from './references_and_rename'; +import {ReferencesBuilder, RenameBuilder} from './references_and_rename'; import {getSignatureHelp} from './signature_help'; import {getTargetAtPosition, TargetContext, TargetNodeKind} from './template_target'; import {findTightestNode, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue} from './ts_utils'; @@ -168,14 +168,14 @@ export class LanguageService { getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[]|undefined { return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => { - return new ReferencesAndRenameBuilder(this.programDriver, this.tsLS, compiler) + return new ReferencesBuilder(this.programDriver, this.tsLS, compiler) .getReferencesAtPosition(fileName, position); }); } getRenameInfo(fileName: string, position: number): ts.RenameInfo { return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => { - const renameInfo = new ReferencesAndRenameBuilder(this.programDriver, this.tsLS, compiler) + const renameInfo = new RenameBuilder(this.programDriver, this.tsLS, compiler) .getRenameInfo(absoluteFrom(fileName), position); if (!renameInfo.canRename) { return renameInfo; @@ -191,7 +191,7 @@ export class LanguageService { findRenameLocations(fileName: string, position: number): readonly ts.RenameLocation[]|undefined { return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => { - return new ReferencesAndRenameBuilder(this.programDriver, this.tsLS, compiler) + return new RenameBuilder(this.programDriver, this.tsLS, compiler) .findRenameLocations(fileName, position); }); } diff --git a/packages/language-service/ivy/references_and_rename.ts b/packages/language-service/ivy/references_and_rename.ts index 5847c366f3..4ad85509fe 100644 --- a/packages/language-service/ivy/references_and_rename.ts +++ b/packages/language-service/ivy/references_and_rename.ts @@ -16,6 +16,61 @@ import {convertToTemplateDocumentSpan, createLocationKey, getRenameTextAndSpanAt import {findTightestNode} from './ts_utils'; 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) {} + + getReferencesAtPosition(filePath: string, position: number): ts.ReferenceEntry[]|undefined { + this.ttc.generateAllTypeCheckBlocks(); + const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler); + if (templateInfo === undefined) { + return this.getReferencesAtTypescriptPosition(filePath, position); + } + return this.getReferencesAtTemplatePosition(templateInfo, position); + } + + private getReferencesAtTemplatePosition(templateInfo: TemplateInfo, position: number): + ts.ReferenceEntry[]|undefined { + const allTargetDetails = getTargetDetailsAtTemplatePosition(templateInfo, position, this.ttc); + if (allTargetDetails === null) { + return undefined; + } + const allReferences: ts.ReferenceEntry[] = []; + for (const targetDetails of allTargetDetails) { + for (const location of targetDetails.typescriptLocations) { + const refs = this.getReferencesAtTypescriptPosition(location.fileName, location.position); + if (refs !== undefined) { + allReferences.push(...refs); + } + } + } + return allReferences.length > 0 ? allReferences : undefined; + } + + private getReferencesAtTypescriptPosition(fileName: string, position: number): + ts.ReferenceEntry[]|undefined { + const refs = this.tsLS.getReferencesAtPosition(fileName, position); + if (refs === undefined) { + return undefined; + } + + const entries: Map = new Map(); + for (const ref of refs) { + if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(ref.fileName))) { + const entry = convertToTemplateDocumentSpan(ref, this.ttc, this.driver.getProgram()); + if (entry !== null) { + entries.set(createLocationKey(entry), entry); + } + } else { + entries.set(createLocationKey(ref), ref); + } + } + return Array.from(entries.values()); + } +} enum RequestKind { Template, @@ -35,7 +90,8 @@ interface TypeScriptRequest { type RequestOrigin = TemplateRequest|TypeScriptRequest; -export class ReferencesAndRenameBuilder { + +export class RenameBuilder { private readonly ttc = this.compiler.getTemplateTypeChecker(); constructor( @@ -125,14 +181,6 @@ export class ReferencesAndRenameBuilder { return allRenameLocations.length > 0 ? allRenameLocations : undefined; } - private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null { - const sf = this.driver.getProgram().getSourceFile(filePath); - if (!sf) { - return null; - } - return findTightestNode(sf, position) ?? null; - } - findRenameLocationsAtTypescriptPosition( filePath: string, position: number, requestOrigin: RequestOrigin): readonly ts.RenameLocation[]|undefined { @@ -181,54 +229,11 @@ export class ReferencesAndRenameBuilder { }); } - getReferencesAtPosition(filePath: string, position: number): ts.ReferenceEntry[]|undefined { - this.ttc.generateAllTypeCheckBlocks(); - - return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => { - const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler); - if (templateInfo === undefined) { - return this.getReferencesAtTypescriptPosition(filePath, position); - } - return this.getReferencesAtTemplatePosition(templateInfo, position); - }); - } - - private getReferencesAtTemplatePosition(templateInfo: TemplateInfo, position: number): - ts.ReferenceEntry[]|undefined { - const allTargetDetails = getTargetDetailsAtTemplatePosition(templateInfo, position, this.ttc); - if (allTargetDetails === null) { - return undefined; + private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null { + const sf = this.driver.getProgram().getSourceFile(filePath); + if (!sf) { + return null; } - const allReferences: ts.ReferenceEntry[] = []; - for (const targetDetails of allTargetDetails) { - for (const location of targetDetails.typescriptLocations) { - const refs = this.getReferencesAtTypescriptPosition(location.fileName, location.position); - if (refs !== undefined) { - allReferences.push(...refs); - } - } - } - return allReferences.length > 0 ? allReferences : undefined; - } - - private getReferencesAtTypescriptPosition(fileName: string, position: number): - ts.ReferenceEntry[]|undefined { - const refs = this.tsLS.getReferencesAtPosition(fileName, position); - if (refs === undefined) { - return undefined; - } - - const entries: Map = new Map(); - for (const ref of refs) { - if (this.ttc.isTrackedTypeCheckFile(absoluteFrom(ref.fileName))) { - const entry = convertToTemplateDocumentSpan(ref, this.ttc, this.driver.getProgram()); - if (entry !== null) { - entries.set(createLocationKey(entry), entry); - } - } else { - entries.set(createLocationKey(ref), ref); - } - } - return Array.from(entries.values()); + return findTightestNode(sf, position) ?? null; } } \ No newline at end of file