Skip to content

Commit 23f793f

Browse files
author
Andy
authored
findAllReferences: Handle root symbols of binding element property symbol (#17738)
1 parent 0434fe7 commit 23f793f

File tree

3 files changed

+66
-36
lines changed

3 files changed

+66
-36
lines changed

src/services/findAllReferences.ts

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,22 +1435,27 @@ namespace ts.FindAllReferences.Core {
14351435
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
14361436
if (bindingElementPropertySymbol) {
14371437
result.push(bindingElementPropertySymbol);
1438+
addRootSymbols(bindingElementPropertySymbol);
14381439
}
14391440

1440-
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
1441-
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
1442-
for (const rootSymbol of checker.getRootSymbols(symbol)) {
1443-
if (rootSymbol !== symbol) {
1444-
result.push(rootSymbol);
1445-
}
1441+
addRootSymbols(symbol);
1442+
1443+
return result;
1444+
1445+
function addRootSymbols(sym: Symbol): void {
1446+
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
1447+
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
1448+
for (const rootSymbol of checker.getRootSymbols(sym)) {
1449+
if (rootSymbol !== sym) {
1450+
result.push(rootSymbol);
1451+
}
14461452

1447-
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
1448-
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
1449-
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
1453+
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
1454+
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
1455+
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
1456+
}
14501457
}
14511458
}
1452-
1453-
return result;
14541459
}
14551460

14561461
/**
@@ -1542,34 +1547,39 @@ namespace ts.FindAllReferences.Core {
15421547
// then include the binding element in the related symbols
15431548
// let { a } : { a };
15441549
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker);
1545-
if (bindingElementPropertySymbol && search.includes(bindingElementPropertySymbol)) {
1546-
return bindingElementPropertySymbol;
1550+
if (bindingElementPropertySymbol) {
1551+
const fromBindingElement = findRootSymbol(bindingElementPropertySymbol);
1552+
if (fromBindingElement) return fromBindingElement;
15471553
}
15481554

1549-
// Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
1550-
// Or a union property, use its underlying unioned symbols
1551-
return forEach(state.checker.getRootSymbols(referenceSymbol), rootSymbol => {
1552-
// if it is in the list, then we are done
1553-
if (search.includes(rootSymbol)) {
1554-
return rootSymbol;
1555-
}
1555+
return findRootSymbol(referenceSymbol);
15561556

1557-
// Finally, try all properties with the same name in any type the containing type extended or implemented, and
1558-
// see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
1559-
// parent symbol
1560-
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
1561-
// Parents will only be defined if implementations is true
1562-
if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) {
1563-
return undefined;
1557+
function findRootSymbol(sym: Symbol): Symbol | undefined {
1558+
// Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
1559+
// Or a union property, use its underlying unioned symbols
1560+
return forEach(state.checker.getRootSymbols(sym), rootSymbol => {
1561+
// if it is in the list, then we are done
1562+
if (search.includes(rootSymbol)) {
1563+
return rootSymbol;
15641564
}
15651565

1566-
const result: Symbol[] = [];
1567-
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker);
1568-
return find(result, search.includes);
1569-
}
1566+
// Finally, try all properties with the same name in any type the containing type extended or implemented, and
1567+
// see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
1568+
// parent symbol
1569+
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
1570+
// Parents will only be defined if implementations is true
1571+
if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) {
1572+
return undefined;
1573+
}
15701574

1571-
return undefined;
1572-
});
1575+
const result: Symbol[] = [];
1576+
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker);
1577+
return find(result, search.includes);
1578+
}
1579+
1580+
return undefined;
1581+
});
1582+
}
15731583
}
15741584

15751585
function getNameFromObjectLiteralElement(node: ObjectLiteralElement): string {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////interface I<T> {
4+
//// [|{| "isWriteAccess": true, "isDefinition": true |}x|]: boolean;
5+
////}
6+
////declare const i: I<number>;
7+
////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } = i;
8+
9+
const [r0, r1] = test.ranges();
10+
11+
verify.referenceGroups(r0, [{ definition: "(property) I<T>.x: boolean", ranges: [r0, r1] }]);
12+
verify.referenceGroups(r1, [
13+
{ definition: "(property) I<T>.x: boolean", ranges: [r0] },
14+
{ definition: "const x: boolean", ranges: [r1] }
15+
]);
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
/// <reference path='fourslash.ts' />
2-
////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { x: 1, y: 2 };
3-
////const z = [|{| "isDefinition": false |}x|];
2+
////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: 1, y: 2 };
3+
////const z = [|x|];
44

5-
verify.singleReferenceGroup("const x: number");
5+
const [r0, r1, r2] = test.ranges();
6+
verify.referenceGroups([r0, r2], [
7+
{ definition: "const x: number", ranges: [r0, r2] },
8+
{ definition: "(property) x: number", ranges: [r1] },
9+
]);
10+
verify.referenceGroups(r1, [{ definition: "(property) x: number", ranges: [r0, r1, r2] }]);

0 commit comments

Comments
 (0)