From b6768eea139f8e97846421bec650032d5d702aa1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 18 Jul 2025 19:33:57 +0000 Subject: [PATCH 1/2] Initial plan From b5edc65371b9906e486ddc5221225e5dbca6769f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 18 Jul 2025 19:53:09 +0000 Subject: [PATCH 2/2] Fix signature help crash on parenthesized call with nil check Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- internal/ls/signaturehelp.go | 11 +++--- internal/ls/signaturehelp_test.go | 57 ++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/internal/ls/signaturehelp.go b/internal/ls/signaturehelp.go index 8ad8567e21..0b9c1c3d80 100644 --- a/internal/ls/signaturehelp.go +++ b/internal/ls/signaturehelp.go @@ -93,11 +93,12 @@ func (l *LanguageService) GetSignatureHelpItems( candidateInfo := getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners) // cancellationToken.throwIfCancellationRequested(); - // if (!candidateInfo) { !!! - // // We didn't have any sig help items produced by the TS compiler. If this is a JS - // // file, then see if we can figure out anything better. - // return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined; - // } + if candidateInfo == nil { + // We didn't have any sig help items produced by the TS compiler. If this is a JS + // file, then see if we can figure out anything better. + // return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined; + return nil + } // return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => if candidateInfo.candidateInfo != nil { diff --git a/internal/ls/signaturehelp_test.go b/internal/ls/signaturehelp_test.go index 36be7655de..b2240ee29c 100644 --- a/internal/ls/signaturehelp_test.go +++ b/internal/ls/signaturehelp_test.go @@ -1006,16 +1006,71 @@ f(1, 2);`, "1": {text: "eval(x: string): any", parameterCount: 1, parameterSpan: "x: string", activeParameter: &lsproto.Nullable[uint32]{Value: 0}}, }, }, + { + title: "signatureHelpParenthesizedCall", + input: `function someCall() { return 42; } +let x = (someCall()/*1*/);`, + expected: map[string]verifySignatureHelpOptions{ + // This test case should not crash but may return no signature help + }, + }, } for _, testCase := range testCases { t.Run(testCase.title, func(t *testing.T) { t.Parallel() - runSignatureHelpTest(t, testCase.input, testCase.expected) + if testCase.title == "signatureHelpParenthesizedCall" { + runSignatureHelpCrashTest(t, testCase.input) + } else { + runSignatureHelpTest(t, testCase.input, testCase.expected) + } }) } } +func runSignatureHelpCrashTest(t *testing.T, input string) { + testData := fourslash.ParseTestData(t, input, "/mainFile.ts") + file := testData.Files[0].FileName() + markerPositions := testData.MarkerPositions + ctx := projecttestutil.WithRequestID(t.Context()) + languageService, done := createLanguageService(ctx, file, map[string]string{ + file: testData.Files[0].Content, + }) + defer done() + + // Use the specific trigger parameters from the issue + context := &lsproto.SignatureHelpContext{ + TriggerKind: lsproto.SignatureHelpTriggerKindTriggerCharacter, + TriggerCharacter: ptrTo("("), + IsRetrigger: false, + } + ptrTrue := ptrTo(true) + capabilities := &lsproto.SignatureHelpClientCapabilities{ + SignatureInformation: &lsproto.ClientSignatureInformationOptions{ + ActiveParameterSupport: ptrTrue, + NoActiveParameterSupport: ptrTrue, + ParameterInformation: &lsproto.ClientSignatureParameterInformationOptions{ + LabelOffsetSupport: ptrTrue, + }, + }, + } + preferences := &ls.UserPreferences{} + + marker, ok := markerPositions["1"] + if !ok { + t.Fatal("No marker found for '1'") + } + + // This should not crash - we just want to ensure it doesn't panic + result := languageService.ProvideSignatureHelp(ctx, ls.FileNameToDocumentURI(file), marker.LSPosition, context, capabilities, preferences) + // The result might be nil, which is fine - we just don't want a crash + if result != nil { + t.Logf("Signature help result: %v", result) + } else { + t.Log("No signature help result (this is expected and OK)") + } +} + func runSignatureHelpTest(t *testing.T, input string, expected map[string]verifySignatureHelpOptions) { testData := fourslash.ParseTestData(t, input, "/mainFile.ts") file := testData.Files[0].FileName()