Skip to content

Fix signature help crash on parenthesized call expressions #1418

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions internal/ls/signaturehelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
57 changes: 56 additions & 1 deletion internal/ls/signaturehelp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1006,16 +1006,71 @@ f</*1*/>(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()
Expand Down