@@ -6018,14 +6018,38 @@ namespace ts {
60186018
60196019 // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
60206020 if ( rootSymbol . parent && rootSymbol . parent . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ) {
6021- getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . getName ( ) , result ) ;
6021+ getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . getName ( ) , result , /*previousIterationSymbolsCache*/ { } ) ;
60226022 }
60236023 } ) ;
60246024
60256025 return result ;
60266026 }
60276027
6028- function getPropertySymbolsFromBaseTypes ( symbol : Symbol , propertyName : string , result : Symbol [ ] ) : void {
6028+ /**
6029+ * Find symbol of the given property-name and add the symbol to the given result array
6030+ * @param symbol a symbol to start searching for the given propertyName
6031+ * @param propertyName a name of property to serach for
6032+ * @param result an array of symbol of found property symbols
6033+ * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisitng of the same symbol.
6034+ * The value of previousIterationSymbol is undefined when the function is first called.
6035+ */
6036+ function getPropertySymbolsFromBaseTypes ( symbol : Symbol , propertyName : string , result : Symbol [ ] ,
6037+ previousIterationSymbolsCache : SymbolTable ) : void {
6038+ // If the current symbol is the same as the previous-iteration symbol, we can just return the symbol that has already been visited
6039+ // This is particularly important for the following cases, so that we do not infinitely visit the same symbol.
6040+ // For example:
6041+ // interface C extends C {
6042+ // /*findRef*/propName: string;
6043+ // }
6044+ // The first time getPropertySymbolsFromBaseTypes is called when finding-all-references at propName,
6045+ // the symbol argument will be the symbol of an interface "C" and previousIterationSymbol is undefined,
6046+ // the function will add any found symbol of the property-name, then its sub-routine will call
6047+ // getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already
6048+ // visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol.
6049+ if ( hasProperty ( previousIterationSymbolsCache , symbol . name ) ) {
6050+ return ;
6051+ }
6052+
60296053 if ( symbol && symbol . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ) {
60306054 forEach ( symbol . getDeclarations ( ) , declaration => {
60316055 if ( declaration . kind === SyntaxKind . ClassDeclaration ) {
@@ -6049,7 +6073,8 @@ namespace ts {
60496073 }
60506074
60516075 // Visit the typeReference as well to see if it directly or indirectly use that property
6052- getPropertySymbolsFromBaseTypes ( type . symbol , propertyName , result ) ;
6076+ previousIterationSymbolsCache [ symbol . name ] = symbol ;
6077+ getPropertySymbolsFromBaseTypes ( type . symbol , propertyName , result , previousIterationSymbolsCache ) ;
60536078 }
60546079 }
60556080 }
@@ -6101,7 +6126,7 @@ namespace ts {
61016126 // see if any is in the list
61026127 if ( rootSymbol . parent && rootSymbol . parent . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ) {
61036128 const result : Symbol [ ] = [ ] ;
6104- getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . getName ( ) , result ) ;
6129+ getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . getName ( ) , result , /*previousIterationSymbolsCache*/ { } ) ;
61056130 return forEach ( result , s => searchSymbols . indexOf ( s ) >= 0 ? s : undefined ) ;
61066131 }
61076132
0 commit comments