Skip to content

Commit 0a72568

Browse files
author
Andy
authored
findAllReferences: Make definition info independent of search location (microsoft#21748)
1 parent bb05122 commit 0a72568

35 files changed

+83
-177
lines changed

src/services/findAllReferences.ts

+38-44
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ts.FindAllReferences {
88
}
99

1010
export type Definition =
11-
| { type: "symbol"; symbol: Symbol; node: Node }
11+
| { type: "symbol"; symbol: Symbol }
1212
| { type: "label"; node: Identifier }
1313
| { type: "keyword"; node: ts.Node }
1414
| { type: "this"; node: ts.Node }
@@ -42,11 +42,12 @@ namespace ts.FindAllReferences {
4242
}
4343

4444
export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
45-
const referencedSymbols = findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position);
45+
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
46+
const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, /*options*/ {});
4647
const checker = program.getTypeChecker();
4748
return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined<SymbolAndEntries, ReferencedSymbol>(referencedSymbols, ({ definition, references }) =>
4849
// Only include referenced symbols that have a valid definition.
49-
definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker), references: references.map(toReferenceEntry) });
50+
definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker, node), references: references.map(toReferenceEntry) });
5051
}
5152

5253
export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ImplementationLocation[] {
@@ -83,31 +84,26 @@ namespace ts.FindAllReferences {
8384
}
8485

8586
export function findReferencedEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): ReferenceEntry[] | undefined {
86-
const x = flattenEntries(findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position, options));
87-
return map(x, toReferenceEntry);
87+
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
88+
return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), toReferenceEntry);
8889
}
8990

9091
export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): Entry[] | undefined {
9192
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options));
9293
}
9394

94-
function findAllReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): SymbolAndEntries[] | undefined {
95-
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
96-
return Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options);
97-
}
98-
9995
function flattenEntries(referenceSymbols: SymbolAndEntries[]): Entry[] {
10096
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
10197
}
10298

103-
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker): ReferencedSymbolDefinitionInfo | undefined {
99+
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo | undefined {
104100
const info = (() => {
105101
switch (def.type) {
106102
case "symbol": {
107-
const { symbol, node } = def;
108-
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, node, checker);
103+
const { symbol } = def;
104+
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
109105
const name = displayParts.map(p => p.text).join("");
110-
return { node, name, kind, displayParts };
106+
return { node: symbol.declarations ? getNameOfDeclaration(first(symbol.declarations)) || first(symbol.declarations) : originalNode, name, kind, displayParts };
111107
}
112108
case "label": {
113109
const { node } = def;
@@ -129,13 +125,11 @@ namespace ts.FindAllReferences {
129125
const { node } = def;
130126
return { node, name: node.text, kind: ScriptElementKind.variableElement, displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)] };
131127
}
128+
default:
129+
return Debug.assertNever(def);
132130
}
133131
})();
134132

135-
if (!info) {
136-
return undefined;
137-
}
138-
139133
const { node, name, kind, displayParts } = info;
140134
const sourceFile = node.getSourceFile();
141135
return {
@@ -149,9 +143,11 @@ namespace ts.FindAllReferences {
149143
};
150144
}
151145

152-
function getDefinitionKindAndDisplayParts(symbol: Symbol, node: Node, checker: TypeChecker): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
146+
function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
147+
const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol);
148+
const enclosingDeclaration = firstOrUndefined(symbol.declarations) || node;
153149
const { displayParts, symbolKind } =
154-
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, node.getSourceFile(), getContainerNode(node), node);
150+
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, enclosingDeclaration.getSourceFile(), enclosingDeclaration, enclosingDeclaration, meaning);
155151
return { displayParts, kind: symbolKind };
156152
}
157153

