@@ -2463,17 +2463,26 @@ namespace ts {
24632463 * Attempts to find the symbol corresponding to the container a symbol is in - usually this
24642464 * is just its' `.parent`, but for locals, this value is `undefined`
24652465 */
2466- function getContainerOfSymbol (symbol: Symbol): Symbol | undefined {
2466+ function getContainersOfSymbol (symbol: Symbol, enclosingDeclaration: Node | undefined ): Symbol[] | undefined {
24672467 const container = getParentOfSymbol(symbol);
24682468 if (container) {
2469- return container;
2469+ const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer);
2470+ if (enclosingDeclaration && getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false)) {
2471+ return concatenate([container], additionalContainers); // This order expresses a preference for the real container if it is in scope
2472+ }
2473+ return append(additionalContainers, container);
24702474 }
2471- const candidate = forEach (symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
2472- if (!candidate ) {
2475+ const candidates = mapDefined (symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
2476+ if (!length(candidates) ) {
24732477 return undefined;
24742478 }
2475- const alias = getAliasForSymbolInContainer(candidate, symbol);
2476- return alias ? candidate : undefined;
2479+ return mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined);
2480+
2481+ function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) {
2482+ const fileSymbol = getExternalModuleContainer(d);
2483+ const exported = fileSymbol && fileSymbol.exports && fileSymbol.exports.get(InternalSymbolName.ExportEquals);
2484+ return resolveSymbol(exported) === resolveSymbol(container) ? fileSymbol : undefined;
2485+ }
24772486 }
24782487
24792488 function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) {
@@ -2759,6 +2768,56 @@ namespace ts {
27592768 return access.accessibility === SymbolAccessibility.Accessible;
27602769 }
27612770
2771+ function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult | undefined {
2772+ if (!length(symbols)) return;
2773+
2774+ let hadAccessibleChain: Symbol | undefined;
2775+ for (const symbol of symbols!) {
2776+ // Symbol is accessible if it by itself is accessible
2777+ const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false);
2778+ if (accessibleSymbolChain) {
2779+ hadAccessibleChain = symbol;
2780+ const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
2781+ if (hasAccessibleDeclarations) {
2782+ return hasAccessibleDeclarations;
2783+ }
2784+ }
2785+ else {
2786+ if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
2787+ // Any meaning of a module symbol is always accessible via an `import` type
2788+ return {
2789+ accessibility: SymbolAccessibility.Accessible
2790+ };
2791+ }
2792+ }
2793+
2794+ // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
2795+ // It could be a qualified symbol and hence verify the path
2796+ // e.g.:
2797+ // module m {
2798+ // export class c {
2799+ // }
2800+ // }
2801+ // const x: typeof m.c
2802+ // In the above example when we start with checking if typeof m.c symbol is accessible,
2803+ // we are going to see if c can be accessed in scope directly.
2804+ // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
2805+ // It is accessible if the parent m is accessible because then m.c can be accessed through qualification
2806+ const parentResult = isAnySymbolAccessible(getContainersOfSymbol(symbol, enclosingDeclaration), enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible);
2807+ if (parentResult) {
2808+ return parentResult;
2809+ }
2810+ }
2811+
2812+ if (hadAccessibleChain) {
2813+ return {
2814+ accessibility: SymbolAccessibility.NotAccessible,
2815+ errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
2816+ errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
2817+ };
2818+ }
2819+ }
2820+
27622821 /**
27632822 * Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
27642823 *
@@ -2769,57 +2828,21 @@ namespace ts {
27692828 */
27702829 function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult {
27712830 if (symbol && enclosingDeclaration) {
2772- const initialSymbol = symbol;
2773- let meaningToLook = meaning;
2774- while (symbol) {
2775- // Symbol is accessible if it by itself is accessible
2776- const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
2777- if (accessibleSymbolChain) {
2778- const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
2779- if (!hasAccessibleDeclarations) {
2780- return {
2781- accessibility: SymbolAccessibility.NotAccessible,
2782- errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
2783- errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
2784- };
2785- }
2786- return hasAccessibleDeclarations;
2787- }
2788- else {
2789- if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
2790- // Any meaning of a module symbol is always accessible via an `import` type
2791- return {
2792- accessibility: SymbolAccessibility.Accessible
2793- };
2794- }
2795- }
2796-
2797- // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
2798- // It could be a qualified symbol and hence verify the path
2799- // e.g.:
2800- // module m {
2801- // export class c {
2802- // }
2803- // }
2804- // const x: typeof m.c
2805- // In the above example when we start with checking if typeof m.c symbol is accessible,
2806- // we are going to see if c can be accessed in scope directly.
2807- // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
2808- // It is accessible if the parent m is accessible because then m.c can be accessed through qualification
2809- meaningToLook = getQualifiedLeftMeaning(meaning);
2810- symbol = getContainerOfSymbol(symbol);
2831+ const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible);
2832+ if (result) {
2833+ return result;
28112834 }
28122835
28132836 // This could be a symbol that is not exported in the external module
28142837 // or it could be a symbol from different external module that is not aliased and hence cannot be named
2815- const symbolExternalModule = forEach(initialSymbol .declarations, getExternalModuleContainer);
2838+ const symbolExternalModule = forEach(symbol .declarations, getExternalModuleContainer);
28162839 if (symbolExternalModule) {
28172840 const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration);
28182841 if (symbolExternalModule !== enclosingExternalModule) {
28192842 // name from different external module that is not visible
28202843 return {
28212844 accessibility: SymbolAccessibility.CannotBeNamed,
2822- errorSymbolName: symbolToString(initialSymbol , enclosingDeclaration, meaning),
2845+ errorSymbolName: symbolToString(symbol , enclosingDeclaration, meaning),
28232846 errorModuleName: symbolToString(symbolExternalModule)
28242847 };
28252848 }
@@ -2828,16 +2851,16 @@ namespace ts {
28282851 // Just a local name that is not accessible
28292852 return {
28302853 accessibility: SymbolAccessibility.NotAccessible,
2831- errorSymbolName: symbolToString(initialSymbol , enclosingDeclaration, meaning),
2854+ errorSymbolName: symbolToString(symbol , enclosingDeclaration, meaning),
28322855 };
28332856 }
28342857
28352858 return { accessibility: SymbolAccessibility.Accessible };
2859+ }
28362860
2837- function getExternalModuleContainer(declaration: Node) {
2838- const node = findAncestor(declaration, hasExternalModuleSymbol);
2839- return node && getSymbolOfNode(node);
2840- }
2861+ function getExternalModuleContainer(declaration: Node) {
2862+ const node = findAncestor(declaration, hasExternalModuleSymbol);
2863+ return node && getSymbolOfNode(node);
28412864 }
28422865
28432866 function hasExternalModuleSymbol(declaration: Node) {
@@ -3667,18 +3690,19 @@ namespace ts {
36673690 /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
36683691 function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
36693692 let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing));
3670- let parentSymbol: Symbol | undefined;
36713693
36723694 if (!accessibleSymbolChain ||
36733695 needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
36743696
36753697 // Go up and add our parent.
3676- const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
3677- if (parent) {
3678- const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
3679- if (parentChain) {
3680- parentSymbol = parent;
3681- accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
3698+ const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration);
3699+ if (length(parents)) {
3700+ for (const parent of parents!) {
3701+ const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
3702+ if (parentChain) {
3703+ accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
3704+ break;
3705+ }
36823706 }
36833707 }
36843708 }
@@ -3689,11 +3713,12 @@ namespace ts {
36893713 if (
36903714 // If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
36913715 endOfChain ||
3692- // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
3693- (yieldModuleSymbol || !(!parentSymbol && forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol))) &&
36943716 // If a parent symbol is an anonymous type, don't write it.
36953717 !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
3696-
3718+ // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
3719+ if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
3720+ return;
3721+ }
36973722 return [symbol];
36983723 }
36993724 }
0 commit comments