From e42eeede279e72660623e946d558113088c21ce7 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 9 Jun 2020 11:44:41 -0700 Subject: [PATCH 1/3] Add containerName to CallHierarchyItem --- src/compiler/utilitiesPublic.ts | 3 +- src/harness/fourslashImpl.ts | 3 + src/server/protocol.ts | 1 + src/services/callHierarchy.ts | 30 +++- src/services/types.ts | 1 + .../callHierarchyAccessor.callHierarchy.txt | 1 + ...llHierarchyContainerName.callHierarchy.txt | 165 ++++++++++++++++++ .../fourslash/callHierarchyContainerName.ts | 40 +++++ 8 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/callHierarchyContainerName.callHierarchy.txt create mode 100644 tests/cases/fourslash/callHierarchyContainerName.ts diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 0da9f34ecec82..add1ad2afab04 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -589,7 +589,8 @@ namespace ts { (isFunctionExpression(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined); } - function getAssignedName(node: Node): DeclarationName | undefined { + /*@internal*/ + export function getAssignedName(node: Node): DeclarationName | undefined { if (!node.parent) { return undefined; } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index d3cdcb1655856..3d3347c3532ba 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3440,6 +3440,9 @@ namespace FourSlash { let text = ""; text += `${prefix}╭ name: ${callHierarchyItem.name}\n`; text += `${prefix}├ kind: ${callHierarchyItem.kind}\n`; + if (callHierarchyItem.containerName) { + text += `${prefix}├ containerName: ${callHierarchyItem.containerName}\n`; + } text += `${prefix}├ file: ${callHierarchyItem.file}\n`; text += `${prefix}├ span:\n`; text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.span, `${prefix}│ `); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index db34b0838d96b..d15040ff9bd5c 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -3069,6 +3069,7 @@ namespace ts.server.protocol { file: string; span: TextSpan; selectionSpan: TextSpan; + containerName?: string; } export interface CallHierarchyIncomingCall { diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index bbf28ac8f1101..f9cf122cd613d 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -129,6 +129,31 @@ namespace ts.CallHierarchy { return { text, pos: declName.getStart(), end: declName.getEnd() }; } + function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): string | undefined { + if (isConstNamedExpression(node)) { + if (isModuleBlock(node.parent.parent.parent.parent) && isIdentifier(node.parent.parent.parent.parent.parent.name)) { + return node.parent.parent.parent.parent.parent.name.getText(); + } + return; + } + + switch (node.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: + if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { + return getAssignedName(node.parent)?.getText(); + } + return getNameOfDeclaration(node.parent)?.getText(); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ModuleDeclaration: + if (isModuleBlock(node.parent) && isIdentifier(node.parent.parent.name)) { + return node.parent.parent.name.getText(); + } + } + } + /** Finds the implementation of a function-like declaration, if one exists. */ function findImplementation(typeChecker: TypeChecker, node: Extract): Extract | undefined; function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined; @@ -245,10 +270,11 @@ namespace ts.CallHierarchy { export function createCallHierarchyItem(program: Program, node: CallHierarchyDeclaration): CallHierarchyItem { const sourceFile = node.getSourceFile(); const name = getCallHierarchyItemName(program, node); + const containerName = getCallHierarchItemContainerName(node); const kind = getNodeKind(node); const span = createTextSpanFromBounds(skipTrivia(sourceFile.text, node.getFullStart(), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), node.getEnd()); const selectionSpan = createTextSpanFromBounds(name.pos, name.end); - return { file: sourceFile.fileName, kind, name: name.text, span, selectionSpan }; + return { file: sourceFile.fileName, kind, name: name.text, containerName, span, selectionSpan }; } function isDefined(x: T): x is NonNullable { @@ -484,4 +510,4 @@ namespace ts.CallHierarchy { } return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries)); } -} \ No newline at end of file +} diff --git a/src/services/types.ts b/src/services/types.ts index d970e5a69e2b8..546df416645dc 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -615,6 +615,7 @@ namespace ts { file: string; span: TextSpan; selectionSpan: TextSpan; + containerName?: string; } export interface CallHierarchyIncomingCall { diff --git a/tests/baselines/reference/callHierarchyAccessor.callHierarchy.txt b/tests/baselines/reference/callHierarchyAccessor.callHierarchy.txt index 0576190daf1f5..cab6d39285ae6 100644 --- a/tests/baselines/reference/callHierarchyAccessor.callHierarchy.txt +++ b/tests/baselines/reference/callHierarchyAccessor.callHierarchy.txt @@ -1,5 +1,6 @@ ╭ name: bar ├ kind: getter +├ containerName: C ├ file: /tests/cases/fourslash/callHierarchyAccessor.ts ├ span: │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:6:5-8:6 diff --git a/tests/baselines/reference/callHierarchyContainerName.callHierarchy.txt b/tests/baselines/reference/callHierarchyContainerName.callHierarchy.txt new file mode 100644 index 0000000000000..7b9c24c8006f3 --- /dev/null +++ b/tests/baselines/reference/callHierarchyContainerName.callHierarchy.txt @@ -0,0 +1,165 @@ +╭ name: f +├ kind: function +├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +├ span: +│ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:1:1-1:16 +│ │ 1: function f() {} +│ │ ^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:1:10-1:11 +│ │ 1: function f() {} +│ │ ^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: sameName +│ │ ├ kind: method +│ │ ├ containerName: A +│ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ ├ span: +│ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:4:3-6:4 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 5: f(); +│ │ │ │ ^^^^^^^^ +│ │ │ │ 6: } +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:4:10-4:18 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^ +│ │ │ ╰ +│ │ ├ incoming: +│ │ │ ╭ from: +│ │ │ │ ╭ name: sameName +│ │ │ │ ├ kind: method +│ │ │ │ ├ containerName: B +│ │ │ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:10:3-12:4 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^^^^^ +│ │ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 12: } +│ │ │ │ │ │ ^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:10:3-10:11 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ incoming: +│ │ │ │ │ ╭ from: +│ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ ├ kind: getter +│ │ │ │ │ │ ├ containerName: Obj +│ │ │ │ │ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:16:3-18:4 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 18: } +│ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:16:7-16:15 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:22:3-24:4 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 24: } +│ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:22:12-22:20 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ ╭ name: C +│ │ │ │ │ │ │ │ │ │ ├ kind: class +│ │ │ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ │ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:26:3-30:4 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 27: constructor() { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 29: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 30: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:26:16-26:17 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar +│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /tests/cases/fourslash/callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:34:20-34:37 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:34:9-34:17 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:34:34-34:35 +│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:28:7-28:15 +│ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:23:16-23:24 +│ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:17:20-17:28 +│ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ ╰ ╰ ╰ +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:11:7-11:15 +│ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ ^^^^^^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /tests/cases/fourslash/callHierarchyContainerName.ts:5:5-5:6 +│ │ │ 5: f(); +│ │ │ ^ +│ ╰ ╰ +╰ outgoing: none diff --git a/tests/cases/fourslash/callHierarchyContainerName.ts b/tests/cases/fourslash/callHierarchyContainerName.ts new file mode 100644 index 0000000000000..6594f20c3cd62 --- /dev/null +++ b/tests/cases/fourslash/callHierarchyContainerName.ts @@ -0,0 +1,40 @@ +/// + +////function /**/f() {} +//// +////class A { +//// static sameName() { +//// f(); +//// } +////} +//// +////class B { +//// sameName() { +//// A.sameName(); +//// } +////} +//// +////const Obj = { +//// get sameName() { +//// return new B().sameName; +//// } +////}; +//// +////namespace Foo { +//// function sameName() { +//// return Obj.sameName; +//// } +//// +//// export class C { +//// constructor() { +//// sameName(); +//// } +//// } +////} +//// +////module Bar { +//// const sameName = () => new Foo.C(); +////} + +goTo.marker(); +verify.baselineCallHierarchy(); From 6e0e065f69ed57ea2d9086fcba6525ff73e74a12 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 9 Jun 2020 12:17:32 -0700 Subject: [PATCH 2/3] Update public APIs --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 ++ tests/baselines/reference/api/typescript.d.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 37ec6e753ab22..0b701ebcadc1d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5427,6 +5427,7 @@ declare namespace ts { file: string; span: TextSpan; selectionSpan: TextSpan; + containerName?: string; } interface CallHierarchyIncomingCall { from: CallHierarchyItem; @@ -8586,6 +8587,7 @@ declare namespace ts.server.protocol { file: string; span: TextSpan; selectionSpan: TextSpan; + containerName?: string; } interface CallHierarchyIncomingCall { from: CallHierarchyItem; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index b20cc1a215a26..3e8dd910afa3e 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5427,6 +5427,7 @@ declare namespace ts { file: string; span: TextSpan; selectionSpan: TextSpan; + containerName?: string; } interface CallHierarchyIncomingCall { from: CallHierarchyItem; From fa6a6e7b0246f32c22c3ebef8399d7e8ac11e028 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 9 Jun 2020 16:33:11 -0700 Subject: [PATCH 3/3] Update test to demonstrate nested namespace working --- tests/cases/fourslash/callHierarchyContainerName.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/callHierarchyContainerName.ts b/tests/cases/fourslash/callHierarchyContainerName.ts index 6594f20c3cd62..a01b44afe6bbf 100644 --- a/tests/cases/fourslash/callHierarchyContainerName.ts +++ b/tests/cases/fourslash/callHierarchyContainerName.ts @@ -32,7 +32,7 @@ //// } ////} //// -////module Bar { +////module Foo.Bar { //// const sameName = () => new Foo.C(); ////}