mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-10 21:07:52 -05:00
Merge pull request #874 from Microsoft/betterAliasSymbolInfo
Shows better information for aliases in the quick info/completion entry
This commit is contained in:
@@ -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 && (<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))) {
|
||||
|
||||
@@ -695,6 +695,9 @@ module ts {
|
||||
// eg. class C<T> { p: T } <-- Show p as C<T>.p here
|
||||
// var a: C<number>;
|
||||
// var p = a.p; <--- Here p is property of C<number> so show it as C<number>.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 {
|
||||
|
||||
@@ -2749,15 +2749,11 @@ module ts {
|
||||
var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags);
|
||||
var hasAddedSymbolInfo: boolean;
|
||||
// Class at constructor site need to be shown as constructor apart from property,method, vars
|
||||
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Signature || symbolFlags & SymbolFlags.Class) {
|
||||
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Import) {
|
||||
// If it is accessor they are allowed only if location is at name of the accessor
|
||||
if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) {
|
||||
symbolKind = ScriptElementKind.memberVariableElement;
|
||||
}
|
||||
else if (symbol.name === "undefined") {
|
||||
// undefined is symbol and not property
|
||||
symbolKind = ScriptElementKind.variableElement;
|
||||
}
|
||||
|
||||
var type = typeResolver.getTypeOfSymbol(symbol);
|
||||
if (type) {
|
||||
@@ -2790,6 +2786,18 @@ module ts {
|
||||
symbolKind = ScriptElementKind.constructorImplementationElement;
|
||||
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
|
||||
}
|
||||
else if (symbolFlags & SymbolFlags.Import) {
|
||||
symbolKind = ScriptElementKind.alias;
|
||||
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
displayParts.push(textPart(symbolKind));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
displayParts.push(spacePart());
|
||||
if (useConstructSignatures) {
|
||||
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
|
||||
displayParts.push(spacePart());
|
||||
}
|
||||
addFullSymbolName(symbol);
|
||||
}
|
||||
else {
|
||||
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
|
||||
}
|
||||
@@ -2851,27 +2859,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 +2887,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 +2905,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));
|
||||
}
|
||||
@@ -2917,11 +2925,28 @@ module ts {
|
||||
}
|
||||
if (symbolFlags & SymbolFlags.Import) {
|
||||
addNewLineIfDisplayPartsExist();
|
||||
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
displayParts.push(textPart("alias"));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
displayParts.push(keywordPart(SyntaxKind.ImportKeyword));
|
||||
displayParts.push(spacePart());
|
||||
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
|
||||
addFullSymbolName(symbol);
|
||||
displayParts.push(spacePart());
|
||||
displayParts.push(punctuationPart(SyntaxKind.EqualsToken));
|
||||
displayParts.push(spacePart());
|
||||
ts.forEach(symbol.declarations, declaration => {
|
||||
if (declaration.kind === SyntaxKind.ImportDeclaration) {
|
||||
var importDeclaration = <ImportDeclaration>declaration;
|
||||
if (importDeclaration.externalModuleName) {
|
||||
displayParts.push(keywordPart(SyntaxKind.RequireKeyword));
|
||||
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
displayParts.push(displayPart(getTextOfNode(importDeclaration.externalModuleName), SymbolDisplayPartKind.stringLiteral));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
else {
|
||||
var internalAliasSymbol = typeResolver.getSymbolInfo(importDeclaration.entityName);
|
||||
addFullSymbolName(internalAliasSymbol, enclosingDeclaration);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!hasAddedSymbolInfo) {
|
||||
if (symbolKind !== ScriptElementKind.unknown) {
|
||||
@@ -2969,6 +2994,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 +3007,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3023,7 +3053,7 @@ module ts {
|
||||
case SyntaxKind.QualifiedName:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
// For the identifiers/this/usper etc get the type at position
|
||||
// For the identifiers/this/super etc get the type at position
|
||||
var type = typeInfoResolver.getTypeOfNode(node);
|
||||
if (type) {
|
||||
return {
|
||||
|
||||
@@ -69,10 +69,10 @@ verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i");
|
||||
|
||||
goTo.file("commentsExternalModules_file1.ts");
|
||||
goTo.marker('9');
|
||||
verify.quickInfoIs('(alias) extMod', "This is on import declaration");
|
||||
verify.quickInfoIs('import extMod = require("commentsExternalModules_file0")', "This is on import declaration");
|
||||
|
||||
goTo.marker('10');
|
||||
verify.completionListContains("extMod", "(alias) extMod", "This is on import declaration");
|
||||
verify.completionListContains("extMod", 'import extMod = require("commentsExternalModules_file0")', "This is on import declaration");
|
||||
|
||||
goTo.marker('11');
|
||||
verify.memberListContains("m1", "module extMod.m1");
|
||||
|
||||
@@ -28,7 +28,7 @@ goTo.marker('2');
|
||||
verify.quickInfoIs("module m1", "ModuleComment");
|
||||
|
||||
goTo.marker('3');
|
||||
verify.quickInfoIs("(alias) extMod", "Import declaration");
|
||||
verify.quickInfoIs('import extMod = require("commentsImportDeclaration_file0")', "Import declaration");
|
||||
|
||||
goTo.marker('6');
|
||||
verify.memberListContains("m1", "module extMod.m1");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.memberListContains("x", "(alias) x", undefined);
|
||||
verify.memberListContains("x", "import x = M", undefined);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.memberListContains("value");
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
////var /*3*/r2 = t./*4*/foo; // t should have 'foo' in dropdown list and be of type 'string'
|
||||
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs('(alias) test');
|
||||
verify.quickInfoIs("import test = require('exportEqualTypes_file0')");
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs('(var) r1: Date');
|
||||
goTo.marker('3');
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
goTo.file("externalModuleWithExportAssignment_file1.ts");
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs("(alias) a1");
|
||||
verify.quickInfoIs('import a1 = require("externalModuleWithExportAssignment_file0")');
|
||||
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs("(var) a: {\n (): a1.connectExport;\n test1: a1.connectModule;\n test2(): a1.connectModule;\n}", undefined);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
edit.insert('');
|
||||
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs('(alias) Foo');
|
||||
verify.quickInfoIs("import Foo = require('mergedDeclarationsWithExportAssignment1_file0')");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.completionListContains('Foo');
|
||||
|
||||
59
tests/cases/fourslash/quickInfoOnInternalAliases.ts
Normal file
59
tests/cases/fourslash/quickInfoOnInternalAliases.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
/////** Module comment*/
|
||||
////export module m1 {
|
||||
//// /** m2 comments*/
|
||||
//// export module m2 {
|
||||
//// /** class comment;*/
|
||||
//// export class /*1*/c {
|
||||
//// };
|
||||
//// }
|
||||
//// export function foo() {
|
||||
//// }
|
||||
////}
|
||||
/////**This is on import declaration*/
|
||||
////import /*2*/internalAlias = m1.m2./*3*/c;
|
||||
////var /*4*/newVar = new /*5*/internalAlias();
|
||||
////var /*6*/anotherAliasVar = /*7*/internalAlias;
|
||||
////import /*8*/internalFoo = m1./*9*/foo;
|
||||
////var /*10*/callVar = /*11*/internalFoo();
|
||||
////var /*12*/anotherAliasFoo = /*13*/internalFoo;
|
||||
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs("class m1.m2.c", "class comment;");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs('import internalAlias = m1.m2.c', "This is on import declaration");
|
||||
|
||||
goTo.marker('3');
|
||||
verify.quickInfoIs("class m1.m2.c", "class comment;");
|
||||
|
||||
goTo.marker('4');
|
||||
verify.quickInfoIs("(var) newVar: internalAlias", "");
|
||||
|
||||
goTo.marker('5');
|
||||
verify.quickInfoIs("(alias) new internalAlias(): internalAlias\nimport internalAlias = m1.m2.c", "");
|
||||
|
||||
goTo.marker('6');
|
||||
verify.quickInfoIs("(var) anotherAliasVar: typeof internalAlias", "");
|
||||
|
||||
goTo.marker('7');
|
||||
verify.quickInfoIs("import internalAlias = m1.m2.c", "This is on import declaration");
|
||||
|
||||
goTo.marker('8');
|
||||
verify.quickInfoIs('import internalFoo = m1.foo', "");
|
||||
|
||||
goTo.marker('9');
|
||||
verify.quickInfoIs("(function) m1.foo(): void", "");
|
||||
|
||||
goTo.marker('10');
|
||||
verify.quickInfoIs("(var) callVar: void", "");
|
||||
|
||||
goTo.marker('11');
|
||||
verify.quickInfoIs("(alias) internalFoo(): void\nimport internalFoo = m1.foo", "");
|
||||
|
||||
goTo.marker('12');
|
||||
verify.quickInfoIs("(var) anotherAliasFoo: () => void", "");
|
||||
|
||||
goTo.marker('13');
|
||||
verify.quickInfoIs("import internalFoo = m1.foo", "");
|
||||
@@ -3,6 +3,13 @@
|
||||
////function foo(a: string) {
|
||||
////}
|
||||
////foo(/*1*/undefined);
|
||||
////var x = {
|
||||
//// undefined: 10
|
||||
////};
|
||||
////x./*2*/undefined = 30;
|
||||
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs('(var) undefined');
|
||||
verify.quickInfoIs('(var) undefined');
|
||||
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs('(property) undefined: number');
|
||||
@@ -5,5 +5,5 @@
|
||||
////A./**/I
|
||||
|
||||
goTo.marker();
|
||||
verify.completionListContains("A", "(alias) A");
|
||||
verify.completionListContains("A", "import A = require('app')");
|
||||
verify.completionListContains("I", "(var) I: number");
|
||||
Reference in New Issue
Block a user