diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts
index 04d383748c..2de7eeb021 100644
--- a/src/services/findAllReferences.ts
+++ b/src/services/findAllReferences.ts
@@ -1435,22 +1435,27 @@ namespace ts.FindAllReferences.Core {
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
if (bindingElementPropertySymbol) {
result.push(bindingElementPropertySymbol);
+ addRootSymbols(bindingElementPropertySymbol);
}
- // If this is a union property, add all the symbols from all its source symbols in all unioned types.
- // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
- for (const rootSymbol of checker.getRootSymbols(symbol)) {
- if (rootSymbol !== symbol) {
- result.push(rootSymbol);
- }
-
- // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
- if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
- getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
- }
- }
+ addRootSymbols(symbol);
return result;
+
+ function addRootSymbols(sym: Symbol): void {
+ // If this is a union property, add all the symbols from all its source symbols in all unioned types.
+ // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
+ for (const rootSymbol of checker.getRootSymbols(sym)) {
+ if (rootSymbol !== sym) {
+ result.push(rootSymbol);
+ }
+
+ // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
+ if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
+ getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
+ }
+ }
+ }
}
/**
@@ -1542,34 +1547,39 @@ namespace ts.FindAllReferences.Core {
// then include the binding element in the related symbols
// let { a } : { a };
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker);
- if (bindingElementPropertySymbol && search.includes(bindingElementPropertySymbol)) {
- return bindingElementPropertySymbol;
+ if (bindingElementPropertySymbol) {
+ const fromBindingElement = findRootSymbol(bindingElementPropertySymbol);
+ if (fromBindingElement) return fromBindingElement;
}
- // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
- // Or a union property, use its underlying unioned symbols
- return forEach(state.checker.getRootSymbols(referenceSymbol), rootSymbol => {
- // if it is in the list, then we are done
- if (search.includes(rootSymbol)) {
- return rootSymbol;
- }
+ return findRootSymbol(referenceSymbol);
- // Finally, try all properties with the same name in any type the containing type extended or implemented, and
- // see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
- // parent symbol
- if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
- // Parents will only be defined if implementations is true
- if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) {
- return undefined;
+ function findRootSymbol(sym: Symbol): Symbol | undefined {
+ // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
+ // Or a union property, use its underlying unioned symbols
+ return forEach(state.checker.getRootSymbols(sym), rootSymbol => {
+ // if it is in the list, then we are done
+ if (search.includes(rootSymbol)) {
+ return rootSymbol;
}
- const result: Symbol[] = [];
- getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker);
- return find(result, search.includes);
- }
+ // Finally, try all properties with the same name in any type the containing type extended or implemented, and
+ // see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
+ // parent symbol
+ if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
+ // Parents will only be defined if implementations is true
+ if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) {
+ return undefined;
+ }
- return undefined;
- });
+ const result: Symbol[] = [];
+ getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker);
+ return find(result, search.includes);
+ }
+
+ return undefined;
+ });
+ }
}
function getNameFromObjectLiteralElement(node: ObjectLiteralElement): string {
diff --git a/tests/cases/fourslash/findAllRefsDestructureGeneric.ts b/tests/cases/fourslash/findAllRefsDestructureGeneric.ts
new file mode 100644
index 0000000000..f3d4635ceb
--- /dev/null
+++ b/tests/cases/fourslash/findAllRefsDestructureGeneric.ts
@@ -0,0 +1,15 @@
+///
+
+////interface I {
+//// [|{| "isWriteAccess": true, "isDefinition": true |}x|]: boolean;
+////}
+////declare const i: I;
+////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } = i;
+
+const [r0, r1] = test.ranges();
+
+verify.referenceGroups(r0, [{ definition: "(property) I.x: boolean", ranges: [r0, r1] }]);
+verify.referenceGroups(r1, [
+ { definition: "(property) I.x: boolean", ranges: [r0] },
+ { definition: "const x: boolean", ranges: [r1] }
+]);
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts
index 7725b2e94f..58814b45e9 100644
--- a/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts
@@ -1,5 +1,10 @@
///
-////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { x: 1, y: 2 };
-////const z = [|{| "isDefinition": false |}x|];
+////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: 1, y: 2 };
+////const z = [|x|];
-verify.singleReferenceGroup("const x: number");
+const [r0, r1, r2] = test.ranges();
+verify.referenceGroups([r0, r2], [
+ { definition: "const x: number", ranges: [r0, r2] },
+ { definition: "(property) x: number", ranges: [r1] },
+]);
+verify.referenceGroups(r1, [{ definition: "(property) x: number", ranges: [r0, r1, r2] }]);