guard against visiting the same symbol table multiple times (#12818)

This commit is contained in:
Vladimir Matveev
2016-12-12 10:17:07 -08:00
committed by GitHub
parent 23ec976719
commit a604d84f5c
5 changed files with 127 additions and 24 deletions

View File

@@ -1742,7 +1742,19 @@ namespace ts {
}
function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] {
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] {
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable) {
return getAccessibleSymbolChainFromSymbolTableWorker(symbols, []);
}
function getAccessibleSymbolChainFromSymbolTableWorker(symbols: SymbolTable, visitedSymbolTables: SymbolTable[]): Symbol[] {
if (contains(visitedSymbolTables, symbols)) {
return undefined;
}
visitedSymbolTables.push(symbols);
const result = trySymbolTable(symbols);
visitedSymbolTables.pop();
return result;
function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) {
// If the symbol is equivalent and doesn't need further qualification, this symbol is accessible
if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) {
@@ -1764,34 +1776,36 @@ namespace ts {
}
}
// If symbol is directly available by its name in the symbol table
if (isAccessible(symbols[symbol.name])) {
return [symbol];
}
function trySymbolTable(symbols: SymbolTable) {
// If symbol is directly available by its name in the symbol table
if (isAccessible(symbols[symbol.name])) {
return [symbol];
}
// Check if symbol is any of the alias
return forEachProperty(symbols, symbolFromSymbolTable => {
if (symbolFromSymbolTable.flags & SymbolFlags.Alias
&& symbolFromSymbolTable.name !== "export="
&& !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) {
if (!useOnlyExternalAliasing || // We can use any type of alias to get the name
// Is this external alias, then use it to name
ts.forEach(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) {
// Check if symbol is any of the alias
return forEachProperty(symbols, symbolFromSymbolTable => {
if (symbolFromSymbolTable.flags & SymbolFlags.Alias
&& symbolFromSymbolTable.name !== "export="
&& !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) {
if (!useOnlyExternalAliasing || // We can use any type of alias to get the name
// Is this external alias, then use it to name
ts.forEach(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) {
const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable);
if (isAccessible(symbolFromSymbolTable, resolveAlias(symbolFromSymbolTable))) {
return [symbolFromSymbolTable];
}
const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable);
if (isAccessible(symbolFromSymbolTable, resolveAlias(symbolFromSymbolTable))) {
return [symbolFromSymbolTable];
}
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
// but only if the symbolFromSymbolTable can be qualified
const accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
// but only if the symbolFromSymbolTable can be qualified
const accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTableWorker(resolvedImportedSymbol.exports, visitedSymbolTables) : undefined;
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
}
}
}
}
});
});
}
}
if (symbol) {