@@ -1438,7 +1438,7 @@ namespace ts.FindAllReferences.Core {
1438
1438
1439
1439
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
1440
1440
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 ) ;
1442
1442
}
1443
1443
}
1444
1444
}
@@ -1458,36 +1458,30 @@ namespace ts.FindAllReferences.Core {
1458
1458
* @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol.
1459
1459
* The value of previousIterationSymbol is undefined when the function is first called.
1460
1460
*/
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 ;
1476
1472
1477
- if ( symbol . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ) {
1478
1473
for ( const declaration of symbol . declarations ) {
1479
1474
for ( const typeReference of getAllSuperTypeNodes ( declaration ) ) {
1480
1475
const type = checker . getTypeAtLocation ( typeReference ) ;
1481
- if ( ! type ) continue ;
1476
+ if ( ! ( type && type . symbol ) ) continue ;
1482
1477
1483
1478
const propertySymbol = checker . getPropertyOfType ( type , propertyName ) ;
1484
1479
if ( propertySymbol ) {
1485
1480
result . push ( ...checker . getRootSymbols ( propertySymbol ) ) ;
1486
1481
}
1487
1482
1488
1483
// 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 ) ;
1491
1485
}
1492
1486
}
1493
1487
}
@@ -1559,9 +1553,7 @@ namespace ts.FindAllReferences.Core {
1559
1553
return undefined ;
1560
1554
}
1561
1555
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 ;
1565
1557
}
1566
1558
1567
1559
return undefined ;
@@ -1667,20 +1659,11 @@ namespace ts.FindAllReferences.Core {
1667
1659
*/
1668
1660
function getParentSymbolsOfPropertyAccess ( location : Node , symbol : Symbol , checker : TypeChecker ) : Symbol [ ] | undefined {
1669
1661
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 ;
1685
1668
}
1686
1669
}
0 commit comments