mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
guard against visiting the same symbol table multiple times (#12818)
This commit is contained in:
+38
-24
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//// [tests/cases/compiler/circularReferenceInImport.ts] ////
|
||||
|
||||
//// [db.d.ts]
|
||||
|
||||
declare namespace Db {
|
||||
export import Types = Db;
|
||||
}
|
||||
|
||||
export = Db;
|
||||
|
||||
//// [app.ts]
|
||||
import * as Db from "./db"
|
||||
|
||||
export function foo() {
|
||||
return new Object()
|
||||
}
|
||||
|
||||
//// [app.js]
|
||||
"use strict";
|
||||
function foo() {
|
||||
return new Object();
|
||||
}
|
||||
exports.foo = foo;
|
||||
|
||||
|
||||
//// [app.d.ts]
|
||||
export declare function foo(): Object;
|
||||
@@ -0,0 +1,23 @@
|
||||
=== tests/cases/compiler/db.d.ts ===
|
||||
|
||||
declare namespace Db {
|
||||
>Db : Symbol(Types, Decl(db.d.ts, 0, 0))
|
||||
|
||||
export import Types = Db;
|
||||
>Types : Symbol(Types, Decl(db.d.ts, 1, 22))
|
||||
>Db : Symbol(Types, Decl(db.d.ts, 0, 0))
|
||||
}
|
||||
|
||||
export = Db;
|
||||
>Db : Symbol(Db, Decl(db.d.ts, 0, 0))
|
||||
|
||||
=== tests/cases/compiler/app.ts ===
|
||||
import * as Db from "./db"
|
||||
>Db : Symbol(Db, Decl(app.ts, 0, 6))
|
||||
|
||||
export function foo() {
|
||||
>foo : Symbol(foo, Decl(app.ts, 0, 26))
|
||||
|
||||
return new Object()
|
||||
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
=== tests/cases/compiler/db.d.ts ===
|
||||
|
||||
declare namespace Db {
|
||||
>Db : typeof Types
|
||||
|
||||
export import Types = Db;
|
||||
>Types : typeof Types
|
||||
>Db : typeof Types
|
||||
}
|
||||
|
||||
export = Db;
|
||||
>Db : typeof Db
|
||||
|
||||
=== tests/cases/compiler/app.ts ===
|
||||
import * as Db from "./db"
|
||||
>Db : typeof Db
|
||||
|
||||
export function foo() {
|
||||
>foo : () => Object
|
||||
|
||||
return new Object()
|
||||
>new Object() : Object
|
||||
>Object : ObjectConstructor
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// @declaration: true
|
||||
|
||||
// @filename: db.d.ts
|
||||
declare namespace Db {
|
||||
export import Types = Db;
|
||||
}
|
||||
|
||||
export = Db;
|
||||
|
||||
// @filename: app.ts
|
||||
import * as Db from "./db"
|
||||
|
||||
export function foo() {
|
||||
return new Object()
|
||||
}
|
||||
Reference in New Issue
Block a user