Dont allow namespace reexport symbols when looking up valid local names (#43969)

This commit is contained in:
Wesley Wigham 2021-05-06 12:03:48 -07:00 committed by GitHub
parent 233f28ca27
commit a5607a4eab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 110 additions and 34 deletions

View File

@ -3935,12 +3935,12 @@ namespace ts {
return typeCopy;
}
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable) => T): T {
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean) => T): T {
let result: T;
for (let location = enclosingDeclaration; location; location = location.parent) {
// Locals of a source file are not in scope (because they get merged into the global symbol table)
if (location.locals && !isGlobalSourceFile(location)) {
if (result = callback(location.locals)) {
if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true)) {
return result;
}
}
@ -3955,7 +3955,7 @@ namespace ts {
// `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten
// into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred
// to one another anyway)
if (result = callback(sym?.exports || emptySymbols)) {
if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true)) {
return result;
}
break;
@ -3983,7 +3983,7 @@ namespace ts {
}
}
return callback(globals);
return callback(globals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true);
}
function getQualifiedLeftMeaning(rightMeaning: SymbolFlags) {
@ -4006,12 +4006,12 @@ namespace ts {
/**
* @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already)
*/
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean): Symbol[] | undefined {
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined {
if (!pushIfUnique(visitedSymbolTables!, symbols)) {
return undefined;
}
const result = trySymbolTable(symbols, ignoreQualification);
const result = trySymbolTable(symbols, ignoreQualification, isLocalNameLookup);
visitedSymbolTables!.pop();
return result;
}
@ -4032,7 +4032,7 @@ namespace ts {
(ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning));
}
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined): Symbol[] | undefined {
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined {
// If symbol is directly available by its name in the symbol table
if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) {
return [symbol!];
@ -4046,6 +4046,8 @@ namespace ts {
&& !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration)))
// If `!useOnlyExternalAliasing`, we can use any type of alias to get the name
&& (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))
// If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it
&& (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true)
// While exports are generally considered to be in scope, export-specifier declared symbols are _not_
// See similar comment in `resolveName` for details
&& (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier))
@ -4160,7 +4162,7 @@ namespace ts {
return hasAccessibleDeclarations;
}
}
else if (allowModules) {
if (allowModules) {
if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
if (shouldComputeAliasesToMakeVisible) {
earlyModuleBail = true;

View File

@ -1971,6 +1971,10 @@ namespace ts {
return node.kind === SyntaxKind.TypeQuery;
}
export function isNamespaceReexportDeclaration(node: Node): boolean {
return isNamespaceExport(node) && !!node.parent.moduleSpecifier;
}
export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } {
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
}

View File

@ -0,0 +1,21 @@
//// [tests/cases/compiler/declarationEmitDoesNotUseReexportedNamespaceAsLocal.ts] ////
//// [sub.ts]
export function a() {}
//// [index.ts]
export const x = add(import("./sub"));
export * as Q from "./sub";
declare function add<T>(x: Promise<T>): T;
//// [sub.js]
export function a() { }
//// [index.js]
export const x = add(import("./sub"));
export * as Q from "./sub";
//// [sub.d.ts]
export declare function a(): void;
//// [index.d.ts]
export declare const x: typeof import("./sub");
export * as Q from "./sub";

View File

@ -0,0 +1,21 @@
=== tests/cases/compiler/sub.ts ===
export function a() {}
>a : Symbol(a, Decl(sub.ts, 0, 0))
=== tests/cases/compiler/index.ts ===
export const x = add(import("./sub"));
>x : Symbol(x, Decl(index.ts, 0, 12))
>add : Symbol(add, Decl(index.ts, 1, 27))
>"./sub" : Symbol("tests/cases/compiler/sub", Decl(sub.ts, 0, 0))
export * as Q from "./sub";
>Q : Symbol(Q, Decl(index.ts, 1, 6))
declare function add<T>(x: Promise<T>): T;
>add : Symbol(add, Decl(index.ts, 1, 27))
>T : Symbol(T, Decl(index.ts, 2, 21))
>x : Symbol(x, Decl(index.ts, 2, 24))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>T : Symbol(T, Decl(index.ts, 2, 21))
>T : Symbol(T, Decl(index.ts, 2, 21))

View File

@ -0,0 +1,19 @@
=== tests/cases/compiler/sub.ts ===
export function a() {}
>a : () => void
=== tests/cases/compiler/index.ts ===
export const x = add(import("./sub"));
>x : typeof import("tests/cases/compiler/sub")
>add(import("./sub")) : typeof import("tests/cases/compiler/sub")
>add : <T>(x: Promise<T>) => T
>import("./sub") : Promise<typeof import("tests/cases/compiler/sub")>
>"./sub" : "./sub"
export * as Q from "./sub";
>Q : typeof import("tests/cases/compiler/sub")
declare function add<T>(x: Promise<T>): T;
>add : <T>(x: Promise<T>) => T
>x : Promise<T>

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -9,7 +9,7 @@ export const b = 2;
=== tests/cases/conformance/es2020/modules/1.ts ===
export * as ns from './0';
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/es2020/modules/0")
ns.a;
>ns.a : any

View File

@ -4,7 +4,7 @@ export class A {}
=== tests/cases/conformance/externalModules/typeOnly/b.ts ===
export * as a from './a';
>a : typeof a
>a : typeof import("tests/cases/conformance/externalModules/typeOnly/a")
=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
import type { a } from './b';

View File

@ -8,7 +8,7 @@ export type { A } from './a';
=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
export * as a from './b';
>a : typeof a
>a : typeof import("tests/cases/conformance/externalModules/typeOnly/b")
=== tests/cases/conformance/externalModules/typeOnly/d.ts ===
import { a } from './c';

View File

@ -7,7 +7,7 @@ export type * from './a'; // Grammar error
No type information for this code.
No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts ===
export type * as ns from './a'; // Grammar error
>ns : typeof ns
>ns : typeof import("tests/cases/conformance/externalModules/typeOnly/a")
=== tests/cases/conformance/externalModules/typeOnly/d.ts ===
import { A } from './b';

View File

@ -27,5 +27,5 @@ register("ok");
export * from "./register";
export * from "./data1";
export * as aliased from "./data1";
>aliased : typeof aliased
>aliased : typeof import("tests/cases/compiler/data1")

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -4,7 +4,7 @@ export class A { }
=== tests/cases/compiler/b.ts ===
export * as a from "./a";
>a : typeof a
>a : typeof import("tests/cases/compiler/a")
=== tests/cases/compiler/tslib.d.ts ===
declare module "tslib" {

View File

@ -0,0 +1,9 @@
// @target: esnext
// @module: esnext
// @declaration: true
// @filename: sub.ts
export function a() {}
// @filename: index.ts
export const x = add(import("./sub"));
export * as Q from "./sub";
declare function add<T>(x: Promise<T>): T;