findAllReferences: Handle root symbols of binding element property symbol (#17738)
This commit is contained in:
parent
0434fe797a
commit
23f793fc3e
|
@ -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 {
|
||||
|
|
15
tests/cases/fourslash/findAllRefsDestructureGeneric.ts
Normal file
15
tests/cases/fourslash/findAllRefsDestructureGeneric.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I<T> {
|
||||
//// [|{| "isWriteAccess": true, "isDefinition": true |}x|]: boolean;
|
||||
////}
|
||||
////declare const i: I<number>;
|
||||
////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } = i;
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
|
||||
verify.referenceGroups(r0, [{ definition: "(property) I<T>.x: boolean", ranges: [r0, r1] }]);
|
||||
verify.referenceGroups(r1, [
|
||||
{ definition: "(property) I<T>.x: boolean", ranges: [r0] },
|
||||
{ definition: "const x: boolean", ranges: [r1] }
|
||||
]);
|
|
@ -1,5 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
////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] }]);
|
||||
|
|
Loading…
Reference in a new issue