refactor(language-service): Separate reference and rename capabilities (#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
This commit is contained in:
parent
9bc8b343ea
commit
c1bcbeb324
|
@ -26,7 +26,7 @@ import {CompilerFactory} from './compiler_factory';
|
||||||
import {CompletionBuilder, CompletionNodeContext} from './completions';
|
import {CompletionBuilder, CompletionNodeContext} from './completions';
|
||||||
import {DefinitionBuilder} from './definitions';
|
import {DefinitionBuilder} from './definitions';
|
||||||
import {QuickInfoBuilder} from './quick_info';
|
import {QuickInfoBuilder} from './quick_info';
|
||||||
import {ReferencesAndRenameBuilder} from './references_and_rename';
|
import {ReferencesBuilder, RenameBuilder} from './references_and_rename';
|
||||||
import {getSignatureHelp} from './signature_help';
|
import {getSignatureHelp} from './signature_help';
|
||||||
import {getTargetAtPosition, TargetContext, TargetNodeKind} from './template_target';
|
import {getTargetAtPosition, TargetContext, TargetNodeKind} from './template_target';
|
||||||
import {findTightestNode, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue} from './ts_utils';
|
import {findTightestNode, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue} from './ts_utils';
|
||||||
|
@ -168,14 +168,14 @@ export class LanguageService {
|
||||||
|
|
||||||
getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[]|undefined {
|
getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[]|undefined {
|
||||||
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
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);
|
.getReferencesAtPosition(fileName, position);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenameInfo(fileName: string, position: number): ts.RenameInfo {
|
getRenameInfo(fileName: string, position: number): ts.RenameInfo {
|
||||||
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
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);
|
.getRenameInfo(absoluteFrom(fileName), position);
|
||||||
if (!renameInfo.canRename) {
|
if (!renameInfo.canRename) {
|
||||||
return renameInfo;
|
return renameInfo;
|
||||||
|
@ -191,7 +191,7 @@ export class LanguageService {
|
||||||
|
|
||||||
findRenameLocations(fileName: string, position: number): readonly ts.RenameLocation[]|undefined {
|
findRenameLocations(fileName: string, position: number): readonly ts.RenameLocation[]|undefined {
|
||||||
return this.withCompilerAndPerfTracing(PerfPhase.LsReferencesAndRenames, (compiler) => {
|
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);
|
.findRenameLocations(fileName, position);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,61 @@ import {convertToTemplateDocumentSpan, createLocationKey, getRenameTextAndSpanAt
|
||||||
import {findTightestNode} from './ts_utils';
|
import {findTightestNode} from './ts_utils';
|
||||||
import {getTemplateInfoAtPosition, TemplateInfo} from './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 {
|
enum RequestKind {
|
||||||
Template,
|
Template,
|
||||||
|
@ -35,7 +90,8 @@ interface TypeScriptRequest {
|
||||||
|
|
||||||
type RequestOrigin = TemplateRequest|TypeScriptRequest;
|
type RequestOrigin = TemplateRequest|TypeScriptRequest;
|
||||||
|
|
||||||
export class ReferencesAndRenameBuilder {
|
|
||||||
|
export class RenameBuilder {
|
||||||
private readonly ttc = this.compiler.getTemplateTypeChecker();
|
private readonly ttc = this.compiler.getTemplateTypeChecker();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -125,14 +181,6 @@ export class ReferencesAndRenameBuilder {
|
||||||
return allRenameLocations.length > 0 ? allRenameLocations : undefined;
|
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(
|
findRenameLocationsAtTypescriptPosition(
|
||||||
filePath: string, position: number,
|
filePath: string, position: number,
|
||||||
requestOrigin: RequestOrigin): readonly ts.RenameLocation[]|undefined {
|
requestOrigin: RequestOrigin): readonly ts.RenameLocation[]|undefined {
|
||||||
|
@ -181,54 +229,11 @@ export class ReferencesAndRenameBuilder {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getReferencesAtPosition(filePath: string, position: number): ts.ReferenceEntry[]|undefined {
|
private getTsNodeAtPosition(filePath: string, position: number): ts.Node|null {
|
||||||
this.ttc.generateAllTypeCheckBlocks();
|
const sf = this.driver.getProgram().getSourceFile(filePath);
|
||||||
|
if (!sf) {
|
||||||
return this.compiler.perfRecorder.inPhase(PerfPhase.LsReferencesAndRenames, () => {
|
return null;
|
||||||
const templateInfo = getTemplateInfoAtPosition(filePath, position, this.compiler);
|
|
||||||
if (templateInfo === undefined) {
|
|
||||||
return this.getReferencesAtTypescriptPosition(filePath, position);
|
|
||||||
}
|
}
|
||||||
return this.getReferencesAtTemplatePosition(templateInfo, position);
|
return findTightestNode(sf, position) ?? null;
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue