Skip to content

Commit e3beec5

Browse files
authored
Port call hierarchy, fourslash tests (#2171)
1 parent 400d542 commit e3beec5

File tree

62 files changed

+4471
-53
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+4471
-53
lines changed

internal/ast/utilities.go

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ func GetNameOfDeclaration(declaration *Node) *Node {
13861386
return nonAssignedName
13871387
}
13881388
if IsFunctionExpression(declaration) || IsArrowFunction(declaration) || IsClassExpression(declaration) {
1389-
return getAssignedName(declaration)
1389+
return GetAssignedName(declaration)
13901390
}
13911391
return nil
13921392
}
@@ -1415,7 +1415,7 @@ func GetNonAssignedNameOfDeclaration(declaration *Node) *Node {
14151415
return declaration.Name()
14161416
}
14171417

1418-
func getAssignedName(node *Node) *Node {
1418+
func GetAssignedName(node *Node) *Node {
14191419
parent := node.Parent
14201420
if parent != nil {
14211421
switch parent.Kind {
@@ -3441,6 +3441,91 @@ func IsRightSideOfPropertyAccess(node *Node) bool {
34413441
return node.Parent.Kind == KindPropertyAccessExpression && node.Parent.Name() == node
34423442
}
34433443

3444+
func IsArgumentExpressionOfElementAccess(node *Node) bool {
3445+
return node.Parent != nil && node.Parent.Kind == KindElementAccessExpression && node.Parent.AsElementAccessExpression().ArgumentExpression == node
3446+
}
3447+
3448+
func ClimbPastPropertyAccess(node *Node) *Node {
3449+
if IsRightSideOfPropertyAccess(node) {
3450+
return node.Parent
3451+
}
3452+
return node
3453+
}
3454+
3455+
func climbPastPropertyOrElementAccess(node *Node) *Node {
3456+
if IsRightSideOfPropertyAccess(node) || IsArgumentExpressionOfElementAccess(node) {
3457+
return node.Parent
3458+
}
3459+
return node
3460+
}
3461+
3462+
func selectExpressionOfCallOrNewExpressionOrDecorator(node *Node) *Node {
3463+
if IsCallExpression(node) || IsNewExpression(node) || IsDecorator(node) {
3464+
return node.Expression()
3465+
}
3466+
return nil
3467+
}
3468+
3469+
func selectTagOfTaggedTemplateExpression(node *Node) *Node {
3470+
if IsTaggedTemplateExpression(node) {
3471+
return node.AsTaggedTemplateExpression().Tag
3472+
}
3473+
return nil
3474+
}
3475+
3476+
func selectTagNameOfJsxOpeningLikeElement(node *Node) *Node {
3477+
if IsJsxOpeningElement(node) || IsJsxSelfClosingElement(node) {
3478+
return node.TagName()
3479+
}
3480+
return nil
3481+
}
3482+
3483+
func IsCallExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3484+
return isCalleeWorker(node, IsCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions)
3485+
}
3486+
3487+
func IsNewExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3488+
return isCalleeWorker(node, IsNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions)
3489+
}
3490+
3491+
func IsCallOrNewExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3492+
return isCalleeWorker(node, IsCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions)
3493+
}
3494+
3495+
func IsTaggedTemplateTag(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3496+
return isCalleeWorker(node, IsTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions)
3497+
}
3498+
3499+
func IsDecoratorTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3500+
return isCalleeWorker(node, IsDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions)
3501+
}
3502+
3503+
func IsJsxOpeningLikeElementTagName(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool {
3504+
return isCalleeWorker(node, IsJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions)
3505+
}
3506+
3507+
func isCalleeWorker(
3508+
node *Node,
3509+
pred func(*Node) bool,
3510+
calleeSelector func(*Node) *Node,
3511+
includeElementAccess bool,
3512+
skipPastOuterExpressions bool,
3513+
) bool {
3514+
var target *Node
3515+
if includeElementAccess {
3516+
target = climbPastPropertyOrElementAccess(node)
3517+
} else {
3518+
target = ClimbPastPropertyAccess(node)
3519+
}
3520+
if skipPastOuterExpressions {
3521+
// Only skip outer expressions if the target is actually an expression node
3522+
if IsExpression(target) {
3523+
target = SkipOuterExpressions(target, OEKAll)
3524+
}
3525+
}
3526+
return target != nil && target.Parent != nil && pred(target.Parent) && calleeSelector(target.Parent) == target
3527+
}
3528+
34443529
func IsRightSideOfQualifiedNameOrPropertyAccess(node *Node) bool {
34453530
parent := node.Parent
34463531
switch parent.Kind {

internal/fourslash/_scripts/convertFourslash.mts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined {
204204
return parseNoSignatureHelpForTriggerReason(callExpression.arguments);
205205
case "baselineSmartSelection":
206206
return [parseBaselineSmartSelection(callExpression.arguments)];
207+
case "baselineCallHierarchy":
208+
return [parseBaselineCallHierarchy(callExpression.arguments)];
207209
case "baselineGoToDefinition":
208210
case "baselineGetDefinitionAtPosition":
209211
case "baselineGoToType":
@@ -2025,6 +2027,15 @@ function parseBaselineSmartSelection(args: ts.NodeArray<ts.Expression>): Cmd {
20252027
};
20262028
}
20272029

2030+
function parseBaselineCallHierarchy(args: ts.NodeArray<ts.Expression>): Cmd {
2031+
if (args.length !== 0) {
2032+
throw new Error("Expected no arguments in verify.baselineCallHierarchy");
2033+
}
2034+
return {
2035+
kind: "verifyBaselineCallHierarchy",
2036+
};
2037+
}
2038+
20282039
function parseKind(expr: ts.Expression): string | undefined {
20292040
if (!ts.isStringLiteral(expr)) {
20302041
console.error(`Expected string literal for kind, got ${expr.getText()}`);
@@ -2399,6 +2410,10 @@ interface VerifyBaselineSmartSelection {
23992410
kind: "verifyBaselineSmartSelection";
24002411
}
24012412

2413+
interface VerifyBaselineCallHierarchy {
2414+
kind: "verifyBaselineCallHierarchy";
2415+
}
2416+
24022417
interface VerifyBaselineRenameCmd {
24032418
kind: "verifyBaselineRename" | "verifyBaselineRenameAtRangesWithText";
24042419
args: string[];
@@ -2511,6 +2526,7 @@ type Cmd =
25112526
| VerifyNoSignatureHelpCmd
25122527
| VerifySignatureHelpPresentCmd
25132528
| VerifyNoSignatureHelpForTriggerReasonCmd
2529+
| VerifyBaselineCallHierarchy
25142530
| GoToCmd
25152531
| EditCmd
25162532
| VerifyQuickInfoCmd
@@ -2777,6 +2793,8 @@ function generateCmd(cmd: Cmd): string {
27772793
return `f.VerifyBaselineSignatureHelp(t)`;
27782794
case "verifyBaselineSmartSelection":
27792795
return `f.VerifyBaselineSelectionRanges(t)`;
2796+
case "verifyBaselineCallHierarchy":
2797+
return `f.VerifyBaselineCallHierarchy(t)`;
27802798
case "goTo":
27812799
return generateGoToCommand(cmd);
27822800
case "edit":

internal/fourslash/baselineutil.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
const (
2424
autoImportsCmd baselineCommand = "Auto Imports"
25+
callHierarchyCmd baselineCommand = "Call Hierarchy"
2526
documentHighlightsCmd baselineCommand = "documentHighlights"
2627
findAllReferencesCmd baselineCommand = "findAllReferences"
2728
goToDefinitionCmd baselineCommand = "goToDefinition"
@@ -71,6 +72,8 @@ func getBaselineExtension(command baselineCommand) string {
7172
switch command {
7273
case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd:
7374
return "baseline"
75+
case callHierarchyCmd:
76+
return "callHierarchy.txt"
7477
case autoImportsCmd:
7578
return "baseline.md"
7679
default:
@@ -91,6 +94,21 @@ func (f *FourslashTest) getBaselineOptions(command baselineCommand, testPath str
9194
Subfolder: subfolder,
9295
IsSubmodule: true,
9396
}
97+
case callHierarchyCmd:
98+
return baseline.Options{
99+
Subfolder: subfolder,
100+
IsSubmodule: true,
101+
DiffFixupOld: func(s string) string {
102+
// TypeScript baselines have "/tests/cases/fourslash/" prefix in file paths
103+
// Handle /server/ subdirectory - need to remove both prefixes
104+
s = strings.ReplaceAll(s, "/tests/cases/fourslash/server/", "/")
105+
s = strings.ReplaceAll(s, "/tests/cases/fourslash/", "/")
106+
// SymbolKind enum differences between Strada and tsgo
107+
s = strings.ReplaceAll(s, "kind: getter", "kind: property")
108+
s = strings.ReplaceAll(s, "kind: script", "kind: file")
109+
return s
110+
},
111+
}
94112
case renameCmd:
95113
return baseline.Options{
96114
Subfolder: subfolder,

0 commit comments

Comments
 (0)