diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 952600b6017..2a9ade5af39 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -736,7 +736,7 @@ module ts { return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; } - function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): Symbol[] { + function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] { function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] { function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible @@ -745,7 +745,7 @@ module ts { } // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too - var accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning)); + var accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing); return !!accessibleParent; } @@ -767,16 +767,21 @@ module ts { // Check if symbol is any of the alias return forEachValue(symbols, symbolFromSymbolTable => { if (symbolFromSymbolTable.flags & SymbolFlags.Import) { - var resolvedImportedSymbol = resolveImport(symbolFromSymbolTable); - if (isAccessible(symbolFromSymbolTable, resolveImport(symbolFromSymbolTable))) { - return [symbolFromSymbolTable]; - } + 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, declaration => + declaration.kind === SyntaxKind.ImportDeclaration && (declaration).externalModuleName)) { + var resolvedImportedSymbol = resolveImport(symbolFromSymbolTable); + if (isAccessible(symbolFromSymbolTable, resolveImport(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 - var 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 + var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined; + if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { + return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); + } } } }); @@ -822,7 +827,7 @@ module ts { var meaningToLook = meaning; while (symbol) { // Symbol is accessible if it by itself is accessible - var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook); + var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false); if (accessibleSymbolChain) { var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]); if (!hasAccessibleDeclarations) { @@ -1005,7 +1010,7 @@ module ts { writer.trackSymbol(symbol, enclosingDeclaration, meaning); function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void { if (symbol) { - var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning); + var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & SymbolFormatFlags.UseOnlyExternalAliasing)); if (!accessibleSymbolChain || needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2a291c828cd..68ef296e263 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -695,6 +695,9 @@ module ts { // eg. class C { p: T } <-- Show p as C.p here // var a: C; // var p = a.p; <--- Here p is property of C so show it as C.p instead of just C.p + UseOnlyExternalAliasing = 0x00000002, // Use only external alias information to get the symbol name in the given context + // eg. module m { export class c { } } import x = m.c; + // When this flag is specified m.c will be used to refer to the class instead of alias symbol x } export enum SymbolAccessibility { diff --git a/src/services/services.ts b/src/services/services.ts index 42f6160bd3e..3df83af1028 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2851,27 +2851,27 @@ module ts { if (symbolFlags & SymbolFlags.Class && !hasAddedSymbolInfo) { displayParts.push(keywordPart(SyntaxKind.ClassKeyword)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + addFullSymbolName(symbol); writeTypeParametersOfSymbol(symbol, sourceFile); } if (symbolFlags & SymbolFlags.Interface) { addNewLineIfDisplayPartsExist(); displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + addFullSymbolName(symbol); writeTypeParametersOfSymbol(symbol, sourceFile); } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); displayParts.push(keywordPart(SyntaxKind.EnumKeyword)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile)); + addFullSymbolName(symbol); } if (symbolFlags & SymbolFlags.Module) { addNewLineIfDisplayPartsExist(); displayParts.push(keywordPart(SyntaxKind.ModuleKeyword)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile)); + addFullSymbolName(symbol); } if (symbolFlags & SymbolFlags.TypeParameter) { addNewLineIfDisplayPartsExist(); @@ -2879,13 +2879,13 @@ module ts { displayParts.push(textPart("type parameter")); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration)); + addFullSymbolName(symbol); displayParts.push(spacePart()); displayParts.push(keywordPart(SyntaxKind.InKeyword)); displayParts.push(spacePart()); if (symbol.parent) { // Class/Interface type parameter - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol.parent, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)) + addFullSymbolName(symbol.parent, enclosingDeclaration); writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration); } else { @@ -2897,7 +2897,7 @@ module ts { displayParts.push(spacePart()); } else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, signatureDeclaration.symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)) + addFullSymbolName(signatureDeclaration.symbol); } displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); } @@ -2921,7 +2921,7 @@ module ts { displayParts.push(textPart("alias")); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile)); + addFullSymbolName(symbol); } if (!hasAddedSymbolInfo) { if (symbolKind !== ScriptElementKind.unknown) { @@ -2969,6 +2969,12 @@ module ts { } } + function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) { + var fullSymbolDisplayParts = symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, + SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing); + displayParts.push.apply(displayParts, fullSymbolDisplayParts); + } + function addPrefixForAnyFunctionOrVar(symbol: Symbol, symbolKind: string) { addNewLineIfDisplayPartsExist(); if (symbolKind) { @@ -2976,8 +2982,7 @@ module ts { displayParts.push(textPart(symbolKind)); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); displayParts.push(spacePart()); - // Write type parameters of class/Interface if it is property/method of the generic class/interface - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + addFullSymbolName(symbol); } } diff --git a/tests/cases/fourslash/quickInfoOnInternalAliases.ts b/tests/cases/fourslash/quickInfoOnInternalAliases.ts new file mode 100644 index 00000000000..8c269ac6565 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnInternalAliases.ts @@ -0,0 +1,22 @@ +/// + +/////** Module comment*/ +////export module m1 { +//// /** m2 comments*/ +//// export module m2 { +//// /** class comment;*/ +//// export class /*1*/c { +//// }; +//// } +////} +/////**This is on import declaration*/ +////import /*2*/internalAlias = m1.m2./*3*/c; + +goTo.marker('1'); +verify.quickInfoIs("class m1.m2.c", "class comment;"); + +goTo.marker('2'); +verify.quickInfoIs('(alias) internalAlias', "This is on import declaration"); + +goTo.marker('3'); +verify.quickInfoIs("class m1.m2.c", "class comment;"); \ No newline at end of file