findAllReferences: Handle root symbols of binding element property symbol (#17738)

This commit is contained in:
Andy 2017-09-07 07:23:06 -07:00 committed by GitHub
parent 0434fe797a
commit 23f793fc3e
3 changed files with 67 additions and 37 deletions

View file

@ -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 {

View 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] }
]);

View file

@ -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] }]);