From 782275924fbb6ae3cee4fdea1c445a3b2372d7fb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 1 Oct 2014 18:51:58 -0700 Subject: [PATCH 1/2] Only show first overload in a series of consecutive overload signatures for navigateTo --- src/services/services.ts | 32 +++++++++++++++---- .../fourslash/navigationItemsOverloads1.ts | 30 +++++++++++++++++ .../fourslash/navigationItemsOverloads2.ts | 12 +++++++ .../navigationItemsOverloadsBroken.ts | 29 +++++++++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/navigationItemsOverloads1.ts create mode 100644 tests/cases/fourslash/navigationItemsOverloads2.ts create mode 100644 tests/cases/fourslash/navigationItemsOverloadsBroken.ts diff --git a/src/services/services.ts b/src/services/services.ts index a35c1213956..a7a3b43afd1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -504,17 +504,36 @@ module ts { if (!this.namedDeclarations) { var sourceFile = this; var namedDeclarations: Declaration[] = []; - var isExternalModule = ts.isExternalModule(sourceFile); + + // This keeps track of the last encountered function/method/method signature + // so that we may ignore all but the first overload. + var overloadDeclaration: FunctionDeclaration; forEachChild(sourceFile, function visit(node: Node): boolean { switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.Method: + var functionDeclaration = node; + + // We can assume that overloadDeclaration will never be "trampled" + // between consecutive overloads because we never dive into parameter initializers. + if (functionDeclaration.name) { + if (overloadDeclaration && + functionDeclaration.name.text === overloadDeclaration.name.text && + node.parent === overloadDeclaration.parent) { + break; + } + + namedDeclarations.push(functionDeclaration); + overloadDeclaration = functionDeclaration; + } + break; + case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: - case SyntaxKind.Method: - case SyntaxKind.FunctionDeclaration: case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -522,9 +541,7 @@ module ts { if ((node).name) { namedDeclarations.push(node); } - forEachChild(node, visit); - break; - + // fall through case SyntaxKind.VariableStatement: case SyntaxKind.ModuleBlock: case SyntaxKind.FunctionBlock: @@ -532,10 +549,11 @@ module ts { break; case SyntaxKind.Parameter: + // Only consider properties defined as constructor parameters if (!(node.flags & NodeFlags.AccessibilityModifier)) { - // Only consider properties defined as constructor parameters break; } + // fall through case SyntaxKind.VariableDeclaration: case SyntaxKind.EnumMember: case SyntaxKind.Property: diff --git a/tests/cases/fourslash/navigationItemsOverloads1.ts b/tests/cases/fourslash/navigationItemsOverloads1.ts new file mode 100644 index 00000000000..5f1981fe917 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloads1.ts @@ -0,0 +1,30 @@ +/// + +////function overload(a: string): boolean; +////function overload(b: boolean): boolean; +////function overload(b: number): boolean; +////function overload(f: typeof overload): boolean; +////function overload(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} +//// +////interface I { +//// interfaceMethodSignature(a: string): boolean; +//// interfaceMethodSignature(b: boolean): boolean; +//// interfaceMethodSignature(b: number): boolean; +//// interfaceMethodSignature(f: I): boolean; +////} +//// +////class C { +//// methodOverload(a: string): boolean; +//// methodOverload(b: boolean): boolean; +//// methodOverload(b: number): boolean; +//// methodOverload(f: I): boolean; +//// methodOverload(x: any, b = (function overload() { return false })): boolean { +//// throw C; +//// } +////} + +verify.navigationItemsListCount(1, "overload", "exact"); +verify.navigationItemsListCount(1, "interfaceMethodSignature", "exact"); +verify.navigationItemsListCount(1, "methodOverload", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloads2.ts b/tests/cases/fourslash/navigationItemsOverloads2.ts new file mode 100644 index 00000000000..c5824b639bc --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloads2.ts @@ -0,0 +1,12 @@ +/// + +////interface I { +//// interfaceMethodSignature(a: string): boolean; +//// interfaceMethodSignature(b: number): boolean; +//// interfaceMethodSignature(f: I): boolean; +////} +////interface I { +//// interfaceMethodSignature(b: boolean): boolean; +////} + +verify.navigationItemsListCount(2, "interfaceMethodSignature", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken.ts new file mode 100644 index 00000000000..f9501948272 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken.ts @@ -0,0 +1,29 @@ +/// + +////function overload1(a: string): boolean; +////function overload1(b: boolean): boolean; +////function overload1(b: number): boolean; +//// +////var heyImNotInterruptingAnythingAmI = '?'; +//// +////function overload1(f: typeof overload): boolean; +////function overload1(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} + +////function overload2(a: string): boolean; +////function overload2(b: boolean): boolean; +////function overload2(b: number): boolean; +//// +////function iJustRuinEverything(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} +//// +////function overload2(f: typeof overload): boolean; +////function overload2(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} + +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(2, "overload2", "exact"); +verify.navigationItemsListCount(3, "overload", "prefix"); \ No newline at end of file From 4069e0a0d00a1bed4654a9c252a895e8ae4b8bf2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 15:53:35 -0700 Subject: [PATCH 2/2] Finished up "overload collapsing" for navigate-to. Current semantics: - If an overload lacks an implementation, go to the first implementation. - If an overload has any implementation, go to the first one. - If there are any declarations between an implementation and any overload, this will split the series of overloads (note that this is invalid code). --- src/services/services.ts | 36 +++++++++---------- ....ts => navigationItemsOverloadsBroken1.ts} | 4 +-- .../navigationItemsOverloadsBroken2.ts | 23 ++++++++++++ 3 files changed, 43 insertions(+), 20 deletions(-) rename tests/cases/fourslash/{navigationItemsOverloadsBroken.ts => navigationItemsOverloadsBroken1.ts} (88%) create mode 100644 tests/cases/fourslash/navigationItemsOverloadsBroken2.ts diff --git a/src/services/services.ts b/src/services/services.ts index a7a3b43afd1..11a84a42635 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -504,28 +504,31 @@ module ts { if (!this.namedDeclarations) { var sourceFile = this; var namedDeclarations: Declaration[] = []; - - // This keeps track of the last encountered function/method/method signature - // so that we may ignore all but the first overload. - var overloadDeclaration: FunctionDeclaration; - forEachChild(sourceFile, function visit(node: Node): boolean { + forEachChild(sourceFile, function visit(node: Node): void { switch (node.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.Method: var functionDeclaration = node; - // We can assume that overloadDeclaration will never be "trampled" - // between consecutive overloads because we never dive into parameter initializers. - if (functionDeclaration.name) { - if (overloadDeclaration && - functionDeclaration.name.text === overloadDeclaration.name.text && - node.parent === overloadDeclaration.parent) { - break; + if (functionDeclaration.name && functionDeclaration.name.kind !== SyntaxKind.Missing) { + var lastDeclaration = namedDeclarations.length > 0 ? + namedDeclarations[namedDeclarations.length - 1] : + undefined; + + // Check whether this declaration belongs to an "overload group". + if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) { + // Overwrite the last declaration if it was an overload + // and this one is an implementation. + if (functionDeclaration.body && !(lastDeclaration).body) { + namedDeclarations[namedDeclarations.length - 1] = functionDeclaration; + } + } + else { + namedDeclarations.push(node); } - namedDeclarations.push(functionDeclaration); - overloadDeclaration = functionDeclaration; + forEachChild(node, visit); } break; @@ -534,7 +537,6 @@ module ts { case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: - case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeLiteral: @@ -542,6 +544,7 @@ module ts { namedDeclarations.push(node); } // fall through + case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: case SyntaxKind.ModuleBlock: case SyntaxKind.FunctionBlock: @@ -560,9 +563,6 @@ module ts { namedDeclarations.push(node); break; } - - // do not go any deeper - return undefined; }); this.namedDeclarations = namedDeclarations; diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts similarity index 88% rename from tests/cases/fourslash/navigationItemsOverloadsBroken.ts rename to tests/cases/fourslash/navigationItemsOverloadsBroken1.ts index f9501948272..7b8ebc9181f 100644 --- a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts @@ -24,6 +24,6 @@ //// throw overload; ////} -verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(2, "overload1", "exact"); verify.navigationItemsListCount(2, "overload2", "exact"); -verify.navigationItemsListCount(3, "overload", "prefix"); \ No newline at end of file +verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts new file mode 100644 index 00000000000..c1f6ccae2f5 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts @@ -0,0 +1,23 @@ +/// + +////function overload1(a: string): boolean; +////function overload1(b: boolean): boolean; +////function overload1(x: any, b = (function overload() { return false })): boolean { +//// throw overload1; +////} +////function overload1(b: number): boolean; +////function overload1(f: typeof overload): boolean; + +////function overload2(a: string): boolean; +////function overload2(b: boolean): boolean; +////function overload2(x: any, b = (function overload() { return false })): boolean { +//// function overload2(): boolean; +//// function overload2(x: any): boolean; +//// throw overload2; +////} +////function overload2(b: number): boolean; +////function overload2(f: typeof overload): boolean; + +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(3, "overload2", "exact"); +verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file