From c450d8d392a4c95caf4881288a2e66372e1db770 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 29 Sep 2014 09:49:09 -0700 Subject: [PATCH] Determine if the function/var is local to function block --- src/compiler/checker.ts | 2 +- src/services/services.ts | 98 +++++++++++-------- ...completionListInNamedFunctionExpression.ts | 6 +- tests/cases/fourslash/functionProperty.ts | 24 ++--- .../genericFunctionWithGenericParams1.ts | 5 +- tests/cases/fourslash/localFunction.ts | 20 ++++ tests/cases/fourslash_old/functionProperty.ts | 49 ---------- 7 files changed, 94 insertions(+), 110 deletions(-) create mode 100644 tests/cases/fourslash/localFunction.ts delete mode 100644 tests/cases/fourslash_old/functionProperty.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4d91893df05..8ed2f185b9b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1014,7 +1014,7 @@ module ts { } // if this is anonymous type break - if (symbol.flags & SymbolFlags.TypeLiteral) { + if (symbol.flags & SymbolFlags.TypeLiteral || symbol.flags & SymbolFlags.ObjectLiteral) { return; } diff --git a/src/services/services.ts b/src/services/services.ts index 6aca2b4bb50..278895dfb33 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1317,6 +1317,38 @@ module ts { return displayPart("\n", SymbolDisplayPartKind.lineBreak); } + function isFirstDeclarationOfSymbolParameter(symbol: Symbol) { + return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter; + } + + function isLocalVariableOrFunction(symbol: Symbol) { + if (symbol.parent) { + return false; // This is exported symbol + } + + return ts.forEach(symbol.declarations, declaration => { + // Function expressions are local + if (declaration.kind === SyntaxKind.FunctionExpression) { + return true; + } + + if (declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.FunctionDeclaration) { + return; + } + + // If the parent is not sourceFile or module element it is local variable + for (var parent = declaration.parent; parent.kind !== SyntaxKind.FunctionBlock; parent = parent.parent) { + // Reached source file or module block + if (parent.kind === SyntaxKind.SourceFile || parent.kind === SyntaxKind.ModuleBlock) { + return; + } + } + + // parent is in function block + return true; + }); + } + export function symbolPart(text: string, symbol: Symbol) { return displayPart(text, displayPartKind(symbol), symbol); @@ -1324,9 +1356,7 @@ module ts { var flags = symbol.flags; if (flags & SymbolFlags.Variable) { - return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter - ? SymbolDisplayPartKind.parameterName - : SymbolDisplayPartKind.localName; + return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName; } else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; } else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; } @@ -2534,27 +2564,35 @@ module ts { if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; + var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags); + if (result === ScriptElementKind.unknown) { + if (flags & SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; + if (flags & SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; + if (flags & SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; + if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + } + + return result; + } + + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags) { if (flags & SymbolFlags.Variable) { - if (ts.forEach(symbol.declarations, declaration => declaration.kind === SyntaxKind.Parameter)) { + if (isFirstDeclarationOfSymbolParameter(symbol)) { return ScriptElementKind.parameterElement; } - return ScriptElementKind.variableElement; + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; } - if (flags & SymbolFlags.Function) return ScriptElementKind.functionElement; + 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; if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; if (flags & SymbolFlags.Property) return ScriptElementKind.memberVariableElement; - if (flags & SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; - if (flags & SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; - if (flags & SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; - if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; return ScriptElementKind.unknown; } - + function getTypeKind(type: Type): string { var flags = type.getFlags(); @@ -2613,7 +2651,7 @@ module ts { function getSymbolDisplayPartsofSymbol(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, typeResolver: TypeChecker): SymbolDisplayPart[] { var displayParts: SymbolDisplayPart[] = []; - var symbolFlags = typeResolver.getTargetSymbol(symbol).flags; + var symbolFlags = typeResolver.getRootSymbol(symbol).flags; if (symbolFlags & SymbolFlags.Class) { displayParts.push(keywordPart(SyntaxKind.ClassKeyword)); displayParts.push(spacePart()); @@ -2647,36 +2685,16 @@ module ts { } else { //public static string FormatSymbolName(string name, string fullSymbolName, string kind, out bool useTypeName) + var symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags); var text: string; - if (symbolFlags & SymbolFlags.Property) { - text = "property"; - } - else if (symbolFlags & SymbolFlags.EnumMember) { + if (symbolKind === ScriptElementKind.unknown) { + if (symbolFlags & SymbolFlags.EnumMember) { text = "enum member"; } - else if (symbolFlags & SymbolFlags.Function) { - text = "function"; - } - else if (symbolFlags & SymbolFlags.Variable) { - if (ts.forEach(symbol.declarations, declaration => declaration.kind === SyntaxKind.Parameter)) { - text = "parameter"; - } - else { - text = "var"; - } - } - else if (symbolFlags & SymbolFlags.Method) { - text = "method"; - } - else if (symbolFlags & SymbolFlags.Constructor) { - text = "constructor"; - } - else if (symbolFlags & SymbolFlags.GetAccessor) { - text = "getter"; - } - else if (symbolFlags & SymbolFlags.SetAccessor) { - text = "setter"; - } + } + else { + text = symbolKind; + } if (text || symbolFlags & SymbolFlags.Signature) { addNewLineIfDisplayPartsExist(); diff --git a/tests/cases/fourslash/completionListInNamedFunctionExpression.ts b/tests/cases/fourslash/completionListInNamedFunctionExpression.ts index 4e2ad4dec3a..6321018f5b5 100644 --- a/tests/cases/fourslash/completionListInNamedFunctionExpression.ts +++ b/tests/cases/fourslash/completionListInNamedFunctionExpression.ts @@ -24,9 +24,7 @@ goTo.marker("insideFunctionExpression"); verify.memberListContains("foo"); goTo.marker("referenceInsideFunctionExpression"); -verify.quickInfoIs("(function) foo(): number"); +verify.quickInfoIs("(local function) foo(): number"); goTo.marker("referenceInGlobalScope"); -verify.quickInfoIs("(function) foo(a: number): string"); - - +verify.quickInfoIs("(function) foo(a: number): string"); \ No newline at end of file diff --git a/tests/cases/fourslash/functionProperty.ts b/tests/cases/fourslash/functionProperty.ts index 4f089d95cf3..e9ffdcf2cdf 100644 --- a/tests/cases/fourslash/functionProperty.ts +++ b/tests/cases/fourslash/functionProperty.ts @@ -30,20 +30,20 @@ verify.currentSignatureHelpIs('x(a: number): void'); goTo.marker('signatureC'); verify.currentSignatureHelpIs('x(a: number): void'); -//goTo.marker('completionA'); -//verify.completionListContains("x", "(a: number): void"); +goTo.marker('completionA'); +verify.completionListContains("x", "(property) x: (a: number) => void"); -//goTo.marker('completionB'); -//verify.completionListContains("x", "(a: number) => void"); +goTo.marker('completionB'); +verify.completionListContains("x", "(property) x: (a: number) => void"); -//goTo.marker('completionC'); -//verify.completionListContains("x", "(a: number) => void"); +goTo.marker('completionC'); +verify.completionListContains("x", "(property) x: (a: number) => void"); -//goTo.marker('quickInfoA'); -//verify.quickInfoIs("(a: number): void", undefined, "x", "local function"); +goTo.marker('quickInfoA'); +verify.quickInfoIs("(property) x: (a: number) => void", undefined); -//goTo.marker('quickInfoB'); -//verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); +goTo.marker('quickInfoB'); +verify.quickInfoIs("(property) x: (a: number) => void", undefined); -//goTo.marker('quickInfoC'); -//verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); \ No newline at end of file +goTo.marker('quickInfoC'); +verify.quickInfoIs("(property) x: (a: number) => void", undefined); \ No newline at end of file diff --git a/tests/cases/fourslash/genericFunctionWithGenericParams1.ts b/tests/cases/fourslash/genericFunctionWithGenericParams1.ts index 10bce872f54..e57da708412 100644 --- a/tests/cases/fourslash/genericFunctionWithGenericParams1.ts +++ b/tests/cases/fourslash/genericFunctionWithGenericParams1.ts @@ -6,7 +6,4 @@ ////}; goTo.marker(); -// TODO (local var) -//verify.quickInfoIs('(local var) xx: T', null); -verify.quickInfoIs('(var) xx: T', null); - +verify.quickInfoIs('(local var) xx: T', null); diff --git a/tests/cases/fourslash/localFunction.ts b/tests/cases/fourslash/localFunction.ts new file mode 100644 index 00000000000..d0227c83a8c --- /dev/null +++ b/tests/cases/fourslash/localFunction.ts @@ -0,0 +1,20 @@ +/// + +////function /*1*/foo() { +//// function /*2*/bar2() { +//// } +//// var y = function /*3*/bar3() { +//// } +////} +////var x = function /*4*/bar4() { +////} + +goTo.marker("1"); +verify.quickInfoIs('(function) foo(): void'); +goTo.marker("2"); +debugger; +verify.quickInfoIs('(local function) bar2(): void'); +goTo.marker("3"); +verify.quickInfoIs('(local function) bar3(): void'); +goTo.marker("4"); +verify.quickInfoIs('(local function) bar4(): void'); diff --git a/tests/cases/fourslash_old/functionProperty.ts b/tests/cases/fourslash_old/functionProperty.ts deleted file mode 100644 index 4fb3ea52949..00000000000 --- a/tests/cases/fourslash_old/functionProperty.ts +++ /dev/null @@ -1,49 +0,0 @@ -/// - -////var a = { -//// x(a: number) { } -////}; -//// -////var b = { -//// x: function (a: number) { } -////}; -//// -////var c = { -//// x: (a: number) => { } -////}; -////a.x(/*signatureA*/1); -////b.x(/*signatureB*/1); -////c.x(/*signatureC*/1); -////a./*completionA*/; -////b./*completionB*/; -////c./*completionC*/; -////a./*quickInfoA*/x; -////b./*quickInfoB*/x; -////c./*quickInfoC*/x; - -goTo.marker('signatureA'); -verify.currentSignatureHelpIs('x(a: number): void'); - -goTo.marker('signatureB'); -verify.currentSignatureHelpIs('x(a: number): void'); - -goTo.marker('signatureC'); -verify.currentSignatureHelpIs('x(a: number): void'); - -goTo.marker('completionA'); -verify.completionListContains("x", "(a: number): void"); - -goTo.marker('completionB'); -verify.completionListContains("x", "(a: number) => void"); - -goTo.marker('completionC'); -verify.completionListContains("x", "(a: number) => void"); - -goTo.marker('quickInfoA'); -verify.quickInfoIs("(a: number): void", undefined, "x", "local function"); - -goTo.marker('quickInfoB'); -verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); - -goTo.marker('quickInfoC'); -verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); \ No newline at end of file