findAllReferences: Be consistent how we handle unions in root symobls (#23002)

This commit is contained in:
Andy 2018-04-05 10:55:55 -07:00 committed by GitHub
parent 4f80fbddc2
commit f61f12613c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 14 additions and 25 deletions

View file

@ -1535,32 +1535,25 @@ namespace ts.FindAllReferences.Core {
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 firstDefined(checker.getRootSymbols(sym), rootSymbol => {
// if it is in the list, then we are done
if (search.includes(rootSymbol)) {
return firstDefined(checker.getRootSymbols(sym), rootSymbol =>
isMatchingRootSymbol(search, rootSymbol, state.inheritsFromCache, checker)
// For a root symbol that is a component of a union or intersection, use the original (union/intersection) symbol.
// That we when a symbol references the whole union we avoid claiming it references some particular member of the union.
// For a transient symbol we want to use the root symbol instead.
return getCheckFlags(sym) & CheckFlags.Synthetic ? sym : rootSymbol;
}
// 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, checker))) {
return undefined;
}
return getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker).some(search.includes) ? rootSymbol : undefined;
}
return undefined;
});
? getCheckFlags(sym) & CheckFlags.Synthetic ? sym : rootSymbol
: undefined);
}
}
function isMatchingRootSymbol(search: Search, rootSymbol: Symbol, inheritsFromCache: Map<boolean>, checker: TypeChecker): boolean {
return search.includes(rootSymbol)
|| rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)
// If we were passed a parent symbol (if 'implementations' set), only include types that are subtypes of the parent symbol.
&& !(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent, parent, inheritsFromCache, checker)))
// Try all properties with the same name in any type the containing type extended or implemented.
&& getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker).some(search.includes);
}
/** Gets all symbols for one property. Does not get symbols for every property. */
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, checker: TypeChecker): ReadonlyArray<Symbol> {
const contextualType = checker.getContextualType(<ObjectLiteralExpression>node.parent);

View file

@ -27,11 +27,7 @@ verify.referenceGroups(one, [
{ definition: "(property) a: number", ranges: [one] },
{ definition: "(property) a: string | number", ranges: [x] },
]);
verify.referenceGroups(base, [
{ definition: "(property) Base.a: string", ranges: [base] },
{ definition: "(property) HasAOrB.a: string", ranges: [hasAOrB, x] },
]);
verify.referenceGroups(hasAOrB, [
verify.referenceGroups([base, hasAOrB], [
{ definition: "(property) Base.a: string", ranges: [base] },
{ definition: "(property) HasAOrB.a: string", ranges: [hasAOrB] },
{ definition: "(property) a: string | number", ranges: [x] },