From 27400b668550ecf54862410bc8f672e68567979f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Nov 2025 18:43:02 -0800 Subject: [PATCH 01/20] starting --- .../fourslash/_scripts/convertFourslash.mts | 18 + internal/fourslash/baselineutil.go | 15 + internal/fourslash/fourslash.go | 321 ++++- .../tests/gen/callHierarchyAccessor_test.go | 29 + ...sionByConstNamedFunctionExpression_test.go | 29 + ...ierarchyClassPropertyArrowFunction_test.go | 25 + .../callHierarchyClassStaticBlock2_test.go | 38 + .../gen/callHierarchyClassStaticBlock_test.go | 38 + .../tests/gen/callHierarchyClass_test.go | 27 + ...llHierarchyConstNamedArrowFunction_test.go | 27 + ...HierarchyConstNamedClassExpression_test.go | 29 + ...rarchyConstNamedFunctionExpression_test.go | 27 + .../callHierarchyContainerNameServer_test.go | 53 + .../gen/callHierarchyContainerName_test.go | 52 + .../tests/gen/callHierarchyCrossFile_test.go | 29 + .../tests/gen/callHierarchyDecorator_test.go | 28 + .../callHierarchyExportDefaultClass_test.go | 32 + ...callHierarchyExportDefaultFunction_test.go | 30 + .../callHierarchyExportEqualsFunction_test.go | 30 + .../tests/gen/callHierarchyFile_test.go | 20 + .../callHierarchyFunctionAmbiguity1_test.go | 26 + .../callHierarchyFunctionAmbiguity2_test.go | 26 + .../callHierarchyFunctionAmbiguity3_test.go | 26 + .../callHierarchyFunctionAmbiguity4_test.go | 26 + .../callHierarchyFunctionAmbiguity5_test.go | 26 + .../tests/gen/callHierarchyFunction_test.go | 32 + .../gen/callHierarchyInterfaceMethod_test.go | 24 + .../tests/gen/callHierarchyJsxElement_test.go | 29 + .../gen/callHierarchyTaggedTemplate_test.go | 27 + internal/ls/callhierarchy.go | 1165 +++++++++++++++++ internal/ls/findallreferences.go | 4 +- internal/lsp/server.go | 62 + internal/testutil/baseline/baseline.go | 5 + .../callHierarchyAccessor.callHierarchy.txt | 67 + ...llHierarchyAccessor.callHierarchy.txt.diff | 10 + ...tNamedFunctionExpression.callHierarchy.txt | 108 ++ ...dFunctionExpression.callHierarchy.txt.diff | 11 + .../callHierarchyClass.callHierarchy.txt | 66 + ...assPropertyArrowFunction.callHierarchy.txt | 44 + ...opertyArrowFunction.callHierarchy.txt.diff | 19 + ...ierarchyClassStaticBlock.callHierarchy.txt | 140 ++ ...chyClassStaticBlock.callHierarchy.txt.diff | 11 + ...erarchyClassStaticBlock2.callHierarchy.txt | 140 ++ ...hyClassStaticBlock2.callHierarchy.txt.diff | 10 + ...yConstNamedArrowFunction.callHierarchy.txt | 66 + ...tNamedArrowFunction.callHierarchy.txt.diff | 10 + ...onstNamedClassExpression.callHierarchy.txt | 70 + ...tNamedFunctionExpression.callHierarchy.txt | 66 + ...llHierarchyContainerName.callHierarchy.txt | 144 ++ ...rarchyContainerName.callHierarchy.txt.diff | 42 + ...archyContainerNameServer.callHierarchy.txt | 144 ++ ...ContainerNameServer.callHierarchy.txt.diff | 42 + .../callHierarchyCrossFile.callHierarchy.txt | 64 + .../callHierarchyDecorator.callHierarchy.txt | 66 + ...rarchyExportDefaultClass.callHierarchy.txt | 70 + ...chyExportDefaultFunction.callHierarchy.txt | 66 + ...rchyExportEqualsFunction.callHierarchy.txt | 26 + ...xportEqualsFunction.callHierarchy.txt.diff | 38 + .../callHierarchyFile.callHierarchy.txt | 66 + .../callHierarchyFile.callHierarchy.txt.diff | 44 + .../callHierarchyFunction.callHierarchy.txt | 96 ++ ...archyFunctionAmbiguity.1.callHierarchy.txt | 40 + ...FunctionAmbiguity.1.callHierarchy.txt.diff | 62 + ...archyFunctionAmbiguity.2.callHierarchy.txt | 40 + ...FunctionAmbiguity.2.callHierarchy.txt.diff | 45 + ...archyFunctionAmbiguity.3.callHierarchy.txt | 40 + ...FunctionAmbiguity.3.callHierarchy.txt.diff | 48 + ...archyFunctionAmbiguity.4.callHierarchy.txt | 40 + ...FunctionAmbiguity.4.callHierarchy.txt.diff | 48 + ...archyFunctionAmbiguity.5.callHierarchy.txt | 60 + ...FunctionAmbiguity.5.callHierarchy.txt.diff | 26 + ...HierarchyInterfaceMethod.callHierarchy.txt | 48 + ...rchyInterfaceMethod.callHierarchy.txt.diff | 11 + .../callHierarchyJsxElement.callHierarchy.txt | 66 + ...lHierarchyTaggedTemplate.callHierarchy.txt | 66 + 75 files changed, 4758 insertions(+), 3 deletions(-) create mode 100644 internal/fourslash/tests/gen/callHierarchyAccessor_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyCallExpressionByConstNamedFunctionExpression_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyClassPropertyArrowFunction_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyClassStaticBlock2_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyClassStaticBlock_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyClass_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyConstNamedArrowFunction_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyConstNamedClassExpression_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyConstNamedFunctionExpression_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyContainerNameServer_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyContainerName_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyCrossFile_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyDecorator_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyExportDefaultClass_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyExportDefaultFunction_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyExportEqualsFunction_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFile_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity1_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity2_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity3_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity4_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity5_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyFunction_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyInterfaceMethod_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyJsxElement_test.go create mode 100644 internal/fourslash/tests/gen/callHierarchyTaggedTemplate_test.go create mode 100644 internal/ls/callhierarchy.go create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClass.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedClassExpression.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedFunctionExpression.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCrossFile.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyDecorator.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultClass.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultFunction.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunction.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyJsxElement.callHierarchy.txt create mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyTaggedTemplate.callHierarchy.txt diff --git a/internal/fourslash/_scripts/convertFourslash.mts b/internal/fourslash/_scripts/convertFourslash.mts index d4dc96c952..0823f80617 100644 --- a/internal/fourslash/_scripts/convertFourslash.mts +++ b/internal/fourslash/_scripts/convertFourslash.mts @@ -196,6 +196,8 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined { return [parseBaselineSignatureHelp(callExpression.arguments)]; case "baselineSmartSelection": return [parseBaselineSmartSelection(callExpression.arguments)]; + case "baselineCallHierarchy": + return [parseBaselineCallHierarchy(callExpression.arguments)]; case "baselineGoToDefinition": case "baselineGetDefinitionAtPosition": case "baselineGoToType": @@ -1689,6 +1691,15 @@ function parseBaselineSmartSelection(args: ts.NodeArray): Cmd { }; } +function parseBaselineCallHierarchy(args: ts.NodeArray): Cmd { + if (args.length !== 0) { + throw new Error("Expected no arguments in verify.baselineCallHierarchy"); + } + return { + kind: "verifyBaselineCallHierarchy", + }; +} + function parseKind(expr: ts.Expression): string | undefined { if (!ts.isStringLiteral(expr)) { console.error(`Expected string literal for kind, got ${expr.getText()}`); @@ -2063,6 +2074,10 @@ interface VerifyBaselineSmartSelection { kind: "verifyBaselineSmartSelection"; } +interface VerifyBaselineCallHierarchy { + kind: "verifyBaselineCallHierarchy"; +} + interface VerifyBaselineRenameCmd { kind: "verifyBaselineRename" | "verifyBaselineRenameAtRangesWithText"; args: string[]; @@ -2135,6 +2150,7 @@ type Cmd = | VerifyBaselineQuickInfoCmd | VerifyBaselineSignatureHelpCmd | VerifyBaselineSmartSelection + | VerifyBaselineCallHierarchy | GoToCmd | EditCmd | VerifyQuickInfoCmd @@ -2283,6 +2299,8 @@ function generateCmd(cmd: Cmd): string { return `f.VerifyBaselineSignatureHelp(t)`; case "verifyBaselineSmartSelection": return `f.VerifyBaselineSelectionRanges(t)`; + case "verifyBaselineCallHierarchy": + return `f.VerifyBaselineCallHierarchy(t)`; case "goTo": return generateGoToCommand(cmd); case "edit": diff --git a/internal/fourslash/baselineutil.go b/internal/fourslash/baselineutil.go index b49fb6b28b..671ad22225 100644 --- a/internal/fourslash/baselineutil.go +++ b/internal/fourslash/baselineutil.go @@ -22,6 +22,7 @@ import ( const ( autoImportsCmd baselineCommand = "Auto Imports" + callHierarchyCmd baselineCommand = "Call Hierarchy" documentHighlightsCmd baselineCommand = "documentHighlights" findAllReferencesCmd baselineCommand = "findAllReferences" goToDefinitionCmd baselineCommand = "goToDefinition" @@ -71,6 +72,8 @@ func getBaselineExtension(command baselineCommand) string { switch command { case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd: return "baseline" + case callHierarchyCmd: + return "callHierarchy.txt" case autoImportsCmd: return "baseline.md" default: @@ -91,6 +94,18 @@ func (f *FourslashTest) getBaselineOptions(command baselineCommand, testPath str Subfolder: subfolder, IsSubmodule: true, } + case callHierarchyCmd: + return baseline.Options{ + Subfolder: subfolder, + IsSubmodule: true, + DiffFixupOld: func(s string) string { + // TypeScript baselines have "/tests/cases/fourslash/" prefix in file paths + // Handle /server/ subdirectory - need to remove both prefixes + s = strings.ReplaceAll(s, "/tests/cases/fourslash/server/", "/") + s = strings.ReplaceAll(s, "/tests/cases/fourslash/", "/") + return s + }, + } case renameCmd: return baseline.Options{ Subfolder: subfolder, diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 90a701b36c..b0a6d2c845 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -7,6 +7,7 @@ import ( "maps" "runtime" "slices" + "strconv" "strings" "testing" "unicode/utf8" @@ -268,7 +269,23 @@ func getBaseFileNameFromTest(t *testing.T) string { name := t.Name() name = core.LastOrNil(strings.Split(name, "/")) name = strings.TrimPrefix(name, "Test") - return stringutil.LowerFirstChar(name) + name = stringutil.LowerFirstChar(name) + + // Special case: TypeScript has "callHierarchyFunctionAmbiguity.N" with periods + switch name { + case "callHierarchyFunctionAmbiguity1": + name = "callHierarchyFunctionAmbiguity.1" + case "callHierarchyFunctionAmbiguity2": + name = "callHierarchyFunctionAmbiguity.2" + case "callHierarchyFunctionAmbiguity3": + name = "callHierarchyFunctionAmbiguity.3" + case "callHierarchyFunctionAmbiguity4": + name = "callHierarchyFunctionAmbiguity.4" + case "callHierarchyFunctionAmbiguity5": + name = "callHierarchyFunctionAmbiguity.5" + } + + return name } func (f *FourslashTest) nextID() int32 { @@ -1742,6 +1759,308 @@ func (f *FourslashTest) VerifyBaselineSelectionRanges(t *testing.T) { f.addResultToBaseline(t, smartSelectionCmd, strings.TrimSuffix(result.String(), "\n")) } +func (f *FourslashTest) VerifyBaselineCallHierarchy(t *testing.T) { + fileName := f.activeFilename + position := f.currentCaretPosition + + params := &lsproto.CallHierarchyPrepareParams{ + TextDocument: lsproto.TextDocumentIdentifier{ + Uri: lsconv.FileNameToDocumentURI(fileName), + }, + Position: position, + } + + prepareResult := sendRequest(t, f, lsproto.TextDocumentPrepareCallHierarchyInfo, params) + if prepareResult.CallHierarchyItems == nil || len(*prepareResult.CallHierarchyItems) == 0 { + f.addResultToBaseline(t, callHierarchyCmd, "No call hierarchy items available") + return + } + + callHierarchyItem := (*prepareResult.CallHierarchyItems)[0] + script := f.getScriptInfo(fileName) + + var result strings.Builder + seen := make(map[callHierarchyItemKey]bool) + formatCallHierarchyItem(t, f, script, &result, *callHierarchyItem, callHierarchyItemDirectionRoot, seen, "") + + f.addResultToBaseline(t, callHierarchyCmd, strings.TrimSuffix(result.String(), "\n")) +} + +type callHierarchyItemDirection int + +const ( + callHierarchyItemDirectionRoot callHierarchyItemDirection = iota + callHierarchyItemDirectionIncoming + callHierarchyItemDirectionOutgoing +) + +type callHierarchyItemKey struct { + uri lsproto.DocumentUri + range_ lsproto.Range + direction callHierarchyItemDirection +} + +func symbolKindToLowercase(kind lsproto.SymbolKind) string { + return strings.ToLower(kind.String()) +} + +func formatCallHierarchyItem( + t *testing.T, + f *FourslashTest, + file *scriptInfo, + result *strings.Builder, + callHierarchyItem lsproto.CallHierarchyItem, + direction callHierarchyItemDirection, + seen map[callHierarchyItemKey]bool, + prefix string, +) { + key := callHierarchyItemKey{ + uri: callHierarchyItem.Uri, + range_: callHierarchyItem.Range, + direction: direction, + } + alreadySeen := seen[key] + seen[key] = true + + type incomingCallResult struct { + skip bool + seen bool + values []*lsproto.CallHierarchyIncomingCall + } + type outgoingCallResult struct { + skip bool + seen bool + values []*lsproto.CallHierarchyOutgoingCall + } + + var incomingCalls incomingCallResult + var outgoingCalls outgoingCallResult + + if direction == callHierarchyItemDirectionOutgoing { + incomingCalls.skip = true + } else if alreadySeen { + incomingCalls.seen = true + } else { + incomingParams := &lsproto.CallHierarchyIncomingCallsParams{ + Item: &callHierarchyItem, + } + incomingResult := sendRequest(t, f, lsproto.CallHierarchyIncomingCallsInfo, incomingParams) + if incomingResult.CallHierarchyIncomingCalls != nil { + incomingCalls.values = *incomingResult.CallHierarchyIncomingCalls + } + } + + if direction == callHierarchyItemDirectionIncoming { + outgoingCalls.skip = true + } else if alreadySeen { + outgoingCalls.seen = true + } else { + outgoingParams := &lsproto.CallHierarchyOutgoingCallsParams{ + Item: &callHierarchyItem, + } + outgoingResult := sendRequest(t, f, lsproto.CallHierarchyOutgoingCallsInfo, outgoingParams) + if outgoingResult.CallHierarchyOutgoingCalls != nil { + outgoingCalls.values = *outgoingResult.CallHierarchyOutgoingCalls + } + } + + trailingPrefix := prefix + result.WriteString(fmt.Sprintf("%s╭ name: %s\n", prefix, callHierarchyItem.Name)) + result.WriteString(fmt.Sprintf("%s├ kind: %s\n", prefix, symbolKindToLowercase(callHierarchyItem.Kind))) + if callHierarchyItem.Detail != nil && *callHierarchyItem.Detail != "" { + result.WriteString(fmt.Sprintf("%s├ containerName: %s\n", prefix, *callHierarchyItem.Detail)) + } + result.WriteString(fmt.Sprintf("%s├ file: %s\n", prefix, callHierarchyItem.Uri.FileName())) + result.WriteString(prefix + "├ span:\n") + formatCallHierarchyItemSpan(f, file, result, callHierarchyItem.Range, prefix+"│ ", prefix+"│ ") + result.WriteString(prefix + "├ selectionSpan:\n") + formatCallHierarchyItemSpan(f, file, result, callHierarchyItem.SelectionRange, prefix+"│ ", prefix+"│ ") + + // Handle incoming calls + if incomingCalls.seen { + if outgoingCalls.skip { + result.WriteString(trailingPrefix + "╰ incoming: ...\n") + } else { + result.WriteString(prefix + "├ incoming: ...\n") + } + } else if !incomingCalls.skip { + if len(incomingCalls.values) == 0 { + if outgoingCalls.skip { + result.WriteString(trailingPrefix + "╰ incoming: none\n") + } else { + result.WriteString(prefix + "├ incoming: none\n") + } + } else { + result.WriteString(prefix + "├ incoming:\n") + for i, incomingCall := range incomingCalls.values { + fromFileName := incomingCall.From.Uri.FileName() + fromFile := f.getScriptInfo(fromFileName) + result.WriteString(prefix + "│ ╭ from:\n") + formatCallHierarchyItem(t, f, fromFile, result, *incomingCall.From, callHierarchyItemDirectionIncoming, seen, prefix+"│ │ ") + result.WriteString(prefix + "│ ├ fromSpans:\n") + + fromSpansTrailingPrefix := trailingPrefix + "╰ ╰ " + if i < len(incomingCalls.values)-1 { + fromSpansTrailingPrefix = prefix + "│ ╰ " + } else if !outgoingCalls.skip && (!outgoingCalls.seen || len(outgoingCalls.values) > 0) { + fromSpansTrailingPrefix = prefix + "│ ╰ " + } + formatCallHierarchyItemSpans(f, fromFile, result, incomingCall.FromRanges, prefix+"│ │ ", fromSpansTrailingPrefix) + } + } + } + + // Handle outgoing calls + if outgoingCalls.seen { + result.WriteString(trailingPrefix + "╰ outgoing: ...\n") + } else if !outgoingCalls.skip { + if len(outgoingCalls.values) == 0 { + result.WriteString(trailingPrefix + "╰ outgoing: none\n") + } else { + result.WriteString(prefix + "├ outgoing:\n") + for i, outgoingCall := range outgoingCalls.values { + toFileName := outgoingCall.To.Uri.FileName() + toFile := f.getScriptInfo(toFileName) + result.WriteString(prefix + "│ ╭ to:\n") + formatCallHierarchyItem(t, f, toFile, result, *outgoingCall.To, callHierarchyItemDirectionOutgoing, seen, prefix+"│ │ ") + result.WriteString(prefix + "│ ├ fromSpans:\n") + + fromSpansTrailingPrefix := trailingPrefix + "╰ ╰ " + if i < len(outgoingCalls.values)-1 { + fromSpansTrailingPrefix = prefix + "│ ╰ " + } + formatCallHierarchyItemSpans(f, file, result, outgoingCall.FromRanges, prefix+"│ │ ", fromSpansTrailingPrefix) + } + } + } +} + +func formatCallHierarchyItemSpan( + f *FourslashTest, + file *scriptInfo, + result *strings.Builder, + span lsproto.Range, + prefix string, + closingPrefix string, +) { + startLc := span.Start + endLc := span.End + startPos := f.converters.LineAndCharacterToPosition(file, span.Start) + endPos := f.converters.LineAndCharacterToPosition(file, span.End) + + // Compute line starts for the file + lineStarts := computeLineStarts(file.content) + + // Find the line boundaries - expand to full lines + contextStart := int(startPos) + contextEnd := int(endPos) + + // Expand to start of first line + for contextStart > 0 && file.content[contextStart-1] != '\n' && file.content[contextStart-1] != '\r' { + contextStart-- + } + + // Expand to end of last line + for contextEnd < len(file.content) && file.content[contextEnd] != '\n' && file.content[contextEnd] != '\r' { + contextEnd++ + } + + // Get actual line and character positions for the context + contextStartLine := int(startLc.Line) + contextEndLine := int(endLc.Line) + + // Calculate line number padding + lineNumWidth := len(strconv.Itoa(contextEndLine+1)) + 2 + + result.WriteString(fmt.Sprintf("%s╭ %s:%d:%d-%d:%d\n", prefix, file.fileName, startLc.Line+1, startLc.Character+1, endLc.Line+1, endLc.Character+1)) + + for lineNum := contextStartLine; lineNum <= contextEndLine; lineNum++ { + lineStart := lineStarts[lineNum] + lineEnd := len(file.content) + if lineNum+1 < len(lineStarts) { + lineEnd = lineStarts[lineNum+1] + } + + // Get the line content, trimming trailing newlines + lineContent := file.content[lineStart:lineEnd] + lineContent = strings.TrimRight(lineContent, "\r\n") + + // Format with line number + lineNumStr := fmt.Sprintf("%d:", lineNum+1) + paddedLineNum := strings.Repeat(" ", lineNumWidth-len(lineNumStr)-1) + lineNumStr + if lineContent == "" { + result.WriteString(fmt.Sprintf("%s│ %s\n", prefix, paddedLineNum)) + } else { + result.WriteString(fmt.Sprintf("%s│ %s %s\n", prefix, paddedLineNum, lineContent)) + } + + // Add selection carets if this line contains part of the span + if lineNum >= int(startLc.Line) && lineNum <= int(endLc.Line) { + selStart := 0 + selEnd := len(lineContent) + + if lineNum == int(startLc.Line) { + selStart = int(startLc.Character) + } + if lineNum == int(endLc.Line) { + selEnd = int(endLc.Character) + } + + // Don't show carets for empty selections + isEmpty := startLc.Line == endLc.Line && startLc.Character == endLc.Character + if isEmpty { + // For empty selections, show a single "<" character + padding := strings.Repeat(" ", lineNumWidth+selStart) + result.WriteString(fmt.Sprintf("%s│ %s<\n", prefix, padding)) + } else { + // Calculate selection length (at least 1) + selLength := selEnd - selStart + selLength = max(selLength, 1) // Trim to actual content on the line + if lineNum < int(endLc.Line) { + // For lines before the last, trim to line content length + if selEnd > len(lineContent) { + selEnd = len(lineContent) + selLength = selEnd - selStart + } + } + + padding := strings.Repeat(" ", lineNumWidth+selStart) + carets := strings.Repeat("^", selLength) + result.WriteString(fmt.Sprintf("%s│ %s%s\n", prefix, padding, carets)) + } + } + } + + result.WriteString(closingPrefix + "╰\n") +} + +func computeLineStarts(content string) []int { + lineStarts := []int{0} + for i, ch := range content { + if ch == '\n' { + lineStarts = append(lineStarts, i+1) + } + } + return lineStarts +} + +func formatCallHierarchyItemSpans( + f *FourslashTest, + file *scriptInfo, + result *strings.Builder, + spans []lsproto.Range, + prefix string, + trailingPrefix string, +) { + for i, span := range spans { + closingPrefix := prefix + if i == len(spans)-1 { + closingPrefix = trailingPrefix + } + formatCallHierarchyItemSpan(f, file, result, span, prefix, closingPrefix) + } +} + func (f *FourslashTest) VerifyBaselineDocumentHighlights( t *testing.T, preferences *lsutil.UserPreferences, diff --git a/internal/fourslash/tests/gen/callHierarchyAccessor_test.go b/internal/fourslash/tests/gen/callHierarchyAccessor_test.go new file mode 100644 index 0000000000..eef2979811 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyAccessor_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyAccessor(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + new C().bar; +} + +class C { + get /**/bar() { + return baz(); + } +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyCallExpressionByConstNamedFunctionExpression_test.go b/internal/fourslash/tests/gen/callHierarchyCallExpressionByConstNamedFunctionExpression_test.go new file mode 100644 index 0000000000..1805a5a0b4 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyCallExpressionByConstNamedFunctionExpression_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyCallExpressionByConstNamedFunctionExpression(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar(); +} + +const bar = function () { + baz(); +} + +function baz() { +} + +/**/bar()` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyClassPropertyArrowFunction_test.go b/internal/fourslash/tests/gen/callHierarchyClassPropertyArrowFunction_test.go new file mode 100644 index 0000000000..1ff33260ec --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyClassPropertyArrowFunction_test.go @@ -0,0 +1,25 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyClassPropertyArrowFunction(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class C { + caller = () => { + this.callee(); + } + + /**/callee = () => { + } +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyClassStaticBlock2_test.go b/internal/fourslash/tests/gen/callHierarchyClassStaticBlock2_test.go new file mode 100644 index 0000000000..b0103cba48 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyClassStaticBlock2_test.go @@ -0,0 +1,38 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyClassStaticBlock2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class C { + /**/static { + function foo() { + bar(); + } + + function bar() { + baz(); + quxx(); + baz(); + } + + foo(); + } +} + +function baz() { +} + +function quxx() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyClassStaticBlock_test.go b/internal/fourslash/tests/gen/callHierarchyClassStaticBlock_test.go new file mode 100644 index 0000000000..a1d028da78 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyClassStaticBlock_test.go @@ -0,0 +1,38 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyClassStaticBlock(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `class C { + static { + function foo() { + bar(); + } + + function /**/bar() { + baz(); + quxx(); + baz(); + } + + foo(); + } +} + +function baz() { +} + +function quxx() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyClass_test.go b/internal/fourslash/tests/gen/callHierarchyClass_test.go new file mode 100644 index 0000000000..59084555e5 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyClass_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyClass(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar(); +} + +function /**/bar() { + new Baz(); +} + +class Baz { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyConstNamedArrowFunction_test.go b/internal/fourslash/tests/gen/callHierarchyConstNamedArrowFunction_test.go new file mode 100644 index 0000000000..8c8f0f89f8 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyConstNamedArrowFunction_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyConstNamedArrowFunction(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar(); +} + +const /**/bar = () => { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyConstNamedClassExpression_test.go b/internal/fourslash/tests/gen/callHierarchyConstNamedClassExpression_test.go new file mode 100644 index 0000000000..e23a9b6f68 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyConstNamedClassExpression_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyConstNamedClassExpression(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + new Bar(); +} + +const /**/Bar = class { + constructor() { + baz(); + } +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyConstNamedFunctionExpression_test.go b/internal/fourslash/tests/gen/callHierarchyConstNamedFunctionExpression_test.go new file mode 100644 index 0000000000..2a56777abf --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyConstNamedFunctionExpression_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyConstNamedFunctionExpression(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar(); +} + +const /**/bar = function () { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyContainerNameServer_test.go b/internal/fourslash/tests/gen/callHierarchyContainerNameServer_test.go new file mode 100644 index 0000000000..0500b18584 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyContainerNameServer_test.go @@ -0,0 +1,53 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyContainerNameServer(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `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 Foo.Bar { + const sameName = () => new Foo.C(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.MarkTestAsStradaServer() + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyContainerName_test.go b/internal/fourslash/tests/gen/callHierarchyContainerName_test.go new file mode 100644 index 0000000000..fcd08b77c5 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyContainerName_test.go @@ -0,0 +1,52 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyContainerName(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `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 Foo.Bar { + const sameName = () => new Foo.C(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyCrossFile_test.go b/internal/fourslash/tests/gen/callHierarchyCrossFile_test.go new file mode 100644 index 0000000000..1467878f7d --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyCrossFile_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyCrossFile(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /a.ts +export function /**/createModelReference() {} +// @filename: /b.ts +import { createModelReference } from "./a"; +function openElementsAtEditor() { + createModelReference(); +} +// @filename: /c.ts +import { createModelReference } from "./a"; +function registerDefaultLanguageCommand() { + createModelReference(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyDecorator_test.go b/internal/fourslash/tests/gen/callHierarchyDecorator_test.go new file mode 100644 index 0000000000..f9c4022129 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyDecorator_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyDecorator(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @experimentalDecorators: true +@bar +class Foo { +} + +function /**/bar() { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyExportDefaultClass_test.go b/internal/fourslash/tests/gen/callHierarchyExportDefaultClass_test.go new file mode 100644 index 0000000000..c4c848f82c --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyExportDefaultClass_test.go @@ -0,0 +1,32 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyExportDefaultClass(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: main.ts +import Bar from "./other"; + +function foo() { + new Bar(); +} +// @filename: other.ts +export /**/default class { + constructor() { + baz(); + } +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyExportDefaultFunction_test.go b/internal/fourslash/tests/gen/callHierarchyExportDefaultFunction_test.go new file mode 100644 index 0000000000..3e64c7179f --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyExportDefaultFunction_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyExportDefaultFunction(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: main.ts +import bar from "./other"; + +function foo() { + bar(); +} +// @filename: other.ts +export /**/default function () { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyExportEqualsFunction_test.go b/internal/fourslash/tests/gen/callHierarchyExportEqualsFunction_test.go new file mode 100644 index 0000000000..ba00b1d6de --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyExportEqualsFunction_test.go @@ -0,0 +1,30 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyExportEqualsFunction(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: main.ts +import bar = require("./other"); + +function foo() { + bar(); +} +// @filename: other.ts +export = /**/function () { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFile_test.go b/internal/fourslash/tests/gen/callHierarchyFile_test.go new file mode 100644 index 0000000000..b10a814a58 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFile_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFile(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `foo(); +function /**/foo() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity1_test.go b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity1_test.go new file mode 100644 index 0000000000..f99348b6d1 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity1_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunctionAmbiguity1(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: a.d.ts +declare function foo(x?: number): void; +// @filename: b.d.ts +declare function foo(x?: string): void; +declare function foo(x?: boolean): void; +// @filename: main.ts +function bar() { + /**/foo(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity2_test.go b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity2_test.go new file mode 100644 index 0000000000..9af650ce83 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity2_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunctionAmbiguity2(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: a.d.ts +declare function /**/foo(x?: number): void; +// @filename: b.d.ts +declare function foo(x?: string): void; +declare function foo(x?: boolean): void; +// @filename: main.ts +function bar() { + foo(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity3_test.go b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity3_test.go new file mode 100644 index 0000000000..667c1e1ed7 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity3_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunctionAmbiguity3(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: a.d.ts +declare function foo(x?: number): void; +// @filename: b.d.ts +declare function /**/foo(x?: string): void; +declare function foo(x?: boolean): void; +// @filename: main.ts +function bar() { + foo(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity4_test.go b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity4_test.go new file mode 100644 index 0000000000..b2e2e40d11 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity4_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunctionAmbiguity4(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: a.d.ts +declare function foo(x?: number): void; +// @filename: b.d.ts +declare function foo(x?: string): void; +declare function /**/foo(x?: boolean): void; +// @filename: main.ts +function bar() { + foo(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity5_test.go b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity5_test.go new file mode 100644 index 0000000000..f4fbc075c7 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunctionAmbiguity5_test.go @@ -0,0 +1,26 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunctionAmbiguity5(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: a.d.ts +declare function foo(x?: number): void; +// @filename: b.d.ts +declare function foo(x?: string): void; +declare function foo(x?: boolean): void; +// @filename: main.ts +function /**/bar() { + foo(); +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyFunction_test.go b/internal/fourslash/tests/gen/callHierarchyFunction_test.go new file mode 100644 index 0000000000..0106d01f3d --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyFunction_test.go @@ -0,0 +1,32 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyFunction(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar(); +} + +function /**/bar() { + baz(); + quxx(); + baz(); +} + +function baz() { +} + +function quxx() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyInterfaceMethod_test.go b/internal/fourslash/tests/gen/callHierarchyInterfaceMethod_test.go new file mode 100644 index 0000000000..51bf532886 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyInterfaceMethod_test.go @@ -0,0 +1,24 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyInterfaceMethod(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `interface I { + /**/foo(): void; +} + +const obj: I = { foo() {} }; + +obj.foo();` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyJsxElement_test.go b/internal/fourslash/tests/gen/callHierarchyJsxElement_test.go new file mode 100644 index 0000000000..7d15e7ab35 --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyJsxElement_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyJsxElement(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @jsx: preserve +// @filename: main.tsx +function foo() { + return ; +} + +function /**/Bar() { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/fourslash/tests/gen/callHierarchyTaggedTemplate_test.go b/internal/fourslash/tests/gen/callHierarchyTaggedTemplate_test.go new file mode 100644 index 0000000000..2ff353d83b --- /dev/null +++ b/internal/fourslash/tests/gen/callHierarchyTaggedTemplate_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestCallHierarchyTaggedTemplate(t *testing.T) { + t.Parallel() + + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function foo() { + bar` + "`" + `a${1}b` + "`" + `; +} + +function /**/bar(array: TemplateStringsArray, ...args: any[]) { + baz(); +} + +function baz() { +}` + f := fourslash.NewFourslash(t, nil /*capabilities*/, content) + f.GoToMarker(t, "") + f.VerifyBaselineCallHierarchy(t) +} diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go new file mode 100644 index 0000000000..91d97a27f5 --- /dev/null +++ b/internal/ls/callhierarchy.go @@ -0,0 +1,1165 @@ +package ls + +import ( + "context" + "slices" + "strings" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/astnav" + "github.com/microsoft/typescript-go/internal/checker" + "github.com/microsoft/typescript-go/internal/compiler" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/debug" + "github.com/microsoft/typescript-go/internal/ls/lsconv" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/scanner" +) + +type CallHierarchyDeclaration = *ast.Node + +// Indictates whether a node is named function or class expression. +func isNamedExpression(node *ast.Node) bool { + if node == nil { + return false + } + if !ast.IsFunctionExpression(node) && !ast.IsClassExpression(node) { + return false + } + // Check if it has a name + name := node.Name() + return name != nil && ast.IsIdentifier(name) +} + +func isVariableLike(node *ast.Node) bool { + if node == nil { + return false + } + return ast.IsPropertyDeclaration(node) || ast.IsVariableDeclaration(node) +} + +// Indicates whether a node is a function, arrow, or class expression assigned to a constant variable or class property. +func isAssignedExpression(node *ast.Node) bool { + if node == nil { + return false + } + if !(ast.IsFunctionExpression(node) || ast.IsArrowFunction(node) || ast.IsClassExpression(node)) { + return false + } + parent := node.Parent + if !isVariableLike(parent) { + return false + } + + // Check if it's the initializer: node === node.parent.initializer + if parent.Initializer() != node { + return false + } + + // Check if the name is an identifier: isIdentifier(node.parent.name) + name := parent.Name() + if !ast.IsIdentifier(name) { + return false + } + + // (!!(getCombinedNodeFlags(node.parent) & NodeFlags.Const) || isPropertyDeclaration(node.parent)) + return (ast.GetCombinedNodeFlags(parent)&ast.NodeFlagsConst) != 0 || ast.IsPropertyDeclaration(parent) +} + +// Indicates whether a node could possibly be a call hierarchy declaration. +// +// See `resolveCallHierarchyDeclaration` for the specific rules. +func isPossibleCallHierarchyDeclaration(node *ast.Node) bool { + if node == nil { + return false + } + return ast.IsSourceFile(node) || + ast.IsModuleDeclaration(node) || + ast.IsFunctionDeclaration(node) || + ast.IsFunctionExpression(node) || + ast.IsClassDeclaration(node) || + ast.IsClassExpression(node) || + ast.IsClassStaticBlockDeclaration(node) || + ast.IsMethodDeclaration(node) || + ast.IsMethodSignatureDeclaration(node) || + ast.IsGetAccessorDeclaration(node) || + ast.IsSetAccessorDeclaration(node) +} + +// Indicates whether a node is a valid a call hierarchy declaration. +// +// See `resolveCallHierarchyDeclaration` for the specific rules. +func isValidCallHierarchyDeclaration(node *ast.Node) bool { + if node == nil { + return false + } + + if ast.IsSourceFile(node) { + return true + } + + if ast.IsModuleDeclaration(node) { + mod := node.AsModuleDeclaration() + return mod != nil && ast.IsIdentifier(mod.Name()) + } + + return ast.IsFunctionDeclaration(node) || + ast.IsClassDeclaration(node) || + ast.IsClassStaticBlockDeclaration(node) || + ast.IsMethodDeclaration(node) || + ast.IsMethodSignatureDeclaration(node) || + ast.IsGetAccessorDeclaration(node) || + ast.IsSetAccessorDeclaration(node) || + isNamedExpression(node) || + isAssignedExpression(node) +} + +// Gets the node that can be used as a reference to a call hierarchy declaration. +func getCallHierarchyDeclarationReferenceNode(node *ast.Node) *ast.Node { + if node == nil { + return nil + } + + if ast.IsSourceFile(node) { + return node + } + + // Check if node has a Name() method and it returns non-nil + if name := node.Name(); name != nil { + return name + } + + if isAssignedExpression(node) { + return node.Parent.Name() + } + + // Find default modifier + if modifiers := node.Modifiers(); modifiers != nil { + for _, mod := range modifiers.Nodes { + if mod.Kind == ast.KindDefaultKeyword { + return mod + } + } + } + + debug.Assert(false, "Expected call hierarchy declaration to have a reference node") + return nil +} + +// Gets the symbol for a call hierarchy declaration. +func getSymbolOfCallHierarchyDeclaration(c *checker.Checker, node *ast.Node) *ast.Symbol { + if ast.IsClassStaticBlockDeclaration(node) { + return nil + } + location := getCallHierarchyDeclarationReferenceNode(node) + if location == nil { + return nil + } + return c.GetSymbolAtLocation(location) +} + +// Gets the text and range for the name of a call hierarchy declaration. +func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text string, pos int, end int) { + if ast.IsSourceFile(node) { + sourceFile := node.AsSourceFile() + return sourceFile.FileName(), 0, 0 + } + + // Check for unnamed function or class declaration with default modifier + if (ast.IsFunctionDeclaration(node) || ast.IsClassDeclaration(node)) && node.Name() == nil { + if modifiers := node.Modifiers(); modifiers != nil { + for _, mod := range modifiers.Nodes { + if mod.Kind == ast.KindDefaultKeyword { + sourceFile := ast.GetSourceFileOfNode(node) + start := scanner.SkipTrivia(sourceFile.Text(), mod.Pos()) + return "default", start, mod.End() + } + } + } + } + + // Class static block + if ast.IsClassStaticBlockDeclaration(node) { + sourceFile := ast.GetSourceFileOfNode(node) + pos := scanner.SkipTrivia(sourceFile.Text(), moveRangePastModifiers(node).Pos()) + end := pos + 6 // "static".length + c, done := program.GetTypeCheckerForFile(context.Background(), sourceFile) + defer done() + symbol := c.GetSymbolAtLocation(node.Parent) + prefix := "" + if symbol != nil { + prefix = c.SymbolToString(symbol) + " " + } + return prefix + "static {}", pos, end + } + + // Get the declaration name + var declName *ast.Node + if isAssignedExpression(node) { + declName = node.Parent.Name() + } else { + declName = ast.GetNameOfDeclaration(node) + } + + debug.AssertIsDefined(declName, "Expected call hierarchy item to have a name") + + // Get text from the name + if ast.IsIdentifier(declName) { + text = declName.Text() + } else if ast.IsStringOrNumericLiteralLike(declName) { + text = declName.Text() + } else if ast.IsComputedPropertyName(declName) { + comp := declName.AsComputedPropertyName() + if ast.IsStringOrNumericLiteralLike(comp.Expression) { + text = comp.Expression.Text() + } + } + + // Try to get text from symbol if undefined + if text == "" { + c, done := program.GetTypeCheckerForFile(context.Background(), ast.GetSourceFileOfNode(node)) + defer done() + symbol := c.GetSymbolAtLocation(declName) + if symbol != nil { + text = c.SymbolToString(symbol) + } + } + + // Last resort: use a generic name + if text == "" { + text = "(anonymous)" + } + + // Use getStart() behavior (skip trivia) for selection span + sourceFile := ast.GetSourceFileOfNode(node) + namePos := scanner.SkipTrivia(sourceFile.Text(), declName.Pos()) + + return text, namePos, declName.End() +} + +func getCallHierarchyItemContainerName(node *ast.Node) string { + if isAssignedExpression(node) { + parent := node.Parent + if ast.IsPropertyDeclaration(parent) && ast.IsClassLike(parent.Parent) { + if name := parent.Parent.Name(); name != nil { + return name.Text() + } + } + // Check for module block + if varDecl := parent.AsVariableDeclaration(); varDecl != nil { + if ast.IsModuleBlock(parent.Parent.Parent.Parent) { + modParent := parent.Parent.Parent.Parent.Parent + if ast.IsModuleDeclaration(modParent) { + mod := modParent.AsModuleDeclaration() + if name := mod.Name(); name != nil && ast.IsIdentifier(name) { + return name.Text() + } + } + } + } + return "" + } + + switch node.Kind { + case ast.KindGetAccessor, ast.KindSetAccessor, ast.KindMethodDeclaration: + if node.Parent.Kind == ast.KindObjectLiteralExpression { + // Skip assigned name check for now + } + if name := ast.GetNameOfDeclaration(node.Parent); name != nil { + return name.Text() + } + case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindModuleDeclaration: + if ast.IsModuleBlock(node.Parent) { + if ast.IsModuleDeclaration(node.Parent.Parent) { + mod := node.Parent.Parent.AsModuleDeclaration() + if name := mod.Name(); name != nil && ast.IsIdentifier(name) { + return name.Text() + } + } + } + } + + return "" +} + +func moveRangePastModifiers(node *ast.Node) core.TextRange { + if modifiers := node.Modifiers(); modifiers != nil && len(modifiers.Nodes) > 0 { + lastMod := modifiers.Nodes[len(modifiers.Nodes)-1] + return core.NewTextRange(lastMod.End(), node.End()) + } + return core.NewTextRange(node.Pos(), node.End()) +} + +// Finds the implementation of a function-like declaration, if one exists. +func findImplementation(c *checker.Checker, node *ast.Node) *ast.Node { + if node == nil { + return nil + } + + if !ast.IsFunctionLikeDeclaration(node) { + return node + } + + // If it has a body, it's already the implementation + if node.Body() != nil { + return node + } + + // For constructors, find the first constructor with a body + if ast.IsConstructorDeclaration(node) { + ctor := ast.GetFirstConstructorWithBody(node.Parent) + if ctor != nil { + return ctor + } + } + + // For function or method declarations, look for the implementation in the symbol + if ast.IsFunctionDeclaration(node) || ast.IsMethodDeclaration(node) { + symbol := getSymbolOfCallHierarchyDeclaration(c, node) + if symbol != nil && symbol.ValueDeclaration != nil { + if ast.IsFunctionLikeDeclaration(symbol.ValueDeclaration) && symbol.ValueDeclaration.Body() != nil { + return symbol.ValueDeclaration + } + } + return nil + } + + return node +} + +func findAllInitialDeclarations(c *checker.Checker, node *ast.Node) []*ast.Node { + if ast.IsClassStaticBlockDeclaration(node) { + return nil + } + + symbol := getSymbolOfCallHierarchyDeclaration(c, node) + if symbol == nil || symbol.Declarations == nil { + return nil + } + + // Sort declarations by file and position + type declKey struct { + file string + pos int + } + + // Create indices for declarations + indices := make([]int, len(symbol.Declarations)) + for i := range indices { + indices[i] = i + } + keys := make([]declKey, len(symbol.Declarations)) + for i, decl := range symbol.Declarations { + keys[i] = declKey{ + file: ast.GetSourceFileOfNode(decl).FileName(), + pos: decl.Pos(), + } + } + + slices.SortFunc(indices, func(a, b int) int { + if keys[a].file != keys[b].file { + return strings.Compare(keys[a].file, keys[b].file) + } + return keys[a].pos - keys[b].pos + }) + + var declarations []*ast.Node + var lastDecl *ast.Node + + for _, i := range indices { + decl := symbol.Declarations[i] + if isValidCallHierarchyDeclaration(decl) { + // Only add if it's not adjacent to the last declaration + if lastDecl == nil || lastDecl.Parent != decl.Parent || lastDecl.End() != decl.Pos() { + declarations = append(declarations, decl) + } + lastDecl = decl + } + } + + return declarations +} + +// Find the implementation or the first declaration for a call hierarchy declaration. +func findImplementationOrAllInitialDeclarations(c *checker.Checker, node *ast.Node) any { + if ast.IsClassStaticBlockDeclaration(node) { + return node + } + + if ast.IsFunctionLikeDeclaration(node) { + if impl := findImplementation(c, node); impl != nil { + return impl + } + if decls := findAllInitialDeclarations(c, node); decls != nil { + return decls + } + return node + } + + if decls := findAllInitialDeclarations(c, node); decls != nil { + return decls + } + return node +} + +// Resolves the call hierarchy declaration for a node. +// +// A call hierarchy item must refer to either a SourceFile, Module Declaration, Class Static Block, or something intrinsically callable that has a name: +// - Class Declarations +// - Class Expressions (with a name) +// - Function Declarations +// - Function Expressions (with a name or assigned to a const variable) +// - Arrow Functions (assigned to a const variable) +// - Constructors +// - Class `static {}` initializer blocks +// - Methods +// - Accessors +// +// If a call is contained in a non-named callable Node (function expression, arrow function, etc.), then +// its containing `CallHierarchyItem` is a containing function or SourceFile that matches the above list. +func resolveCallHierarchyDeclaration(program *compiler.Program, location *ast.Node) (result any) { + c, done := program.GetTypeChecker(context.Background()) + defer done() + + followingSymbol := false + + for location != nil { + if isValidCallHierarchyDeclaration(location) { + return findImplementationOrAllInitialDeclarations(c, location) + } + + if isPossibleCallHierarchyDeclaration(location) { + ancestor := ast.FindAncestor(location, isValidCallHierarchyDeclaration) + if ancestor != nil { + return findImplementationOrAllInitialDeclarations(c, ancestor) + } + } + + if ast.IsDeclarationName(location) { + if isValidCallHierarchyDeclaration(location.Parent) { + return findImplementationOrAllInitialDeclarations(c, location.Parent) + } + if isPossibleCallHierarchyDeclaration(location.Parent) { + ancestor := ast.FindAncestor(location.Parent, isValidCallHierarchyDeclaration) + if ancestor != nil { + return findImplementationOrAllInitialDeclarations(c, ancestor) + } + } + if isVariableLike(location.Parent) { + initializer := location.Parent.Initializer() + if initializer != nil && isAssignedExpression(initializer) { + return initializer + } + } + return nil + } + + if ast.IsConstructorDeclaration(location) { + if isValidCallHierarchyDeclaration(location.Parent) { + return location.Parent + } + return nil + } + + // Check for static keyword in class static block + if location.Kind == ast.KindStaticKeyword && ast.IsClassStaticBlockDeclaration(location.Parent) { + location = location.Parent + continue + } + + // Variable declaration with assigned expression + if ast.IsVariableDeclaration(location) { + varDecl := location.AsVariableDeclaration() + if varDecl != nil && varDecl.Initializer != nil && isAssignedExpression(varDecl.Initializer) { + return varDecl.Initializer + } + } + + // Follow symbol if we haven't already + if !followingSymbol { + symbol := c.GetSymbolAtLocation(location) + if symbol != nil { + if (symbol.Flags & ast.SymbolFlagsAlias) != 0 { + symbol = c.GetAliasedSymbol(symbol) + } + if symbol.ValueDeclaration != nil { + followingSymbol = true + location = symbol.ValueDeclaration + continue + } + } + } + + return nil + } + + return nil +} + +// Creates a `CallHierarchyItem` for a call hierarchy declaration. +func (l *LanguageService) createCallHierarchyItem(program *compiler.Program, node *ast.Node) *lsproto.CallHierarchyItem { + sourceFile := ast.GetSourceFileOfNode(node) + nameText, namePos, nameEnd := getCallHierarchyItemName(program, node) + containerName := getCallHierarchyItemContainerName(node) + + kind := getSymbolKindFromNode(node) + + fullStart := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) + script := l.getScript(sourceFile.FileName()) + span := l.converters.ToLSPRange(script, core.NewTextRange(fullStart, node.End())) + selectionSpan := l.converters.ToLSPRange(script, core.NewTextRange(namePos, nameEnd)) + + item := &lsproto.CallHierarchyItem{ + Name: nameText, + Kind: kind, + Uri: lsconv.FileNameToDocumentURI(sourceFile.FileName()), + Range: span, + SelectionRange: selectionSpan, + } + + // kindModifiers is a Set, not a string - skip for now + // TODO: convert modifiers to SymbolTag array + + if containerName != "" { + item.Detail = &containerName + } + + return item +} + +type callSite struct { + declaration *ast.Node + textRange core.TextRange +} + +func isCallLikeTarget(node *ast.Node) bool { + if node == nil || node.Parent == nil { + return false + } + + parent := node.Parent + + // CallExpression or NewExpression: node.expression === parent + if ast.IsCallExpression(parent) { + callExpr := parent.AsCallExpression() + return callExpr != nil && callExpr.Expression == node + } + if ast.IsNewExpression(parent) { + newExpr := parent.AsNewExpression() + return newExpr != nil && newExpr.Expression == node + } + + // TaggedTemplateExpression: node.tag === parent + if ast.IsTaggedTemplateExpression(parent) { + taggedTemplate := parent.AsTaggedTemplateExpression() + return taggedTemplate != nil && taggedTemplate.Tag == node + } + + // Decorator: node.expression === parent + if ast.IsDecorator(parent) { + decorator := parent.AsDecorator() + return decorator != nil && decorator.Expression == node + } + + // JsxOpeningElement or JsxSelfClosingElement: node.tagName === parent + if ast.IsJsxOpeningElement(parent) { + jsxOpen := parent.AsJsxOpeningElement() + return jsxOpen != nil && jsxOpen.TagName == node + } + if ast.IsJsxSelfClosingElement(parent) { + jsxSelf := parent.AsJsxSelfClosingElement() + return jsxSelf != nil && jsxSelf.TagName == node + } + + // PropertyAccessExpression: is right side + if ast.IsPropertyAccessExpression(parent) { + propAccess := parent.AsPropertyAccessExpression() + return propAccess != nil && propAccess.Name() == node + } + + // ElementAccessExpression: is argument expression + if ast.IsElementAccessExpression(parent) { + elemAccess := parent.AsElementAccessExpression() + return elemAccess != nil && elemAccess.ArgumentExpression == node + } + + return false +} + +func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *callSite { + if entry.kind != entryKindNode { + return nil + } + + node := entry.node + if !isCallLikeTarget(node) { + return nil + } + + sourceFile := ast.GetSourceFileOfNode(node) + ancestor := ast.FindAncestor(node, isValidCallHierarchyDeclaration) + if ancestor == nil { + ancestor = sourceFile.AsNode() + } + + start := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) + return &callSite{ + declaration: ancestor, + textRange: core.NewTextRange(start, node.End()), + } +} + +func getCallSiteGroupKey(site *callSite) ast.NodeId { + return ast.GetNodeId(site.declaration) +} + +func (l *LanguageService) convertCallSiteGroupToIncomingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyIncomingCall { + fromRanges := make([]lsproto.Range, len(entries)) + for i, entry := range entries { + // Get source file from the declaration node to find the script + sourceFile := ast.GetSourceFileOfNode(entry.declaration) + script := l.getScript(sourceFile.FileName()) + fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) + } + + // Sort fromRanges for consistent ordering + slices.SortFunc(fromRanges, func(a, b lsproto.Range) int { + return lsproto.CompareRanges(&a, &b) + }) + + return &lsproto.CallHierarchyIncomingCall{ + From: l.createCallHierarchyItem(program, entries[0].declaration), + FromRanges: fromRanges, + } +} + +// Gets the call sites that call into the provided call hierarchy declaration. +func (l *LanguageService) getIncomingCalls(ctx context.Context, program *compiler.Program, declaration *ast.Node) []*lsproto.CallHierarchyIncomingCall { + // Source files and modules have no incoming calls. + if ast.IsSourceFile(declaration) || ast.IsModuleDeclaration(declaration) || ast.IsClassStaticBlockDeclaration(declaration) { + return nil + } + + location := getCallHierarchyDeclarationReferenceNode(declaration) + if location == nil { + return nil + } + + // Find all references using getReferencedSymbolsForNode + sourceFiles := program.GetSourceFiles() + options := refOptions{use: referenceUseReferences} + symbolsAndEntries := l.getReferencedSymbolsForNode(ctx, location.Pos(), location, program, sourceFiles, options, nil) + + // Flatten to get all reference entries + var refEntries []*ReferenceEntry + for _, symbolAndEntry := range symbolsAndEntries { + refEntries = append(refEntries, symbolAndEntry.references...) + } + + // Convert to call sites + var callSites []*callSite + for _, entry := range refEntries { + if site := convertEntryToCallSite(program, entry); site != nil { + callSites = append(callSites, site) + } + } + + if len(callSites) == 0 { + return nil + } + + // Group by declaration + grouped := make(map[ast.NodeId][]*callSite) + for _, site := range callSites { + key := getCallSiteGroupKey(site) + grouped[key] = append(grouped[key], site) + } + + // Convert groups to incoming calls + var result []*lsproto.CallHierarchyIncomingCall + for _, sites := range grouped { + result = append(result, l.convertCallSiteGroupToIncomingCall(program, sites)) + } + + // Sort result by file first, then position for deterministic order + slices.SortFunc(result, func(a, b *lsproto.CallHierarchyIncomingCall) int { + // Compare by file URI first + if uriComp := strings.Compare(string(a.From.Uri), string(b.From.Uri)); uriComp != 0 { + return uriComp + } + // Then compare by first fromRange + if len(a.FromRanges) == 0 || len(b.FromRanges) == 0 { + return 0 + } + return lsproto.CompareRanges(&a.FromRanges[0], &b.FromRanges[0]) + }) + + return result +} + +type callSiteCollector struct { + program *compiler.Program + callSites []*callSite +} + +func (c *callSiteCollector) recordCallSite(node *ast.Node) { + var target *ast.Node + + switch { + case ast.IsTaggedTemplateExpression(node): + tagged := node.AsTaggedTemplateExpression() + target = tagged.Tag + case ast.IsJsxOpeningElement(node): + jsxOpen := node.AsJsxOpeningElement() + target = jsxOpen.TagName + case ast.IsJsxSelfClosingElement(node): + jsxSelf := node.AsJsxSelfClosingElement() + target = jsxSelf.TagName + case ast.IsPropertyAccessExpression(node) || ast.IsElementAccessExpression(node): + target = node + case ast.IsClassStaticBlockDeclaration(node): + target = node + case ast.IsCallExpression(node): + callExpr := node.AsCallExpression() + target = callExpr.Expression + case ast.IsNewExpression(node): + newExpr := node.AsNewExpression() + target = newExpr.Expression + case ast.IsDecorator(node): + decorator := node.AsDecorator() + target = decorator.Expression + } + + if target == nil { + return + } + + declaration := resolveCallHierarchyDeclaration(c.program, target) + if declaration == nil { + return + } + + // Skip trivia to get the actual start position (equivalent to getStart()) + sourceFile := ast.GetSourceFileOfNode(target) + start := scanner.SkipTrivia(sourceFile.Text(), target.Pos()) + textRange := core.NewTextRange(start, target.End()) + + // Handle both single node and array of nodes + switch decl := declaration.(type) { + case *ast.Node: + c.callSites = append(c.callSites, &callSite{ + declaration: decl, + textRange: textRange, + }) + case []*ast.Node: + for _, d := range decl { + c.callSites = append(c.callSites, &callSite{ + declaration: d, + textRange: textRange, + }) + } + } +} + +func (c *callSiteCollector) collect(node *ast.Node) { + if node == nil { + return + } + + // Do not descend into ambient nodes + if (node.Flags & ast.NodeFlagsAmbient) != 0 { + return + } + + // Do not descend into other call site declarations, except class member names + if isValidCallHierarchyDeclaration(node) { + if ast.IsClassLike(node) { + // Collect from computed property names + classLike := node.AsClassDeclaration() + if classLike != nil && classLike.Members != nil { + for _, member := range classLike.Members.Nodes { + if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { + comp := member.Name().AsComputedPropertyName() + c.collect(comp.Expression) + } + } + } + } + return + } + + switch node.Kind { + case ast.KindIdentifier, + ast.KindImportEqualsDeclaration, + ast.KindImportDeclaration, + ast.KindExportDeclaration, + ast.KindInterfaceDeclaration, + ast.KindTypeAliasDeclaration: + // do not descend into nodes that cannot contain callable nodes + return + case ast.KindClassStaticBlockDeclaration: + c.recordCallSite(node) + return + case ast.KindTypeAssertionExpression, ast.KindAsExpression: + // do not descend into the type side of an assertion + var expr *ast.Node + if typeAssert := node.AsAsExpression(); typeAssert != nil { + expr = typeAssert.Expression + } else if asExpr := node.AsAsExpression(); asExpr != nil { + expr = asExpr.Expression + } + c.collect(expr) + return + case ast.KindVariableDeclaration, ast.KindParameter: + // do not descend into the type of a variable or parameter declaration + var name, initializer *ast.Node + if node.Kind == ast.KindVariableDeclaration { + varDecl := node.AsVariableDeclaration() + name = varDecl.Name() + initializer = varDecl.Initializer + } else { + param := node.AsParameterDeclaration() + name = param.Name() + initializer = param.Initializer + } + c.collect(name) + c.collect(initializer) + return + case ast.KindCallExpression: + // do not descend into the type arguments of a call expression + c.recordCallSite(node) + callExpr := node.AsCallExpression() + c.collect(callExpr.Expression) + if callExpr.Arguments != nil { + for _, arg := range callExpr.Arguments.Nodes { + c.collect(arg) + } + } + return + case ast.KindNewExpression: + // do not descend into the type arguments of a new expression + c.recordCallSite(node) + newExpr := node.AsNewExpression() + c.collect(newExpr.Expression) + if newExpr.Arguments != nil { + for _, arg := range newExpr.Arguments.Nodes { + c.collect(arg) + } + } + return + case ast.KindTaggedTemplateExpression: + // do not descend into the type arguments of a tagged template expression + c.recordCallSite(node) + tagged := node.AsTaggedTemplateExpression() + c.collect(tagged.Tag) + c.collect(tagged.Template) + return + case ast.KindJsxOpeningElement, ast.KindJsxSelfClosingElement: + // do not descend into the type arguments of a JsxOpeningLikeElement + c.recordCallSite(node) + if jsxOpen := node.AsJsxOpeningElement(); jsxOpen != nil { + c.collect(jsxOpen.TagName) + c.collect(jsxOpen.Attributes) + } else if jsxSelf := node.AsJsxSelfClosingElement(); jsxSelf != nil { + c.collect(jsxSelf.TagName) + c.collect(jsxSelf.Attributes) + } + return + case ast.KindDecorator: + c.recordCallSite(node) + decorator := node.AsDecorator() + c.collect(decorator.Expression) + return + case ast.KindPropertyAccessExpression, ast.KindElementAccessExpression: + c.recordCallSite(node) + node.ForEachChild(func(child *ast.Node) bool { + c.collect(child) + return false + }) + return + case ast.KindSatisfiesExpression: + // do not descend into the type side of an assertion + satisfies := node.AsSatisfiesExpression() + c.collect(satisfies.Expression) + return + } + + if ast.IsPartOfTypeNode(node) { + // do not descend into types + return + } + + node.ForEachChild(func(child *ast.Node) bool { + c.collect(child) + return false + }) +} + +func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.Node) []*callSite { + collector := &callSiteCollector{ + program: program, + callSites: make([]*callSite, 0), + } + + switch node.Kind { + case ast.KindSourceFile: + sourceFile := node.AsSourceFile() + if sourceFile.Statements != nil { + for _, stmt := range sourceFile.Statements.Nodes { + collector.collect(stmt) + } + } + + case ast.KindModuleDeclaration: + mod := node.AsModuleDeclaration() + if !ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) && mod.Body != nil && ast.IsModuleBlock(mod.Body) { + modBlock := mod.Body.AsModuleBlock() + if modBlock.Statements != nil { + for _, stmt := range modBlock.Statements.Nodes { + collector.collect(stmt) + } + } + } + + case ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, + ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor: + impl := findImplementation(c, node) + if impl != nil { + if impl.Parameters() != nil { + for _, param := range impl.Parameters() { + collector.collect(param) + } + } + collector.collect(impl.Body()) + } + + case ast.KindClassDeclaration, ast.KindClassExpression: + // Collect from modifiers + if modifiers := node.Modifiers(); modifiers != nil { + for _, mod := range modifiers.Nodes { + collector.collect(mod) + } + } + + // Collect from heritage + heritage := ast.GetClassExtendsHeritageElement(node) + if heritage != nil { + collector.collect(heritage.Expression()) + } + + // Collect from members + members := node.Members() + + if members != nil { + for _, member := range members { + if ast.CanHaveModifiers(member) && member.Modifiers() != nil { + for _, mod := range member.Modifiers().Nodes { + collector.collect(mod) + } + } + + if ast.IsPropertyDeclaration(member) { + propDecl := member.AsPropertyDeclaration() + collector.collect(propDecl.Initializer) + } else if ast.IsConstructorDeclaration(member) { + ctor := member.AsConstructorDeclaration() + if ctor.Body != nil { + if ctor.Parameters != nil { + for _, param := range ctor.Parameters.Nodes { + collector.collect(param) + } + } + collector.collect(ctor.Body) + } + } else if ast.IsClassStaticBlockDeclaration(member) { + collector.collect(member) + } + } + } + + case ast.KindClassStaticBlockDeclaration: + staticBlock := node.AsClassStaticBlockDeclaration() + collector.collect(staticBlock.Body) + } + + return collector.callSites +} + +func (l *LanguageService) convertCallSiteGroupToOutgoingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyOutgoingCall { + fromRanges := make([]lsproto.Range, len(entries)) + for i, entry := range entries { + sourceFile := ast.GetSourceFileOfNode(entries[0].declaration) + script := l.getScript(sourceFile.FileName()) + fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) + } + + // Sort fromRanges for consistent ordering + slices.SortFunc(fromRanges, func(a, b lsproto.Range) int { + return lsproto.CompareRanges(&a, &b) + }) + + return &lsproto.CallHierarchyOutgoingCall{ + To: l.createCallHierarchyItem(program, entries[0].declaration), + FromRanges: fromRanges, + } +} + +// Gets the call sites that call out of the provided call hierarchy declaration. +func (l *LanguageService) getOutgoingCalls(program *compiler.Program, declaration *ast.Node) []*lsproto.CallHierarchyOutgoingCall { + if (declaration.Flags & ast.NodeFlagsAmbient) != 0 { + return nil + } + + c, done := program.GetTypeChecker(context.Background()) + defer done() + + callSites := collectCallSites(program, c, declaration) + + if len(callSites) == 0 { + return nil + } + + // Group by declaration + grouped := make(map[ast.NodeId][]*callSite) + for _, site := range callSites { + key := getCallSiteGroupKey(site) + grouped[key] = append(grouped[key], site) + } + + // Convert groups to outgoing calls + var result []*lsproto.CallHierarchyOutgoingCall + for _, sites := range grouped { + result = append(result, l.convertCallSiteGroupToOutgoingCall(program, sites)) + } + + // Sort result by file first, then position for deterministic order + slices.SortFunc(result, func(a, b *lsproto.CallHierarchyOutgoingCall) int { + // Compare by file URI first + if uriComp := strings.Compare(string(a.To.Uri), string(b.To.Uri)); uriComp != 0 { + return uriComp + } + // Then compare by first fromRange + if len(a.FromRanges) == 0 || len(b.FromRanges) == 0 { + return 0 + } + return lsproto.CompareRanges(&a.FromRanges[0], &b.FromRanges[0]) + }) + + return result +} + +func (l *LanguageService) ProvidePrepareCallHierarchy( + ctx context.Context, + documentURI lsproto.DocumentUri, + position lsproto.Position, +) ([]*lsproto.CallHierarchyItem, error) { + program, file := l.getProgramAndFile(documentURI) + node := astnav.GetTouchingPropertyName(file, int(l.converters.LineAndCharacterToPosition(file, position))) + + if node.Kind == ast.KindSourceFile { + return nil, nil + } + + declaration := resolveCallHierarchyDeclaration(program, node) + if declaration == nil { + return nil, nil + } + + // Handle both single node and array of nodes + switch decl := declaration.(type) { + case *ast.Node: + return []*lsproto.CallHierarchyItem{l.createCallHierarchyItem(program, decl)}, nil + case []*ast.Node: + items := make([]*lsproto.CallHierarchyItem, len(decl)) + for i, d := range decl { + items[i] = l.createCallHierarchyItem(program, d) + } + return items, nil + } + + return nil, nil +} + +func (l *LanguageService) ProvideCallHierarchyIncomingCalls( + ctx context.Context, + item *lsproto.CallHierarchyItem, +) ([]*lsproto.CallHierarchyIncomingCall, error) { + program := l.GetProgram() + fileName := item.Uri.FileName() + file := program.GetSourceFile(fileName) + if file == nil { + return nil, nil + } + + // Get the node at the selection range + pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) + node := astnav.GetTokenAtPosition(file, pos) + + if node == nil { + return nil, nil + } + + declaration := resolveCallHierarchyDeclaration(program, node) + if declaration == nil { + return nil, nil + } + + // Get the first declaration (or the single one) + var decl *ast.Node + switch d := declaration.(type) { + case *ast.Node: + decl = d + case []*ast.Node: + if len(d) > 0 { + decl = d[0] + } + } + + if decl == nil { + return nil, nil + } + + return l.getIncomingCalls(ctx, program, decl), nil +} + +func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( + ctx context.Context, + item *lsproto.CallHierarchyItem, +) ([]*lsproto.CallHierarchyOutgoingCall, error) { + program := l.GetProgram() + fileName := item.Uri.FileName() + file := program.GetSourceFile(fileName) + if file == nil { + return nil, nil + } + + // Get the node at the selection range + pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) + node := astnav.GetTokenAtPosition(file, pos) + + if node == nil { + return nil, nil + } + + declaration := resolveCallHierarchyDeclaration(program, node) + if declaration == nil { + return nil, nil + } + + // Get the first declaration (or the single one) + var decl *ast.Node + switch d := declaration.(type) { + case *ast.Node: + decl = d + case []*ast.Node: + if len(d) > 0 { + decl = d[0] + } + } + + if decl == nil { + return nil, nil + } + + return l.getOutgoingCalls(program, decl), nil +} diff --git a/internal/ls/findallreferences.go b/internal/ls/findallreferences.go index 4f84c8b4bf..e94f90e29e 100644 --- a/internal/ls/findallreferences.go +++ b/internal/ls/findallreferences.go @@ -2163,7 +2163,7 @@ func (state *refState) forEachRelatedSymbol( } if res := fromRoot(symbol); res != nil { - return res, entryKindNone + return res, entryKindNode } if symbol.ValueDeclaration != nil && ast.IsParameterPropertyDeclaration(symbol.ValueDeclaration, symbol.ValueDeclaration.Parent) { @@ -2176,7 +2176,7 @@ func (state *refState) forEachRelatedSymbol( if !(paramProp1.Flags&ast.SymbolFlagsFunctionScopedVariable != 0 && paramProp2.Flags&ast.SymbolFlagsProperty != 0) { panic("Expected a parameter and a property") } - return fromRoot(core.IfElse(symbol.Flags&ast.SymbolFlagsFunctionScopedVariable != 0, paramProp2, paramProp1)), entryKindNone + return fromRoot(core.IfElse(symbol.Flags&ast.SymbolFlagsFunctionScopedVariable != 0, paramProp2, paramProp1)), entryKindNode } if exportSpecifier := ast.GetDeclarationOfKind(symbol, ast.KindExportSpecifier); exportSpecifier != nil && (!isForRenamePopulateSearchSymbolSet || exportSpecifier.PropertyName() == nil) { diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 55fe97d68d..2884842211 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -517,10 +517,14 @@ var handlers = sync.OnceValue(func() handlerMap { registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentSelectionRangeInfo, (*Server).handleSelectionRange) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentInlayHintInfo, (*Server).handleInlayHint) registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentCodeActionInfo, (*Server).handleCodeAction) + registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentPrepareCallHierarchyInfo, (*Server).handlePrepareCallHierarchy) registerMultiProjectReferenceRequestHandler(handlers, lsproto.TextDocumentReferencesInfo, (*Server).handleReferences, combineReferences) registerMultiProjectReferenceRequestHandler(handlers, lsproto.TextDocumentRenameInfo, (*Server).handleRename, combineRenameResponse) + registerRequestHandler(handlers, lsproto.CallHierarchyIncomingCallsInfo, (*Server).handleCallHierarchyIncomingCalls) + registerRequestHandler(handlers, lsproto.CallHierarchyOutgoingCallsInfo, (*Server).handleCallHierarchyOutgoingCalls) + registerRequestHandler(handlers, lsproto.WorkspaceSymbolInfo, (*Server).handleWorkspaceSymbol) registerRequestHandler(handlers, lsproto.CompletionItemResolveInfo, (*Server).handleCompletionItemResolve) @@ -952,6 +956,9 @@ func (s *Server) handleInitialize(ctx context.Context, params *lsproto.Initializ }, }, }, + CallHierarchyProvider: &lsproto.BooleanOrCallHierarchyOptionsOrCallHierarchyRegistrationOptions{ + Boolean: ptrTo(true), + }, }, } @@ -1285,6 +1292,61 @@ func (s *Server) handleInlayHint( return languageService.ProvideInlayHint(ctx, params) } +func (s *Server) handlePrepareCallHierarchy( + ctx context.Context, + languageService *ls.LanguageService, + params *lsproto.CallHierarchyPrepareParams, +) (lsproto.CallHierarchyPrepareResponse, error) { + items, err := languageService.ProvidePrepareCallHierarchy(ctx, params.TextDocument.Uri, params.Position) + if err != nil { + return lsproto.CallHierarchyItemsOrNull{}, err + } + if items == nil { + return lsproto.CallHierarchyItemsOrNull{}, nil + } + return lsproto.CallHierarchyItemsOrNull{CallHierarchyItems: &items}, nil +} + +func (s *Server) handleCallHierarchyIncomingCalls( + ctx context.Context, + params *lsproto.CallHierarchyIncomingCallsParams, + _ *lsproto.RequestMessage, +) (lsproto.CallHierarchyIncomingCallsResponse, error) { + languageService, err := s.session.GetLanguageService(ctx, params.Item.Uri) + if err != nil { + return lsproto.CallHierarchyIncomingCallsOrNull{}, err + } + + calls, err := languageService.ProvideCallHierarchyIncomingCalls(ctx, params.Item) + if err != nil { + return lsproto.CallHierarchyIncomingCallsOrNull{}, err + } + if calls == nil { + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil + } + return lsproto.CallHierarchyIncomingCallsOrNull{CallHierarchyIncomingCalls: &calls}, nil +} + +func (s *Server) handleCallHierarchyOutgoingCalls( + ctx context.Context, + params *lsproto.CallHierarchyOutgoingCallsParams, + _ *lsproto.RequestMessage, +) (lsproto.CallHierarchyOutgoingCallsResponse, error) { + languageService, err := s.session.GetLanguageService(ctx, params.Item.Uri) + if err != nil { + return lsproto.CallHierarchyOutgoingCallsOrNull{}, err + } + + calls, err := languageService.ProvideCallHierarchyOutgoingCalls(ctx, params.Item) + if err != nil { + return lsproto.CallHierarchyOutgoingCallsOrNull{}, err + } + if calls == nil { + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil + } + return lsproto.CallHierarchyOutgoingCallsOrNull{CallHierarchyOutgoingCalls: &calls}, nil +} + func (s *Server) Log(msg ...any) { fmt.Fprintln(s.stderr, msg...) } diff --git a/internal/testutil/baseline/baseline.go b/internal/testutil/baseline/baseline.go index 1d2afd939b..ff6cf23c4b 100644 --- a/internal/testutil/baseline/baseline.go +++ b/internal/testutil/baseline/baseline.go @@ -126,6 +126,11 @@ func getBaselineDiff(t *testing.T, actual string, expected string, fileName stri } s := DiffText("old."+fileName, "new."+fileName, expected, actual) + // If the diff is empty (just headers, no hunks), return NoContent + if !strings.Contains(s, "@@") { + return NoContent + } + // Remove line numbers from unified diff headers; this avoids adding/deleting // lines in our baselines from causing knock-on header changes later in the diff. diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt new file mode 100644 index 0000000000..68b3d05e3f --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt @@ -0,0 +1,67 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: property +├ containerName: C +├ file: /callHierarchyAccessor.ts +├ span: +│ ╭ /callHierarchyAccessor.ts:6:5-8:6 +│ │ 6: get bar() { +│ │ ^^^^^^^^^^^ +│ │ 7: return baz(); +│ │ ^^^^^^^^^^^^^^^^^^^^^ +│ │ 8: } +│ │ ^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyAccessor.ts:6:9-6:12 +│ │ 6: get bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyAccessor.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyAccessor.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: new C().bar; +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyAccessor.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyAccessor.ts:2:13-2:16 +│ │ │ 2: new C().bar; +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyAccessor.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyAccessor.ts:11:1-12:2 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 12: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyAccessor.ts:11:10-11:13 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyAccessor.ts:7:16-7:19 +│ │ │ 7: return baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff new file mode 100644 index 0000000000..ed3c852f13 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff @@ -0,0 +1,10 @@ +--- old.callHierarchyAccessor.callHierarchy.txt ++++ new.callHierarchyAccessor.callHierarchy.txt +@@= skipped -0, +0 lines =@@ + // === Call Hierarchy === + ╭ name: bar +-├ kind: getter ++├ kind: property + ├ containerName: C + ├ file: /callHierarchyAccessor.ts + ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt new file mode 100644 index 0000000000..e313e6bdc4 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt @@ -0,0 +1,108 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +├ span: +│ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:5:13-7:2 +│ │ 5: const bar = function () { +│ │ ^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:5:7-5:10 +│ │ 5: const bar = function () { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:2:5-2:8 +│ │ │ 2: bar(); +│ │ │ ^^^ +│ ╰ ╰ +│ ╭ from: +│ │ ╭ name: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +│ │ ├ kind: variable +│ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-12:6 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ │ 4: +│ │ │ │ ^ +│ │ │ │ 5: const bar = function () { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 6: baz(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 7: } +│ │ │ │ ^ +│ │ │ │ 8: +│ │ │ │ ^ +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ │ 11: +│ │ │ │ ^ +│ │ │ │ 12: bar() +│ │ │ │ ^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-1:1 +│ │ │ │ 1: function foo() { +│ │ │ │ < +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:12:1-12:4 +│ │ │ 12: bar() +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff new file mode 100644 index 0000000000..b5ba13a5c1 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff @@ -0,0 +1,11 @@ +--- old.callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt ++++ new.callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt +@@= skipped -42, +42 lines =@@ + │ ╰ ╰ + │ ╭ from: + │ │ ╭ name: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts +-│ │ ├ kind: script ++│ │ ├ kind: variable + │ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts + │ │ ├ span: + │ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-12:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClass.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClass.callHierarchy.txt new file mode 100644 index 0000000000..801b8d4041 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClass.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyClass.ts +├ span: +│ ╭ /callHierarchyClass.ts:5:1-7:2 +│ │ 5: function bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 6: new Baz(); +│ │ ^^^^^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyClass.ts:5:10-5:13 +│ │ 5: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyClass.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClass.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClass.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyClass.ts:2:5-2:8 +│ │ │ 2: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: Baz +│ │ ├ kind: class +│ │ ├ file: /callHierarchyClass.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClass.ts:9:1-10:2 +│ │ │ │ 9: class Baz { +│ │ │ │ ^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClass.ts:9:7-9:10 +│ │ │ │ 9: class Baz { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyClass.ts:6:9-6:12 +│ │ │ 6: new Baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt new file mode 100644 index 0000000000..4281cad266 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt @@ -0,0 +1,44 @@ +// === Call Hierarchy === +╭ name: callee +├ kind: variable +├ containerName: C +├ file: /callHierarchyClassPropertyArrowFunction.ts +├ span: +│ ╭ /callHierarchyClassPropertyArrowFunction.ts:6:14-7:6 +│ │ 6: callee = () => { +│ │ ^^^^^^^ +│ │ 7: } +│ │ ^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyClassPropertyArrowFunction.ts:6:5-6:11 +│ │ 6: callee = () => { +│ │ ^^^^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: caller +│ │ ├ kind: variable +│ │ ├ containerName: C +│ │ ├ file: /callHierarchyClassPropertyArrowFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClassPropertyArrowFunction.ts:2:14-4:6 +│ │ │ │ 2: caller = () => { +│ │ │ │ ^^^^^^^ +│ │ │ │ 3: this.callee(); +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 4: } +│ │ │ │ ^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClassPropertyArrowFunction.ts:2:5-2:11 +│ │ │ │ 2: caller = () => { +│ │ │ │ ^^^^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyClassPropertyArrowFunction.ts:3:14-3:20 +│ │ │ 3: this.callee(); +│ │ │ ^^^^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff new file mode 100644 index 0000000000..7bf18a40a7 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff @@ -0,0 +1,19 @@ +--- old.callHierarchyClassPropertyArrowFunction.callHierarchy.txt ++++ new.callHierarchyClassPropertyArrowFunction.callHierarchy.txt +@@= skipped -0, +0 lines =@@ + // === Call Hierarchy === + ╭ name: callee +-├ kind: function ++├ kind: variable + ├ containerName: C + ├ file: /callHierarchyClassPropertyArrowFunction.ts + ├ span: +@@= skipped -17, +17 lines =@@ + ├ incoming: + │ ╭ from: + │ │ ╭ name: caller +-│ │ ├ kind: function ++│ │ ├ kind: variable + │ │ ├ containerName: C + │ │ ├ file: /callHierarchyClassPropertyArrowFunction.ts + │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt new file mode 100644 index 0000000000..d6d69497a5 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt @@ -0,0 +1,140 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyClassStaticBlock.ts +├ span: +│ ╭ /callHierarchyClassStaticBlock.ts:7:9-11:10 +│ │ 7: function bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 8: baz(); +│ │ ^^^^^^^^^^^^^^^^^^ +│ │ 9: quxx(); +│ │ ^^^^^^^^^^^^^^^^^^^ +│ │ 10: baz(); +│ │ ^^^^^^^^^^^^^^^^^^ +│ │ 11: } +│ │ ^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyClassStaticBlock.ts:7:18-7:21 +│ │ 7: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyClassStaticBlock.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:3:9-5:10 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 4: bar(); +│ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ 5: } +│ │ │ │ ^^^^^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:3:18-3:21 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ├ incoming: +│ │ │ ╭ from: +│ │ │ │ ╭ name: static {} +│ │ │ │ ├ kind: variable +│ │ │ │ ├ file: /callHierarchyClassStaticBlock.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:2:5-14:6 +│ │ │ │ │ │ 2: static { +│ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ 3: function foo() { +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 4: bar(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 5: } +│ │ │ │ │ │ ^^^^^^^^^ +│ │ │ │ │ │ 6: +│ │ │ │ │ │ ^ +│ │ │ │ │ │ 7: function bar() { +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 8: baz(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 9: quxx(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 10: baz(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 11: } +│ │ │ │ │ │ ^^^^^^^^^ +│ │ │ │ │ │ 12: +│ │ │ │ │ │ ^ +│ │ │ │ │ │ 13: foo(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^ +│ │ │ │ │ │ 14: } +│ │ │ │ │ │ ^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:2:5-2:11 +│ │ │ │ │ │ 2: static { +│ │ │ │ │ │ ^^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ╰ incoming: none +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:13:9-13:12 +│ │ │ │ │ 13: foo(); +│ │ │ │ │ ^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /callHierarchyClassStaticBlock.ts:4:13-4:16 +│ │ │ 4: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyClassStaticBlock.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:17:1-18:2 +│ │ │ │ 17: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 18: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:17:10-17:13 +│ │ │ │ 17: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyClassStaticBlock.ts:8:13-8:16 +│ │ │ 8: baz(); +│ │ │ ^^^ +│ │ ╰ +│ │ ╭ /callHierarchyClassStaticBlock.ts:10:13-10:16 +│ │ │ 10: baz(); +│ │ │ ^^^ +│ ╰ ╰ +│ ╭ to: +│ │ ╭ name: quxx +│ │ ├ kind: function +│ │ ├ file: /callHierarchyClassStaticBlock.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:20:1-21:2 +│ │ │ │ 20: function quxx() { +│ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ 21: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClassStaticBlock.ts:20:10-20:14 +│ │ │ │ 20: function quxx() { +│ │ │ │ ^^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyClassStaticBlock.ts:9:13-9:17 +│ │ │ 9: quxx(); +│ │ │ ^^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff new file mode 100644 index 0000000000..fc1bdd692e --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff @@ -0,0 +1,11 @@ +--- old.callHierarchyClassStaticBlock.callHierarchy.txt ++++ new.callHierarchyClassStaticBlock.callHierarchy.txt +@@= skipped -41, +41 lines =@@ + │ │ ├ incoming: + │ │ │ ╭ from: + │ │ │ │ ╭ name: static {} +-│ │ │ │ ├ kind: constructor ++│ │ │ │ ├ kind: variable + │ │ │ │ ├ file: /callHierarchyClassStaticBlock.ts + │ │ │ │ ├ span: + │ │ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:2:5-14:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt new file mode 100644 index 0000000000..f0a55f3e09 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt @@ -0,0 +1,140 @@ +// === Call Hierarchy === +╭ name: static {} +├ kind: variable +├ file: /callHierarchyClassStaticBlock2.ts +├ span: +│ ╭ /callHierarchyClassStaticBlock2.ts:2:5-14:6 +│ │ 2: static { +│ │ ^^^^^^^^ +│ │ 3: function foo() { +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ 4: bar(); +│ │ ^^^^^^^^^^^^^^^^^^ +│ │ 5: } +│ │ ^^^^^^^^^ +│ │ 6: +│ │ ^ +│ │ 7: function bar() { +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ 8: baz(); +│ │ ^^^^^^^^^^^^^^^^^^ +│ │ 9: quxx(); +│ │ ^^^^^^^^^^^^^^^^^^^ +│ │ 10: baz(); +│ │ ^^^^^^^^^^^^^^^^^^ +│ │ 11: } +│ │ ^^^^^^^^^ +│ │ 12: +│ │ ^ +│ │ 13: foo(); +│ │ ^^^^^^^^^^^^^^ +│ │ 14: } +│ │ ^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyClassStaticBlock2.ts:2:5-2:11 +│ │ 2: static { +│ │ ^^^^^^ +│ ╰ +├ incoming: none +├ outgoing: +│ ╭ to: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyClassStaticBlock2.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyClassStaticBlock2.ts:3:9-5:10 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 4: bar(); +│ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ 5: } +│ │ │ │ ^^^^^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyClassStaticBlock2.ts:3:18-3:21 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ├ outgoing: +│ │ │ ╭ to: +│ │ │ │ ╭ name: bar +│ │ │ │ ├ kind: function +│ │ │ │ ├ file: /callHierarchyClassStaticBlock2.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:7:9-11:10 +│ │ │ │ │ │ 7: function bar() { +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 8: baz(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 9: quxx(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 10: baz(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 11: } +│ │ │ │ │ │ ^^^^^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:7:18-7:21 +│ │ │ │ │ │ 7: function bar() { +│ │ │ │ │ │ ^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ outgoing: +│ │ │ │ │ ╭ to: +│ │ │ │ │ │ ╭ name: baz +│ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ ├ file: /callHierarchyClassStaticBlock2.ts +│ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:17:1-18:2 +│ │ │ │ │ │ │ │ 17: function baz() { +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 18: } +│ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:17:10-17:13 +│ │ │ │ │ │ │ │ 17: function baz() { +│ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ╰ outgoing: none +│ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:8:13-8:16 +│ │ │ │ │ │ │ 8: baz(); +│ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ ╰ +│ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:10:13-10:16 +│ │ │ │ │ │ │ 10: baz(); +│ │ │ │ │ │ │ ^^^ +│ │ │ │ │ ╰ ╰ +│ │ │ │ │ ╭ to: +│ │ │ │ │ │ ╭ name: quxx +│ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ ├ file: /callHierarchyClassStaticBlock2.ts +│ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:20:1-21:2 +│ │ │ │ │ │ │ │ 20: function quxx() { +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 21: } +│ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:20:10-20:14 +│ │ │ │ │ │ │ │ 20: function quxx() { +│ │ │ │ │ │ │ │ ^^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ╰ outgoing: none +│ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:9:13-9:17 +│ │ │ │ │ │ │ 9: quxx(); +│ │ │ │ │ │ │ ^^^^ +│ │ │ │ ╰ ╰ ╰ +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /callHierarchyClassStaticBlock2.ts:4:13-4:16 +│ │ │ │ │ 4: bar(); +│ │ │ │ │ ^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /callHierarchyClassStaticBlock2.ts:13:9-13:12 +│ │ │ 13: foo(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff new file mode 100644 index 0000000000..9d456600d3 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff @@ -0,0 +1,10 @@ +--- old.callHierarchyClassStaticBlock2.callHierarchy.txt ++++ new.callHierarchyClassStaticBlock2.callHierarchy.txt +@@= skipped -0, +0 lines =@@ + // === Call Hierarchy === + ╭ name: static {} +-├ kind: constructor ++├ kind: variable + ├ file: /callHierarchyClassStaticBlock2.ts + ├ span: + │ ╭ /callHierarchyClassStaticBlock2.ts:2:5-14:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt new file mode 100644 index 0000000000..6e547d7ff3 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: variable +├ file: /callHierarchyConstNamedArrowFunction.ts +├ span: +│ ╭ /callHierarchyConstNamedArrowFunction.ts:5:13-7:2 +│ │ 5: const bar = () => { +│ │ ^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyConstNamedArrowFunction.ts:5:7-5:10 +│ │ 5: const bar = () => { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedArrowFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedArrowFunction.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedArrowFunction.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedArrowFunction.ts:2:5-2:8 +│ │ │ 2: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedArrowFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedArrowFunction.ts:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedArrowFunction.ts:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedArrowFunction.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff new file mode 100644 index 0000000000..925d9d5743 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff @@ -0,0 +1,10 @@ +--- old.callHierarchyConstNamedArrowFunction.callHierarchy.txt ++++ new.callHierarchyConstNamedArrowFunction.callHierarchy.txt +@@= skipped -0, +0 lines =@@ + // === Call Hierarchy === + ╭ name: bar +-├ kind: function ++├ kind: variable + ├ file: /callHierarchyConstNamedArrowFunction.ts + ├ span: + │ ╭ /callHierarchyConstNamedArrowFunction.ts:5:13-7:2 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedClassExpression.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedClassExpression.callHierarchy.txt new file mode 100644 index 0000000000..61abee5bec --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedClassExpression.callHierarchy.txt @@ -0,0 +1,70 @@ +// === Call Hierarchy === +╭ name: Bar +├ kind: class +├ file: /callHierarchyConstNamedClassExpression.ts +├ span: +│ ╭ /callHierarchyConstNamedClassExpression.ts:5:13-9:2 +│ │ 5: const Bar = class { +│ │ ^^^^^^^ +│ │ 6: constructor() { +│ │ ^^^^^^^^^^^^^^^^^^^ +│ │ 7: baz(); +│ │ ^^^^^^^^^^^^^^ +│ │ 8: } +│ │ ^^^^^ +│ │ 9: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyConstNamedClassExpression.ts:5:7-5:10 +│ │ 5: const Bar = class { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedClassExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedClassExpression.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: new Bar(); +│ │ │ │ ^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedClassExpression.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedClassExpression.ts:2:9-2:12 +│ │ │ 2: new Bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedClassExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedClassExpression.ts:11:1-12:2 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 12: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedClassExpression.ts:11:10-11:13 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedClassExpression.ts:7:9-7:12 +│ │ │ 7: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedFunctionExpression.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedFunctionExpression.callHierarchy.txt new file mode 100644 index 0000000000..d1bb8a767c --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedFunctionExpression.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyConstNamedFunctionExpression.ts +├ span: +│ ╭ /callHierarchyConstNamedFunctionExpression.ts:5:13-7:2 +│ │ 5: const bar = function () { +│ │ ^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyConstNamedFunctionExpression.ts:5:7-5:10 +│ │ 5: const bar = function () { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedFunctionExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:2:5-2:8 +│ │ │ 2: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyConstNamedFunctionExpression.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyConstNamedFunctionExpression.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt new file mode 100644 index 0000000000..3ee60e0a19 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt @@ -0,0 +1,144 @@ +// === Call Hierarchy === +╭ name: f +├ kind: function +├ file: /callHierarchyContainerName.ts +├ span: +│ ╭ /callHierarchyContainerName.ts:1:1-1:16 +│ │ 1: function f() {} +│ │ ^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyContainerName.ts:1:10-1:11 +│ │ 1: function f() {} +│ │ ^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: sameName +│ │ ├ kind: method +│ │ ├ containerName: A +│ │ ├ file: /callHierarchyContainerName.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyContainerName.ts:4:3-6:4 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 5: f(); +│ │ │ │ ^^^^^^^^ +│ │ │ │ 6: } +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyContainerName.ts:4:10-4:18 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^ +│ │ │ ╰ +│ │ ├ incoming: +│ │ │ ╭ from: +│ │ │ │ ╭ name: sameName +│ │ │ │ ├ kind: method +│ │ │ │ ├ containerName: B +│ │ │ │ ├ file: /callHierarchyContainerName.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /callHierarchyContainerName.ts:10:3-12:4 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^^^^^ +│ │ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 12: } +│ │ │ │ │ │ ^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /callHierarchyContainerName.ts:10:3-10:11 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ incoming: +│ │ │ │ │ ╭ from: +│ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ ├ kind: property +│ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts +│ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:3-18:4 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 18: } +│ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:7-16:15 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:22:3-24:4 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 24: } +│ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:22:12-22:20 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ ╭ name: C +│ │ │ │ │ │ │ │ │ │ ├ kind: class +│ │ │ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:26:3-30:4 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 27: constructor() { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 29: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 30: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:26:16-26:17 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:28:7-28:15 +│ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:23:16-23:24 +│ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:17:20-17:28 +│ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ ╰ ╰ ╰ +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /callHierarchyContainerName.ts:11:7-11:15 +│ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ ^^^^^^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /callHierarchyContainerName.ts:5:5-5:6 +│ │ │ 5: f(); +│ │ │ ^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff new file mode 100644 index 0000000000..f35a2312f1 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff @@ -0,0 +1,42 @@ +--- old.callHierarchyContainerName.callHierarchy.txt ++++ new.callHierarchyContainerName.callHierarchy.txt +@@= skipped -54, +54 lines =@@ + │ │ │ │ ├ incoming: + │ │ │ │ │ ╭ from: + │ │ │ │ │ │ ╭ name: sameName +-│ │ │ │ │ │ ├ kind: getter +-│ │ │ │ │ │ ├ containerName: Obj ++│ │ │ │ │ │ ├ kind: property + │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts + │ │ │ │ │ │ ├ span: + │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:3-18:4 +@@= skipped -61, +60 lines =@@ + │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { + │ │ │ │ │ │ │ │ │ │ │ │ ^ + │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ ├ incoming: +-│ │ │ │ │ │ │ │ │ │ │ ╭ from: +-│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +-│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function +-│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar +-│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts +-│ │ │ │ │ │ │ │ │ │ │ │ ├ span: +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:20-34:37 +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:9-34:17 +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none +-│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: +-│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:34-34:35 +-│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ ^ +-│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ ++│ │ │ │ │ │ │ │ │ │ ╰ incoming: none + │ │ │ │ │ │ │ │ │ ├ fromSpans: + │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:28:7-28:15 + │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt new file mode 100644 index 0000000000..94e5766b7e --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt @@ -0,0 +1,144 @@ +// === Call Hierarchy === +╭ name: f +├ kind: function +├ file: /callHierarchyContainerNameServer.ts +├ span: +│ ╭ /callHierarchyContainerNameServer.ts:1:1-1:16 +│ │ 1: function f() {} +│ │ ^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyContainerNameServer.ts:1:10-1:11 +│ │ 1: function f() {} +│ │ ^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: sameName +│ │ ├ kind: method +│ │ ├ containerName: A +│ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyContainerNameServer.ts:4:3-6:4 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 5: f(); +│ │ │ │ ^^^^^^^^ +│ │ │ │ 6: } +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyContainerNameServer.ts:4:10-4:18 +│ │ │ │ 4: static sameName() { +│ │ │ │ ^^^^^^^^ +│ │ │ ╰ +│ │ ├ incoming: +│ │ │ ╭ from: +│ │ │ │ ╭ name: sameName +│ │ │ │ ├ kind: method +│ │ │ │ ├ containerName: B +│ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:10:3-12:4 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^^^^^ +│ │ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 12: } +│ │ │ │ │ │ ^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:10:3-10:11 +│ │ │ │ │ │ 10: sameName() { +│ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ ╰ +│ │ │ │ ├ incoming: +│ │ │ │ │ ╭ from: +│ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ ├ kind: property +│ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:3-18:4 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ 18: } +│ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:7-16:15 +│ │ │ │ │ │ │ │ 16: get sameName() { +│ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ ├ kind: function +│ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:22:3-24:4 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ 24: } +│ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:22:12-22:20 +│ │ │ │ │ │ │ │ │ │ 22: function sameName() { +│ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ ╭ name: C +│ │ │ │ │ │ │ │ │ │ ├ kind: class +│ │ │ │ │ │ │ │ │ │ ├ containerName: Foo +│ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:26:3-30:4 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 27: constructor() { +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 29: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ 30: } +│ │ │ │ │ │ │ │ │ │ │ │ ^^^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:26:16-26:17 +│ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { +│ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:28:7-28:15 +│ │ │ │ │ │ │ │ │ │ │ 28: sameName(); +│ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:23:16-23:24 +│ │ │ │ │ │ │ │ │ 23: return Obj.sameName; +│ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ ╰ ╰ ╰ +│ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:17:20-17:28 +│ │ │ │ │ │ │ 17: return new B().sameName; +│ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ ╰ ╰ ╰ +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /callHierarchyContainerNameServer.ts:11:7-11:15 +│ │ │ │ │ 11: A.sameName(); +│ │ │ │ │ ^^^^^^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /callHierarchyContainerNameServer.ts:5:5-5:6 +│ │ │ 5: f(); +│ │ │ ^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff new file mode 100644 index 0000000000..b9cdd9ab71 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff @@ -0,0 +1,42 @@ +--- old.callHierarchyContainerNameServer.callHierarchy.txt ++++ new.callHierarchyContainerNameServer.callHierarchy.txt +@@= skipped -54, +54 lines =@@ + │ │ │ │ ├ incoming: + │ │ │ │ │ ╭ from: + │ │ │ │ │ │ ╭ name: sameName +-│ │ │ │ │ │ ├ kind: getter +-│ │ │ │ │ │ ├ containerName: Obj ++│ │ │ │ │ │ ├ kind: property + │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts + │ │ │ │ │ │ ├ span: + │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:3-18:4 +@@= skipped -61, +60 lines =@@ + │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { + │ │ │ │ │ │ │ │ │ │ │ │ ^ + │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ ├ incoming: +-│ │ │ │ │ │ │ │ │ │ │ ╭ from: +-│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +-│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function +-│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar +-│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +-│ │ │ │ │ │ │ │ │ │ │ │ ├ span: +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:20-34:37 +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:9-34:17 +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +-│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +-│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none +-│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: +-│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:34-34:35 +-│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +-│ │ │ │ │ │ │ │ │ │ │ │ │ ^ +-│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ ++│ │ │ │ │ │ │ │ │ │ ╰ incoming: none + │ │ │ │ │ │ │ │ │ ├ fromSpans: + │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:28:7-28:15 + │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCrossFile.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCrossFile.callHierarchy.txt new file mode 100644 index 0000000000..e11d62c05a --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCrossFile.callHierarchy.txt @@ -0,0 +1,64 @@ +// === Call Hierarchy === +╭ name: createModelReference +├ kind: function +├ file: /a.ts +├ span: +│ ╭ /a.ts:1:1-1:42 +│ │ 1: export function createModelReference() {} +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /a.ts:1:17-1:37 +│ │ 1: export function createModelReference() {} +│ │ ^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: openElementsAtEditor +│ │ ├ kind: function +│ │ ├ file: /b.ts +│ │ ├ span: +│ │ │ ╭ /b.ts:2:1-4:2 +│ │ │ │ 2: function openElementsAtEditor() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 3: createModelReference(); +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 4: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /b.ts:2:10-2:30 +│ │ │ │ 2: function openElementsAtEditor() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /b.ts:3:3-3:23 +│ │ │ 3: createModelReference(); +│ │ │ ^^^^^^^^^^^^^^^^^^^^ +│ ╰ ╰ +│ ╭ from: +│ │ ╭ name: registerDefaultLanguageCommand +│ │ ├ kind: function +│ │ ├ file: /c.ts +│ │ ├ span: +│ │ │ ╭ /c.ts:2:1-4:2 +│ │ │ │ 2: function registerDefaultLanguageCommand() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 3: createModelReference(); +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 4: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /c.ts:2:10-2:40 +│ │ │ │ 2: function registerDefaultLanguageCommand() { +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /c.ts:3:3-3:23 +│ │ │ 3: createModelReference(); +│ │ │ ^^^^^^^^^^^^^^^^^^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyDecorator.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyDecorator.callHierarchy.txt new file mode 100644 index 0000000000..879d802f63 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyDecorator.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyDecorator.ts +├ span: +│ ╭ /callHierarchyDecorator.ts:5:1-7:2 +│ │ 5: function bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyDecorator.ts:5:10-5:13 +│ │ 5: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: Foo +│ │ ├ kind: class +│ │ ├ file: /callHierarchyDecorator.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyDecorator.ts:1:1-3:2 +│ │ │ │ 1: @bar +│ │ │ │ ^^^^ +│ │ │ │ 2: class Foo { +│ │ │ │ ^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyDecorator.ts:2:7-2:10 +│ │ │ │ 2: class Foo { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyDecorator.ts:1:2-1:5 +│ │ │ 1: @bar +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyDecorator.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyDecorator.ts:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyDecorator.ts:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyDecorator.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultClass.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultClass.callHierarchy.txt new file mode 100644 index 0000000000..430a44c476 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultClass.callHierarchy.txt @@ -0,0 +1,70 @@ +// === Call Hierarchy === +╭ name: default +├ kind: class +├ file: /other.ts +├ span: +│ ╭ /other.ts:1:1-5:2 +│ │ 1: export default class { +│ │ ^^^^^^^^^^^^^^^^^^^^^^ +│ │ 2: constructor() { +│ │ ^^^^^^^^^^^^^^^^^^^ +│ │ 3: baz(); +│ │ ^^^^^^^^^^^^^^ +│ │ 4: } +│ │ ^^^^^ +│ │ 5: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /other.ts:1:8-1:15 +│ │ 1: export default class { +│ │ ^^^^^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:3:1-5:2 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 4: new Bar(); +│ │ │ │ ^^^^^^^^^^^^^^ +│ │ │ │ 5: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:3:10-3:13 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:4:9-4:12 +│ │ │ 4: new Bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /other.ts +│ │ ├ span: +│ │ │ ╭ /other.ts:7:1-8:2 +│ │ │ │ 7: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 8: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /other.ts:7:10-7:13 +│ │ │ │ 7: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /other.ts:3:9-3:12 +│ │ │ 3: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultFunction.callHierarchy.txt new file mode 100644 index 0000000000..eba573d573 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportDefaultFunction.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: default +├ kind: function +├ file: /other.ts +├ span: +│ ╭ /other.ts:1:1-3:2 +│ │ 1: export default function () { +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ 2: baz(); +│ │ ^^^^^^^^^^ +│ │ 3: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /other.ts:1:8-1:15 +│ │ 1: export default function () { +│ │ ^^^^^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:3:1-5:2 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 4: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 5: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:3:10-3:13 +│ │ │ │ 3: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:4:5-4:8 +│ │ │ 4: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /other.ts +│ │ ├ span: +│ │ │ ╭ /other.ts:5:1-6:2 +│ │ │ │ 5: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 6: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /other.ts:5:10-5:13 +│ │ │ │ 5: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /other.ts:2:5-2:8 +│ │ │ 2: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt new file mode 100644 index 0000000000..03540d447f --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt @@ -0,0 +1,26 @@ +// === Call Hierarchy === +╭ name: /other.ts +├ kind: variable +├ file: /other.ts +├ span: +│ ╭ /other.ts:1:1-6:2 +│ │ 1: export = function () { +│ │ ^^^^^^^^^^^^^^^^^^^^^^ +│ │ 2: baz(); +│ │ ^^^^^^^^^^ +│ │ 3: } +│ │ ^ +│ │ 4: +│ │ ^ +│ │ 5: function baz() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 6: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /other.ts:1:1-1:1 +│ │ 1: export = function () { +│ │ < +│ ╰ +├ incoming: none +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff new file mode 100644 index 0000000000..7f47b15a67 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff @@ -0,0 +1,38 @@ +--- old.callHierarchyExportEqualsFunction.callHierarchy.txt ++++ new.callHierarchyExportEqualsFunction.callHierarchy.txt +@@= skipped -0, +0 lines =@@ + // === Call Hierarchy === + ╭ name: /other.ts +-├ kind: module ++├ kind: variable + ├ file: /other.ts + ├ span: + │ ╭ /other.ts:1:1-6:2 +@@= skipped -22, +22 lines =@@ + │ │ < + │ ╰ + ├ incoming: none +-├ outgoing: +-│ ╭ to: +-│ │ ╭ name: baz +-│ │ ├ kind: function +-│ │ ├ file: /other.ts +-│ │ ├ span: +-│ │ │ ╭ /other.ts:5:1-6:2 +-│ │ │ │ 5: function baz() { +-│ │ │ │ ^^^^^^^^^^^^^^^^ +-│ │ │ │ 6: } +-│ │ │ │ ^ +-│ │ │ ╰ +-│ │ ├ selectionSpan: +-│ │ │ ╭ /other.ts:5:10-5:13 +-│ │ │ │ 5: function baz() { +-│ │ │ │ ^^^ +-│ │ │ ╰ +-│ │ ╰ outgoing: none +-│ ├ fromSpans: +-│ │ ╭ /other.ts:2:5-2:8 +-│ │ │ 2: baz(); +-│ │ │ ^^^ +-╰ ╰ ╰ ++╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt new file mode 100644 index 0000000000..676141306f --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: function +├ file: /callHierarchyFile.ts +├ span: +│ ╭ /callHierarchyFile.ts:2:1-3:2 +│ │ 2: function foo() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 3: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyFile.ts:2:10-2:13 +│ │ 2: function foo() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: /callHierarchyFile.ts +│ │ ├ kind: variable +│ │ ├ file: /callHierarchyFile.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 +│ │ │ │ 1: foo(); +│ │ │ │ ^^^^^^ +│ │ │ │ 2: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyFile.ts:1:1-1:1 +│ │ │ │ 1: foo(); +│ │ │ │ < +│ │ │ ╰ +│ │ ├ incoming: +│ │ │ ╭ from: +│ │ │ │ ╭ name: /callHierarchyFile.ts +│ │ │ │ ├ kind: variable +│ │ │ │ ├ file: /callHierarchyFile.ts +│ │ │ │ ├ span: +│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 +│ │ │ │ │ │ 1: foo(); +│ │ │ │ │ │ ^^^^^^ +│ │ │ │ │ │ 2: function foo() { +│ │ │ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ 3: } +│ │ │ │ │ │ ^ +│ │ │ │ │ ╰ +│ │ │ │ ├ selectionSpan: +│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:1 +│ │ │ │ │ │ 1: foo(); +│ │ │ │ │ │ < +│ │ │ │ │ ╰ +│ │ │ │ ╰ incoming: ... +│ │ │ ├ fromSpans: +│ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:4 +│ │ │ │ │ 1: foo(); +│ │ │ │ │ ^^^ +│ │ ╰ ╰ ╰ +│ ├ fromSpans: +│ │ ╭ /callHierarchyFile.ts:1:1-1:4 +│ │ │ 1: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff new file mode 100644 index 0000000000..8a61de80ec --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff @@ -0,0 +1,44 @@ +--- old.callHierarchyFile.callHierarchy.txt ++++ new.callHierarchyFile.callHierarchy.txt +@@= skipped -16, +16 lines =@@ + ├ incoming: + │ ╭ from: + │ │ ╭ name: /callHierarchyFile.ts +-│ │ ├ kind: script ++│ │ ├ kind: variable + │ │ ├ file: /callHierarchyFile.ts + │ │ ├ span: + │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 +@@= skipped -16, +16 lines =@@ + │ │ │ │ 1: foo(); + │ │ │ │ < + │ │ │ ╰ +-│ │ ╰ incoming: none ++│ │ ├ incoming: ++│ │ │ ╭ from: ++│ │ │ │ ╭ name: /callHierarchyFile.ts ++│ │ │ │ ├ kind: variable ++│ │ │ │ ├ file: /callHierarchyFile.ts ++│ │ │ │ ├ span: ++│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 ++│ │ │ │ │ │ 1: foo(); ++│ │ │ │ │ │ ^^^^^^ ++│ │ │ │ │ │ 2: function foo() { ++│ │ │ │ │ │ ^^^^^^^^^^^^^^^^ ++│ │ │ │ │ │ 3: } ++│ │ │ │ │ │ ^ ++│ │ │ │ │ ╰ ++│ │ │ │ ├ selectionSpan: ++│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:1 ++│ │ │ │ │ │ 1: foo(); ++│ │ │ │ │ │ < ++│ │ │ │ │ ╰ ++│ │ │ │ ╰ incoming: ... ++│ │ │ ├ fromSpans: ++│ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:4 ++│ │ │ │ │ 1: foo(); ++│ │ │ │ │ ^^^ ++│ │ ╰ ╰ ╰ + │ ├ fromSpans: + │ │ ╭ /callHierarchyFile.ts:1:1-1:4 + │ │ │ 1: foo(); \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunction.callHierarchy.txt new file mode 100644 index 0000000000..c43da437ea --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunction.callHierarchy.txt @@ -0,0 +1,96 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyFunction.ts +├ span: +│ ╭ /callHierarchyFunction.ts:5:1-9:2 +│ │ 5: function bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: quxx(); +│ │ ^^^^^^^^^^^ +│ │ 8: baz(); +│ │ ^^^^^^^^^^ +│ │ 9: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyFunction.ts:5:10-5:13 +│ │ 5: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyFunction.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyFunction.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyFunction.ts:2:5-2:8 +│ │ │ 2: bar(); +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyFunction.ts:11:1-12:2 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 12: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyFunction.ts:11:10-11:13 +│ │ │ │ 11: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyFunction.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +│ │ ╰ +│ │ ╭ /callHierarchyFunction.ts:8:5-8:8 +│ │ │ 8: baz(); +│ │ │ ^^^ +│ ╰ ╰ +│ ╭ to: +│ │ ╭ name: quxx +│ │ ├ kind: function +│ │ ├ file: /callHierarchyFunction.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyFunction.ts:14:1-15:2 +│ │ │ │ 14: function quxx() { +│ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ 15: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyFunction.ts:14:10-14:14 +│ │ │ │ 14: function quxx() { +│ │ │ │ ^^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyFunction.ts:7:5-7:9 +│ │ │ 7: quxx(); +│ │ │ ^^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt new file mode 100644 index 0000000000..bacb2b695f --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt @@ -0,0 +1,40 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: function +├ file: /a.d.ts +├ span: +│ ╭ /main.ts:1:1-1:40 +│ │ 1: function bar() { +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /main.ts:1:18-1:21 +│ │ 1: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff new file mode 100644 index 0000000000..09246fddd3 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff @@ -0,0 +1,62 @@ +--- old.callHierarchyFunctionAmbiguity.1.callHierarchy.txt ++++ new.callHierarchyFunctionAmbiguity.1.callHierarchy.txt +@@= skipped -2, +2 lines =@@ + ├ kind: function + ├ file: /a.d.ts + ├ span: +-│ ╭ /a.d.ts:1:1-1:40 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-│ ╰ +-├ selectionSpan: +-│ ╭ /a.d.ts:1:18-1:21 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^ +-│ ╰ +-├ incoming: +-│ ╭ from: +-│ │ ╭ name: bar +-│ │ ├ kind: function +-│ │ ├ file: /main.ts +-│ │ ├ span: +-│ │ │ ╭ /main.ts:1:1-3:2 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^^^^^^^^^^^^^^ +-│ │ │ │ 2: foo(); +-│ │ │ │ ^^^^^^^^^^ +-│ │ │ │ 3: } +-│ │ │ │ ^ +-│ │ │ ╰ +-│ │ ├ selectionSpan: +-│ │ │ ╭ /main.ts:1:10-1:13 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^ +-│ │ │ ╰ +-│ │ ╰ incoming: none +-│ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ +-│ ╰ ╰ +-╰ outgoing: none +-╭ name: foo +-├ kind: function +-├ file: /b.d.ts +-├ span: +-│ ╭ /b.d.ts:1:1-1:40 +-│ │ 1: declare function foo(x?: string): void; +-│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-│ ╰ +-├ selectionSpan: +-│ ╭ /b.d.ts:1:18-1:21 +-│ │ 1: declare function foo(x?: string): void; ++│ ╭ /main.ts:1:1-1:40 ++│ │ 1: function bar() { ++│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++│ ╰ ++├ selectionSpan: ++│ ╭ /main.ts:1:18-1:21 ++│ │ 1: function bar() { + │ │ ^^^ + │ ╰ + ├ incoming: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt new file mode 100644 index 0000000000..87ebaaad52 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt @@ -0,0 +1,40 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: function +├ file: /a.d.ts +├ span: +│ ╭ /a.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /a.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff new file mode 100644 index 0000000000..f5b1ee161c --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff @@ -0,0 +1,45 @@ +--- old.callHierarchyFunctionAmbiguity.2.callHierarchy.txt ++++ new.callHierarchyFunctionAmbiguity.2.callHierarchy.txt +@@= skipped -37, +37 lines =@@ + │ │ │ ^^^ + │ ╰ ╰ + ╰ outgoing: none +-╭ name: foo +-├ kind: function +-├ file: /b.d.ts +-├ span: +-│ ╭ /b.d.ts:1:1-1:40 +-│ │ 1: declare function foo(x?: string): void; +-│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-│ ╰ +-├ selectionSpan: +-│ ╭ /b.d.ts:1:18-1:21 +-│ │ 1: declare function foo(x?: string): void; +-│ │ ^^^ +-│ ╰ +-├ incoming: +-│ ╭ from: +-│ │ ╭ name: bar +-│ │ ├ kind: function +-│ │ ├ file: /main.ts +-│ │ ├ span: +-│ │ │ ╭ /main.ts:1:1-3:2 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^^^^^^^^^^^^^^ +-│ │ │ │ 2: foo(); +-│ │ │ │ ^^^^^^^^^^ +-│ │ │ │ 3: } +-│ │ │ │ ^ +-│ │ │ ╰ +-│ │ ├ selectionSpan: +-│ │ │ ╭ /main.ts:1:10-1:13 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^ +-│ │ │ ╰ +-│ │ ╰ incoming: none +-│ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ +-│ ╰ ╰ +-╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt new file mode 100644 index 0000000000..791c5a45d2 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt @@ -0,0 +1,40 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: function +├ file: /a.d.ts +├ span: +│ ╭ /b.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /b.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff new file mode 100644 index 0000000000..bac9cf6d32 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff @@ -0,0 +1,48 @@ +--- old.callHierarchyFunctionAmbiguity.3.callHierarchy.txt ++++ new.callHierarchyFunctionAmbiguity.3.callHierarchy.txt +@@= skipped -2, +2 lines =@@ + ├ kind: function + ├ file: /a.d.ts + ├ span: +-│ ╭ /a.d.ts:1:1-1:40 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-│ ╰ +-├ selectionSpan: +-│ ╭ /a.d.ts:1:18-1:21 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^ +-│ ╰ +-├ incoming: +-│ ╭ from: +-│ │ ╭ name: bar +-│ │ ├ kind: function +-│ │ ├ file: /main.ts +-│ │ ├ span: +-│ │ │ ╭ /main.ts:1:1-3:2 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^^^^^^^^^^^^^^ +-│ │ │ │ 2: foo(); +-│ │ │ │ ^^^^^^^^^^ +-│ │ │ │ 3: } +-│ │ │ │ ^ +-│ │ │ ╰ +-│ │ ├ selectionSpan: +-│ │ │ ╭ /main.ts:1:10-1:13 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^ +-│ │ │ ╰ +-│ │ ╰ incoming: none +-│ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ +-│ ╰ ╰ +-╰ outgoing: none +-╭ name: foo +-├ kind: function +-├ file: /b.d.ts +-├ span: + │ ╭ /b.d.ts:1:1-1:40 + │ │ 1: declare function foo(x?: string): void; + │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt new file mode 100644 index 0000000000..791c5a45d2 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt @@ -0,0 +1,40 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: function +├ file: /a.d.ts +├ span: +│ ╭ /b.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /b.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff new file mode 100644 index 0000000000..0ad01b7ca7 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff @@ -0,0 +1,48 @@ +--- old.callHierarchyFunctionAmbiguity.4.callHierarchy.txt ++++ new.callHierarchyFunctionAmbiguity.4.callHierarchy.txt +@@= skipped -2, +2 lines =@@ + ├ kind: function + ├ file: /a.d.ts + ├ span: +-│ ╭ /a.d.ts:1:1-1:40 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-│ ╰ +-├ selectionSpan: +-│ ╭ /a.d.ts:1:18-1:21 +-│ │ 1: declare function foo(x?: number): void; +-│ │ ^^^ +-│ ╰ +-├ incoming: +-│ ╭ from: +-│ │ ╭ name: bar +-│ │ ├ kind: function +-│ │ ├ file: /main.ts +-│ │ ├ span: +-│ │ │ ╭ /main.ts:1:1-3:2 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^^^^^^^^^^^^^^ +-│ │ │ │ 2: foo(); +-│ │ │ │ ^^^^^^^^^^ +-│ │ │ │ 3: } +-│ │ │ │ ^ +-│ │ │ ╰ +-│ │ ├ selectionSpan: +-│ │ │ ╭ /main.ts:1:10-1:13 +-│ │ │ │ 1: function bar() { +-│ │ │ │ ^^^ +-│ │ │ ╰ +-│ │ ╰ incoming: none +-│ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ +-│ ╰ ╰ +-╰ outgoing: none +-╭ name: foo +-├ kind: function +-├ file: /b.d.ts +-├ span: + │ ╭ /b.d.ts:1:1-1:40 + │ │ 1: declare function foo(x?: string): void; + │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt new file mode 100644 index 0000000000..093197302f --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt @@ -0,0 +1,60 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /main.ts +├ span: +│ ╭ /main.ts:1:1-3:2 +│ │ 1: function bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 2: foo(); +│ │ ^^^^^^^^^^ +│ │ 3: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /main.ts:1:10-1:13 +│ │ 1: function bar() { +│ │ ^^^ +│ ╰ +├ incoming: none +├ outgoing: +│ ╭ to: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /a.d.ts +│ │ ├ span: +│ │ │ ╭ /a.d.ts:1:1-1:40 +│ │ │ │ 1: declare function foo(x?: number): void; +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /a.d.ts:1:18-1:21 +│ │ │ │ 1: declare function foo(x?: number): void; +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /main.ts:1:22-1:25 +│ │ │ 1: function bar() { +│ │ │ ^^^ +│ ╰ ╰ +│ ╭ to: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /b.d.ts +│ │ ├ span: +│ │ │ ╭ /b.d.ts:1:1-1:40 +│ │ │ │ 1: declare function foo(x?: string): void; +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /b.d.ts:1:18-1:21 +│ │ │ │ 1: declare function foo(x?: string): void; +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /main.ts:1:22-1:25 +│ │ │ 1: function bar() { +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff new file mode 100644 index 0000000000..553ee83996 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff @@ -0,0 +1,26 @@ +--- old.callHierarchyFunctionAmbiguity.5.callHierarchy.txt ++++ new.callHierarchyFunctionAmbiguity.5.callHierarchy.txt +@@= skipped -33, +33 lines =@@ + │ │ │ ╰ + │ │ ╰ outgoing: none + │ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ ++│ │ ╭ /main.ts:1:22-1:25 ++│ │ │ 1: function bar() { ++│ │ │ ^^^ + │ ╰ ╰ + │ ╭ to: + │ │ ╭ name: foo +@@= skipped -20, +20 lines =@@ + │ │ │ ╰ + │ │ ╰ outgoing: none + │ ├ fromSpans: +-│ │ ╭ /main.ts:2:5-2:8 +-│ │ │ 2: foo(); +-│ │ │ ^^^ ++│ │ ╭ /main.ts:1:22-1:25 ++│ │ │ 1: function bar() { ++│ │ │ ^^^ + ╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt new file mode 100644 index 0000000000..121271cf6d --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt @@ -0,0 +1,48 @@ +// === Call Hierarchy === +╭ name: foo +├ kind: method +├ file: /callHierarchyInterfaceMethod.ts +├ span: +│ ╭ /callHierarchyInterfaceMethod.ts:2:5-2:17 +│ │ 2: foo(): void; +│ │ ^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyInterfaceMethod.ts:2:5-2:8 +│ │ 2: foo(): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: /callHierarchyInterfaceMethod.ts +│ │ ├ kind: variable +│ │ ├ file: /callHierarchyInterfaceMethod.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-7:11 +│ │ │ │ 1: interface I { +│ │ │ │ ^^^^^^^^^^^^^ +│ │ │ │ 2: foo(): void; +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ │ 4: +│ │ │ │ ^ +│ │ │ │ 5: const obj: I = { foo() {} }; +│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ │ │ 6: +│ │ │ │ ^ +│ │ │ │ 7: obj.foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-1:1 +│ │ │ │ 1: interface I { +│ │ │ │ < +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyInterfaceMethod.ts:7:5-7:8 +│ │ │ 7: obj.foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff new file mode 100644 index 0000000000..d0c9e4aa07 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff @@ -0,0 +1,11 @@ +--- old.callHierarchyInterfaceMethod.callHierarchy.txt ++++ new.callHierarchyInterfaceMethod.callHierarchy.txt +@@= skipped -14, +14 lines =@@ + ├ incoming: + │ ╭ from: + │ │ ╭ name: /callHierarchyInterfaceMethod.ts +-│ │ ├ kind: script ++│ │ ├ kind: variable + │ │ ├ file: /callHierarchyInterfaceMethod.ts + │ │ ├ span: + │ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-7:11 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyJsxElement.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyJsxElement.callHierarchy.txt new file mode 100644 index 0000000000..4609c0ecd6 --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyJsxElement.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: Bar +├ kind: function +├ file: /main.tsx +├ span: +│ ╭ /main.tsx:5:1-7:2 +│ │ 5: function Bar() { +│ │ ^^^^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /main.tsx:5:10-5:13 +│ │ 5: function Bar() { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /main.tsx +│ │ ├ span: +│ │ │ ╭ /main.tsx:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: return ; +│ │ │ │ ^^^^^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.tsx:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.tsx:2:13-2:16 +│ │ │ 2: return ; +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /main.tsx +│ │ ├ span: +│ │ │ ╭ /main.tsx:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.tsx:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /main.tsx:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyTaggedTemplate.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyTaggedTemplate.callHierarchy.txt new file mode 100644 index 0000000000..e7b0093b0c --- /dev/null +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyTaggedTemplate.callHierarchy.txt @@ -0,0 +1,66 @@ +// === Call Hierarchy === +╭ name: bar +├ kind: function +├ file: /callHierarchyTaggedTemplate.ts +├ span: +│ ╭ /callHierarchyTaggedTemplate.ts:5:1-7:2 +│ │ 5: function bar(array: TemplateStringsArray, ...args: any[]) { +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ │ 6: baz(); +│ │ ^^^^^^^^^^ +│ │ 7: } +│ │ ^ +│ ╰ +├ selectionSpan: +│ ╭ /callHierarchyTaggedTemplate.ts:5:10-5:13 +│ │ 5: function bar(array: TemplateStringsArray, ...args: any[]) { +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: foo +│ │ ├ kind: function +│ │ ├ file: /callHierarchyTaggedTemplate.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyTaggedTemplate.ts:1:1-3:2 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: bar`a${1}b`; +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyTaggedTemplate.ts:1:10-1:13 +│ │ │ │ 1: function foo() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyTaggedTemplate.ts:2:5-2:8 +│ │ │ 2: bar`a${1}b`; +│ │ │ ^^^ +│ ╰ ╰ +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /callHierarchyTaggedTemplate.ts +│ │ ├ span: +│ │ │ ╭ /callHierarchyTaggedTemplate.ts:9:1-10:2 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 10: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /callHierarchyTaggedTemplate.ts:9:10-9:13 +│ │ │ │ 9: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /callHierarchyTaggedTemplate.ts:6:5-6:8 +│ │ │ 6: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file From 35fe5b7c6f36614603870536b2d96ff13ec47cdc Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Nov 2025 18:48:10 -0800 Subject: [PATCH 02/20] more --- internal/ls/callhierarchy.go | 14 ++++++-- ...rchyExportEqualsFunction.callHierarchy.txt | 24 ++++++++++++- ...xportEqualsFunction.callHierarchy.txt.diff | 30 +--------------- .../callHierarchyFile.callHierarchy.txt | 26 +------------- .../callHierarchyFile.callHierarchy.txt.diff | 35 +------------------ 5 files changed, 38 insertions(+), 91 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 91d97a27f5..9cd4e92f91 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -1093,7 +1093,12 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( // Get the node at the selection range pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) - node := astnav.GetTokenAtPosition(file, pos) + var node *ast.Node + if pos == 0 { + node = file.AsNode() + } else { + node = astnav.GetTokenAtPosition(file, pos) + } if node == nil { return nil, nil @@ -1135,7 +1140,12 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( // Get the node at the selection range pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) - node := astnav.GetTokenAtPosition(file, pos) + var node *ast.Node + if pos == 0 { + node = file.AsNode() + } else { + node = astnav.GetTokenAtPosition(file, pos) + } if node == nil { return nil, nil diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt index 03540d447f..208d07a873 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt @@ -23,4 +23,26 @@ │ │ < │ ╰ ├ incoming: none -╰ outgoing: none \ No newline at end of file +├ outgoing: +│ ╭ to: +│ │ ╭ name: baz +│ │ ├ kind: function +│ │ ├ file: /other.ts +│ │ ├ span: +│ │ │ ╭ /other.ts:5:1-6:2 +│ │ │ │ 5: function baz() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 6: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /other.ts:5:10-5:13 +│ │ │ │ 5: function baz() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ outgoing: none +│ ├ fromSpans: +│ │ ╭ /other.ts:2:5-2:8 +│ │ │ 2: baz(); +│ │ │ ^^^ +╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff index 7f47b15a67..73e0c26bca 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff @@ -7,32 +7,4 @@ +├ kind: variable ├ file: /other.ts ├ span: - │ ╭ /other.ts:1:1-6:2 -@@= skipped -22, +22 lines =@@ - │ │ < - │ ╰ - ├ incoming: none --├ outgoing: --│ ╭ to: --│ │ ╭ name: baz --│ │ ├ kind: function --│ │ ├ file: /other.ts --│ │ ├ span: --│ │ │ ╭ /other.ts:5:1-6:2 --│ │ │ │ 5: function baz() { --│ │ │ │ ^^^^^^^^^^^^^^^^ --│ │ │ │ 6: } --│ │ │ │ ^ --│ │ │ ╰ --│ │ ├ selectionSpan: --│ │ │ ╭ /other.ts:5:10-5:13 --│ │ │ │ 5: function baz() { --│ │ │ │ ^^^ --│ │ │ ╰ --│ │ ╰ outgoing: none --│ ├ fromSpans: --│ │ ╭ /other.ts:2:5-2:8 --│ │ │ 2: baz(); --│ │ │ ^^^ --╰ ╰ ╰ -+╰ outgoing: none \ No newline at end of file + │ ╭ /other.ts:1:1-6:2 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt index 676141306f..241644d516 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt @@ -33,31 +33,7 @@ │ │ │ │ 1: foo(); │ │ │ │ < │ │ │ ╰ -│ │ ├ incoming: -│ │ │ ╭ from: -│ │ │ │ ╭ name: /callHierarchyFile.ts -│ │ │ │ ├ kind: variable -│ │ │ │ ├ file: /callHierarchyFile.ts -│ │ │ │ ├ span: -│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 -│ │ │ │ │ │ 1: foo(); -│ │ │ │ │ │ ^^^^^^ -│ │ │ │ │ │ 2: function foo() { -│ │ │ │ │ │ ^^^^^^^^^^^^^^^^ -│ │ │ │ │ │ 3: } -│ │ │ │ │ │ ^ -│ │ │ │ │ ╰ -│ │ │ │ ├ selectionSpan: -│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:1 -│ │ │ │ │ │ 1: foo(); -│ │ │ │ │ │ < -│ │ │ │ │ ╰ -│ │ │ │ ╰ incoming: ... -│ │ │ ├ fromSpans: -│ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:4 -│ │ │ │ │ 1: foo(); -│ │ │ │ │ ^^^ -│ │ ╰ ╰ ╰ +│ │ ╰ incoming: none │ ├ fromSpans: │ │ ╭ /callHierarchyFile.ts:1:1-1:4 │ │ │ 1: foo(); diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff index 8a61de80ec..3cf4a3ed11 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff @@ -8,37 +8,4 @@ +│ │ ├ kind: variable │ │ ├ file: /callHierarchyFile.ts │ │ ├ span: - │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 -@@= skipped -16, +16 lines =@@ - │ │ │ │ 1: foo(); - │ │ │ │ < - │ │ │ ╰ --│ │ ╰ incoming: none -+│ │ ├ incoming: -+│ │ │ ╭ from: -+│ │ │ │ ╭ name: /callHierarchyFile.ts -+│ │ │ │ ├ kind: variable -+│ │ │ │ ├ file: /callHierarchyFile.ts -+│ │ │ │ ├ span: -+│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 -+│ │ │ │ │ │ 1: foo(); -+│ │ │ │ │ │ ^^^^^^ -+│ │ │ │ │ │ 2: function foo() { -+│ │ │ │ │ │ ^^^^^^^^^^^^^^^^ -+│ │ │ │ │ │ 3: } -+│ │ │ │ │ │ ^ -+│ │ │ │ │ ╰ -+│ │ │ │ ├ selectionSpan: -+│ │ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:1 -+│ │ │ │ │ │ 1: foo(); -+│ │ │ │ │ │ < -+│ │ │ │ │ ╰ -+│ │ │ │ ╰ incoming: ... -+│ │ │ ├ fromSpans: -+│ │ │ │ ╭ /callHierarchyFile.ts:1:1-1:4 -+│ │ │ │ │ 1: foo(); -+│ │ │ │ │ ^^^ -+│ │ ╰ ╰ ╰ - │ ├ fromSpans: - │ │ ╭ /callHierarchyFile.ts:1:1-1:4 - │ │ │ 1: foo(); \ No newline at end of file + │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 \ No newline at end of file From 3b56d34658c4e5251198c8843ab30f845e7509d8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 06:44:00 -0800 Subject: [PATCH 03/20] Port helpers directly --- internal/ast/utilities.go | 85 +++++++++++++++++++ internal/ls/callhierarchy.go | 63 ++------------ internal/ls/findallreferences.go | 43 +++------- ...dAllReferencesOfConstructor.baseline.jsonc | 6 +- ...llHierarchyContainerName.callHierarchy.txt | 23 ++++- ...rarchyContainerName.callHierarchy.txt.diff | 37 ++------ ...archyContainerNameServer.callHierarchy.txt | 23 ++++- ...ContainerNameServer.callHierarchy.txt.diff | 37 ++------ 8 files changed, 166 insertions(+), 151 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 72ba07ee60..89b6ecfb98 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -3441,6 +3441,91 @@ func IsRightSideOfPropertyAccess(node *Node) bool { return node.Parent.Kind == KindPropertyAccessExpression && node.Parent.Name() == node } +func IsArgumentExpressionOfElementAccess(node *Node) bool { + return node.Parent != nil && node.Parent.Kind == KindElementAccessExpression && node.Parent.AsElementAccessExpression().ArgumentExpression == node +} + +func ClimbPastPropertyAccess(node *Node) *Node { + if IsRightSideOfPropertyAccess(node) { + return node.Parent + } + return node +} + +func climbPastPropertyOrElementAccess(node *Node) *Node { + if IsRightSideOfPropertyAccess(node) || IsArgumentExpressionOfElementAccess(node) { + return node.Parent + } + return node +} + +func selectExpressionOfCallOrNewExpressionOrDecorator(node *Node) *Node { + if IsCallExpression(node) || IsNewExpression(node) || IsDecorator(node) { + return node.Expression() + } + return nil +} + +func selectTagOfTaggedTemplateExpression(node *Node) *Node { + if IsTaggedTemplateExpression(node) { + return node.AsTaggedTemplateExpression().Tag + } + return nil +} + +func selectTagNameOfJsxOpeningLikeElement(node *Node) *Node { + if IsJsxOpeningElement(node) || IsJsxSelfClosingElement(node) { + return node.TagName() + } + return nil +} + +func IsCallExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions) +} + +func IsNewExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions) +} + +func IsCallOrNewExpressionTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions) +} + +func IsTaggedTemplateTag(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions) +} + +func IsDecoratorTarget(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions) +} + +func IsJsxOpeningLikeElementTagName(node *Node, includeElementAccess bool, skipPastOuterExpressions bool) bool { + return isCalleeWorker(node, IsJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions) +} + +func isCalleeWorker( + node *Node, + pred func(*Node) bool, + calleeSelector func(*Node) *Node, + includeElementAccess bool, + skipPastOuterExpressions bool, +) bool { + var target *Node + if includeElementAccess { + target = climbPastPropertyOrElementAccess(node) + } else { + target = ClimbPastPropertyAccess(node) + } + if skipPastOuterExpressions { + // Only skip outer expressions if the target is actually an expression node + if IsExpression(target) { + target = SkipOuterExpressions(target, OEKAll) + } + } + return target != nil && target.Parent != nil && pred(target.Parent) && calleeSelector(target.Parent) == target +} + func IsRightSideOfQualifiedNameOrPropertyAccess(node *Node) bool { parent := node.Parent switch parent.Kind { diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 9cd4e92f91..c751b7fe52 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -532,67 +532,18 @@ type callSite struct { textRange core.TextRange } -func isCallLikeTarget(node *ast.Node) bool { - if node == nil || node.Parent == nil { - return false - } - - parent := node.Parent - - // CallExpression or NewExpression: node.expression === parent - if ast.IsCallExpression(parent) { - callExpr := parent.AsCallExpression() - return callExpr != nil && callExpr.Expression == node - } - if ast.IsNewExpression(parent) { - newExpr := parent.AsNewExpression() - return newExpr != nil && newExpr.Expression == node - } - - // TaggedTemplateExpression: node.tag === parent - if ast.IsTaggedTemplateExpression(parent) { - taggedTemplate := parent.AsTaggedTemplateExpression() - return taggedTemplate != nil && taggedTemplate.Tag == node - } - - // Decorator: node.expression === parent - if ast.IsDecorator(parent) { - decorator := parent.AsDecorator() - return decorator != nil && decorator.Expression == node - } - - // JsxOpeningElement or JsxSelfClosingElement: node.tagName === parent - if ast.IsJsxOpeningElement(parent) { - jsxOpen := parent.AsJsxOpeningElement() - return jsxOpen != nil && jsxOpen.TagName == node - } - if ast.IsJsxSelfClosingElement(parent) { - jsxSelf := parent.AsJsxSelfClosingElement() - return jsxSelf != nil && jsxSelf.TagName == node - } - - // PropertyAccessExpression: is right side - if ast.IsPropertyAccessExpression(parent) { - propAccess := parent.AsPropertyAccessExpression() - return propAccess != nil && propAccess.Name() == node - } - - // ElementAccessExpression: is argument expression - if ast.IsElementAccessExpression(parent) { - elemAccess := parent.AsElementAccessExpression() - return elemAccess != nil && elemAccess.ArgumentExpression == node - } - - return false -} - func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *callSite { if entry.kind != entryKindNode { return nil } node := entry.node - if !isCallLikeTarget(node) { + if !ast.IsCallOrNewExpressionTarget(node, true /*includeElementAccess*/, true /*skipPastOuterExpressions*/) && + !ast.IsTaggedTemplateTag(node, true, true) && + !ast.IsDecoratorTarget(node, true, true) && + !ast.IsJsxOpeningLikeElementTagName(node, true, true) && + !ast.IsRightSideOfPropertyAccess(node) && + !ast.IsArgumentExpressionOfElementAccess(node) { return nil } @@ -648,7 +599,7 @@ func (l *LanguageService) getIncomingCalls(ctx context.Context, program *compile // Find all references using getReferencedSymbolsForNode sourceFiles := program.GetSourceFiles() options := refOptions{use: referenceUseReferences} - symbolsAndEntries := l.getReferencedSymbolsForNode(ctx, location.Pos(), location, program, sourceFiles, options, nil) + symbolsAndEntries := l.getReferencedSymbolsForNode(ctx, 0, location, program, sourceFiles, options, nil) // Flatten to get all reference entries var refEntries []*ReferenceEntry diff --git a/internal/ls/findallreferences.go b/internal/ls/findallreferences.go index e94f90e29e..afe9099743 100644 --- a/internal/ls/findallreferences.go +++ b/internal/ls/findallreferences.go @@ -1421,7 +1421,7 @@ func getReferencedSymbolsForSymbol(originalSymbol *ast.Symbol, node *ast.Node, s // When renaming at an export specifier, rename the export and not the thing being exported. // state.getReferencesAtExportSpecifier(exportSpecifier.Name(), symbol, exportSpecifier.AsExportSpecifier(), state.createSearch(node, originalSymbol, comingFromUnknown /*comingFrom*/, "", nil), true /*addReferencesHere*/, true /*alwaysGetReferences*/) } else if node != nil && node.Kind == ast.KindDefaultKeyword && symbol.Name == ast.InternalSymbolNameDefault && symbol.Parent != nil { - state.addReference(node, symbol, entryKindNone) + state.addReference(node, symbol, entryKindNode) state.searchForImportsOfExport(node, symbol, &ExportInfo{exportingModuleSymbol: symbol.Parent, exportKind: ExportKindDefault}) } else { search := state.createSearch(node, symbol, ImpExpKindUnknown /*comingFrom*/, "", state.populateSearchSymbolSet(symbol, node, options.use == referenceUseRename, options.useAliasesForRename, options.implementations)) @@ -1573,33 +1573,12 @@ func getReferenceEntriesForShorthandPropertyAssignment(node *ast.Node, checker * } } -func climbPastPropertyAccess(node *ast.Node) *ast.Node { - if ast.IsRightSideOfPropertyAccess(node) { - return node.Parent - } - return node -} - -func isNewExpressionTarget(node *ast.Node) bool { - if node.Parent == nil { - return false - } - return node.Parent.Kind == ast.KindNewExpression && node.Parent.Expression() == node -} - -func isCallExpressionTarget(node *ast.Node) bool { - if node.Parent == nil { - return false - } - return node.Parent.Kind == ast.KindCallExpression && node.Parent.Expression() == node -} - func isMethodOrAccessor(node *ast.Node) bool { return node.Kind == ast.KindMethodDeclaration || node.Kind == ast.KindGetAccessor || node.Kind == ast.KindSetAccessor } func tryGetClassByExtendingIdentifier(node *ast.Node) *ast.ClassLikeDeclaration { - return ast.TryGetClassExtendingExpressionWithTypeArguments(climbPastPropertyAccess(node).Parent) + return ast.TryGetClassExtendingExpressionWithTypeArguments(ast.ClimbPastPropertyAccess(node).Parent) } func getClassConstructorSymbol(classSymbol *ast.Symbol) *ast.Symbol { @@ -1632,7 +1611,7 @@ func findOwnConstructorReferences(classSymbol *ast.Symbol, sourceFile *ast.Sourc body := decl.Body() if body != nil { forEachDescendantOfKind(body, ast.KindThisKeyword, func(thisKeyword *ast.Node) { - if isNewExpressionTarget(thisKeyword) { + if ast.IsNewExpressionTarget(thisKeyword, false, false) { addNode(thisKeyword) } }) @@ -1653,7 +1632,7 @@ func findSuperConstructorAccesses(classDeclaration *ast.ClassLikeDeclaration, ad body := decl.Body() if body != nil { forEachDescendantOfKind(body, ast.KindSuperKeyword, func(node *ast.Node) { - if isCallExpressionTarget(node) { + if ast.IsCallExpressionTarget(node, false, false) { addNode(node) } }) @@ -1853,8 +1832,8 @@ func (state *refState) getReferencesAtLocation(sourceFile *ast.SourceFile, posit } func (state *refState) addConstructorReferences(referenceLocation *ast.Node, symbol *ast.Symbol, search *refSearch, addReferencesHere bool) { - if isNewExpressionTarget(referenceLocation) && addReferencesHere { - state.addReference(referenceLocation, symbol, entryKindNone) + if ast.IsNewExpressionTarget(referenceLocation, false, false) && addReferencesHere { + state.addReference(referenceLocation, symbol, entryKindNode) } pusher := func() func(*ast.Node, entryKind) { @@ -1865,13 +1844,13 @@ func (state *refState) addConstructorReferences(referenceLocation *ast.Node, sym // This is the class declaration containing the constructor. sourceFile := ast.GetSourceFileOfNode(referenceLocation) findOwnConstructorReferences(search.symbol, sourceFile, func(n *ast.Node) { - pusher()(n, entryKindNone) + pusher()(n, entryKindNode) }) } else { // If this class appears in `extends C`, then the extending class' "super" calls are references. if classExtending := tryGetClassByExtendingIdentifier(referenceLocation); classExtending != nil { findSuperConstructorAccesses(classExtending, func(n *ast.Node) { - pusher()(n, entryKindNone) + pusher()(n, entryKindNode) }) state.findInheritedConstructorReferences(classExtending) } @@ -1880,7 +1859,7 @@ func (state *refState) addConstructorReferences(referenceLocation *ast.Node, sym func (state *refState) addClassStaticThisReferences(referenceLocation *ast.Node, symbol *ast.Symbol, search *refSearch, addReferencesHere bool) { if addReferencesHere { - state.addReference(referenceLocation, symbol, entryKindNone) + state.addReference(referenceLocation, symbol, entryKindNode) } classLike := referenceLocation.Parent @@ -1902,7 +1881,7 @@ func (state *refState) addClassStaticThisReferences(referenceLocation *ast.Node, var cb func(*ast.Node) cb = func(node *ast.Node) { if node.Kind == ast.KindThisKeyword { - addRef(node, entryKindNone) + addRef(node, entryKindNode) } else if !ast.IsFunctionLike(node) && !ast.IsClassLike(node) { node.ForEachChild(func(child *ast.Node) bool { cb(child) @@ -2017,7 +1996,7 @@ func (state *refState) getReferenceForShorthandProperty(referenceSymbol *ast.Sym // the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the // position of property accessing, the referenceEntry of such position will be handled in the first case. if name != nil && search.includes(shorthandValueSymbol) { - state.addReference(name, shorthandValueSymbol, entryKindNone) + state.addReference(name, shorthandValueSymbol, entryKindNode) } } diff --git a/testdata/baselines/reference/fourslash/findAllReferences/findAllReferencesOfConstructor.baseline.jsonc b/testdata/baselines/reference/fourslash/findAllReferences/findAllReferencesOfConstructor.baseline.jsonc index 90ec6e075a..4e2671027f 100644 --- a/testdata/baselines/reference/fourslash/findAllReferences/findAllReferencesOfConstructor.baseline.jsonc +++ b/testdata/baselines/reference/fourslash/findAllReferences/findAllReferencesOfConstructor.baseline.jsonc @@ -29,7 +29,7 @@ // === /d.ts === // import * as a from "./a"; -// new a.C(); +// new a.[|C|](); // class d extends a.C { constructor() { [|super|](); } @@ -65,7 +65,7 @@ // === /d.ts === // import * as a from "./a"; -// new a.C(); +// new a.[|C|](); // class d extends a.C { constructor() { [|super|](); } @@ -101,5 +101,5 @@ // === /d.ts === // import * as a from "./a"; -// new a.C(); +// new a.[|C|](); // class d extends a.C { constructor() { [|super|](); } \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt index 3ee60e0a19..04dee73387 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt @@ -115,7 +115,28 @@ │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { │ │ │ │ │ │ │ │ │ │ │ │ ^ │ │ │ │ │ │ │ │ │ │ │ ╰ -│ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable +│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar +│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts +│ │ │ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:20-34:37 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:9-34:17 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:34-34:35 +│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ │ │ │ │ │ │ │ │ │ ├ fromSpans: │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:28:7-28:15 │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff index f35a2312f1..8b907bed2e 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff @@ -10,33 +10,12 @@ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts │ │ │ │ │ │ ├ span: │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:3-18:4 -@@= skipped -61, +60 lines =@@ - │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { - │ │ │ │ │ │ │ │ │ │ │ │ ^ - │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ ├ incoming: --│ │ │ │ │ │ │ │ │ │ │ ╭ from: --│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +@@= skipped -64, +63 lines =@@ + │ │ │ │ │ │ │ │ │ │ ├ incoming: + │ │ │ │ │ │ │ │ │ │ │ ╭ from: + │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function --│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar --│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts --│ │ │ │ │ │ │ │ │ │ │ │ ├ span: --│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:20-34:37 --│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ --│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: --│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:9-34:17 --│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ --│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none --│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: --│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:34:34-34:35 --│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ ^ --│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ -+│ │ │ │ │ │ │ │ │ │ ╰ incoming: none - │ │ │ │ │ │ │ │ │ ├ fromSpans: - │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:28:7-28:15 - │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); \ No newline at end of file ++│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable + │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar + │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts + │ │ │ │ │ │ │ │ │ │ │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt index 94e5766b7e..51013a1104 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt @@ -115,7 +115,28 @@ │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { │ │ │ │ │ │ │ │ │ │ │ │ ^ │ │ │ │ │ │ │ │ │ │ │ ╰ -│ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ │ ├ incoming: +│ │ │ │ │ │ │ │ │ │ │ ╭ from: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable +│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar +│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts +│ │ │ │ │ │ │ │ │ │ │ │ ├ span: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:20-34:37 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: +│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:9-34:17 +│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ +│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ +│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none +│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: +│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:34-34:35 +│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); +│ │ │ │ │ │ │ │ │ │ │ │ │ ^ +│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ │ │ │ │ │ │ │ │ │ ├ fromSpans: │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:28:7-28:15 │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff index b9cdd9ab71..64c81dc740 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff @@ -10,33 +10,12 @@ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts │ │ │ │ │ │ ├ span: │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:3-18:4 -@@= skipped -61, +60 lines =@@ - │ │ │ │ │ │ │ │ │ │ │ │ 26: export class C { - │ │ │ │ │ │ │ │ │ │ │ │ ^ - │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ ├ incoming: --│ │ │ │ │ │ │ │ │ │ │ ╭ from: --│ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName +@@= skipped -64, +63 lines =@@ + │ │ │ │ │ │ │ │ │ │ ├ incoming: + │ │ │ │ │ │ │ │ │ │ │ ╭ from: + │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function --│ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar --│ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts --│ │ │ │ │ │ │ │ │ │ │ │ ├ span: --│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:20-34:37 --│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^^^^^^^^^^ --│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ │ │ ├ selectionSpan: --│ │ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:9-34:17 --│ │ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ │ ^^^^^^^^ --│ │ │ │ │ │ │ │ │ │ │ │ │ ╰ --│ │ │ │ │ │ │ │ │ │ │ │ ╰ incoming: none --│ │ │ │ │ │ │ │ │ │ │ ├ fromSpans: --│ │ │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:34:34-34:35 --│ │ │ │ │ │ │ │ │ │ │ │ │ 34: const sameName = () => new Foo.C(); --│ │ │ │ │ │ │ │ │ │ │ │ │ ^ --│ │ │ │ │ │ │ │ │ │ ╰ ╰ ╰ -+│ │ │ │ │ │ │ │ │ │ ╰ incoming: none - │ │ │ │ │ │ │ │ │ ├ fromSpans: - │ │ │ │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:28:7-28:15 - │ │ │ │ │ │ │ │ │ │ │ 28: sameName(); \ No newline at end of file ++│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable + │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar + │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts + │ │ │ │ │ │ │ │ │ │ │ │ ├ span: \ No newline at end of file From e5aafede636096509039aebbe4933f62b09ff1c4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 06:51:36 -0800 Subject: [PATCH 04/20] bugfix --- internal/ast/utilities.go | 4 ++-- internal/ls/callhierarchy.go | 14 +++++++++++--- .../callHierarchyContainerName.callHierarchy.txt | 1 + ...llHierarchyContainerName.callHierarchy.txt.diff | 5 ++--- ...lHierarchyContainerNameServer.callHierarchy.txt | 1 + ...archyContainerNameServer.callHierarchy.txt.diff | 5 ++--- 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 89b6ecfb98..fff659314b 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -1386,7 +1386,7 @@ func GetNameOfDeclaration(declaration *Node) *Node { return nonAssignedName } if IsFunctionExpression(declaration) || IsArrowFunction(declaration) || IsClassExpression(declaration) { - return getAssignedName(declaration) + return GetAssignedName(declaration) } return nil } @@ -1415,7 +1415,7 @@ func GetNonAssignedNameOfDeclaration(declaration *Node) *Node { return declaration.Name() } -func getAssignedName(node *Node) *Node { +func GetAssignedName(node *Node) *Node { parent := node.Parent if parent != nil { switch parent.Kind { diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index c751b7fe52..b07ff7703f 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -241,8 +241,14 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { if isAssignedExpression(node) { parent := node.Parent if ast.IsPropertyDeclaration(parent) && ast.IsClassLike(parent.Parent) { - if name := parent.Parent.Name(); name != nil { - return name.Text() + if ast.IsClassExpression(parent.Parent) { + if assignedName := ast.GetAssignedName(parent.Parent); assignedName != nil { + return assignedName.Text() + } + } else { + if name := parent.Parent.Name(); name != nil { + return name.Text() + } } } // Check for module block @@ -263,7 +269,9 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { switch node.Kind { case ast.KindGetAccessor, ast.KindSetAccessor, ast.KindMethodDeclaration: if node.Parent.Kind == ast.KindObjectLiteralExpression { - // Skip assigned name check for now + if assignedName := ast.GetAssignedName(node.Parent); assignedName != nil { + return assignedName.Text() + } } if name := ast.GetNameOfDeclaration(node.Parent); name != nil { return name.Text() diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt index 04dee73387..68799b87a1 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt @@ -56,6 +56,7 @@ │ │ │ │ │ ╭ from: │ │ │ │ │ │ ╭ name: sameName │ │ │ │ │ │ ├ kind: property +│ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts │ │ │ │ │ │ ├ span: │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:3-18:4 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff index 8b907bed2e..d5a3f7479c 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff @@ -5,12 +5,11 @@ │ │ │ │ │ ╭ from: │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ ├ kind: getter --│ │ │ │ │ │ ├ containerName: Obj +│ │ │ │ │ │ ├ kind: property + │ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts │ │ │ │ │ │ ├ span: - │ │ │ │ │ │ │ ╭ /callHierarchyContainerName.ts:16:3-18:4 -@@= skipped -64, +63 lines =@@ +@@= skipped -64, +64 lines =@@ │ │ │ │ │ │ │ │ │ │ ├ incoming: │ │ │ │ │ │ │ │ │ │ │ ╭ from: │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt index 51013a1104..8bf7e106ac 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt @@ -56,6 +56,7 @@ │ │ │ │ │ ╭ from: │ │ │ │ │ │ ╭ name: sameName │ │ │ │ │ │ ├ kind: property +│ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts │ │ │ │ │ │ ├ span: │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:3-18:4 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff index 64c81dc740..0b88732f1d 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff @@ -5,12 +5,11 @@ │ │ │ │ │ ╭ from: │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ ├ kind: getter --│ │ │ │ │ │ ├ containerName: Obj +│ │ │ │ │ │ ├ kind: property + │ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts │ │ │ │ │ │ ├ span: - │ │ │ │ │ │ │ ╭ /callHierarchyContainerNameServer.ts:16:3-18:4 -@@= skipped -64, +63 lines =@@ +@@= skipped -64, +64 lines =@@ │ │ │ │ │ │ │ │ │ │ ├ incoming: │ │ │ │ │ │ │ │ │ │ │ ╭ from: │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName From 2befbb14a383165d6dcdc8af36ff3b91aeffbffe Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 06:59:26 -0800 Subject: [PATCH 05/20] bugfix --- internal/ls/callhierarchy.go | 13 ++++++---- ...archyFunctionAmbiguity.5.callHierarchy.txt | 12 ++++----- ...FunctionAmbiguity.5.callHierarchy.txt.diff | 26 ------------------- 3 files changed, 14 insertions(+), 37 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index b07ff7703f..3ce04e9eb4 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -538,6 +538,7 @@ func (l *LanguageService) createCallHierarchyItem(program *compiler.Program, nod type callSite struct { declaration *ast.Node textRange core.TextRange + sourceFile *ast.Node // The source file containing the call site } func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *callSite { @@ -565,6 +566,7 @@ func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *c return &callSite{ declaration: ancestor, textRange: core.NewTextRange(start, node.End()), + sourceFile: sourceFile.AsNode(), } } @@ -575,9 +577,8 @@ func getCallSiteGroupKey(site *callSite) ast.NodeId { func (l *LanguageService) convertCallSiteGroupToIncomingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyIncomingCall { fromRanges := make([]lsproto.Range, len(entries)) for i, entry := range entries { - // Get source file from the declaration node to find the script - sourceFile := ast.GetSourceFileOfNode(entry.declaration) - script := l.getScript(sourceFile.FileName()) + // Get source file where the call site is located + script := l.getScript(entry.sourceFile.AsSourceFile().FileName()) fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) } @@ -709,12 +710,14 @@ func (c *callSiteCollector) recordCallSite(node *ast.Node) { c.callSites = append(c.callSites, &callSite{ declaration: decl, textRange: textRange, + sourceFile: sourceFile.AsNode(), }) case []*ast.Node: for _, d := range decl { c.callSites = append(c.callSites, &callSite{ declaration: d, textRange: textRange, + sourceFile: sourceFile.AsNode(), }) } } @@ -947,8 +950,8 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N func (l *LanguageService) convertCallSiteGroupToOutgoingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyOutgoingCall { fromRanges := make([]lsproto.Range, len(entries)) for i, entry := range entries { - sourceFile := ast.GetSourceFileOfNode(entries[0].declaration) - script := l.getScript(sourceFile.FileName()) + // Get source file where the call site is located + script := l.getScript(entry.sourceFile.AsSourceFile().FileName()) fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) } diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt index 093197302f..b4b46fc4f5 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt @@ -34,9 +34,9 @@ │ │ │ ╰ │ │ ╰ outgoing: none │ ├ fromSpans: -│ │ ╭ /main.ts:1:22-1:25 -│ │ │ 1: function bar() { -│ │ │ ^^^ +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ │ ╰ ╰ │ ╭ to: │ │ ╭ name: foo @@ -54,7 +54,7 @@ │ │ │ ╰ │ │ ╰ outgoing: none │ ├ fromSpans: -│ │ ╭ /main.ts:1:22-1:25 -│ │ │ 1: function bar() { -│ │ │ ^^^ +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ ╰ ╰ ╰ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff deleted file mode 100644 index 553ee83996..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.5.callHierarchy.txt.diff +++ /dev/null @@ -1,26 +0,0 @@ ---- old.callHierarchyFunctionAmbiguity.5.callHierarchy.txt -+++ new.callHierarchyFunctionAmbiguity.5.callHierarchy.txt -@@= skipped -33, +33 lines =@@ - │ │ │ ╰ - │ │ ╰ outgoing: none - │ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ -+│ │ ╭ /main.ts:1:22-1:25 -+│ │ │ 1: function bar() { -+│ │ │ ^^^ - │ ╰ ╰ - │ ╭ to: - │ │ ╭ name: foo -@@= skipped -20, +20 lines =@@ - │ │ │ ╰ - │ │ ╰ outgoing: none - │ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ -+│ │ ╭ /main.ts:1:22-1:25 -+│ │ │ 1: function bar() { -+│ │ │ ^^^ - ╰ ╰ ╰ \ No newline at end of file From f1725a117adea7f280af11bd41aa1f9a5e2438c4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 07:04:35 -0800 Subject: [PATCH 06/20] Fix baseline --- internal/fourslash/fourslash.go | 12 ++-- ...archyFunctionAmbiguity.1.callHierarchy.txt | 47 ++++++++++++-- ...FunctionAmbiguity.1.callHierarchy.txt.diff | 62 ------------------- ...archyFunctionAmbiguity.2.callHierarchy.txt | 39 ++++++++++++ ...FunctionAmbiguity.2.callHierarchy.txt.diff | 45 -------------- ...archyFunctionAmbiguity.3.callHierarchy.txt | 39 ++++++++++++ ...FunctionAmbiguity.3.callHierarchy.txt.diff | 48 -------------- ...archyFunctionAmbiguity.4.callHierarchy.txt | 39 ++++++++++++ ...FunctionAmbiguity.4.callHierarchy.txt.diff | 48 -------------- 9 files changed, 167 insertions(+), 212 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index b0a6d2c845..2721266fc6 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -1776,12 +1776,14 @@ func (f *FourslashTest) VerifyBaselineCallHierarchy(t *testing.T) { return } - callHierarchyItem := (*prepareResult.CallHierarchyItems)[0] - script := f.getScriptInfo(fileName) - var result strings.Builder - seen := make(map[callHierarchyItemKey]bool) - formatCallHierarchyItem(t, f, script, &result, *callHierarchyItem, callHierarchyItemDirectionRoot, seen, "") + + for _, callHierarchyItem := range *prepareResult.CallHierarchyItems { + seen := make(map[callHierarchyItemKey]bool) + itemFileName := callHierarchyItem.Uri.FileName() + script := f.getScriptInfo(itemFileName) + formatCallHierarchyItem(t, f, script, &result, *callHierarchyItem, callHierarchyItemDirectionRoot, seen, "") + } f.addResultToBaseline(t, callHierarchyCmd, strings.TrimSuffix(result.String(), "\n")) } diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt index bacb2b695f..3b77dc6cfb 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt @@ -3,13 +3,52 @@ ├ kind: function ├ file: /a.d.ts ├ span: -│ ╭ /main.ts:1:1-1:40 -│ │ 1: function bar() { +│ ╭ /a.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: number): void; │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ │ ╰ ├ selectionSpan: -│ ╭ /main.ts:1:18-1:21 -│ │ 1: function bar() { +│ ╭ /a.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none +╭ name: foo +├ kind: function +├ file: /b.d.ts +├ span: +│ ╭ /b.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /b.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: string): void; │ │ ^^^ │ ╰ ├ incoming: diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff deleted file mode 100644 index 09246fddd3..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.1.callHierarchy.txt.diff +++ /dev/null @@ -1,62 +0,0 @@ ---- old.callHierarchyFunctionAmbiguity.1.callHierarchy.txt -+++ new.callHierarchyFunctionAmbiguity.1.callHierarchy.txt -@@= skipped -2, +2 lines =@@ - ├ kind: function - ├ file: /a.d.ts - ├ span: --│ ╭ /a.d.ts:1:1-1:40 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --│ ╰ --├ selectionSpan: --│ ╭ /a.d.ts:1:18-1:21 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^ --│ ╰ --├ incoming: --│ ╭ from: --│ │ ╭ name: bar --│ │ ├ kind: function --│ │ ├ file: /main.ts --│ │ ├ span: --│ │ │ ╭ /main.ts:1:1-3:2 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^^^^^^^^^^^^^^ --│ │ │ │ 2: foo(); --│ │ │ │ ^^^^^^^^^^ --│ │ │ │ 3: } --│ │ │ │ ^ --│ │ │ ╰ --│ │ ├ selectionSpan: --│ │ │ ╭ /main.ts:1:10-1:13 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^ --│ │ │ ╰ --│ │ ╰ incoming: none --│ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ --│ ╰ ╰ --╰ outgoing: none --╭ name: foo --├ kind: function --├ file: /b.d.ts --├ span: --│ ╭ /b.d.ts:1:1-1:40 --│ │ 1: declare function foo(x?: string): void; --│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --│ ╰ --├ selectionSpan: --│ ╭ /b.d.ts:1:18-1:21 --│ │ 1: declare function foo(x?: string): void; -+│ ╭ /main.ts:1:1-1:40 -+│ │ 1: function bar() { -+│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+│ ╰ -+├ selectionSpan: -+│ ╭ /main.ts:1:18-1:21 -+│ │ 1: function bar() { - │ │ ^^^ - │ ╰ - ├ incoming: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt index 87ebaaad52..3b77dc6cfb 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt @@ -37,4 +37,43 @@ │ │ │ 2: foo(); │ │ │ ^^^ │ ╰ ╰ +╰ outgoing: none +╭ name: foo +├ kind: function +├ file: /b.d.ts +├ span: +│ ╭ /b.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /b.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: string): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ ╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff deleted file mode 100644 index f5b1ee161c..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.2.callHierarchy.txt.diff +++ /dev/null @@ -1,45 +0,0 @@ ---- old.callHierarchyFunctionAmbiguity.2.callHierarchy.txt -+++ new.callHierarchyFunctionAmbiguity.2.callHierarchy.txt -@@= skipped -37, +37 lines =@@ - │ │ │ ^^^ - │ ╰ ╰ - ╰ outgoing: none --╭ name: foo --├ kind: function --├ file: /b.d.ts --├ span: --│ ╭ /b.d.ts:1:1-1:40 --│ │ 1: declare function foo(x?: string): void; --│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --│ ╰ --├ selectionSpan: --│ ╭ /b.d.ts:1:18-1:21 --│ │ 1: declare function foo(x?: string): void; --│ │ ^^^ --│ ╰ --├ incoming: --│ ╭ from: --│ │ ╭ name: bar --│ │ ├ kind: function --│ │ ├ file: /main.ts --│ │ ├ span: --│ │ │ ╭ /main.ts:1:1-3:2 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^^^^^^^^^^^^^^ --│ │ │ │ 2: foo(); --│ │ │ │ ^^^^^^^^^^ --│ │ │ │ 3: } --│ │ │ │ ^ --│ │ │ ╰ --│ │ ├ selectionSpan: --│ │ │ ╭ /main.ts:1:10-1:13 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^ --│ │ │ ╰ --│ │ ╰ incoming: none --│ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ --│ ╰ ╰ --╰ outgoing: none \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt index 791c5a45d2..3b77dc6cfb 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt @@ -3,6 +3,45 @@ ├ kind: function ├ file: /a.d.ts ├ span: +│ ╭ /a.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /a.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none +╭ name: foo +├ kind: function +├ file: /b.d.ts +├ span: │ ╭ /b.d.ts:1:1-1:40 │ │ 1: declare function foo(x?: string): void; │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff deleted file mode 100644 index bac9cf6d32..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.3.callHierarchy.txt.diff +++ /dev/null @@ -1,48 +0,0 @@ ---- old.callHierarchyFunctionAmbiguity.3.callHierarchy.txt -+++ new.callHierarchyFunctionAmbiguity.3.callHierarchy.txt -@@= skipped -2, +2 lines =@@ - ├ kind: function - ├ file: /a.d.ts - ├ span: --│ ╭ /a.d.ts:1:1-1:40 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --│ ╰ --├ selectionSpan: --│ ╭ /a.d.ts:1:18-1:21 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^ --│ ╰ --├ incoming: --│ ╭ from: --│ │ ╭ name: bar --│ │ ├ kind: function --│ │ ├ file: /main.ts --│ │ ├ span: --│ │ │ ╭ /main.ts:1:1-3:2 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^^^^^^^^^^^^^^ --│ │ │ │ 2: foo(); --│ │ │ │ ^^^^^^^^^^ --│ │ │ │ 3: } --│ │ │ │ ^ --│ │ │ ╰ --│ │ ├ selectionSpan: --│ │ │ ╭ /main.ts:1:10-1:13 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^ --│ │ │ ╰ --│ │ ╰ incoming: none --│ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ --│ ╰ ╰ --╰ outgoing: none --╭ name: foo --├ kind: function --├ file: /b.d.ts --├ span: - │ ╭ /b.d.ts:1:1-1:40 - │ │ 1: declare function foo(x?: string): void; - │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt index 791c5a45d2..3b77dc6cfb 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt @@ -3,6 +3,45 @@ ├ kind: function ├ file: /a.d.ts ├ span: +│ ╭ /a.d.ts:1:1-1:40 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +│ ╰ +├ selectionSpan: +│ ╭ /a.d.ts:1:18-1:21 +│ │ 1: declare function foo(x?: number): void; +│ │ ^^^ +│ ╰ +├ incoming: +│ ╭ from: +│ │ ╭ name: bar +│ │ ├ kind: function +│ │ ├ file: /main.ts +│ │ ├ span: +│ │ │ ╭ /main.ts:1:1-3:2 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^^^^^^^^^^^^^^ +│ │ │ │ 2: foo(); +│ │ │ │ ^^^^^^^^^^ +│ │ │ │ 3: } +│ │ │ │ ^ +│ │ │ ╰ +│ │ ├ selectionSpan: +│ │ │ ╭ /main.ts:1:10-1:13 +│ │ │ │ 1: function bar() { +│ │ │ │ ^^^ +│ │ │ ╰ +│ │ ╰ incoming: none +│ ├ fromSpans: +│ │ ╭ /main.ts:2:5-2:8 +│ │ │ 2: foo(); +│ │ │ ^^^ +│ ╰ ╰ +╰ outgoing: none +╭ name: foo +├ kind: function +├ file: /b.d.ts +├ span: │ ╭ /b.d.ts:1:1-1:40 │ │ 1: declare function foo(x?: string): void; │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff deleted file mode 100644 index 0ad01b7ca7..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFunctionAmbiguity.4.callHierarchy.txt.diff +++ /dev/null @@ -1,48 +0,0 @@ ---- old.callHierarchyFunctionAmbiguity.4.callHierarchy.txt -+++ new.callHierarchyFunctionAmbiguity.4.callHierarchy.txt -@@= skipped -2, +2 lines =@@ - ├ kind: function - ├ file: /a.d.ts - ├ span: --│ ╭ /a.d.ts:1:1-1:40 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --│ ╰ --├ selectionSpan: --│ ╭ /a.d.ts:1:18-1:21 --│ │ 1: declare function foo(x?: number): void; --│ │ ^^^ --│ ╰ --├ incoming: --│ ╭ from: --│ │ ╭ name: bar --│ │ ├ kind: function --│ │ ├ file: /main.ts --│ │ ├ span: --│ │ │ ╭ /main.ts:1:1-3:2 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^^^^^^^^^^^^^^ --│ │ │ │ 2: foo(); --│ │ │ │ ^^^^^^^^^^ --│ │ │ │ 3: } --│ │ │ │ ^ --│ │ │ ╰ --│ │ ├ selectionSpan: --│ │ │ ╭ /main.ts:1:10-1:13 --│ │ │ │ 1: function bar() { --│ │ │ │ ^^^ --│ │ │ ╰ --│ │ ╰ incoming: none --│ ├ fromSpans: --│ │ ╭ /main.ts:2:5-2:8 --│ │ │ 2: foo(); --│ │ │ ^^^ --│ ╰ ╰ --╰ outgoing: none --╭ name: foo --├ kind: function --├ file: /b.d.ts --├ span: - │ ╭ /b.d.ts:1:1-1:40 - │ │ 1: declare function foo(x?: string): void; - │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file From 5f4519484f0a0aa7b67f466b1280b813429c2062 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 07:34:32 -0800 Subject: [PATCH 07/20] Fix --- internal/ls/symbols.go | 44 +++++++++++++------ ...assPropertyArrowFunction.callHierarchy.txt | 4 +- ...opertyArrowFunction.callHierarchy.txt.diff | 19 -------- ...ierarchyClassStaticBlock.callHierarchy.txt | 2 +- ...chyClassStaticBlock.callHierarchy.txt.diff | 11 ----- ...erarchyClassStaticBlock2.callHierarchy.txt | 2 +- ...hyClassStaticBlock2.callHierarchy.txt.diff | 10 ----- ...yConstNamedArrowFunction.callHierarchy.txt | 2 +- ...tNamedArrowFunction.callHierarchy.txt.diff | 10 ----- ...llHierarchyContainerName.callHierarchy.txt | 2 +- ...rarchyContainerName.callHierarchy.txt.diff | 11 +---- ...archyContainerNameServer.callHierarchy.txt | 2 +- ...ContainerNameServer.callHierarchy.txt.diff | 11 +---- ...rchyExportEqualsFunction.callHierarchy.txt | 2 +- ...xportEqualsFunction.callHierarchy.txt.diff | 10 ----- 15 files changed, 41 insertions(+), 101 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff diff --git a/internal/ls/symbols.go b/internal/ls/symbols.go index b45695e703..83acc57e0f 100644 --- a/internal/ls/symbols.go +++ b/internal/ls/symbols.go @@ -350,35 +350,53 @@ func compareDeclarationInfos(d1, d2 DeclarationInfo) int { return d1.declaration.Pos() - d2.declaration.Pos() } +// getSymbolKindFromNode converts an AST node to an LSP SymbolKind. +// Combines getNodeKind with VS Code's fromProtocolScriptElementKind. func getSymbolKindFromNode(node *ast.Node) lsproto.SymbolKind { switch node.Kind { + case ast.KindSourceFile: + if ast.IsExternalModule(node.AsSourceFile()) { + return lsproto.SymbolKindModule + } + return lsproto.SymbolKindVariable // SymbolKindFile? case ast.KindModuleDeclaration: - return lsproto.SymbolKindNamespace - case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindTypeAliasDeclaration: + return lsproto.SymbolKindModule + case ast.KindClassDeclaration, ast.KindClassExpression: + return lsproto.SymbolKindClass + case ast.KindInterfaceDeclaration: + return lsproto.SymbolKindInterface + case ast.KindTypeAliasDeclaration: return lsproto.SymbolKindClass + case ast.KindEnumDeclaration: + return lsproto.SymbolKindEnum + case ast.KindVariableDeclaration: + return lsproto.SymbolKindVariable + case ast.KindArrowFunction, ast.KindFunctionDeclaration, ast.KindFunctionExpression: + return lsproto.SymbolKindFunction + case ast.KindGetAccessor, ast.KindSetAccessor: + return lsproto.SymbolKindProperty case ast.KindMethodDeclaration, ast.KindMethodSignature: return lsproto.SymbolKindMethod - case ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindGetAccessor, ast.KindSetAccessor: + case ast.KindPropertyDeclaration, ast.KindPropertySignature: return lsproto.SymbolKindProperty - case ast.KindConstructor, ast.KindConstructSignature: + case ast.KindIndexSignature, ast.KindCallSignature: + return lsproto.SymbolKindMethod + case ast.KindConstructSignature: + return lsproto.SymbolKindConstructor + case ast.KindConstructor, ast.KindClassStaticBlockDeclaration: return lsproto.SymbolKindConstructor - case ast.KindEnumDeclaration: - return lsproto.SymbolKindEnum - case ast.KindInterfaceDeclaration: - return lsproto.SymbolKindInterface - case ast.KindFunctionDeclaration, ast.KindFunctionExpression: - return lsproto.SymbolKindFunction - case ast.KindEnumMember: - return lsproto.SymbolKindEnumMember case ast.KindTypeParameter: return lsproto.SymbolKindTypeParameter + case ast.KindEnumMember: + return lsproto.SymbolKindEnumMember case ast.KindParameter: if ast.HasSyntacticModifier(node, ast.ModifierFlagsParameterPropertyModifier) { return lsproto.SymbolKindProperty } return lsproto.SymbolKindVariable case ast.KindBinaryExpression: - switch ast.GetAssignmentDeclarationKind(node.AsBinaryExpression()) { + kind := ast.GetAssignmentDeclarationKind(node.AsBinaryExpression()) + switch kind { case ast.JSDeclarationKindThisProperty, ast.JSDeclarationKindProperty: return lsproto.SymbolKindProperty } diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt index 4281cad266..6a78d564e4 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt @@ -1,6 +1,6 @@ // === Call Hierarchy === ╭ name: callee -├ kind: variable +├ kind: function ├ containerName: C ├ file: /callHierarchyClassPropertyArrowFunction.ts ├ span: @@ -18,7 +18,7 @@ ├ incoming: │ ╭ from: │ │ ╭ name: caller -│ │ ├ kind: variable +│ │ ├ kind: function │ │ ├ containerName: C │ │ ├ file: /callHierarchyClassPropertyArrowFunction.ts │ │ ├ span: diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff deleted file mode 100644 index 7bf18a40a7..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassPropertyArrowFunction.callHierarchy.txt.diff +++ /dev/null @@ -1,19 +0,0 @@ ---- old.callHierarchyClassPropertyArrowFunction.callHierarchy.txt -+++ new.callHierarchyClassPropertyArrowFunction.callHierarchy.txt -@@= skipped -0, +0 lines =@@ - // === Call Hierarchy === - ╭ name: callee --├ kind: function -+├ kind: variable - ├ containerName: C - ├ file: /callHierarchyClassPropertyArrowFunction.ts - ├ span: -@@= skipped -17, +17 lines =@@ - ├ incoming: - │ ╭ from: - │ │ ╭ name: caller --│ │ ├ kind: function -+│ │ ├ kind: variable - │ │ ├ containerName: C - │ │ ├ file: /callHierarchyClassPropertyArrowFunction.ts - │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt index d6d69497a5..cef1e4637d 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt @@ -42,7 +42,7 @@ │ │ ├ incoming: │ │ │ ╭ from: │ │ │ │ ╭ name: static {} -│ │ │ │ ├ kind: variable +│ │ │ │ ├ kind: constructor │ │ │ │ ├ file: /callHierarchyClassStaticBlock.ts │ │ │ │ ├ span: │ │ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:2:5-14:6 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff deleted file mode 100644 index fc1bdd692e..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyClassStaticBlock.callHierarchy.txt -+++ new.callHierarchyClassStaticBlock.callHierarchy.txt -@@= skipped -41, +41 lines =@@ - │ │ ├ incoming: - │ │ │ ╭ from: - │ │ │ │ ╭ name: static {} --│ │ │ │ ├ kind: constructor -+│ │ │ │ ├ kind: variable - │ │ │ │ ├ file: /callHierarchyClassStaticBlock.ts - │ │ │ │ ├ span: - │ │ │ │ │ ╭ /callHierarchyClassStaticBlock.ts:2:5-14:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt index f0a55f3e09..dd4bfa270c 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt @@ -1,6 +1,6 @@ // === Call Hierarchy === ╭ name: static {} -├ kind: variable +├ kind: constructor ├ file: /callHierarchyClassStaticBlock2.ts ├ span: │ ╭ /callHierarchyClassStaticBlock2.ts:2:5-14:6 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff deleted file mode 100644 index 9d456600d3..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyClassStaticBlock2.callHierarchy.txt.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- old.callHierarchyClassStaticBlock2.callHierarchy.txt -+++ new.callHierarchyClassStaticBlock2.callHierarchy.txt -@@= skipped -0, +0 lines =@@ - // === Call Hierarchy === - ╭ name: static {} --├ kind: constructor -+├ kind: variable - ├ file: /callHierarchyClassStaticBlock2.ts - ├ span: - │ ╭ /callHierarchyClassStaticBlock2.ts:2:5-14:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt index 6e547d7ff3..9d7eef6e05 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt @@ -1,6 +1,6 @@ // === Call Hierarchy === ╭ name: bar -├ kind: variable +├ kind: function ├ file: /callHierarchyConstNamedArrowFunction.ts ├ span: │ ╭ /callHierarchyConstNamedArrowFunction.ts:5:13-7:2 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff deleted file mode 100644 index 925d9d5743..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyConstNamedArrowFunction.callHierarchy.txt.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- old.callHierarchyConstNamedArrowFunction.callHierarchy.txt -+++ new.callHierarchyConstNamedArrowFunction.callHierarchy.txt -@@= skipped -0, +0 lines =@@ - // === Call Hierarchy === - ╭ name: bar --├ kind: function -+├ kind: variable - ├ file: /callHierarchyConstNamedArrowFunction.ts - ├ span: - │ ╭ /callHierarchyConstNamedArrowFunction.ts:5:13-7:2 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt index 68799b87a1..237f7ae11a 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt @@ -119,7 +119,7 @@ │ │ │ │ │ │ │ │ │ │ ├ incoming: │ │ │ │ │ │ │ │ │ │ │ ╭ from: │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable +│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts │ │ │ │ │ │ │ │ │ │ │ │ ├ span: diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff index d5a3f7479c..41f8fa8bf6 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff @@ -8,13 +8,4 @@ +│ │ │ │ │ │ ├ kind: property │ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts - │ │ │ │ │ │ ├ span: -@@= skipped -64, +64 lines =@@ - │ │ │ │ │ │ │ │ │ │ ├ incoming: - │ │ │ │ │ │ │ │ │ │ │ ╭ from: - │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName --│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function -+│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable - │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar - │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts - │ │ │ │ │ │ │ │ │ │ │ │ ├ span: \ No newline at end of file + │ │ │ │ │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt index 8bf7e106ac..22c38f323c 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt @@ -119,7 +119,7 @@ │ │ │ │ │ │ │ │ │ │ ├ incoming: │ │ │ │ │ │ │ │ │ │ │ ╭ from: │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName -│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable +│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts │ │ │ │ │ │ │ │ │ │ │ │ ├ span: diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff index 0b88732f1d..1620ec4b41 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff @@ -8,13 +8,4 @@ +│ │ │ │ │ │ ├ kind: property │ │ │ │ │ │ ├ containerName: Obj │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts - │ │ │ │ │ │ ├ span: -@@= skipped -64, +64 lines =@@ - │ │ │ │ │ │ │ │ │ │ ├ incoming: - │ │ │ │ │ │ │ │ │ │ │ ╭ from: - │ │ │ │ │ │ │ │ │ │ │ │ ╭ name: sameName --│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: function -+│ │ │ │ │ │ │ │ │ │ │ │ ├ kind: variable - │ │ │ │ │ │ │ │ │ │ │ │ ├ containerName: Bar - │ │ │ │ │ │ │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts - │ │ │ │ │ │ │ │ │ │ │ │ ├ span: \ No newline at end of file + │ │ │ │ │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt index 208d07a873..3e85787a89 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt @@ -1,6 +1,6 @@ // === Call Hierarchy === ╭ name: /other.ts -├ kind: variable +├ kind: module ├ file: /other.ts ├ span: │ ╭ /other.ts:1:1-6:2 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff deleted file mode 100644 index 73e0c26bca..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyExportEqualsFunction.callHierarchy.txt.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- old.callHierarchyExportEqualsFunction.callHierarchy.txt -+++ new.callHierarchyExportEqualsFunction.callHierarchy.txt -@@= skipped -0, +0 lines =@@ - // === Call Hierarchy === - ╭ name: /other.ts --├ kind: module -+├ kind: variable - ├ file: /other.ts - ├ span: - │ ╭ /other.ts:1:1-6:2 \ No newline at end of file From 93595e34095fc84757858787d5a2e9b7fa5e86ef Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 07:50:44 -0800 Subject: [PATCH 08/20] Some cleanup --- internal/ls/callhierarchy.go | 80 ++++++++++-------------------------- 1 file changed, 22 insertions(+), 58 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 3ce04e9eb4..ad662d926f 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -18,7 +18,7 @@ import ( type CallHierarchyDeclaration = *ast.Node -// Indictates whether a node is named function or class expression. +// Indicates whether a node is named function or class expression. func isNamedExpression(node *ast.Node) bool { if node == nil { return false @@ -99,8 +99,7 @@ func isValidCallHierarchyDeclaration(node *ast.Node) bool { } if ast.IsModuleDeclaration(node) { - mod := node.AsModuleDeclaration() - return mod != nil && ast.IsIdentifier(mod.Name()) + return ast.IsIdentifier(node.Name()) } return ast.IsFunctionDeclaration(node) || @@ -209,9 +208,9 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s } else if ast.IsStringOrNumericLiteralLike(declName) { text = declName.Text() } else if ast.IsComputedPropertyName(declName) { - comp := declName.AsComputedPropertyName() - if ast.IsStringOrNumericLiteralLike(comp.Expression) { - text = comp.Expression.Text() + expr := declName.Expression() + if ast.IsStringOrNumericLiteralLike(expr) { + text = expr.Text() } } @@ -525,9 +524,6 @@ func (l *LanguageService) createCallHierarchyItem(program *compiler.Program, nod SelectionRange: selectionSpan, } - // kindModifiers is a Set, not a string - skip for now - // TODO: convert modifiers to SymbolTag array - if containerName != "" { item.Detail = &containerName } @@ -741,8 +737,7 @@ func (c *callSiteCollector) collect(node *ast.Node) { if classLike != nil && classLike.Members != nil { for _, member := range classLike.Members.Nodes { if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { - comp := member.Name().AsComputedPropertyName() - c.collect(comp.Expression) + c.collect(member.Name().Expression()) } } } @@ -764,49 +759,27 @@ func (c *callSiteCollector) collect(node *ast.Node) { return case ast.KindTypeAssertionExpression, ast.KindAsExpression: // do not descend into the type side of an assertion - var expr *ast.Node - if typeAssert := node.AsAsExpression(); typeAssert != nil { - expr = typeAssert.Expression - } else if asExpr := node.AsAsExpression(); asExpr != nil { - expr = asExpr.Expression - } - c.collect(expr) + c.collect(node.Expression()) return case ast.KindVariableDeclaration, ast.KindParameter: // do not descend into the type of a variable or parameter declaration - var name, initializer *ast.Node - if node.Kind == ast.KindVariableDeclaration { - varDecl := node.AsVariableDeclaration() - name = varDecl.Name() - initializer = varDecl.Initializer - } else { - param := node.AsParameterDeclaration() - name = param.Name() - initializer = param.Initializer - } - c.collect(name) - c.collect(initializer) + c.collect(node.Name()) + c.collect(node.Initializer()) return case ast.KindCallExpression: // do not descend into the type arguments of a call expression c.recordCallSite(node) - callExpr := node.AsCallExpression() - c.collect(callExpr.Expression) - if callExpr.Arguments != nil { - for _, arg := range callExpr.Arguments.Nodes { - c.collect(arg) - } + c.collect(node.Expression()) + for _, arg := range node.Arguments() { + c.collect(arg) } return case ast.KindNewExpression: // do not descend into the type arguments of a new expression c.recordCallSite(node) - newExpr := node.AsNewExpression() - c.collect(newExpr.Expression) - if newExpr.Arguments != nil { - for _, arg := range newExpr.Arguments.Nodes { - c.collect(arg) - } + c.collect(node.Expression()) + for _, arg := range node.Arguments() { + c.collect(arg) } return case ast.KindTaggedTemplateExpression: @@ -819,18 +792,12 @@ func (c *callSiteCollector) collect(node *ast.Node) { case ast.KindJsxOpeningElement, ast.KindJsxSelfClosingElement: // do not descend into the type arguments of a JsxOpeningLikeElement c.recordCallSite(node) - if jsxOpen := node.AsJsxOpeningElement(); jsxOpen != nil { - c.collect(jsxOpen.TagName) - c.collect(jsxOpen.Attributes) - } else if jsxSelf := node.AsJsxSelfClosingElement(); jsxSelf != nil { - c.collect(jsxSelf.TagName) - c.collect(jsxSelf.Attributes) - } + c.collect(node.TagName()) + c.collect(node.Attributes()) return case ast.KindDecorator: c.recordCallSite(node) - decorator := node.AsDecorator() - c.collect(decorator.Expression) + c.collect(node.Expression()) return case ast.KindPropertyAccessExpression, ast.KindElementAccessExpression: c.recordCallSite(node) @@ -841,8 +808,7 @@ func (c *callSiteCollector) collect(node *ast.Node) { return case ast.KindSatisfiesExpression: // do not descend into the type side of an assertion - satisfies := node.AsSatisfiesExpression() - c.collect(satisfies.Expression) + c.collect(node.Expression()) return } @@ -921,8 +887,7 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N } if ast.IsPropertyDeclaration(member) { - propDecl := member.AsPropertyDeclaration() - collector.collect(propDecl.Initializer) + collector.collect(member.Initializer()) } else if ast.IsConstructorDeclaration(member) { ctor := member.AsConstructorDeclaration() if ctor.Body != nil { @@ -940,8 +905,7 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N } case ast.KindClassStaticBlockDeclaration: - staticBlock := node.AsClassStaticBlockDeclaration() - collector.collect(staticBlock.Body) + collector.collect(node.Body()) } return collector.callSites @@ -968,7 +932,7 @@ func (l *LanguageService) convertCallSiteGroupToOutgoingCall(program *compiler.P // Gets the call sites that call out of the provided call hierarchy declaration. func (l *LanguageService) getOutgoingCalls(program *compiler.Program, declaration *ast.Node) []*lsproto.CallHierarchyOutgoingCall { - if (declaration.Flags & ast.NodeFlagsAmbient) != 0 { + if (declaration.Flags&ast.NodeFlagsAmbient) != 0 || ast.IsMethodSignatureDeclaration(declaration) { return nil } From 2fb43f7b867c70e69cda07a92ba8531013a8dfa4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:05:36 -0800 Subject: [PATCH 09/20] Undo oops --- internal/ls/callhierarchy.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index ad662d926f..021c2a53eb 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -905,7 +905,8 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N } case ast.KindClassStaticBlockDeclaration: - collector.collect(node.Body()) + staticBlock := node.AsClassStaticBlockDeclaration() + collector.collect(staticBlock.Body) } return collector.callSites From 6dbe715d1a865cf8676b6a4f49a6657abeacd2f4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:09:34 -0800 Subject: [PATCH 10/20] Bad nil checks --- internal/ls/callhierarchy.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 021c2a53eb..72e2a6f1ac 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -251,14 +251,12 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { } } // Check for module block - if varDecl := parent.AsVariableDeclaration(); varDecl != nil { - if ast.IsModuleBlock(parent.Parent.Parent.Parent) { - modParent := parent.Parent.Parent.Parent.Parent - if ast.IsModuleDeclaration(modParent) { - mod := modParent.AsModuleDeclaration() - if name := mod.Name(); name != nil && ast.IsIdentifier(name) { - return name.Text() - } + if ast.IsModuleBlock(parent.Parent.Parent.Parent) { + modParent := parent.Parent.Parent.Parent.Parent + if ast.IsModuleDeclaration(modParent) { + mod := modParent.AsModuleDeclaration() + if name := mod.Name(); name != nil && ast.IsIdentifier(name) { + return name.Text() } } } @@ -477,7 +475,7 @@ func resolveCallHierarchyDeclaration(program *compiler.Program, location *ast.No // Variable declaration with assigned expression if ast.IsVariableDeclaration(location) { varDecl := location.AsVariableDeclaration() - if varDecl != nil && varDecl.Initializer != nil && isAssignedExpression(varDecl.Initializer) { + if varDecl.Initializer != nil && isAssignedExpression(varDecl.Initializer) { return varDecl.Initializer } } @@ -734,7 +732,7 @@ func (c *callSiteCollector) collect(node *ast.Node) { if ast.IsClassLike(node) { // Collect from computed property names classLike := node.AsClassDeclaration() - if classLike != nil && classLike.Members != nil { + if classLike.Members != nil { for _, member := range classLike.Members.Nodes { if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { c.collect(member.Name().Expression()) @@ -842,10 +840,8 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N mod := node.AsModuleDeclaration() if !ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) && mod.Body != nil && ast.IsModuleBlock(mod.Body) { modBlock := mod.Body.AsModuleBlock() - if modBlock.Statements != nil { - for _, stmt := range modBlock.Statements.Nodes { - collector.collect(stmt) - } + for _, stmt := range modBlock.Statements.Nodes { + collector.collect(stmt) } } From 0d6279267332813e8e7f9d788e8e4eb9d0635947 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:14:18 -0800 Subject: [PATCH 11/20] Helpers --- internal/ls/callhierarchy.go | 67 +++++++++++++----------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 72e2a6f1ac..79ae49f783 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -254,8 +254,7 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { if ast.IsModuleBlock(parent.Parent.Parent.Parent) { modParent := parent.Parent.Parent.Parent.Parent if ast.IsModuleDeclaration(modParent) { - mod := modParent.AsModuleDeclaration() - if name := mod.Name(); name != nil && ast.IsIdentifier(name) { + if name := modParent.Name(); name != nil && ast.IsIdentifier(name) { return name.Text() } } @@ -276,8 +275,7 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindModuleDeclaration: if ast.IsModuleBlock(node.Parent) { if ast.IsModuleDeclaration(node.Parent.Parent) { - mod := node.Parent.Parent.AsModuleDeclaration() - if name := mod.Name(); name != nil && ast.IsIdentifier(name) { + if name := node.Parent.Parent.Name(); name != nil && ast.IsIdentifier(name) { return name.Text() } } @@ -474,9 +472,8 @@ func resolveCallHierarchyDeclaration(program *compiler.Program, location *ast.No // Variable declaration with assigned expression if ast.IsVariableDeclaration(location) { - varDecl := location.AsVariableDeclaration() - if varDecl.Initializer != nil && isAssignedExpression(varDecl.Initializer) { - return varDecl.Initializer + if initializer := location.Initializer(); initializer != nil && isAssignedExpression(initializer) { + return initializer } } @@ -661,27 +658,21 @@ func (c *callSiteCollector) recordCallSite(node *ast.Node) { switch { case ast.IsTaggedTemplateExpression(node): - tagged := node.AsTaggedTemplateExpression() - target = tagged.Tag + target = node.Expression() case ast.IsJsxOpeningElement(node): - jsxOpen := node.AsJsxOpeningElement() - target = jsxOpen.TagName + target = node.TagName() case ast.IsJsxSelfClosingElement(node): - jsxSelf := node.AsJsxSelfClosingElement() - target = jsxSelf.TagName + target = node.TagName() case ast.IsPropertyAccessExpression(node) || ast.IsElementAccessExpression(node): target = node case ast.IsClassStaticBlockDeclaration(node): target = node case ast.IsCallExpression(node): - callExpr := node.AsCallExpression() - target = callExpr.Expression + target = node.Expression() case ast.IsNewExpression(node): - newExpr := node.AsNewExpression() - target = newExpr.Expression + target = node.Expression() case ast.IsDecorator(node): - decorator := node.AsDecorator() - target = decorator.Expression + target = node.Expression() } if target == nil { @@ -731,12 +722,9 @@ func (c *callSiteCollector) collect(node *ast.Node) { if isValidCallHierarchyDeclaration(node) { if ast.IsClassLike(node) { // Collect from computed property names - classLike := node.AsClassDeclaration() - if classLike.Members != nil { - for _, member := range classLike.Members.Nodes { - if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { - c.collect(member.Name().Expression()) - } + for _, member := range node.Members() { + if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { + c.collect(member.Name().Expression()) } } } @@ -783,9 +771,8 @@ func (c *callSiteCollector) collect(node *ast.Node) { case ast.KindTaggedTemplateExpression: // do not descend into the type arguments of a tagged template expression c.recordCallSite(node) - tagged := node.AsTaggedTemplateExpression() - c.collect(tagged.Tag) - c.collect(tagged.Template) + c.collect(node.Expression()) + c.collect(node.Body()) return case ast.KindJsxOpeningElement, ast.KindJsxSelfClosingElement: // do not descend into the type arguments of a JsxOpeningLikeElement @@ -829,18 +816,13 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N switch node.Kind { case ast.KindSourceFile: - sourceFile := node.AsSourceFile() - if sourceFile.Statements != nil { - for _, stmt := range sourceFile.Statements.Nodes { - collector.collect(stmt) - } + for _, stmt := range node.Statements() { + collector.collect(stmt) } case ast.KindModuleDeclaration: - mod := node.AsModuleDeclaration() - if !ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) && mod.Body != nil && ast.IsModuleBlock(mod.Body) { - modBlock := mod.Body.AsModuleBlock() - for _, stmt := range modBlock.Statements.Nodes { + if body := node.Body(); !ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) && body != nil && ast.IsModuleBlock(body) { + for _, stmt := range body.Statements() { collector.collect(stmt) } } @@ -885,14 +867,11 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N if ast.IsPropertyDeclaration(member) { collector.collect(member.Initializer()) } else if ast.IsConstructorDeclaration(member) { - ctor := member.AsConstructorDeclaration() - if ctor.Body != nil { - if ctor.Parameters != nil { - for _, param := range ctor.Parameters.Nodes { - collector.collect(param) - } + if body := member.Body(); body != nil { + for _, param := range member.Parameters() { + collector.collect(param) } - collector.collect(ctor.Body) + collector.collect(body) } } else if ast.IsClassStaticBlockDeclaration(member) { collector.collect(member) From c11a9373c7dc8f7e156d95311fee31e67e0b5dcb Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:20:44 -0800 Subject: [PATCH 12/20] Simplify --- internal/ls/callhierarchy.go | 38 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 79ae49f783..f6ba42b801 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -831,10 +831,8 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor: impl := findImplementation(c, node) if impl != nil { - if impl.Parameters() != nil { - for _, param := range impl.Parameters() { - collector.collect(param) - } + for _, param := range impl.Parameters() { + collector.collect(param) } collector.collect(impl.Body()) } @@ -854,28 +852,24 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N } // Collect from members - members := node.Members() - - if members != nil { - for _, member := range members { - if ast.CanHaveModifiers(member) && member.Modifiers() != nil { - for _, mod := range member.Modifiers().Nodes { - collector.collect(mod) - } + for _, member := range node.Members() { + if ast.CanHaveModifiers(member) && member.Modifiers() != nil { + for _, mod := range member.Modifiers().Nodes { + collector.collect(mod) } + } - if ast.IsPropertyDeclaration(member) { - collector.collect(member.Initializer()) - } else if ast.IsConstructorDeclaration(member) { - if body := member.Body(); body != nil { - for _, param := range member.Parameters() { - collector.collect(param) - } - collector.collect(body) + if ast.IsPropertyDeclaration(member) { + collector.collect(member.Initializer()) + } else if ast.IsConstructorDeclaration(member) { + if body := member.Body(); body != nil { + for _, param := range member.Parameters() { + collector.collect(param) } - } else if ast.IsClassStaticBlockDeclaration(member) { - collector.collect(member) + collector.collect(body) } + } else if ast.IsClassStaticBlockDeclaration(member) { + collector.collect(member) } } From e96e1200e4b0c872475cbe7e782389dfbd2479c7 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 28 Nov 2025 08:36:57 -0800 Subject: [PATCH 13/20] todo --- internal/ls/symbols.go | 2 +- ...llExpressionByConstNamedFunctionExpression.callHierarchy.txt | 2 +- ...ressionByConstNamedFunctionExpression.callHierarchy.txt.diff | 2 +- .../fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt | 2 +- .../callHierarchy/callHierarchyFile.callHierarchy.txt.diff | 2 +- .../callHierarchyInterfaceMethod.callHierarchy.txt | 2 +- .../callHierarchyInterfaceMethod.callHierarchy.txt.diff | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/ls/symbols.go b/internal/ls/symbols.go index 83acc57e0f..5ca7d20d5c 100644 --- a/internal/ls/symbols.go +++ b/internal/ls/symbols.go @@ -358,7 +358,7 @@ func getSymbolKindFromNode(node *ast.Node) lsproto.SymbolKind { if ast.IsExternalModule(node.AsSourceFile()) { return lsproto.SymbolKindModule } - return lsproto.SymbolKindVariable // SymbolKindFile? + return lsproto.SymbolKindFile case ast.KindModuleDeclaration: return lsproto.SymbolKindModule case ast.KindClassDeclaration, ast.KindClassExpression: diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt index e313e6bdc4..bfa14daf2e 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt @@ -43,7 +43,7 @@ │ ╰ ╰ │ ╭ from: │ │ ╭ name: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts -│ │ ├ kind: variable +│ │ ├ kind: file │ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts │ │ ├ span: │ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-12:6 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff index b5ba13a5c1..db8d51084d 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff @@ -5,7 +5,7 @@ │ ╭ from: │ │ ╭ name: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts -│ │ ├ kind: script -+│ │ ├ kind: variable ++│ │ ├ kind: file │ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts │ │ ├ span: │ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-12:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt index 241644d516..be23e82ae3 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt @@ -17,7 +17,7 @@ ├ incoming: │ ╭ from: │ │ ╭ name: /callHierarchyFile.ts -│ │ ├ kind: variable +│ │ ├ kind: file │ │ ├ file: /callHierarchyFile.ts │ │ ├ span: │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff index 3cf4a3ed11..4efb8d8acd 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff @@ -5,7 +5,7 @@ │ ╭ from: │ │ ╭ name: /callHierarchyFile.ts -│ │ ├ kind: script -+│ │ ├ kind: variable ++│ │ ├ kind: file │ │ ├ file: /callHierarchyFile.ts │ │ ├ span: │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt index 121271cf6d..4cdbb8c53b 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt @@ -15,7 +15,7 @@ ├ incoming: │ ╭ from: │ │ ╭ name: /callHierarchyInterfaceMethod.ts -│ │ ├ kind: variable +│ │ ├ kind: file │ │ ├ file: /callHierarchyInterfaceMethod.ts │ │ ├ span: │ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-7:11 diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff index d0c9e4aa07..996489c97f 100644 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff +++ b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff @@ -5,7 +5,7 @@ │ ╭ from: │ │ ╭ name: /callHierarchyInterfaceMethod.ts -│ │ ├ kind: script -+│ │ ├ kind: variable ++│ │ ├ kind: file │ │ ├ file: /callHierarchyInterfaceMethod.ts │ │ ├ span: │ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-7:11 \ No newline at end of file From 771f2363a796fcf55cb760d3ad528eaa6a03b7b2 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:18:10 -0800 Subject: [PATCH 14/20] porting diff --- internal/ls/callhierarchy.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index f6ba42b801..f38ea4ccab 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -46,6 +46,10 @@ func isAssignedExpression(node *ast.Node) bool { if !(ast.IsFunctionExpression(node) || ast.IsArrowFunction(node) || ast.IsClassExpression(node)) { return false } + // The expression must not have a name (otherwise it would be a NamedExpression) + if node.Name() != nil { + return false + } parent := node.Parent if !isVariableLike(parent) { return false @@ -310,10 +314,7 @@ func findImplementation(c *checker.Checker, node *ast.Node) *ast.Node { // For constructors, find the first constructor with a body if ast.IsConstructorDeclaration(node) { - ctor := ast.GetFirstConstructorWithBody(node.Parent) - if ctor != nil { - return ctor - } + return ast.GetFirstConstructorWithBody(node.Parent) } // For function or method declarations, look for the implementation in the symbol @@ -506,7 +507,7 @@ func (l *LanguageService) createCallHierarchyItem(program *compiler.Program, nod kind := getSymbolKindFromNode(node) - fullStart := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) + fullStart := scanner.SkipTriviaEx(sourceFile.Text(), node.Pos(), &scanner.SkipTriviaOptions{StopAtComments: true}) script := l.getScript(sourceFile.FileName()) span := l.converters.ToLSPRange(script, core.NewTextRange(fullStart, node.End())) selectionSpan := l.converters.ToLSPRange(script, core.NewTextRange(namePos, nameEnd)) @@ -658,7 +659,7 @@ func (c *callSiteCollector) recordCallSite(node *ast.Node) { switch { case ast.IsTaggedTemplateExpression(node): - target = node.Expression() + target = node.AsTaggedTemplateExpression().Tag case ast.IsJsxOpeningElement(node): target = node.TagName() case ast.IsJsxSelfClosingElement(node): @@ -771,8 +772,9 @@ func (c *callSiteCollector) collect(node *ast.Node) { case ast.KindTaggedTemplateExpression: // do not descend into the type arguments of a tagged template expression c.recordCallSite(node) - c.collect(node.Expression()) - c.collect(node.Body()) + taggedTemplate := node.AsTaggedTemplateExpression() + c.collect(taggedTemplate.Tag) + c.collect(taggedTemplate.Template) return case ast.KindJsxOpeningElement, ast.KindJsxSelfClosingElement: // do not descend into the type arguments of a JsxOpeningLikeElement From 5fc1c1510aee75dfcddfa719eebd3339dab96c0e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:37:45 -0800 Subject: [PATCH 15/20] Add an assert from the original code --- internal/ls/callhierarchy.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index f38ea4ccab..31818fbb39 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -878,6 +878,9 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N case ast.KindClassStaticBlockDeclaration: staticBlock := node.AsClassStaticBlockDeclaration() collector.collect(staticBlock.Body) + + default: + debug.AssertNever(node) } return collector.callSites From 3d2b97e4ea3c8d3523137d6a0c23f77f06650b9d Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:40:39 -0800 Subject: [PATCH 16/20] use actual printer --- internal/ls/callhierarchy.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 31818fbb39..54513ffc9f 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -13,6 +13,7 @@ import ( "github.com/microsoft/typescript-go/internal/debug" "github.com/microsoft/typescript-go/internal/ls/lsconv" "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/scanner" ) @@ -228,9 +229,14 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s } } - // Last resort: use a generic name + // Last resort: print the node on a single line without comments if text == "" { - text = "(anonymous)" + sourceFile := ast.GetSourceFileOfNode(node) + writer, putWriter := printer.GetSingleLineStringWriter() + defer putWriter() + p := printer.NewPrinter(printer.PrinterOptions{RemoveComments: true}, printer.PrintHandlers{}, nil) + p.Write(node, sourceFile, writer, nil) + text = writer.String() } // Use getStart() behavior (skip trivia) for selection span From 1ad31284b9d6088db8392a1f74d697a449b4fb82 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:45:58 -0800 Subject: [PATCH 17/20] Correct comments --- internal/ls/callhierarchy.go | 90 ++++++++---------------------------- 1 file changed, 20 insertions(+), 70 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 54513ffc9f..643f3777f8 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -19,7 +19,7 @@ import ( type CallHierarchyDeclaration = *ast.Node -// Indicates whether a node is named function or class expression. +// Indictates whether a node is named function or class expression. func isNamedExpression(node *ast.Node) bool { if node == nil { return false @@ -27,7 +27,6 @@ func isNamedExpression(node *ast.Node) bool { if !ast.IsFunctionExpression(node) && !ast.IsClassExpression(node) { return false } - // Check if it has a name name := node.Name() return name != nil && ast.IsIdentifier(name) } @@ -47,7 +46,6 @@ func isAssignedExpression(node *ast.Node) bool { if !(ast.IsFunctionExpression(node) || ast.IsArrowFunction(node) || ast.IsClassExpression(node)) { return false } - // The expression must not have a name (otherwise it would be a NamedExpression) if node.Name() != nil { return false } @@ -56,18 +54,15 @@ func isAssignedExpression(node *ast.Node) bool { return false } - // Check if it's the initializer: node === node.parent.initializer if parent.Initializer() != node { return false } - // Check if the name is an identifier: isIdentifier(node.parent.name) name := parent.Name() if !ast.IsIdentifier(name) { return false } - // (!!(getCombinedNodeFlags(node.parent) & NodeFlags.Const) || isPropertyDeclaration(node.parent)) return (ast.GetCombinedNodeFlags(parent)&ast.NodeFlagsConst) != 0 || ast.IsPropertyDeclaration(parent) } @@ -128,7 +123,6 @@ func getCallHierarchyDeclarationReferenceNode(node *ast.Node) *ast.Node { return node } - // Check if node has a Name() method and it returns non-nil if name := node.Name(); name != nil { return name } @@ -137,7 +131,6 @@ func getCallHierarchyDeclarationReferenceNode(node *ast.Node) *ast.Node { return node.Parent.Name() } - // Find default modifier if modifiers := node.Modifiers(); modifiers != nil { for _, mod := range modifiers.Nodes { if mod.Kind == ast.KindDefaultKeyword { @@ -169,7 +162,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s return sourceFile.FileName(), 0, 0 } - // Check for unnamed function or class declaration with default modifier if (ast.IsFunctionDeclaration(node) || ast.IsClassDeclaration(node)) && node.Name() == nil { if modifiers := node.Modifiers(); modifiers != nil { for _, mod := range modifiers.Nodes { @@ -182,7 +174,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s } } - // Class static block if ast.IsClassStaticBlockDeclaration(node) { sourceFile := ast.GetSourceFileOfNode(node) pos := scanner.SkipTrivia(sourceFile.Text(), moveRangePastModifiers(node).Pos()) @@ -197,7 +188,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s return prefix + "static {}", pos, end } - // Get the declaration name var declName *ast.Node if isAssignedExpression(node) { declName = node.Parent.Name() @@ -207,7 +197,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s debug.AssertIsDefined(declName, "Expected call hierarchy item to have a name") - // Get text from the name if ast.IsIdentifier(declName) { text = declName.Text() } else if ast.IsStringOrNumericLiteralLike(declName) { @@ -219,7 +208,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s } } - // Try to get text from symbol if undefined if text == "" { c, done := program.GetTypeCheckerForFile(context.Background(), ast.GetSourceFileOfNode(node)) defer done() @@ -229,7 +217,7 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s } } - // Last resort: print the node on a single line without comments + // get the text from printing the node on a single line without comments... if text == "" { sourceFile := ast.GetSourceFileOfNode(node) writer, putWriter := printer.GetSingleLineStringWriter() @@ -239,7 +227,6 @@ func getCallHierarchyItemName(program *compiler.Program, node *ast.Node) (text s text = writer.String() } - // Use getStart() behavior (skip trivia) for selection span sourceFile := ast.GetSourceFileOfNode(node) namePos := scanner.SkipTrivia(sourceFile.Text(), declName.Pos()) @@ -260,7 +247,6 @@ func getCallHierarchyItemContainerName(node *ast.Node) string { } } } - // Check for module block if ast.IsModuleBlock(parent.Parent.Parent.Parent) { modParent := parent.Parent.Parent.Parent.Parent if ast.IsModuleDeclaration(modParent) { @@ -313,17 +299,14 @@ func findImplementation(c *checker.Checker, node *ast.Node) *ast.Node { return node } - // If it has a body, it's already the implementation if node.Body() != nil { return node } - // For constructors, find the first constructor with a body if ast.IsConstructorDeclaration(node) { return ast.GetFirstConstructorWithBody(node.Parent) } - // For function or method declarations, look for the implementation in the symbol if ast.IsFunctionDeclaration(node) || ast.IsMethodDeclaration(node) { symbol := getSymbolOfCallHierarchyDeclaration(c, node) if symbol != nil && symbol.ValueDeclaration != nil { @@ -347,13 +330,11 @@ func findAllInitialDeclarations(c *checker.Checker, node *ast.Node) []*ast.Node return nil } - // Sort declarations by file and position type declKey struct { file string pos int } - // Create indices for declarations indices := make([]int, len(symbol.Declarations)) for i := range indices { indices[i] = i @@ -379,7 +360,6 @@ func findAllInitialDeclarations(c *checker.Checker, node *ast.Node) []*ast.Node for _, i := range indices { decl := symbol.Declarations[i] if isValidCallHierarchyDeclaration(decl) { - // Only add if it's not adjacent to the last declaration if lastDecl == nil || lastDecl.Parent != decl.Parent || lastDecl.End() != decl.Pos() { declarations = append(declarations, decl) } @@ -413,21 +393,21 @@ func findImplementationOrAllInitialDeclarations(c *checker.Checker, node *ast.No } // Resolves the call hierarchy declaration for a node. -// -// A call hierarchy item must refer to either a SourceFile, Module Declaration, Class Static Block, or something intrinsically callable that has a name: -// - Class Declarations -// - Class Expressions (with a name) -// - Function Declarations -// - Function Expressions (with a name or assigned to a const variable) -// - Arrow Functions (assigned to a const variable) -// - Constructors -// - Class `static {}` initializer blocks -// - Methods -// - Accessors -// -// If a call is contained in a non-named callable Node (function expression, arrow function, etc.), then -// its containing `CallHierarchyItem` is a containing function or SourceFile that matches the above list. func resolveCallHierarchyDeclaration(program *compiler.Program, location *ast.Node) (result any) { + // A call hierarchy item must refer to either a SourceFile, Module Declaration, Class Static Block, or something intrinsically callable that has a name: + // - Class Declarations + // - Class Expressions (with a name) + // - Function Declarations + // - Function Expressions (with a name or assigned to a const variable) + // - Arrow Functions (assigned to a const variable) + // - Constructors + // - Class `static {}` initializer blocks + // - Methods + // - Accessors + // + // If a call is contained in a non-named callable Node (function expression, arrow function, etc.), then + // its containing `CallHierarchyItem` is a containing function or SourceFile that matches the above list. + c, done := program.GetTypeChecker(context.Background()) defer done() @@ -471,20 +451,18 @@ func resolveCallHierarchyDeclaration(program *compiler.Program, location *ast.No return nil } - // Check for static keyword in class static block if location.Kind == ast.KindStaticKeyword && ast.IsClassStaticBlockDeclaration(location.Parent) { location = location.Parent continue } - // Variable declaration with assigned expression + // #39453 if ast.IsVariableDeclaration(location) { if initializer := location.Initializer(); initializer != nil && isAssignedExpression(initializer) { return initializer } } - // Follow symbol if we haven't already if !followingSymbol { symbol := c.GetSymbolAtLocation(location) if symbol != nil { @@ -536,7 +514,7 @@ func (l *LanguageService) createCallHierarchyItem(program *compiler.Program, nod type callSite struct { declaration *ast.Node textRange core.TextRange - sourceFile *ast.Node // The source file containing the call site + sourceFile *ast.Node } func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *callSite { @@ -575,12 +553,10 @@ func getCallSiteGroupKey(site *callSite) ast.NodeId { func (l *LanguageService) convertCallSiteGroupToIncomingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyIncomingCall { fromRanges := make([]lsproto.Range, len(entries)) for i, entry := range entries { - // Get source file where the call site is located script := l.getScript(entry.sourceFile.AsSourceFile().FileName()) fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) } - // Sort fromRanges for consistent ordering slices.SortFunc(fromRanges, func(a, b lsproto.Range) int { return lsproto.CompareRanges(&a, &b) }) @@ -603,18 +579,15 @@ func (l *LanguageService) getIncomingCalls(ctx context.Context, program *compile return nil } - // Find all references using getReferencedSymbolsForNode sourceFiles := program.GetSourceFiles() options := refOptions{use: referenceUseReferences} symbolsAndEntries := l.getReferencedSymbolsForNode(ctx, 0, location, program, sourceFiles, options, nil) - // Flatten to get all reference entries var refEntries []*ReferenceEntry for _, symbolAndEntry := range symbolsAndEntries { refEntries = append(refEntries, symbolAndEntry.references...) } - // Convert to call sites var callSites []*callSite for _, entry := range refEntries { if site := convertEntryToCallSite(program, entry); site != nil { @@ -626,26 +599,21 @@ func (l *LanguageService) getIncomingCalls(ctx context.Context, program *compile return nil } - // Group by declaration grouped := make(map[ast.NodeId][]*callSite) for _, site := range callSites { key := getCallSiteGroupKey(site) grouped[key] = append(grouped[key], site) } - // Convert groups to incoming calls var result []*lsproto.CallHierarchyIncomingCall for _, sites := range grouped { result = append(result, l.convertCallSiteGroupToIncomingCall(program, sites)) } - // Sort result by file first, then position for deterministic order slices.SortFunc(result, func(a, b *lsproto.CallHierarchyIncomingCall) int { - // Compare by file URI first if uriComp := strings.Compare(string(a.From.Uri), string(b.From.Uri)); uriComp != 0 { return uriComp } - // Then compare by first fromRange if len(a.FromRanges) == 0 || len(b.FromRanges) == 0 { return 0 } @@ -691,12 +659,10 @@ func (c *callSiteCollector) recordCallSite(node *ast.Node) { return } - // Skip trivia to get the actual start position (equivalent to getStart()) sourceFile := ast.GetSourceFileOfNode(target) start := scanner.SkipTrivia(sourceFile.Text(), target.Pos()) textRange := core.NewTextRange(start, target.End()) - // Handle both single node and array of nodes switch decl := declaration.(type) { case *ast.Node: c.callSites = append(c.callSites, &callSite{ @@ -720,15 +686,14 @@ func (c *callSiteCollector) collect(node *ast.Node) { return } - // Do not descend into ambient nodes + // do not descend into ambient nodes. if (node.Flags & ast.NodeFlagsAmbient) != 0 { return } - // Do not descend into other call site declarations, except class member names + // do not descend into other call site declarations, other than class member names if isValidCallHierarchyDeclaration(node) { if ast.IsClassLike(node) { - // Collect from computed property names for _, member := range node.Members() { if member.Name() != nil && ast.IsComputedPropertyName(member.Name()) { c.collect(member.Name().Expression()) @@ -846,20 +811,17 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N } case ast.KindClassDeclaration, ast.KindClassExpression: - // Collect from modifiers if modifiers := node.Modifiers(); modifiers != nil { for _, mod := range modifiers.Nodes { collector.collect(mod) } } - // Collect from heritage heritage := ast.GetClassExtendsHeritageElement(node) if heritage != nil { collector.collect(heritage.Expression()) } - // Collect from members for _, member := range node.Members() { if ast.CanHaveModifiers(member) && member.Modifiers() != nil { for _, mod := range member.Modifiers().Nodes { @@ -895,12 +857,10 @@ func collectCallSites(program *compiler.Program, c *checker.Checker, node *ast.N func (l *LanguageService) convertCallSiteGroupToOutgoingCall(program *compiler.Program, entries []*callSite) *lsproto.CallHierarchyOutgoingCall { fromRanges := make([]lsproto.Range, len(entries)) for i, entry := range entries { - // Get source file where the call site is located script := l.getScript(entry.sourceFile.AsSourceFile().FileName()) fromRanges[i] = l.converters.ToLSPRange(script, entry.textRange) } - // Sort fromRanges for consistent ordering slices.SortFunc(fromRanges, func(a, b lsproto.Range) int { return lsproto.CompareRanges(&a, &b) }) @@ -926,26 +886,21 @@ func (l *LanguageService) getOutgoingCalls(program *compiler.Program, declaratio return nil } - // Group by declaration grouped := make(map[ast.NodeId][]*callSite) for _, site := range callSites { key := getCallSiteGroupKey(site) grouped[key] = append(grouped[key], site) } - // Convert groups to outgoing calls var result []*lsproto.CallHierarchyOutgoingCall for _, sites := range grouped { result = append(result, l.convertCallSiteGroupToOutgoingCall(program, sites)) } - // Sort result by file first, then position for deterministic order slices.SortFunc(result, func(a, b *lsproto.CallHierarchyOutgoingCall) int { - // Compare by file URI first if uriComp := strings.Compare(string(a.To.Uri), string(b.To.Uri)); uriComp != 0 { return uriComp } - // Then compare by first fromRange if len(a.FromRanges) == 0 || len(b.FromRanges) == 0 { return 0 } @@ -972,7 +927,6 @@ func (l *LanguageService) ProvidePrepareCallHierarchy( return nil, nil } - // Handle both single node and array of nodes switch decl := declaration.(type) { case *ast.Node: return []*lsproto.CallHierarchyItem{l.createCallHierarchyItem(program, decl)}, nil @@ -998,7 +952,6 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( return nil, nil } - // Get the node at the selection range pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) var node *ast.Node if pos == 0 { @@ -1016,7 +969,6 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( return nil, nil } - // Get the first declaration (or the single one) var decl *ast.Node switch d := declaration.(type) { case *ast.Node: @@ -1045,7 +997,6 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( return nil, nil } - // Get the node at the selection range pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) var node *ast.Node if pos == 0 { @@ -1063,7 +1014,6 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( return nil, nil } - // Get the first declaration (or the single one) var decl *ast.Node switch d := declaration.(type) { case *ast.Node: From af1f5132c0a5f48a5a227ec7a452234813647954 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:00:30 -0800 Subject: [PATCH 18/20] Shift response type into provider where it should be --- internal/ls/callhierarchy.go | 49 ++++++++++++++++++++++-------------- internal/lsp/server.go | 29 +++------------------ 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 643f3777f8..6e575943c5 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -914,42 +914,45 @@ func (l *LanguageService) ProvidePrepareCallHierarchy( ctx context.Context, documentURI lsproto.DocumentUri, position lsproto.Position, -) ([]*lsproto.CallHierarchyItem, error) { +) (lsproto.CallHierarchyPrepareResponse, error) { program, file := l.getProgramAndFile(documentURI) node := astnav.GetTouchingPropertyName(file, int(l.converters.LineAndCharacterToPosition(file, position))) if node.Kind == ast.KindSourceFile { - return nil, nil + return lsproto.CallHierarchyItemsOrNull{}, nil } declaration := resolveCallHierarchyDeclaration(program, node) if declaration == nil { - return nil, nil + return lsproto.CallHierarchyItemsOrNull{}, nil } + var items []*lsproto.CallHierarchyItem switch decl := declaration.(type) { case *ast.Node: - return []*lsproto.CallHierarchyItem{l.createCallHierarchyItem(program, decl)}, nil + items = []*lsproto.CallHierarchyItem{l.createCallHierarchyItem(program, decl)} case []*ast.Node: - items := make([]*lsproto.CallHierarchyItem, len(decl)) + items = make([]*lsproto.CallHierarchyItem, len(decl)) for i, d := range decl { items[i] = l.createCallHierarchyItem(program, d) } - return items, nil } - return nil, nil + if items == nil { + return lsproto.CallHierarchyItemsOrNull{}, nil + } + return lsproto.CallHierarchyItemsOrNull{CallHierarchyItems: &items}, nil } func (l *LanguageService) ProvideCallHierarchyIncomingCalls( ctx context.Context, item *lsproto.CallHierarchyItem, -) ([]*lsproto.CallHierarchyIncomingCall, error) { +) (lsproto.CallHierarchyIncomingCallsResponse, error) { program := l.GetProgram() fileName := item.Uri.FileName() file := program.GetSourceFile(fileName) if file == nil { - return nil, nil + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil } pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) @@ -961,12 +964,12 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( } if node == nil { - return nil, nil + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil } declaration := resolveCallHierarchyDeclaration(program, node) if declaration == nil { - return nil, nil + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil } var decl *ast.Node @@ -980,21 +983,25 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( } if decl == nil { - return nil, nil + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil } - return l.getIncomingCalls(ctx, program, decl), nil + calls := l.getIncomingCalls(ctx, program, decl) + if calls == nil { + return lsproto.CallHierarchyIncomingCallsOrNull{}, nil + } + return lsproto.CallHierarchyIncomingCallsOrNull{CallHierarchyIncomingCalls: &calls}, nil } func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( ctx context.Context, item *lsproto.CallHierarchyItem, -) ([]*lsproto.CallHierarchyOutgoingCall, error) { +) (lsproto.CallHierarchyOutgoingCallsResponse, error) { program := l.GetProgram() fileName := item.Uri.FileName() file := program.GetSourceFile(fileName) if file == nil { - return nil, nil + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil } pos := int(l.converters.LineAndCharacterToPosition(file, item.SelectionRange.Start)) @@ -1006,12 +1013,12 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( } if node == nil { - return nil, nil + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil } declaration := resolveCallHierarchyDeclaration(program, node) if declaration == nil { - return nil, nil + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil } var decl *ast.Node @@ -1025,8 +1032,12 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( } if decl == nil { - return nil, nil + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil } - return l.getOutgoingCalls(program, decl), nil + calls := l.getOutgoingCalls(program, decl) + if calls == nil { + return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil + } + return lsproto.CallHierarchyOutgoingCallsOrNull{CallHierarchyOutgoingCalls: &calls}, nil } diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 2884842211..3b078bda03 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -1297,14 +1297,7 @@ func (s *Server) handlePrepareCallHierarchy( languageService *ls.LanguageService, params *lsproto.CallHierarchyPrepareParams, ) (lsproto.CallHierarchyPrepareResponse, error) { - items, err := languageService.ProvidePrepareCallHierarchy(ctx, params.TextDocument.Uri, params.Position) - if err != nil { - return lsproto.CallHierarchyItemsOrNull{}, err - } - if items == nil { - return lsproto.CallHierarchyItemsOrNull{}, nil - } - return lsproto.CallHierarchyItemsOrNull{CallHierarchyItems: &items}, nil + return languageService.ProvidePrepareCallHierarchy(ctx, params.TextDocument.Uri, params.Position) } func (s *Server) handleCallHierarchyIncomingCalls( @@ -1316,15 +1309,7 @@ func (s *Server) handleCallHierarchyIncomingCalls( if err != nil { return lsproto.CallHierarchyIncomingCallsOrNull{}, err } - - calls, err := languageService.ProvideCallHierarchyIncomingCalls(ctx, params.Item) - if err != nil { - return lsproto.CallHierarchyIncomingCallsOrNull{}, err - } - if calls == nil { - return lsproto.CallHierarchyIncomingCallsOrNull{}, nil - } - return lsproto.CallHierarchyIncomingCallsOrNull{CallHierarchyIncomingCalls: &calls}, nil + return languageService.ProvideCallHierarchyIncomingCalls(ctx, params.Item) } func (s *Server) handleCallHierarchyOutgoingCalls( @@ -1336,15 +1321,7 @@ func (s *Server) handleCallHierarchyOutgoingCalls( if err != nil { return lsproto.CallHierarchyOutgoingCallsOrNull{}, err } - - calls, err := languageService.ProvideCallHierarchyOutgoingCalls(ctx, params.Item) - if err != nil { - return lsproto.CallHierarchyOutgoingCallsOrNull{}, err - } - if calls == nil { - return lsproto.CallHierarchyOutgoingCallsOrNull{}, nil - } - return lsproto.CallHierarchyOutgoingCallsOrNull{CallHierarchyOutgoingCalls: &calls}, nil + return languageService.ProvideCallHierarchyOutgoingCalls(ctx, params.Item) } func (s *Server) Log(msg ...any) { From c977a846c7f0691c9e12a6d158882b4ee4f118c4 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:25:31 -0800 Subject: [PATCH 19/20] minor fixes --- internal/ls/callhierarchy.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/ls/callhierarchy.go b/internal/ls/callhierarchy.go index 6e575943c5..766d0eb64f 100644 --- a/internal/ls/callhierarchy.go +++ b/internal/ls/callhierarchy.go @@ -517,7 +517,7 @@ type callSite struct { sourceFile *ast.Node } -func convertEntryToCallSite(program *compiler.Program, entry *ReferenceEntry) *callSite { +func convertEntryToCallSite(entry *ReferenceEntry) *callSite { if entry.kind != entryKindNode { return nil } @@ -590,7 +590,7 @@ func (l *LanguageService) getIncomingCalls(ctx context.Context, program *compile var callSites []*callSite for _, entry := range refEntries { - if site := convertEntryToCallSite(program, entry); site != nil { + if site := convertEntryToCallSite(entry); site != nil { callSites = append(callSites, site) } } @@ -960,7 +960,7 @@ func (l *LanguageService) ProvideCallHierarchyIncomingCalls( if pos == 0 { node = file.AsNode() } else { - node = astnav.GetTokenAtPosition(file, pos) + node = astnav.GetTouchingPropertyName(file, pos) } if node == nil { @@ -1009,7 +1009,7 @@ func (l *LanguageService) ProvideCallHierarchyOutgoingCalls( if pos == 0 { node = file.AsNode() } else { - node = astnav.GetTokenAtPosition(file, pos) + node = astnav.GetTouchingPropertyName(file, pos) } if node == nil { From e36d7b45c78c54a45ee1060ced5109ba683ad702 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:33:05 -0800 Subject: [PATCH 20/20] Do more diff fixups --- internal/fourslash/baselineutil.go | 3 +++ .../callHierarchyAccessor.callHierarchy.txt.diff | 10 ---------- ...onstNamedFunctionExpression.callHierarchy.txt.diff | 11 ----------- .../callHierarchyContainerName.callHierarchy.txt.diff | 11 ----------- ...ierarchyContainerNameServer.callHierarchy.txt.diff | 11 ----------- .../callHierarchyFile.callHierarchy.txt.diff | 11 ----------- ...allHierarchyInterfaceMethod.callHierarchy.txt.diff | 11 ----------- 7 files changed, 3 insertions(+), 65 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff delete mode 100644 testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff diff --git a/internal/fourslash/baselineutil.go b/internal/fourslash/baselineutil.go index 671ad22225..7f2fdf27a0 100644 --- a/internal/fourslash/baselineutil.go +++ b/internal/fourslash/baselineutil.go @@ -103,6 +103,9 @@ func (f *FourslashTest) getBaselineOptions(command baselineCommand, testPath str // Handle /server/ subdirectory - need to remove both prefixes s = strings.ReplaceAll(s, "/tests/cases/fourslash/server/", "/") s = strings.ReplaceAll(s, "/tests/cases/fourslash/", "/") + // SymbolKind enum differences between Strada and tsgo + s = strings.ReplaceAll(s, "kind: getter", "kind: property") + s = strings.ReplaceAll(s, "kind: script", "kind: file") return s }, } diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff deleted file mode 100644 index ed3c852f13..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyAccessor.callHierarchy.txt.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- old.callHierarchyAccessor.callHierarchy.txt -+++ new.callHierarchyAccessor.callHierarchy.txt -@@= skipped -0, +0 lines =@@ - // === Call Hierarchy === - ╭ name: bar --├ kind: getter -+├ kind: property - ├ containerName: C - ├ file: /callHierarchyAccessor.ts - ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff deleted file mode 100644 index db8d51084d..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt -+++ new.callHierarchyCallExpressionByConstNamedFunctionExpression.callHierarchy.txt -@@= skipped -42, +42 lines =@@ - │ ╰ ╰ - │ ╭ from: - │ │ ╭ name: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts --│ │ ├ kind: script -+│ │ ├ kind: file - │ │ ├ file: /callHierarchyCallExpressionByConstNamedFunctionExpression.ts - │ │ ├ span: - │ │ │ ╭ /callHierarchyCallExpressionByConstNamedFunctionExpression.ts:1:1-12:6 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff deleted file mode 100644 index 41f8fa8bf6..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerName.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyContainerName.callHierarchy.txt -+++ new.callHierarchyContainerName.callHierarchy.txt -@@= skipped -54, +54 lines =@@ - │ │ │ │ ├ incoming: - │ │ │ │ │ ╭ from: - │ │ │ │ │ │ ╭ name: sameName --│ │ │ │ │ │ ├ kind: getter -+│ │ │ │ │ │ ├ kind: property - │ │ │ │ │ │ ├ containerName: Obj - │ │ │ │ │ │ ├ file: /callHierarchyContainerName.ts - │ │ │ │ │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff deleted file mode 100644 index 1620ec4b41..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyContainerNameServer.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyContainerNameServer.callHierarchy.txt -+++ new.callHierarchyContainerNameServer.callHierarchy.txt -@@= skipped -54, +54 lines =@@ - │ │ │ │ ├ incoming: - │ │ │ │ │ ╭ from: - │ │ │ │ │ │ ╭ name: sameName --│ │ │ │ │ │ ├ kind: getter -+│ │ │ │ │ │ ├ kind: property - │ │ │ │ │ │ ├ containerName: Obj - │ │ │ │ │ │ ├ file: /callHierarchyContainerNameServer.ts - │ │ │ │ │ │ ├ span: \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff deleted file mode 100644 index 4efb8d8acd..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyFile.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyFile.callHierarchy.txt -+++ new.callHierarchyFile.callHierarchy.txt -@@= skipped -16, +16 lines =@@ - ├ incoming: - │ ╭ from: - │ │ ╭ name: /callHierarchyFile.ts --│ │ ├ kind: script -+│ │ ├ kind: file - │ │ ├ file: /callHierarchyFile.ts - │ │ ├ span: - │ │ │ ╭ /callHierarchyFile.ts:1:1-3:2 \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff b/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff deleted file mode 100644 index 996489c97f..0000000000 --- a/testdata/baselines/reference/submodule/fourslash/callHierarchy/callHierarchyInterfaceMethod.callHierarchy.txt.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.callHierarchyInterfaceMethod.callHierarchy.txt -+++ new.callHierarchyInterfaceMethod.callHierarchy.txt -@@= skipped -14, +14 lines =@@ - ├ incoming: - │ ╭ from: - │ │ ╭ name: /callHierarchyInterfaceMethod.ts --│ │ ├ kind: script -+│ │ ├ kind: file - │ │ ├ file: /callHierarchyInterfaceMethod.ts - │ │ ├ span: - │ │ │ ╭ /callHierarchyInterfaceMethod.ts:1:1-7:11 \ No newline at end of file