Skip to content

Commit

Permalink
refactor(language-service): Separate reference and rename capabilities (
Browse files Browse the repository at this point in the history
#40523)

This commit separates the reference and rename functions into separate builders so it's easier
to locate functions specific to each

PR Close #40523
  • Loading branch information
atscott authored and alxhub committed May 6, 2021
1 parent 9bc8b34 commit c1bcbeb
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 61 deletions.
8 changes: 4 additions & 4 deletions packages/language-service/ivy/language_service.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -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);
});
}
Expand Down
119 changes: 62 additions & 57 deletions packages/language-service/ivy/references_and_rename.ts
Expand Up @@ -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<string, ts.ReferenceEntry> = 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,
Expand All @@ -35,7 +90,8 @@ interface TypeScriptRequest {

type RequestOrigin = TemplateRequest|TypeScriptRequest;

export class ReferencesAndRenameBuilder {

export class RenameBuilder {
private readonly ttc = this.compiler.getTemplateTypeChecker();

constructor(
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
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<string, ts.ReferenceEntry> = 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);
}
private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null {
const sf = this.driver.getProgram().getSourceFile(filePath);
if (!sf) {
return null;
}
return Array.from(entries.values());
return findTightestNode(sf, position) ?? null;
}
}

0 comments on commit c1bcbeb

Please sign in to comment.