mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-11 17:41:26 -06:00
Check if accessible symbol needs futher qualification
This commit is contained in:
parent
d8f3481d38
commit
5a23dd0684
@ -586,56 +586,102 @@ module ts {
|
||||
return (propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark) && propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
|
||||
}
|
||||
|
||||
function getAccessibleSymbol(symbol: Symbol, enclosingDeclaration: Node) {
|
||||
function forEachSymbolTable<T>(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
|
||||
var result: T;
|
||||
for (var 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 && (location.kind !== SyntaxKind.SourceFile || location.flags & NodeFlags.ExternalModule)) {
|
||||
if (result = callback(location.locals)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
switch (location.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
if (!(location.flags & NodeFlags.ExternalModule)) {
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (result = callback(getSymbolOfNode(location).exports)) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
if (result = callback(getSymbolOfNode(location).members)) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return callback(globals);
|
||||
}
|
||||
|
||||
function getAccessibleSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) {
|
||||
function getAccessibleSymbolFromSymbolTable(symbols: SymbolTable) {
|
||||
function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) {
|
||||
if (symbol === (resolvedAliasSymbol || symbolFromSymbolTable)) {
|
||||
// If the symbol is equivalent and doesnt need futher qualification, this symbol is accessible
|
||||
if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// isAccessible is parent is accessible
|
||||
var accessibleParent = getAccessibleSymbol(symbolFromSymbolTable.parent, enclosingDeclaration, SymbolFlags.Namespace);
|
||||
return !!accessibleParent;
|
||||
}
|
||||
}
|
||||
|
||||
// If symbol is directly available by its name in the symbol table
|
||||
if (symbol === symbols[symbol.name]) {
|
||||
if (isAccessible(symbols[symbol.name])) {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// Check if symbol is any of the alias
|
||||
return forEachValue(symbols, symbolFromSymbolTable => {
|
||||
if (symbolFromSymbolTable.flags & SymbolFlags.Import) {
|
||||
var resolvedImportSymbol = resolveImport(symbolFromSymbolTable);
|
||||
if (resolvedImportSymbol === symbol) {
|
||||
if (isAccessible(symbolFromSymbolTable, resolveImport(symbolFromSymbolTable))) {
|
||||
return symbolFromSymbolTable;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var accessibleSymbol: Symbol;
|
||||
while (enclosingDeclaration) {
|
||||
// Locals of a source file are not in scope (because they get merged into the global symbol table)
|
||||
if (enclosingDeclaration.locals && (enclosingDeclaration.kind !== SyntaxKind.SourceFile || enclosingDeclaration.flags & NodeFlags.ExternalModule)) {
|
||||
if (accessibleSymbol = getAccessibleSymbolFromSymbolTable(enclosingDeclaration.locals)) {
|
||||
return accessibleSymbol;
|
||||
}
|
||||
}
|
||||
switch (enclosingDeclaration.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
if (!(enclosingDeclaration.flags & NodeFlags.ExternalModule)) {
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (accessibleSymbol = getAccessibleSymbolFromSymbolTable(getSymbolOfNode(enclosingDeclaration).exports)) {
|
||||
return accessibleSymbol;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
if (accessibleSymbol = getAccessibleSymbolFromSymbolTable(getSymbolOfNode(enclosingDeclaration).members)) {
|
||||
return accessibleSymbol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
enclosingDeclaration = enclosingDeclaration.parent;
|
||||
}
|
||||
|
||||
return getAccessibleSymbolFromSymbolTable(globals);
|
||||
if (symbol) {
|
||||
return forEachSymbolTable(enclosingDeclaration, getAccessibleSymbolFromSymbolTable);
|
||||
}
|
||||
}
|
||||
|
||||
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node) {
|
||||
function needsQualification(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) {
|
||||
var qualify = false;
|
||||
forEachSymbolTable(enclosingDeclaration, symbolTable => {
|
||||
// If symbol of this name is not available in the symbol table we are ok
|
||||
if (!symbolTable[symbol.name]) {
|
||||
// Continue to the next symbol table
|
||||
return false;
|
||||
}
|
||||
// If the symbol with this name is present it should refer to the symbol
|
||||
var symbolFromSymbolTable = symbolTable[symbol.name];
|
||||
if (symbolFromSymbolTable === symbol) {
|
||||
// No need to qualify
|
||||
return true;
|
||||
}
|
||||
|
||||
// Qualify if the symbol from symbol table has same meaning as expected
|
||||
symbolFromSymbolTable = (symbolFromSymbolTable.flags & SymbolFlags.Import) ? resolveImport(symbolFromSymbolTable) : symbolFromSymbolTable;
|
||||
if (symbolFromSymbolTable.flags & meaning) {
|
||||
qualify = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue to the next symbol table
|
||||
return false;
|
||||
});
|
||||
|
||||
return qualify
|
||||
}
|
||||
|
||||
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
function getSymbolName(symbol: Symbol) {
|
||||
if (symbol.declarations && symbol.declarations.length > 0) {
|
||||
var declaration = symbol.declarations[0];
|
||||
@ -651,12 +697,14 @@ module ts {
|
||||
!(symbol.flags & SymbolFlags.PropertyOrAccessor & SymbolFlags.Signature & SymbolFlags.Constructor & SymbolFlags.Method & SymbolFlags.TypeParameter)) {
|
||||
var symbolName: string;
|
||||
while (symbol) {
|
||||
var accessibleParent = getAccessibleSymbol(symbol, enclosingDeclaration);
|
||||
symbolName = getSymbolName(accessibleParent || symbol) + (symbolName ? ("." + symbolName) : "");
|
||||
if (accessibleParent) {
|
||||
var isFirstName = !symbolName;
|
||||
var meaningToLook = isFirstName ? meaning : SymbolFlags.Namespace;
|
||||
var accessibleSymbol = getAccessibleSymbol(symbol, enclosingDeclaration, meaningToLook);
|
||||
symbolName = getSymbolName(accessibleSymbol || symbol) + (isFirstName ? "" : ("." + symbolName));
|
||||
if (accessibleSymbol && !needsQualification(accessibleSymbol, enclosingDeclaration, meaningToLook)) {
|
||||
break;
|
||||
}
|
||||
symbol = symbol.parent;
|
||||
symbol = accessibleSymbol ? accessibleSymbol.parent : symbol.parent;
|
||||
}
|
||||
|
||||
return symbolName;
|
||||
@ -695,7 +743,7 @@ module ts {
|
||||
writeTypeReference(<TypeReference>type);
|
||||
}
|
||||
else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
|
||||
writer.write(symbolToString(type.symbol, enclosingDeclaration));
|
||||
writer.write(symbolToString(type.symbol, enclosingDeclaration, SymbolFlags.Type));
|
||||
}
|
||||
else if (type.flags & TypeFlags.Anonymous) {
|
||||
writeAnonymousType(<ObjectType>type, allowFunctionOrConstructorTypeLiteral);
|
||||
@ -717,7 +765,7 @@ module ts {
|
||||
writer.write("[]");
|
||||
}
|
||||
else {
|
||||
writer.write(symbolToString(type.target.symbol, enclosingDeclaration));
|
||||
writer.write(symbolToString(type.target.symbol, enclosingDeclaration, SymbolFlags.Type));
|
||||
writer.write("<");
|
||||
for (var i = 0; i < type.typeArguments.length; i++) {
|
||||
if (i > 0) {
|
||||
@ -751,7 +799,7 @@ module ts {
|
||||
|
||||
function writeTypeofSymbol(type: ObjectType) {
|
||||
writer.write("typeof ");
|
||||
writer.write(symbolToString(type.symbol, enclosingDeclaration));
|
||||
writer.write(symbolToString(type.symbol, enclosingDeclaration, SymbolFlags.Value));
|
||||
}
|
||||
|
||||
function writeLiteralType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) {
|
||||
|
||||
@ -99,17 +99,17 @@ declare module templa.mvc {
|
||||
declare module templa.mvc.composite {
|
||||
}
|
||||
declare module templa.dom.mvc {
|
||||
interface IElementController<ModelType extends mvc.IModel> extends mvc.IController<ModelType> {
|
||||
interface IElementController<ModelType extends templa.mvc.IModel> extends templa.mvc.IController<ModelType> {
|
||||
}
|
||||
}
|
||||
declare module templa.dom.mvc {
|
||||
class AbstractElementController<ModelType extends mvc.IModel> extends mvc.AbstractController<ModelType> implments IElementController<ModelType> {
|
||||
class AbstractElementController<ModelType extends templa.mvc.IModel> extends templa.mvc.AbstractController<ModelType> implments IElementController<ModelType> {
|
||||
constructor();
|
||||
}
|
||||
}
|
||||
declare module templa.dom.mvc.composite {
|
||||
class AbstractCompositeElementController<ModelType extends mvc.composite.ICompositeControllerModel> extends AbstractElementController<ModelType> {
|
||||
_controllers: mvc.IController<mvc.IModel>[];
|
||||
class AbstractCompositeElementController<ModelType extends templa.mvc.composite.ICompositeControllerModel> extends AbstractElementController<ModelType> {
|
||||
_controllers: templa.mvc.IController<templa.mvc.IModel>[];
|
||||
constructor();
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,6 @@ declare module A.C {
|
||||
}
|
||||
}
|
||||
declare module A.B.C {
|
||||
class W implments C.Z {
|
||||
class W implments A.C.Z {
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ declare module X.Y.base {
|
||||
}
|
||||
}
|
||||
declare module X.Y.base.Z {
|
||||
class W<TValue> extends W {
|
||||
class W<TValue> extends base.W {
|
||||
value: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,6 @@ declare module X.A.C {
|
||||
}
|
||||
}
|
||||
declare module X.A.B.C {
|
||||
class W implments C.Z {
|
||||
class W implments X.A.C.Z {
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ declare module X.A.C {
|
||||
}
|
||||
}
|
||||
declare module X.A.B.C {
|
||||
class W implments C.Z {
|
||||
class W implments A.C.Z {
|
||||
}
|
||||
}
|
||||
declare module X.A.B.C {
|
||||
|
||||
@ -41,7 +41,7 @@ declare module X.A.C {
|
||||
}
|
||||
}
|
||||
declare module X.A.B.C {
|
||||
class W implments C.Z {
|
||||
class W implments X.A.C.Z {
|
||||
}
|
||||
}
|
||||
declare module X.A.B.C {
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
==== tests/cases/compiler/declarationEmit_nameConflicts_0.ts (1 errors) ====
|
||||
import im = require('declarationEmit_nameConflicts_1');
|
||||
export module M {
|
||||
export function f() { }
|
||||
export class C { }
|
||||
export module N {
|
||||
export function g() { };
|
||||
export interface I { }
|
||||
}
|
||||
|
||||
export import a = M.f;
|
||||
export import b = M.C;
|
||||
export import c = N;
|
||||
export import d = im;
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! Cannot find name 'im'.
|
||||
}
|
||||
|
||||
export module M.P {
|
||||
export function f() { }
|
||||
export class C { }
|
||||
export module N {
|
||||
export function g() { };
|
||||
export interface I { }
|
||||
}
|
||||
export import im = M.P.f;
|
||||
// Bug 887180: Invalid .d.ts when an aliased entity is referenced, and a different entity is closer in scope
|
||||
export var a = M.a; // emitted incorrectly as typeof f
|
||||
export var b = M.b; // ok
|
||||
export var c = M.c; // ok
|
||||
export var g = M.c.g; // ok
|
||||
export var d = M.d; // emitted incorrectly as typeof im
|
||||
}
|
||||
|
||||
export module M.Q {
|
||||
export function f() { }
|
||||
export class C { }
|
||||
export module N {
|
||||
export function g() { };
|
||||
export interface I { }
|
||||
}
|
||||
export interface b extends M.b { } // ok
|
||||
export interface I extends M.c.I { } // ok
|
||||
export module c {
|
||||
export interface I extends M.c.I { } // ok
|
||||
}
|
||||
}
|
||||
==== tests/cases/compiler/declarationEmit_nameConflicts_1.ts (1 errors) ====
|
||||
function f() { }
|
||||
export = f;
|
||||
~~~~~~~~~~~
|
||||
!!! Cannot compile external modules unless the '--module' flag is provided.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//// [tests/cases/compiler/declarationEmit_nameConflicts.ts] ////
|
||||
|
||||
//// [declarationEmit_nameConflicts_1.ts]
|
||||
function f() { }
|
||||
module f { export class c { } }
|
||||
export = f;
|
||||
|
||||
//// [declarationEmit_nameConflicts_0.ts]
|
||||
@ -51,10 +51,18 @@ export module M.Q {
|
||||
}
|
||||
|
||||
//// [declarationEmit_nameConflicts_1.js]
|
||||
function f() {
|
||||
}
|
||||
var f;
|
||||
(function (f) {
|
||||
var c = (function () {
|
||||
function c() {
|
||||
}
|
||||
return c;
|
||||
})();
|
||||
f.c = c;
|
||||
})(f || (f = {}));
|
||||
module.exports = f;
|
||||
//// [declarationEmit_nameConflicts_0.js]
|
||||
var im = require('declarationEmit_nameConflicts_1');
|
||||
(function (M) {
|
||||
function f() {
|
||||
}
|
||||
@ -75,6 +83,7 @@ module.exports = f;
|
||||
M.a = M.f;
|
||||
M.b = M.C;
|
||||
M.c = N;
|
||||
M.d = im;
|
||||
})(exports.M || (exports.M = {}));
|
||||
var M = exports.M;
|
||||
(function (M) {
|
||||
@ -127,3 +136,60 @@ var M = exports.M;
|
||||
var Q = M.Q;
|
||||
})(exports.M || (exports.M = {}));
|
||||
var M = exports.M;
|
||||
|
||||
|
||||
//// [declarationEmit_nameConflicts_1.d.ts]
|
||||
declare module f {
|
||||
class c {
|
||||
}
|
||||
}
|
||||
export = f;
|
||||
//// [declarationEmit_nameConflicts_0.d.ts]
|
||||
export declare module M {
|
||||
function f(): void;
|
||||
class C {
|
||||
}
|
||||
module N {
|
||||
function g(): void;
|
||||
interface I {
|
||||
}
|
||||
}
|
||||
export import a = M.f;
|
||||
export import b = M.C;
|
||||
export import c = N;
|
||||
export import d = im;
|
||||
}
|
||||
export declare module M.P {
|
||||
function f(): void;
|
||||
class C {
|
||||
}
|
||||
module N {
|
||||
function g(): void;
|
||||
interface I {
|
||||
}
|
||||
}
|
||||
export import im = M.P.f;
|
||||
var a: () => void;
|
||||
var b: typeof M.C;
|
||||
var c: typeof M.N;
|
||||
var g: () => void;
|
||||
var d: typeof M.d;
|
||||
}
|
||||
export declare module M.Q {
|
||||
function f(): void;
|
||||
class C {
|
||||
}
|
||||
module N {
|
||||
function g(): void;
|
||||
interface I {
|
||||
}
|
||||
}
|
||||
interface b extends M.C {
|
||||
}
|
||||
interface I extends M.N.I {
|
||||
}
|
||||
module c {
|
||||
interface I extends M.N.I {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ declare module X.Y.base {
|
||||
}
|
||||
declare module X.Y.base.Z {
|
||||
var f: () => void;
|
||||
var C: typeof C;
|
||||
var M: typeof M;
|
||||
var E: typeof E;
|
||||
var C: typeof base.C;
|
||||
var M: typeof base.M;
|
||||
var E: typeof base.E;
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ declare module M.P {
|
||||
enum D {
|
||||
f = 0,
|
||||
}
|
||||
var v: D;
|
||||
var v: M.D;
|
||||
var w: () => void;
|
||||
var x: () => void;
|
||||
var x: () => void;
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
==== tests/cases/compiler/declarationEmit_nameConflictsWithAlias.ts (1 errors) ====
|
||||
// Bug 887180
|
||||
export module C { export interface I { } }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! Cannot compile external modules unless the '--module' flag is provided.
|
||||
export import v = C;
|
||||
export module M {
|
||||
export module C { export interface I { } }
|
||||
export var w: v.I; // Gets emitted as C.I, which is the wrong interface
|
||||
}
|
||||
@ -12,3 +12,18 @@ export module M {
|
||||
M.w;
|
||||
})(exports.M || (exports.M = {}));
|
||||
var M = exports.M;
|
||||
|
||||
|
||||
//// [declarationEmit_nameConflictsWithAlias.d.ts]
|
||||
export declare module C {
|
||||
interface I {
|
||||
}
|
||||
}
|
||||
export import v = C;
|
||||
export declare module M {
|
||||
module C {
|
||||
interface I {
|
||||
}
|
||||
}
|
||||
var w: v.I;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// @declaration: true
|
||||
// @module: commonjs
|
||||
// @Filename: declarationEmit_nameConflicts_1.ts
|
||||
function f() { }
|
||||
module f { export class c { } }
|
||||
export = f;
|
||||
|
||||
// @Filename: declarationEmit_nameConflicts_0.ts
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// @declaration: true
|
||||
// @module: commonjs
|
||||
module M {
|
||||
export interface D { }
|
||||
export module D {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// @declaration: true
|
||||
// @module: commonjs
|
||||
// Bug 887180
|
||||
export module C { export interface I { } }
|
||||
export import v = C;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user