Skip to content

Commit 77a93d2

Browse files
committed
Merge pull request #874 from Microsoft/betterAliasSymbolInfo
Shows better information for aliases in the quick info/completion entry
2 parents bdac6ca + 6f6be7e commit 77a93d2

12 files changed

+145
-41
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ module ts {
736736
return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace;
737737
}
738738

739-
function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): Symbol[] {
739+
function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] {
740740
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] {
741741
function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) {
742742
// If the symbol is equivalent and doesn't need further qualification, this symbol is accessible
@@ -745,7 +745,7 @@ module ts {
745745
}
746746

747747
// If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too
748-
var accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning));
748+
var accessibleParent = getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing);
749749
return !!accessibleParent;
750750
}
751751

@@ -767,16 +767,21 @@ module ts {
767767
// Check if symbol is any of the alias
768768
return forEachValue(symbols, symbolFromSymbolTable => {
769769
if (symbolFromSymbolTable.flags & SymbolFlags.Import) {
770-
var resolvedImportedSymbol = resolveImport(symbolFromSymbolTable);
771-
if (isAccessible(symbolFromSymbolTable, resolveImport(symbolFromSymbolTable))) {
772-
return [symbolFromSymbolTable];
773-
}
770+
if (!useOnlyExternalAliasing || // We can use any type of alias to get the name
771+
// Is this external alias, then use it to name
772+
ts.forEach(symbolFromSymbolTable.declarations, declaration =>
773+
declaration.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>declaration).externalModuleName)) {
774+
var resolvedImportedSymbol = resolveImport(symbolFromSymbolTable);
775+
if (isAccessible(symbolFromSymbolTable, resolveImport(symbolFromSymbolTable))) {
776+
return [symbolFromSymbolTable];
777+
}
774778

775-
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
776-
// but only if the symbolFromSymbolTable can be qualified
777-
var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
778-
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
779-
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
779+
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
780+
// but only if the symbolFromSymbolTable can be qualified
781+
var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
782+
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
783+
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
784+
}
780785
}
781786
}
782787
});
@@ -822,7 +827,7 @@ module ts {
822827
var meaningToLook = meaning;
823828
while (symbol) {
824829
// Symbol is accessible if it by itself is accessible
825-
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook);
830+
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
826831
if (accessibleSymbolChain) {
827832
var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]);
828833
if (!hasAccessibleDeclarations) {
@@ -1005,7 +1010,7 @@ module ts {
10051010
writer.trackSymbol(symbol, enclosingDeclaration, meaning);
10061011
function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void {
10071012
if (symbol) {
1008-
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning);
1013+
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, !!(flags & SymbolFormatFlags.UseOnlyExternalAliasing));
10091014

10101015
if (!accessibleSymbolChain ||
10111016
needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {

src/compiler/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,9 @@ module ts {
695695
// eg. class C<T> { p: T } <-- Show p as C<T>.p here
696696
// var a: C<number>;
697697
// var p = a.p; <--- Here p is property of C<number> so show it as C<number>.p instead of just C.p
698+
UseOnlyExternalAliasing = 0x00000002, // Use only external alias information to get the symbol name in the given context
699+
// eg. module m { export class c { } } import x = m.c;
700+
// When this flag is specified m.c will be used to refer to the class instead of alias symbol x
698701
}
699702

700703
export enum SymbolAccessibility {

src/services/services.ts

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,15 +2749,11 @@ module ts {
27492749
var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags);
27502750
var hasAddedSymbolInfo: boolean;
27512751
// Class at constructor site need to be shown as constructor apart from property,method, vars
2752-
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Signature || symbolFlags & SymbolFlags.Class) {
2752+
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Import) {
27532753
// If it is accessor they are allowed only if location is at name of the accessor
27542754
if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) {
27552755
symbolKind = ScriptElementKind.memberVariableElement;
27562756
}
2757-
else if (symbol.name === "undefined") {
2758-
// undefined is symbol and not property
2759-
symbolKind = ScriptElementKind.variableElement;
2760-
}
27612757

27622758
var type = typeResolver.getTypeOfSymbol(symbol);
27632759
if (type) {
@@ -2790,6 +2786,18 @@ module ts {
27902786
symbolKind = ScriptElementKind.constructorImplementationElement;
27912787
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
27922788
}
2789+
else if (symbolFlags & SymbolFlags.Import) {
2790+
symbolKind = ScriptElementKind.alias;
2791+
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
2792+
displayParts.push(textPart(symbolKind));
2793+
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
2794+
displayParts.push(spacePart());
2795+
if (useConstructSignatures) {
2796+
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
2797+
displayParts.push(spacePart());
2798+
}
2799+
addFullSymbolName(symbol);
2800+
}
27932801
else {
27942802
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
27952803
}
@@ -2851,41 +2859,41 @@ module ts {
28512859
if (symbolFlags & SymbolFlags.Class && !hasAddedSymbolInfo) {
28522860
displayParts.push(keywordPart(SyntaxKind.ClassKeyword));
28532861
displayParts.push(spacePart());
2854-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
2862+
addFullSymbolName(symbol);
28552863
writeTypeParametersOfSymbol(symbol, sourceFile);
28562864
}
28572865
if (symbolFlags & SymbolFlags.Interface) {
28582866
addNewLineIfDisplayPartsExist();
28592867
displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
28602868
displayParts.push(spacePart());
2861-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
2869+
addFullSymbolName(symbol);
28622870
writeTypeParametersOfSymbol(symbol, sourceFile);
28632871
}
28642872
if (symbolFlags & SymbolFlags.Enum) {
28652873
addNewLineIfDisplayPartsExist();
28662874
displayParts.push(keywordPart(SyntaxKind.EnumKeyword));
28672875
displayParts.push(spacePart());
2868-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
2876+
addFullSymbolName(symbol);
28692877
}
28702878
if (symbolFlags & SymbolFlags.Module) {
28712879
addNewLineIfDisplayPartsExist();
28722880
displayParts.push(keywordPart(SyntaxKind.ModuleKeyword));
28732881
displayParts.push(spacePart());
2874-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
2882+
addFullSymbolName(symbol);
28752883
}
28762884
if (symbolFlags & SymbolFlags.TypeParameter) {
28772885
addNewLineIfDisplayPartsExist();
28782886
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
28792887
displayParts.push(textPart("type parameter"));
28802888
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
28812889
displayParts.push(spacePart());
2882-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration));
2890+
addFullSymbolName(symbol);
28832891
displayParts.push(spacePart());
28842892
displayParts.push(keywordPart(SyntaxKind.InKeyword));
28852893
displayParts.push(spacePart());
28862894
if (symbol.parent) {
28872895
// Class/Interface type parameter
2888-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol.parent, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments))
2896+
addFullSymbolName(symbol.parent, enclosingDeclaration);
28892897
writeTypeParametersOfSymbol(symbol.parent, enclosingDeclaration);
28902898
}
28912899
else {
@@ -2897,7 +2905,7 @@ module ts {
28972905
displayParts.push(spacePart());
28982906
}
28992907
else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) {
2900-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, signatureDeclaration.symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments))
2908+
addFullSymbolName(signatureDeclaration.symbol);
29012909
}
29022910
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature));
29032911
}
@@ -2917,11 +2925,28 @@ module ts {
29172925
}
29182926
if (symbolFlags & SymbolFlags.Import) {
29192927
addNewLineIfDisplayPartsExist();
2920-
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
2921-
displayParts.push(textPart("alias"));
2922-
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
2928+
displayParts.push(keywordPart(SyntaxKind.ImportKeyword));
2929+
displayParts.push(spacePart());
2930+
addFullSymbolName(symbol);
2931+
displayParts.push(spacePart());
2932+
displayParts.push(punctuationPart(SyntaxKind.EqualsToken));
29232933
displayParts.push(spacePart());
2924-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
2934+
ts.forEach(symbol.declarations, declaration => {
2935+
if (declaration.kind === SyntaxKind.ImportDeclaration) {
2936+
var importDeclaration = <ImportDeclaration>declaration;
2937+
if (importDeclaration.externalModuleName) {
2938+
displayParts.push(keywordPart(SyntaxKind.RequireKeyword));
2939+
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
2940+
displayParts.push(displayPart(getTextOfNode(importDeclaration.externalModuleName), SymbolDisplayPartKind.stringLiteral));
2941+
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
2942+
}
2943+
else {
2944+
var internalAliasSymbol = typeResolver.getSymbolInfo(importDeclaration.entityName);
2945+
addFullSymbolName(internalAliasSymbol, enclosingDeclaration);
2946+
}
2947+
return true;
2948+
}
2949+
});
29252950
}
29262951
if (!hasAddedSymbolInfo) {
29272952
if (symbolKind !== ScriptElementKind.unknown) {
@@ -2969,15 +2994,20 @@ module ts {
29692994
}
29702995
}
29712996

2997+
function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) {
2998+
var fullSymbolDisplayParts = symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
2999+
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing);
3000+
displayParts.push.apply(displayParts, fullSymbolDisplayParts);
3001+
}
3002+
29723003
function addPrefixForAnyFunctionOrVar(symbol: Symbol, symbolKind: string) {
29733004
addNewLineIfDisplayPartsExist();
29743005
if (symbolKind) {
29753006
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
29763007
displayParts.push(textPart(symbolKind));
29773008
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
29783009
displayParts.push(spacePart());
2979-
// Write type parameters of class/Interface if it is property/method of the generic class/interface
2980-
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
3010+
addFullSymbolName(symbol);
29813011
}
29823012
}
29833013

