Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add containerName to CallHierarchyItem #38997

Merged
merged 3 commits into from
Jun 10, 2020
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
@@ -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}│ `);
1 change: 1 addition & 0 deletions src/server/protocol.ts
Original file line number Diff line number Diff line change
@@ -3069,6 +3069,7 @@ namespace ts.server.protocol {
file: string;
span: TextSpan;
selectionSpan: TextSpan;
containerName?: string;
}

export interface CallHierarchyIncomingCall {
30 changes: 28 additions & 2 deletions src/services/callHierarchy.ts
Original file line number Diff line number Diff line change
@@ -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)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to do this many unguarded parent accesses?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes—isConstNamedExpression guarantees that the third-to-last .parent is a VariableDeclarationList or CatchClause, so the second-to-last is VariableStatement | ForStatement | ForOfStatement | ForInStatement | TryStatement, so one more .parent is safe from there.

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<CallHierarchyDeclaration, FunctionLikeDeclaration>): Extract<CallHierarchyDeclaration, FunctionLikeDeclaration> | 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<T>(x: T): x is NonNullable<T> {
@@ -484,4 +510,4 @@ namespace ts.CallHierarchy {
}
return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries));
}
}
}
1 change: 1 addition & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
@@ -615,6 +615,7 @@ namespace ts {
file: string;
span: TextSpan;
selectionSpan: TextSpan;
containerName?: string;
}

export interface CallHierarchyIncomingCall {
2 changes: 2 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
@@ -5427,6 +5427,7 @@ declare namespace ts {
file: string;
span: TextSpan;
selectionSpan: TextSpan;
containerName?: string;
}
interface CallHierarchyIncomingCall {
from: CallHierarchyItem;
Original file line number Diff line number Diff line change
@@ -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
165 changes: 165 additions & 0 deletions tests/baselines/reference/callHierarchyContainerName.callHierarchy.txt
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions tests/cases/fourslash/callHierarchyContainerName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// <reference path="fourslash.ts" />

////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 {
andrewbranch marked this conversation as resolved.
Show resolved Hide resolved
//// const sameName = () => new Foo.C();
////}

goTo.marker();
verify.baselineCallHierarchy();