Skip to content

Commit a5df301

Browse files
author
Andy
authored
Simplify getPropertySymbolsFromBaseTypes (#23004)
1 parent 31c3ef5 commit a5df301

File tree

1 file changed

+21
-38
lines changed

1 file changed

+21
-38
lines changed

src/services/findAllReferences.ts

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,7 @@ namespace ts.FindAllReferences.Core {
14381438

14391439
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
14401440
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
1441-
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
1441+
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, result);
14421442
}
14431443
}
14441444
}
@@ -1458,36 +1458,30 @@ namespace ts.FindAllReferences.Core {
14581458
* @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol.
14591459
* The value of previousIterationSymbol is undefined when the function is first called.
14601460
*/
1461-
function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, result: Push<Symbol>, previousIterationSymbolsCache: SymbolTable, checker: TypeChecker): void {
1462-
// If the current symbol is the same as the previous-iteration symbol, we can just return the symbol that has already been visited
1463-
// This is particularly important for the following cases, so that we do not infinitely visit the same symbol.
1464-
// For example:
1465-
// interface C extends C {
1466-
// /*findRef*/propName: string;
1467-
// }
1468-
// The first time getPropertySymbolsFromBaseTypes is called when finding-all-references at propName,
1469-
// the symbol argument will be the symbol of an interface "C" and previousIterationSymbol is undefined,
1470-
// the function will add any found symbol of the property-name, then its sub-routine will call
1471-
// getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already
1472-
// visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol.
1473-
if (!symbol || previousIterationSymbolsCache.has(symbol.escapedName)) {
1474-
return;
1475-
}
1461+
function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, checker: TypeChecker, result: Symbol[] = []): Symbol[] {
1462+
const seen = createMap<true>();
1463+
recur(symbol);
1464+
return result;
1465+
1466+
function recur(symbol: Symbol): void {
1467+
// Use `addToSeen` to ensure we don't infinitely recurse in this situation:
1468+
// interface C extends C {
1469+
// /*findRef*/propName: string;
1470+
// }
1471+
if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return;
14761472

1477-
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
14781473
for (const declaration of symbol.declarations) {
14791474
for (const typeReference of getAllSuperTypeNodes(declaration)) {
14801475
const type = checker.getTypeAtLocation(typeReference);
1481-
if (!type) continue;
1476+
if (!(type && type.symbol)) continue;
14821477

14831478
const propertySymbol = checker.getPropertyOfType(type, propertyName);
14841479
if (propertySymbol) {
14851480
result.push(...checker.getRootSymbols(propertySymbol));
14861481
}
14871482

14881483
// Visit the typeReference as well to see if it directly or indirectly use that property
1489-
previousIterationSymbolsCache.set(symbol.escapedName, symbol);
1490-
getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, previousIterationSymbolsCache, checker);
1484+
recur(type.symbol);
14911485
}
14921486
}
14931487
}
@@ -1559,9 +1553,7 @@ namespace ts.FindAllReferences.Core {
15591553
return undefined;
15601554
}
15611555

1562-
const result: Symbol[] = [];
1563-
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker);
1564-
return result.some(search.includes) ? rootSymbol : undefined;
1556+
return getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker).some(search.includes) ? rootSymbol : undefined;
15651557
}
15661558

15671559
return undefined;
@@ -1667,20 +1659,11 @@ namespace ts.FindAllReferences.Core {
16671659
*/
16681660
function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): Symbol[] | undefined {
16691661
const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide(location);
1670-
if (!propertyAccessExpression) {
1671-
return undefined;
1672-
}
1673-
1674-
const localParentType = checker.getTypeAtLocation(propertyAccessExpression.expression);
1675-
if (!localParentType) {
1676-
return undefined;
1677-
}
1678-
1679-
if (localParentType.symbol && localParentType.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) && localParentType.symbol !== symbol.parent) {
1680-
return [localParentType.symbol];
1681-
}
1682-
else if (localParentType.flags & TypeFlags.UnionOrIntersection) {
1683-
return getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>localParentType);
1684-
}
1662+
const localParentType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression);
1663+
return localParentType && localParentType.symbol && localParentType.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) && localParentType.symbol !== symbol.parent
1664+
? [localParentType.symbol]
1665+
: localParentType && localParentType.flags & TypeFlags.UnionOrIntersection
1666+
? getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>localParentType)
1667+
: undefined;
16851668
}
16861669
}

0 commit comments

Comments
 (0)