@@ -3023,7 +3053,7 @@ module ts {
30233053
case SyntaxKind.QualifiedName:
30243054
case SyntaxKind.ThisKeyword:
30253055
case SyntaxKind.SuperKeyword:
3026-
// For the identifiers/this/usper etc get the type at position
3056+
// For the identifiers/this/super etc get the type at position
30273057
var type = typeInfoResolver.getTypeOfNode(node);
30283058
if (type) {
30293059
return {

tests/cases/fourslash/commentsExternalModules.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i");
6969

7070
goTo.file("commentsExternalModules_file1.ts");
7171
goTo.marker('9');
72-
verify.quickInfoIs('(alias) extMod', "This is on import declaration");
72+
verify.quickInfoIs('import extMod = require("commentsExternalModules_file0")', "This is on import declaration");
7373

7474
goTo.marker('10');
75-
verify.completionListContains("extMod", "(alias) extMod", "This is on import declaration");
75+
verify.completionListContains("extMod", 'import extMod = require("commentsExternalModules_file0")', "This is on import declaration");
7676

7777
goTo.marker('11');
7878
verify.memberListContains("m1", "module extMod.m1");

tests/cases/fourslash/commentsImportDeclaration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ goTo.marker('2');
2828
verify.quickInfoIs("module m1", "ModuleComment");
2929

3030
goTo.marker('3');
31-
verify.quickInfoIs("(alias) extMod", "Import declaration");
31+
verify.quickInfoIs('import extMod = require("commentsImportDeclaration_file0")', "Import declaration");
3232

3333
goTo.marker('6');
3434
verify.memberListContains("m1", "module extMod.m1");

tests/cases/fourslash/completionListOnAliases.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
////}
1010

1111
goTo.marker("1");
12-
verify.memberListContains("x", "(alias) x", undefined);
12+
verify.memberListContains("x", "import x = M", undefined);
1313

1414
goTo.marker("2");
1515
verify.memberListContains("value");

tests/cases/fourslash/exportEqualTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
////var /*3*/r2 = t./*4*/foo; // t should have 'foo' in dropdown list and be of type 'string'
1616

1717
goTo.marker('1');
18-
verify.quickInfoIs('(alias) test');
18+
verify.quickInfoIs("import test = require('exportEqualTypes_file0')");
1919
goTo.marker('2');
2020
verify.quickInfoIs('(var) r1: Date');
2121
goTo.marker('3');

tests/cases/fourslash/externalModuleWithExportAssignment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
goTo.file("externalModuleWithExportAssignment_file1.ts");
3232
goTo.marker('1');
33-
verify.quickInfoIs("(alias) a1");
33+
verify.quickInfoIs('import a1 = require("externalModuleWithExportAssignment_file0")');
3434

3535
goTo.marker('2');
3636
verify.quickInfoIs("(var) a: {\n (): a1.connectExport;\n test1: a1.connectModule;\n test2(): a1.connectModule;\n}", undefined);

tests/cases/fourslash/mergedDeclarationsWithExportAssignment1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
edit.insert('');
2020

2121
goTo.marker('1');
22-
verify.quickInfoIs('(alias) Foo');
22+
verify.quickInfoIs("import Foo = require('mergedDeclarationsWithExportAssignment1_file0')");
2323

2424
goTo.marker('2');
2525
verify.completionListContains('Foo');

0 commit comments

Comments
 (0)