fix(56706): "Show call hierarchy" does not work with arrow methods in a class (#56715)

This commit is contained in:
Oleksandr T 2024-01-02 19:15:28 +02:00 committed by GitHub
parent b999336b35
commit 4dbb267b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 15 deletions

View File

@ -91,6 +91,7 @@ import {
ParameterDeclaration,
Program,
PropertyAccessExpression,
PropertyDeclaration,
SatisfiesExpression,
SetAccessorDeclaration,
skipTrivia,
@ -117,18 +118,27 @@ function isNamedExpression(node: Node): node is NamedExpression {
}
/** @internal */
export type ConstNamedExpression =
| ClassExpression & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; }
| FunctionExpression & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; }
| ArrowFunction & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; };
export type VariableLike =
| VariableDeclaration
| PropertyDeclaration;
/** Indicates whether a node is a function, arrow, or class expression assigned to a constant variable. */
function isConstNamedExpression(node: Node): node is ConstNamedExpression {
function isVariableLike(node: Node): node is VariableLike {
return isPropertyDeclaration(node) || isVariableDeclaration(node);
}
/** @internal */
export type AssignedExpression =
| ClassExpression & { name: undefined; parent: VariableLike & { name: Identifier; }; }
| FunctionExpression & { name: undefined; parent: VariableLike & { name: Identifier; }; }
| ArrowFunction & { name: undefined; parent: VariableLike & { name: Identifier; }; };
/** Indicates whether a node is a function, arrow, or class expression assigned to a constant variable or class property. */
function isAssignedExpression(node: Node): node is AssignedExpression {
return (isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node))
&& isVariableDeclaration(node.parent)
&& isVariableLike(node.parent)
&& node === node.parent.initializer
&& isIdentifier(node.parent.name)
&& !!(getCombinedNodeFlags(node.parent) & NodeFlags.Const);
&& (!!(getCombinedNodeFlags(node.parent) & NodeFlags.Const) || isPropertyDeclaration(node.parent));
}
/** @internal */
@ -142,7 +152,7 @@ export type CallHierarchyDeclaration =
| GetAccessorDeclaration
| SetAccessorDeclaration
| NamedExpression
| ConstNamedExpression;
| AssignedExpression;
/**
* Indicates whether a node could possibly be a call hierarchy declaration.
@ -179,14 +189,14 @@ function isValidCallHierarchyDeclaration(node: Node): node is CallHierarchyDecla
|| isGetAccessorDeclaration(node)
|| isSetAccessorDeclaration(node)
|| isNamedExpression(node)
|| isConstNamedExpression(node);
|| isAssignedExpression(node);
}
/** Gets the node that can be used as a reference to a call hierarchy declaration. */
function getCallHierarchyDeclarationReferenceNode(node: Exclude<CallHierarchyDeclaration, ClassStaticBlockDeclaration>) {
if (isSourceFile(node)) return node;
if (isNamedDeclaration(node)) return node.name;
if (isConstNamedExpression(node)) return node.parent.name;
if (isAssignedExpression(node)) return node.parent.name;
return Debug.checkDefined(node.modifiers && find(node.modifiers, isDefaultModifier));
}
@ -223,7 +233,7 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati
return { text: `${prefix}static {}`, pos, end };
}
const declName = isConstNamedExpression(node) ? node.parent.name :
const declName = isAssignedExpression(node) ? node.parent.name :
Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name");
let text = isIdentifier(declName) ? idText(declName) :
@ -248,7 +258,10 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati
}
function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): string | undefined {
if (isConstNamedExpression(node)) {
if (isAssignedExpression(node)) {
if (isPropertyDeclaration(node.parent) && isClassLike(node.parent.parent)) {
return isClassExpression(node.parent.parent) ? getAssignedName(node.parent.parent)?.getText() : node.parent.parent.name?.getText();
}
if (isModuleBlock(node.parent.parent.parent.parent) && isIdentifier(node.parent.parent.parent.parent.parent.name)) {
return node.parent.parent.parent.parent.parent.name.getText();
}
@ -364,7 +377,7 @@ export function resolveCallHierarchyDeclaration(program: Program, location: Node
const ancestor = findAncestor(location.parent, isValidCallHierarchyDeclaration);
return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor);
}
if (isVariableDeclaration(location.parent) && location.parent.initializer && isConstNamedExpression(location.parent.initializer)) {
if (isVariableLike(location.parent) && location.parent.initializer && isAssignedExpression(location.parent.initializer)) {
return location.parent.initializer;
}
return undefined;
@ -380,7 +393,7 @@ export function resolveCallHierarchyDeclaration(program: Program, location: Node
continue;
}
// #39453
if (isVariableDeclaration(location) && location.initializer && isConstNamedExpression(location.initializer)) {
if (isVariableDeclaration(location) && location.initializer && isAssignedExpression(location.initializer)) {
return location.initializer;
}
if (!followingSymbol) {

View File

@ -0,0 +1,44 @@
// === Call Hierarchy ===
╭ name: callee
├ kind: function
├ containerName: C
├ file: /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts
├ span:
│ ╭ /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts:6:14-7:6
│ │ 6: callee = () => {
│ │ ^^^^^^^
│ │ 7: }
│ │ ^^^^^
│ ╰
├ selectionSpan:
│ ╭ /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts:6:5-6:11
│ │ 6: callee = () => {
│ │ ^^^^^^
│ ╰
├ incoming:
│ ╭ from:
│ │ ╭ name: caller
│ │ ├ kind: function
│ │ ├ containerName: C
│ │ ├ file: /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts
│ │ ├ span:
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts:2:14-4:6
│ │ │ │ 2: caller = () => {
│ │ │ │ ^^^^^^^
│ │ │ │ 3: this.callee();
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^
│ │ │ │ 4: }
│ │ │ │ ^^^^^
│ │ │ ╰
│ │ ├ selectionSpan:
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts:2:5-2:11
│ │ │ │ 2: caller = () => {
│ │ │ │ ^^^^^^
│ │ │ ╰
│ │ ╰ incoming: none
│ ├ fromSpans:
│ │ ╭ /tests/cases/fourslash/callHierarchyClassPropertyArrowFunction.ts:3:14-3:20
│ │ │ 3: this.callee();
│ │ │ ^^^^^^
│ ╰ ╰
╰ outgoing: none

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////class C {
//// caller = () => {
//// this.callee();
//// }
////
//// /**/callee = () => {
//// }
////}
goTo.marker();
verify.baselineCallHierarchy();