From 8ff6251200a49e4e5c105bd61cb2c035e9bfe320 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 10 Oct 2014 15:02:48 -0700 Subject: [PATCH 1/6] Do not use internal aliasing when getting symbol full name to show in quickInfo or completion list --- src/compiler/checker.ts | 31 +++++++++++-------- src/compiler/types.ts | 3 ++ src/services/services.ts | 25 +++++++++------ .../fourslash/quickInfoOnInternalAliases.ts | 22 +++++++++++++ 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 tests/cases/fourslash/quickInfoOnInternalAliases.ts 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 From 471d80d91e43a9f66a205addec87ac190387be15 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 10 Oct 2014 15:24:19 -0700 Subject: [PATCH 2/6] Show better alias information in completion entry and quickInfo --- src/services/services.ts | 25 ++++++++++++++++--- .../fourslash/commentsExternalModules.ts | 4 +-- .../fourslash/commentsImportDeclaration.ts | 2 +- .../fourslash/completionListOnAliases.ts | 2 +- tests/cases/fourslash/exportEqualTypes.ts | 2 +- .../externalModuleWithExportAssignment.ts | 2 +- ...mergedDeclarationsWithExportAssignment1.ts | 2 +- .../fourslash/quickInfoOnInternalAliases.ts | 19 ++++++++++++-- .../fourslash/selfReferencedExternalModule.ts | 2 +- 9 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 3df83af1028..4b1a16a89b6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2917,11 +2917,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()); 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 = 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) { @@ -3028,7 +3045,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 { diff --git a/tests/cases/fourslash/commentsExternalModules.ts b/tests/cases/fourslash/commentsExternalModules.ts index 0eed08ca01e..c0e27149202 100644 --- a/tests/cases/fourslash/commentsExternalModules.ts +++ b/tests/cases/fourslash/commentsExternalModules.ts @@ -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"); diff --git a/tests/cases/fourslash/commentsImportDeclaration.ts b/tests/cases/fourslash/commentsImportDeclaration.ts index 192cb2763ca..f115f3607b7 100644 --- a/tests/cases/fourslash/commentsImportDeclaration.ts +++ b/tests/cases/fourslash/commentsImportDeclaration.ts @@ -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"); diff --git a/tests/cases/fourslash/completionListOnAliases.ts b/tests/cases/fourslash/completionListOnAliases.ts index 68c25d3608e..3d9026c3036 100644 --- a/tests/cases/fourslash/completionListOnAliases.ts +++ b/tests/cases/fourslash/completionListOnAliases.ts @@ -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"); diff --git a/tests/cases/fourslash/exportEqualTypes.ts b/tests/cases/fourslash/exportEqualTypes.ts index 47a266f7f39..8cfe931d87b 100644 --- a/tests/cases/fourslash/exportEqualTypes.ts +++ b/tests/cases/fourslash/exportEqualTypes.ts @@ -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'); diff --git a/tests/cases/fourslash/externalModuleWithExportAssignment.ts b/tests/cases/fourslash/externalModuleWithExportAssignment.ts index 952640f2c6c..1de1e55579b 100644 --- a/tests/cases/fourslash/externalModuleWithExportAssignment.ts +++ b/tests/cases/fourslash/externalModuleWithExportAssignment.ts @@ -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); diff --git a/tests/cases/fourslash/mergedDeclarationsWithExportAssignment1.ts b/tests/cases/fourslash/mergedDeclarationsWithExportAssignment1.ts index be5376d5de5..3198b6e9243 100644 --- a/tests/cases/fourslash/mergedDeclarationsWithExportAssignment1.ts +++ b/tests/cases/fourslash/mergedDeclarationsWithExportAssignment1.ts @@ -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'); diff --git a/tests/cases/fourslash/quickInfoOnInternalAliases.ts b/tests/cases/fourslash/quickInfoOnInternalAliases.ts index 8c269ac6565..d144594197a 100644 --- a/tests/cases/fourslash/quickInfoOnInternalAliases.ts +++ b/tests/cases/fourslash/quickInfoOnInternalAliases.ts @@ -11,12 +11,27 @@ ////} /////**This is on import declaration*/ ////import /*2*/internalAlias = m1.m2./*3*/c; +////var /*4*/newVar = new /*5*/internalAlias(); +////var /*6*/anotherAliasVar = /*7*/internalAlias; + goTo.marker('1'); verify.quickInfoIs("class m1.m2.c", "class comment;"); goTo.marker('2'); -verify.quickInfoIs('(alias) internalAlias', "This is on import declaration"); +verify.quickInfoIs('import internalAlias = m1.m2.c', "This is on import declaration"); goTo.marker('3'); -verify.quickInfoIs("class m1.m2.c", "class comment;"); \ No newline at end of file +verify.quickInfoIs("class m1.m2.c", "class comment;"); + +goTo.marker('4'); +verify.quickInfoIs("(var) newVar: internalAlias", ""); + +goTo.marker('5'); +verify.quickInfoIs("import internalAlias = m1.m2.c", "This is on import declaration"); + +goTo.marker('6'); +verify.quickInfoIs("(var) anotherAliasVar: typeof internalAlias", ""); + +goTo.marker('7'); +verify.quickInfoIs("import internalAlias = m1.m2.c", "This is on import declaration"); \ No newline at end of file diff --git a/tests/cases/fourslash/selfReferencedExternalModule.ts b/tests/cases/fourslash/selfReferencedExternalModule.ts index ec312ccb1e5..f5e955839c7 100644 --- a/tests/cases/fourslash/selfReferencedExternalModule.ts +++ b/tests/cases/fourslash/selfReferencedExternalModule.ts @@ -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"); \ No newline at end of file From 3715af1a5abddcf62e56f66a429a5ee6cc62fd53 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 10 Oct 2014 15:52:34 -0700 Subject: [PATCH 3/6] Show call and construct signatures when using aliases --- src/services/services.ts | 14 +++++++++- .../fourslash/quickInfoOnInternalAliases.ts | 28 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 4b1a16a89b6..a3e6d7a5445 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2749,7 +2749,7 @@ 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; @@ -2790,6 +2790,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); } diff --git a/tests/cases/fourslash/quickInfoOnInternalAliases.ts b/tests/cases/fourslash/quickInfoOnInternalAliases.ts index d144594197a..b1c562df494 100644 --- a/tests/cases/fourslash/quickInfoOnInternalAliases.ts +++ b/tests/cases/fourslash/quickInfoOnInternalAliases.ts @@ -8,12 +8,16 @@ //// 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;"); @@ -28,10 +32,28 @@ goTo.marker('4'); verify.quickInfoIs("(var) newVar: internalAlias", ""); goTo.marker('5'); -verify.quickInfoIs("import internalAlias = m1.m2.c", "This is on import declaration"); +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"); \ No newline at end of file +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", ""); \ No newline at end of file From 6f6be7e0e4af34d385eacca9f9de001699c7554e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 10 Oct 2014 15:58:33 -0700 Subject: [PATCH 4/6] Removed incorrect check of symbolKind determination of undefined symbol --- src/services/services.ts | 4 ---- tests/cases/fourslash/quickInfoOnUndefined.ts | 9 ++++++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index a3e6d7a5445..05aeb47f7c6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2754,10 +2754,6 @@ module ts { 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) { diff --git a/tests/cases/fourslash/quickInfoOnUndefined.ts b/tests/cases/fourslash/quickInfoOnUndefined.ts index 252da49d4fe..1bb516d2c18 100644 --- a/tests/cases/fourslash/quickInfoOnUndefined.ts +++ b/tests/cases/fourslash/quickInfoOnUndefined.ts @@ -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'); \ No newline at end of file +verify.quickInfoIs('(var) undefined'); + +goTo.marker('2'); +verify.quickInfoIs('(property) undefined: number'); \ No newline at end of file From ab48363bfa17cc7f6d86872dabb9993a09c6bd93 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 13 Oct 2014 13:06:03 -0700 Subject: [PATCH 5/6] Fix how arguments and undefined are shown in the quickInfo Removes the undefined identication from symbol flags instead add method to typechecker --- src/compiler/checker.ts | 6 ++-- src/compiler/types.ts | 4 +-- src/services/services.ts | 35 +++++++++++-------- .../quickInfoOnArgumentsInsideFunction.ts | 9 +++++ 4 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0a40d881433..6c9a943b951 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -105,10 +105,12 @@ module ts { writeTypeParameter: writeTypeParameter, writeTypeParametersOfSymbol: writeTypeParametersOfSymbol, isImplementationOfOverload: isImplementationOfOverload, - getAliasedSymbol: resolveImport + getAliasedSymbol: resolveImport, + isUndefinedSymbol: symbol => symbol === undefinedSymbol, + isArgumentsSymbol: symbol => symbol === argumentsSymbol }; - var undefinedSymbol = createSymbol(SymbolFlags.Undefined | SymbolFlags.Property | SymbolFlags.Transient, "undefined"); + var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined"); var argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments"); var unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown"); var resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__"); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 68ef296e263..c0571bdfb60 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -656,6 +656,8 @@ module ts { writeTypeParameter(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; writeTypeParametersOfSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void; isImplementationOfOverload(node: FunctionDeclaration): boolean; + isUndefinedSymbol(symbol: Symbol): boolean; + isArgumentsSymbol(symbol: Symbol): boolean; // Returns the constant value of this enum member, or 'undefined' if the enum member has a // computed value. @@ -767,8 +769,6 @@ module ts { Transient = 0x02000000, // Transient symbol (created during type check) Prototype = 0x04000000, // Symbol for the prototype property (without source code representation) - Undefined = 0x08000000, // Symbol for the undefined - Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter, Namespace = ValueModule | NamespaceModule, diff --git a/src/services/services.ts b/src/services/services.ts index 05aeb47f7c6..0e8b00f2faf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2250,7 +2250,7 @@ module ts { return undefined; } - function createCompletionEntry(symbol: Symbol): CompletionEntry { + function createCompletionEntry(symbol: Symbol, typeChecker: TypeChecker): CompletionEntry { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) @@ -2261,7 +2261,7 @@ module ts { return { name: displayName, - kind: getSymbolKind(symbol), + kind: getSymbolKind(symbol, typeChecker), kindModifiers: getSymbolModifiers(symbol) }; } @@ -2269,7 +2269,7 @@ module ts { function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { forEach(symbols, symbol => { - var entry = createCompletionEntry(symbol); + var entry = createCompletionEntry(symbol, session.typeChecker); if (entry && !lookUp(session.symbols, entry.name)) { session.entries.push(entry); session.symbols[entry.name] = symbol; @@ -2608,7 +2608,7 @@ module ts { if (symbol) { var type = session.typeChecker.getTypeOfSymbol(symbol); Debug.assert(type, "Could not find type for symbol"); - var completionEntry = createCompletionEntry(symbol); + var completionEntry = createCompletionEntry(symbol, session.typeChecker); // TODO(drosen): Right now we just permit *all* semantic meanings when calling 'getSymbolKind' // which is permissible given that it is backwards compatible; but really we should consider // passing the meaning for the node so that we don't report that a suggestion for a value is an interface. @@ -2657,7 +2657,7 @@ module ts { } // TODO(drosen): use contextual SemanticMeaning. - function getSymbolKind(symbol: Symbol): string { + function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker): string { var flags = typeInfoResolver.getRootSymbol(symbol).getFlags(); if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; @@ -2665,7 +2665,7 @@ module ts { if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags); + var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver); if (result === ScriptElementKind.unknown) { if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; @@ -2675,16 +2675,19 @@ module ts { return result; } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags) { + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, typeResolver: TypeChecker) { + if (typeResolver.isUndefinedSymbol(symbol)) { + return ScriptElementKind.variableElement; + } + if (typeResolver.isArgumentsSymbol(symbol)) { + return ScriptElementKind.localVariableElement; + } if (flags & SymbolFlags.Variable) { if (isFirstDeclarationOfSymbolParameter(symbol)) { return ScriptElementKind.parameterElement; } return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; } - if (flags & SymbolFlags.Undefined) { - return ScriptElementKind.variableElement; - } if (flags & SymbolFlags.Function) return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; @@ -2746,7 +2749,7 @@ module ts { var displayParts: SymbolDisplayPart[] = []; var documentation: SymbolDisplayPart[]; var symbolFlags = typeResolver.getRootSymbol(symbol).flags; - var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags); + var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, typeResolver); var hasAddedSymbolInfo: boolean; // Class at constructor site need to be shown as constructor apart from property,method, vars if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Import) { @@ -2952,8 +2955,10 @@ module ts { if (symbolKind !== ScriptElementKind.unknown) { if (type) { addPrefixForAnyFunctionOrVar(symbol, symbolKind); + // For properties, variables and local vars: show the type if (symbolKind === ScriptElementKind.memberVariableElement || - symbolFlags & SymbolFlags.Variable) { + symbolFlags & SymbolFlags.Variable || + symbolKind === ScriptElementKind.localVariableElement) { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); // If the type is type parameter, format it specially @@ -2978,7 +2983,7 @@ module ts { } } else { - symbolKind = getSymbolKind(symbol); + symbolKind = getSymbolKind(symbol, typeResolver); } } @@ -3184,7 +3189,7 @@ module ts { var declarations = symbol.getDeclarations(); var symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - var symbolKind = getSymbolKind(symbol); + var symbolKind = getSymbolKind(symbol, typeInfoResolver); var containerSymbol = symbol.parent; var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; @@ -5175,7 +5180,7 @@ module ts { // Only allow a symbol to be renamed if it actually has at least one declaration. if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) { - var kind = getSymbolKind(symbol); + var kind = getSymbolKind(symbol, typeInfoResolver); if (kind) { return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind, getSymbolModifiers(symbol), diff --git a/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts b/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts new file mode 100644 index 00000000000..7ac1502ed8c --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts @@ -0,0 +1,9 @@ +/// + +////function foo(x: string) { +//// return /*1*/arguments; +////} + +goTo.marker('1'); +debugger; +verify.quickInfoIs('(local var) arguments: IArguments'); \ No newline at end of file From dfb7785da07141b4fddc88252bcd0ac28a6b8ca7 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 13 Oct 2014 15:03:11 -0700 Subject: [PATCH 6/6] Removed the debugger statement --- tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts b/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts index 7ac1502ed8c..6f08b15da7b 100644 --- a/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts +++ b/tests/cases/fourslash/quickInfoOnArgumentsInsideFunction.ts @@ -5,5 +5,4 @@ ////} goTo.marker('1'); -debugger; verify.quickInfoIs('(local var) arguments: IArguments'); \ No newline at end of file