@@ -186,7 +182,7 @@ namespace ts.FindAllReferences {
186182
function implementationKindDisplayParts(node: ts.Node, checker: ts.TypeChecker): { kind: ScriptElementKind, displayParts: SymbolDisplayPart[] } {
187183
const symbol = checker.getSymbolAtLocation(isDeclaration(node) && node.name ? node.name : node);
188184
if (symbol) {
189-
return getDefinitionKindAndDisplayParts(symbol, node, checker);
185+
return getDefinitionKindAndDisplayParts(symbol, checker, node);
190186
}
191187
else if (node.kind === SyntaxKind.ObjectLiteralExpression) {
192188
return {
@@ -317,10 +313,7 @@ namespace ts.FindAllReferences.Core {
317313
}
318314
}
319315

320-
return [{
321-
definition: { type: "symbol", symbol, node: symbol.valueDeclaration },
322-
references
323-
}];
316+
return [{ definition: { type: "symbol", symbol }, references }];
324317
}
325318

326319
/** getReferencedSymbols for special node kinds. */
@@ -357,13 +350,13 @@ namespace ts.FindAllReferences.Core {
357350
symbol = skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol;
358351

359352
// Compute the meaning from the location and the symbol it references
360-
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.declarations);
353+
const searchMeaning = getIntersectingMeaningFromDeclarations(node, symbol);
361354

362355
const result: SymbolAndEntries[] = [];
363356
const state = new State(sourceFiles, getSpecialSearchKind(node), checker, cancellationToken, searchMeaning, options, result);
364357

365358
if (node.kind === SyntaxKind.DefaultKeyword) {
366-
addReference(node, symbol, node, state);
359+
addReference(node, symbol, state);
367360
searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state);
368361
}
369362
else {
@@ -434,7 +427,6 @@ namespace ts.FindAllReferences.Core {
434427
/** If coming from an export, we will not recursively search for the imported symbol (since that's where we came from). */
435428
readonly comingFrom?: ImportExport;
436429

437-
readonly location: Node;
438430
readonly symbol: Symbol;
439431
readonly text: string;
440432
readonly escapedText: __String;
@@ -514,7 +506,7 @@ namespace ts.FindAllReferences.Core {
514506
const escapedText = escapeLeadingUnderscores(text);
515507
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
516508
return {
517-
location, symbol, comingFrom, text, escapedText, parents,
509+
symbol, comingFrom, text, escapedText, parents,
518510
includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol,
519511
};
520512
}
@@ -524,12 +516,12 @@ namespace ts.FindAllReferences.Core {
524516
* Callback to add references for a particular searched symbol.
525517
* This initializes a reference group, so only call this if you will add at least one reference.
526518
*/
527-
referenceAdder(searchSymbol: Symbol, searchLocation: Node): (node: Node) => void {
519+
referenceAdder(searchSymbol: Symbol): (node: Node) => void {
528520
const symbolId = getSymbolId(searchSymbol);
529521
let references = this.symbolIdToReferences[symbolId];
530522
if (!references) {
531523
references = this.symbolIdToReferences[symbolId] = [];
532-
this.result.push({ definition: { type: "symbol", symbol: searchSymbol, node: searchLocation }, references });
524+
this.result.push({ definition: { type: "symbol", symbol: searchSymbol }, references });
533525
}
534526
return node => references.push(nodeEntry(node));
535527
}
@@ -559,7 +551,7 @@ namespace ts.FindAllReferences.Core {
559551

560552
// For `import { foo as bar }` just add the reference to `foo`, and don't otherwise search in the file.
561553
if (singleReferences.length) {
562-
const addRef = state.referenceAdder(exportSymbol, exportLocation);
554+
const addRef = state.referenceAdder(exportSymbol);
563555
for (const singleRef of singleReferences) {
564556
addRef(singleRef);
565557
}
@@ -862,7 +854,7 @@ namespace ts.FindAllReferences.Core {
862854

863855
switch (state.specialSearchKind) {
864856
case SpecialSearchKind.None:
865-
addReference(referenceLocation, relatedSymbol, search.location, state);
857+
addReference(referenceLocation, relatedSymbol, state);
866858
break;
867859
case SpecialSearchKind.Constructor:
868860
addConstructorReferences(referenceLocation, sourceFile, search, state);
@@ -896,7 +888,7 @@ namespace ts.FindAllReferences.Core {
896888
}
897889

898890
if (!state.options.isForRename && state.markSeenReExportRHS(name)) {
899-
addReference(name, referenceSymbol, name, state);
891+
addReference(name, referenceSymbol, state);
900892
}
901893
}
902894
else {
@@ -920,7 +912,7 @@ namespace ts.FindAllReferences.Core {
920912
}
921913

922914
function addRef() {
923-
addReference(referenceLocation, localSymbol, search.location, state);
915+
addReference(referenceLocation, localSymbol, state);
924916
}
925917
}
926918

@@ -969,12 +961,12 @@ namespace ts.FindAllReferences.Core {
969961
* position of property accessing, the referenceEntry of such position will be handled in the first case.
970962
*/
971963
if (!(flags & SymbolFlags.Transient) && search.includes(shorthandValueSymbol)) {
972-
addReference(getNameOfDeclaration(valueDeclaration), shorthandValueSymbol, search.location, state);
964+
addReference(getNameOfDeclaration(valueDeclaration), shorthandValueSymbol, state);
973965
}
974966
}
975967

976-
function addReference(referenceLocation: Node, relatedSymbol: Symbol, searchLocation: Node, state: State): void {
977-
const addRef = state.referenceAdder(relatedSymbol, searchLocation);
968+
function addReference(referenceLocation: Node, relatedSymbol: Symbol, state: State): void {
969+
const addRef = state.referenceAdder(relatedSymbol);
978970
if (state.options.implementations) {
979971
addImplementationReferences(referenceLocation, addRef, state);
980972
}
@@ -986,10 +978,10 @@ namespace ts.FindAllReferences.Core {
986978
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
987979
function addConstructorReferences(referenceLocation: Node, sourceFile: SourceFile, search: Search, state: State): void {
988980
if (isNewExpressionTarget(referenceLocation)) {
989-
addReference(referenceLocation, search.symbol, search.location, state);
981+
addReference(referenceLocation, search.symbol, state);
990982
}
991983

992-
const pusher = () => state.referenceAdder(search.symbol, search.location);
984+
const pusher = () => state.referenceAdder(search.symbol);
993985

994986
if (isClassLike(referenceLocation.parent)) {
995987
Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation);
@@ -1006,11 +998,11 @@ namespace ts.FindAllReferences.Core {
1006998
}
1007999

10081000
function addClassStaticThisReferences(referenceLocation: Node, search: Search, state: State): void {
1009-
addReference(referenceLocation, search.symbol, search.location, state);
1001+
addReference(referenceLocation, search.symbol, state);
10101002
if (isClassLike(referenceLocation.parent)) {
10111003
Debug.assert(referenceLocation.parent.name === referenceLocation);
10121004
// This is the class declaration.
1013-
addStaticThisReferences(referenceLocation.parent, state.referenceAdder(search.symbol, search.location));
1005+
addStaticThisReferences(referenceLocation.parent, state.referenceAdder(search.symbol));
10141006
}
10151007
}
10161008

@@ -1300,7 +1292,7 @@ namespace ts.FindAllReferences.Core {
13001292
return container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
13011293
});
13021294

1303-
return [{ definition: { type: "symbol", symbol: searchSpaceNode.symbol, node: superKeyword }, references }];
1295+
return [{ definition: { type: "symbol", symbol: searchSpaceNode.symbol }, references }];
13041296
}
13051297

13061298
function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] {
@@ -1645,7 +1637,9 @@ namespace ts.FindAllReferences.Core {
16451637
* module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
16461638
* do not intersect in any of the three spaces.
16471639
*/
1648-
function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning {
1640+
export function getIntersectingMeaningFromDeclarations(node: Node, symbol: Symbol): SemanticMeaning {
1641+
let meaning = getMeaningFromLocation(node);
1642+
const { declarations } = symbol;
16491643
if (declarations) {
16501644
let lastIterationMeaning: SemanticMeaning;
16511645
do {

tests/cases/fourslash/cancellationWhenfindingAllRefsOnDefinition.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,5 @@ cancellation.resetCancelled();
3333
checkRefs();
3434

3535
function checkRefs() {
36-
const ranges = test.ranges();
37-
const [r0, r1] = ranges;
38-
verify.referenceGroups(r0, [{ definition: "(method) Test.start(): this", ranges }]);
39-
verify.referenceGroups(r1, [{ definition: "(method) Second.Test.start(): Second.Test", ranges }]);
36+
verify.singleReferenceGroup("(method) Test.start(): this");
4037
}

tests/cases/fourslash/findAllReferencesOfConstructor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242

4343
const ranges = test.ranges();
4444
const [a0, a1, a2, a3, a4, b0, c0, d0, d1] = ranges;
45-
verify.referenceGroups([a0, a2], defs("constructor C(n: number): C (+1 overload)"));
46-
verify.referenceGroups(a1, defs("constructor C(): C (+1 overload)"));
45+
verify.referenceGroups([a0, a2], defs("class C"));
46+
verify.referenceGroups(a1, defs("class C"));
4747

4848
function defs(definition: string) {
4949
return [

tests/cases/fourslash/findAllReferencesOfConstructor_badOverload.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
//// [|constructor|](){}
66
////}
77

8-
verify.singleReferenceGroup("constructor C(n: number): C");
8+
verify.singleReferenceGroup("class C");

tests/cases/fourslash/findAllRefsDefinition.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
////const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
44
////[|x|];
55

6-
// TODO: GH#21301
7-
86
const ranges = test.ranges();
9-
const [r0, r1] = ranges;
10-
verify.referenceGroups(r1, [
7+
verify.referenceGroups(ranges, [
118
{
12-
definition: { text: "const x: 0", range: r1 },
9+
definition: { text: "const x: 0", range: ranges[0] },
1310
ranges,
1411
},
1512
])

tests/cases/fourslash/findAllRefsExportDefaultClassConstructor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
//// [|constructor|]() {}
33
////}
44

5-
verify.singleReferenceGroup("constructor default(): default");
5+
verify.singleReferenceGroup("class default");

tests/cases/fourslash/findAllRefsForDefaultExport.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ verify.referenceGroups(r0, [
1616
{ definition: "function f(): void", ranges: [r0] },
1717
{ definition: "(alias) function g(): void\nimport g", ranges: [r1, r2] }
1818
]);
19-
verify.referenceGroups(r1, [{ definition: "(alias) function g(): void\nimport g", ranges: [r1, r2] }]);
20-
verify.referenceGroups(r2, [{ definition: "(alias) g(): void\nimport g", ranges: [r1, r2] }]);
19+
verify.singleReferenceGroup("(alias) function g(): void\nimport g", [r1, r2]);
2120

2221
verify.goToDefinition("ref", "def");

tests/cases/fourslash/findAllRefsForDefaultExport01.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,4 @@
77
////
88
////var y = new [|DefaultExportedClass|];
99

10-
const ranges = test.ranges();
11-
const [r0, r1, r2] = ranges;
12-
verify.referenceGroups([r0, r1], [{ definition: "class DefaultExportedClass", ranges }]);
13-
verify.referenceGroups(r2, [{ definition: "constructor DefaultExportedClass(): DefaultExportedClass", ranges }]);
10+
verify.singleReferenceGroup("class DefaultExportedClass");

tests/cases/fourslash/findAllRefsForDefaultExport03.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,4 @@
1414
//// var local = 100;
1515
////}
1616

17-
const ranges = test.ranges();
18-
const [r0, r1, r2, r3, r4] = ranges;
19-
verify.referenceGroups([r0, r3], [{ definition: "function f(): number\nnamespace f", ranges }]);
20-
verify.referenceGroups([r1, r2, r4], [{ definition: "namespace f\nfunction f(): number", ranges }]);
17+
verify.singleReferenceGroup("namespace f\nfunction f(): number");

0 commit comments

Comments
 (0)