Skip to content

Commit 00e99d1

Browse files
authored
Generate remaining sig help tests, fix remaining bugs (#2170)
1 parent 921184c commit 00e99d1

File tree

145 files changed

+8167
-560
lines changed

Some content is hidden

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

145 files changed

+8167
-560
lines changed

internal/fourslash/_scripts/convertFourslash.mts

Lines changed: 502 additions & 0 deletions
Large diffs are not rendered by default.

internal/fourslash/_scripts/failingTests.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,17 @@ TestAutoImportTypeOnlyPreferred2
4343
TestAutoImportVerbatimTypeOnly1
4444
TestBestCommonTypeObjectLiterals
4545
TestBestCommonTypeObjectLiterals1
46+
TestCalledUnionsOfDissimilarTyeshaveGoodDisplay
4647
TestCodeCompletionEscaping
4748
TestCommentsEnumsFourslash
49+
TestCommentsExternalModulesFourslash
50+
TestCommentsImportDeclaration
51+
TestCommentsInheritanceFourslash
52+
TestCommentsInterfaceFourslash
4853
TestCommentsLinePreservation
54+
TestCommentsOverloadsFourslash
4955
TestCommentsUnion
56+
TestCommentsVariables
5057
TestCompletionAfterQuestionDot
5158
TestCompletionAutoInsertQuestionDot
5259
TestCompletionCloneQuestionToken
@@ -227,6 +234,7 @@ TestCompletionWithConditionalOperatorMissingColon
227234
TestConstEnumQuickInfoAndCompletionList
228235
TestConstQuickInfoAndCompletionList
229236
TestContextuallyTypedFunctionExpressionGeneric1
237+
TestCrossFileQuickInfoExportedTypeDoesNotUseImportType
230238
TestDoubleUnderscoreCompletions
231239
TestEditJsdocType
232240
TestExportDefaultClass
@@ -331,7 +339,6 @@ TestJsdocCallbackTag
331339
TestJsDocExtends
332340
TestJsDocFunctionSignatures10
333341
TestJsDocFunctionSignatures11
334-
TestJsDocFunctionSignatures12
335342
TestJsDocFunctionSignatures13
336343
TestJsDocFunctionSignatures7
337344
TestJsDocFunctionSignatures8
@@ -428,11 +435,13 @@ TestPathCompletionsTypesVersionsWildcard4
428435
TestPathCompletionsTypesVersionsWildcard5
429436
TestPathCompletionsTypesVersionsWildcard6
430437
TestProtoVarVisibleWithOuterScopeUnderscoreProto
438+
TestQualifyModuleTypeNames
431439
TestQuickInfo_notInsideComment
432440
TestQuickinfo01
433441
TestQuickInfoAlias
434442
TestQuickInfoAssertionNodeNotReusedWhenTypeNotEquivalent1
435443
TestQuickInfoBindingPatternInJsdocNoCrash1
444+
TestQuickInfoCanBeTruncated
436445
TestQuickInfoClassKeyword
437446
TestQuickInfoContextuallyTypedSignatureOptionalParameterFromIntersection1
438447
TestQuickInfoContextualTyping
@@ -541,7 +550,6 @@ TestRenameFromNodeModulesDep4
541550
TestRenamePrivateFields
542551
TestReverseMappedTypeQuickInfo
543552
TestSelfReferencedExternalModule
544-
TestSignatureHelpInferenceJsDocImportTag
545553
TestStringCompletionsImportOrExportSpecifier
546554
TestStringCompletionsVsEscaping
547555
TestSymbolCompletionLowerPriority

internal/fourslash/_scripts/manualTests.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ quickInfoForOverloadOnConst1
1313
renameDefaultKeyword
1414
renameForDefaultExport01
1515
tsxCompletion12
16+
jsDocFunctionSignatures2
17+
jsDocFunctionSignatures12

internal/fourslash/fourslash.go

Lines changed: 277 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,7 @@ func (f *FourslashTest) VerifyBaselineSignatureHelp(t *testing.T) {
15161516

15171517
params := &lsproto.SignatureHelpParams{
15181518
TextDocument: lsproto.TextDocumentIdentifier{
1519-
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
1519+
Uri: lsconv.FileNameToDocumentURI(marker.FileName()),
15201520
},
15211521
Position: marker.LSPosition,
15221522
}
@@ -1547,9 +1547,18 @@ func (f *FourslashTest) VerifyBaselineSignatureHelp(t *testing.T) {
15471547
signatureLine := sig.Label
15481548
activeParamLine := ""
15491549

1550+
// Determine active parameter: per-signature takes precedence over top-level per LSP spec
1551+
// "If provided (or `null`), this is used in place of `SignatureHelp.activeParameter`."
1552+
var activeParamPtr *lsproto.UintegerOrNull
1553+
if sig.ActiveParameter != nil {
1554+
activeParamPtr = sig.ActiveParameter
1555+
} else {
1556+
activeParamPtr = item.ActiveParameter
1557+
}
1558+
15501559
// Show active parameter if specified, and the signature text.
1551-
if item.ActiveParameter != nil && sig.Parameters != nil {
1552-
activeParamIndex := int(*item.ActiveParameter.Uinteger)
1560+
if activeParamPtr != nil && activeParamPtr.Uinteger != nil && sig.Parameters != nil {
1561+
activeParamIndex := int(*activeParamPtr.Uinteger)
15531562
if activeParamIndex >= 0 && activeParamIndex < len(*sig.Parameters) {
15541563
activeParam := (*sig.Parameters)[activeParamIndex]
15551564

@@ -2083,13 +2092,277 @@ func (f *FourslashTest) VerifyQuickInfoIs(t *testing.T, expectedText string, exp
20832092
f.verifyHoverContent(t, hover.Contents, expectedText, expectedDocumentation, f.getCurrentPositionPrefix())
20842093
}
20852094

2095+
// VerifySignatureHelpOptions contains options for verifying signature help.
2096+
// All fields are optional - only specified fields will be verified.
2097+
type VerifySignatureHelpOptions struct {
2098+
// Text is the full signature text (e.g., "fn(x: string, y: number): void")
2099+
Text string
2100+
// DocComment is the documentation comment for the signature
2101+
DocComment string
2102+
// ParameterCount is the expected number of parameters
2103+
ParameterCount int
2104+
// ParameterName is the expected name of the active parameter
2105+
ParameterName string
2106+
// ParameterSpan is the expected label of the active parameter (e.g., "x: string")
2107+
ParameterSpan string
2108+
// ParameterDocComment is the documentation for the active parameter
2109+
ParameterDocComment string
2110+
// OverloadsCount is the expected number of overloads (signatures)
2111+
OverloadsCount int
2112+
// OverrideSelectedItemIndex overrides which signature to check (default: ActiveSignature)
2113+
OverrideSelectedItemIndex int
2114+
// IsVariadic indicates if the signature has a rest parameter
2115+
IsVariadic bool
2116+
// IsVariadicSet is true when IsVariadic was explicitly set (to distinguish from default false)
2117+
IsVariadicSet bool
2118+
}
2119+
2120+
// VerifySignatureHelp verifies signature help at the current position matches the expected options.
2121+
func (f *FourslashTest) VerifySignatureHelp(t *testing.T, expected VerifySignatureHelpOptions) {
2122+
t.Helper()
2123+
prefix := f.getCurrentPositionPrefix()
2124+
params := &lsproto.SignatureHelpParams{
2125+
TextDocument: lsproto.TextDocumentIdentifier{
2126+
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
2127+
},
2128+
Position: f.currentCaretPosition,
2129+
}
2130+
result := sendRequest(t, f, lsproto.TextDocumentSignatureHelpInfo, params)
2131+
help := result.SignatureHelp
2132+
if help == nil {
2133+
t.Fatalf("%sCould not get signature help", prefix)
2134+
}
2135+
2136+
// Determine which signature to check
2137+
selectedIndex := 0
2138+
if expected.OverrideSelectedItemIndex > 0 {
2139+
selectedIndex = expected.OverrideSelectedItemIndex
2140+
} else if help.ActiveSignature != nil {
2141+
selectedIndex = int(*help.ActiveSignature)
2142+
}
2143+
2144+
if selectedIndex >= len(help.Signatures) {
2145+
t.Fatalf("%sSelected signature index %d out of range (have %d signatures)", prefix, selectedIndex, len(help.Signatures))
2146+
}
2147+
2148+
selectedSig := help.Signatures[selectedIndex]
2149+
2150+
// Verify overloads count
2151+
if expected.OverloadsCount > 0 {
2152+
if len(help.Signatures) != expected.OverloadsCount {
2153+
t.Errorf("%sExpected %d overloads, got %d", prefix, expected.OverloadsCount, len(help.Signatures))
2154+
}
2155+
}
2156+
2157+
// Verify signature text
2158+
if expected.Text != "" {
2159+
if selectedSig.Label != expected.Text {
2160+
t.Errorf("%sExpected signature text %q, got %q", prefix, expected.Text, selectedSig.Label)
2161+
}
2162+
}
2163+
2164+
// Verify doc comment
2165+
if expected.DocComment != "" {
2166+
actualDoc := ""
2167+
if selectedSig.Documentation != nil {
2168+
if selectedSig.Documentation.MarkupContent != nil {
2169+
actualDoc = selectedSig.Documentation.MarkupContent.Value
2170+
} else if selectedSig.Documentation.String != nil {
2171+
actualDoc = *selectedSig.Documentation.String
2172+
}
2173+
}
2174+
if actualDoc != expected.DocComment {
2175+
t.Errorf("%sExpected doc comment %q, got %q", prefix, expected.DocComment, actualDoc)
2176+
}
2177+
}
2178+
2179+
// Verify parameter count
2180+
if expected.ParameterCount > 0 {
2181+
paramCount := 0
2182+
if selectedSig.Parameters != nil {
2183+
paramCount = len(*selectedSig.Parameters)
2184+
}
2185+
if paramCount != expected.ParameterCount {
2186+
t.Errorf("%sExpected %d parameters, got %d", prefix, expected.ParameterCount, paramCount)
2187+
}
2188+
}
2189+
2190+
// Get active parameter
2191+
var activeParamIndex int
2192+
if selectedSig.ActiveParameter != nil && selectedSig.ActiveParameter.Uinteger != nil {
2193+
activeParamIndex = int(*selectedSig.ActiveParameter.Uinteger)
2194+
} else if help.ActiveParameter != nil && help.ActiveParameter.Uinteger != nil {
2195+
activeParamIndex = int(*help.ActiveParameter.Uinteger)
2196+
}
2197+
2198+
var activeParam *lsproto.ParameterInformation
2199+
if selectedSig.Parameters != nil && activeParamIndex < len(*selectedSig.Parameters) {
2200+
activeParam = (*selectedSig.Parameters)[activeParamIndex]
2201+
}
2202+
2203+
// Verify parameter name
2204+
if expected.ParameterName != "" {
2205+
if activeParam == nil {
2206+
t.Errorf("%sExpected parameter name %q, but no active parameter", prefix, expected.ParameterName)
2207+
} else {
2208+
// Parameter name is extracted from the label
2209+
actualName := ""
2210+
if activeParam.Label.String != nil {
2211+
// Extract name from label like "x: string" -> "x" or "T extends Foo" -> "T" or "...x: any[]" -> "x"
2212+
label := *activeParam.Label.String
2213+
// Strip leading "..." for rest parameters
2214+
label = strings.TrimPrefix(label, "...")
2215+
if name, _, found := strings.Cut(label, ":"); found {
2216+
actualName = strings.TrimSpace(name)
2217+
} else if name, _, found := strings.Cut(label, " extends "); found {
2218+
actualName = strings.TrimSpace(name)
2219+
} else {
2220+
actualName = label
2221+
}
2222+
}
2223+
if actualName != expected.ParameterName {
2224+
t.Errorf("%sExpected parameter name %q, got %q", prefix, expected.ParameterName, actualName)
2225+
}
2226+
}
2227+
}
2228+
2229+
// Verify parameter span (label)
2230+
if expected.ParameterSpan != "" {
2231+
if activeParam == nil {
2232+
t.Errorf("%sExpected parameter span %q, but no active parameter", prefix, expected.ParameterSpan)
2233+
} else {
2234+
actualSpan := ""
2235+
if activeParam.Label.String != nil {
2236+
actualSpan = *activeParam.Label.String
2237+
}
2238+
if actualSpan != expected.ParameterSpan {
2239+
t.Errorf("%sExpected parameter span %q, got %q", prefix, expected.ParameterSpan, actualSpan)
2240+
}
2241+
}
2242+
}
2243+
2244+
// Verify parameter doc comment
2245+
if expected.ParameterDocComment != "" {
2246+
if activeParam == nil {
2247+
t.Errorf("%sExpected parameter doc comment %q, but no active parameter", prefix, expected.ParameterDocComment)
2248+
} else {
2249+
actualDoc := ""
2250+
if activeParam.Documentation != nil {
2251+
if activeParam.Documentation.MarkupContent != nil {
2252+
actualDoc = activeParam.Documentation.MarkupContent.Value
2253+
} else if activeParam.Documentation.String != nil {
2254+
actualDoc = *activeParam.Documentation.String
2255+
}
2256+
}
2257+
if actualDoc != expected.ParameterDocComment {
2258+
t.Errorf("%sExpected parameter doc comment %q, got %q", prefix, expected.ParameterDocComment, actualDoc)
2259+
}
2260+
}
2261+
}
2262+
2263+
// Verify isVariadic (check if any parameter starts with "...")
2264+
if expected.IsVariadicSet {
2265+
actualIsVariadic := false
2266+
if selectedSig.Parameters != nil {
2267+
for _, param := range *selectedSig.Parameters {
2268+
if param.Label.String != nil && strings.HasPrefix(*param.Label.String, "...") {
2269+
actualIsVariadic = true
2270+
break
2271+
}
2272+
}
2273+
}
2274+
if actualIsVariadic != expected.IsVariadic {
2275+
t.Errorf("%sExpected isVariadic=%v, got %v", prefix, expected.IsVariadic, actualIsVariadic)
2276+
}
2277+
}
2278+
}
2279+
2280+
// VerifyNoSignatureHelp verifies that no signature help is available at the current position.
2281+
func (f *FourslashTest) VerifyNoSignatureHelp(t *testing.T) {
2282+
t.Helper()
2283+
prefix := f.getCurrentPositionPrefix()
2284+
params := &lsproto.SignatureHelpParams{
2285+
TextDocument: lsproto.TextDocumentIdentifier{
2286+
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
2287+
},
2288+
Position: f.currentCaretPosition,
2289+
}
2290+
result := sendRequest(t, f, lsproto.TextDocumentSignatureHelpInfo, params)
2291+
if result.SignatureHelp != nil && len(result.SignatureHelp.Signatures) > 0 {
2292+
t.Errorf("%sExpected no signature help, but got %d signatures", prefix, len(result.SignatureHelp.Signatures))
2293+
}
2294+
}
2295+
2296+
// VerifyNoSignatureHelpWithContext verifies that no signature help is available at the current position with a given context.
2297+
func (f *FourslashTest) VerifyNoSignatureHelpWithContext(t *testing.T, context *lsproto.SignatureHelpContext) {
2298+
t.Helper()
2299+
prefix := f.getCurrentPositionPrefix()
2300+
params := &lsproto.SignatureHelpParams{
2301+
TextDocument: lsproto.TextDocumentIdentifier{
2302+
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
2303+
},
2304+
Position: f.currentCaretPosition,
2305+
Context: context,
2306+
}
2307+
result := sendRequest(t, f, lsproto.TextDocumentSignatureHelpInfo, params)
2308+
if result.SignatureHelp != nil && len(result.SignatureHelp.Signatures) > 0 {
2309+
t.Errorf("%sExpected no signature help, but got %d signatures", prefix, len(result.SignatureHelp.Signatures))
2310+
}
2311+
}
2312+
2313+
// VerifyNoSignatureHelpForMarkersWithContext verifies that no signature help is available at the given markers with a given context.
2314+
func (f *FourslashTest) VerifyNoSignatureHelpForMarkersWithContext(t *testing.T, context *lsproto.SignatureHelpContext, markers ...string) {
2315+
t.Helper()
2316+
for _, marker := range markers {
2317+
f.GoToMarker(t, marker)
2318+
f.VerifyNoSignatureHelpWithContext(t, context)
2319+
}
2320+
}
2321+
2322+
// VerifySignatureHelpPresent verifies that signature help is available at the current position with a given context.
2323+
func (f *FourslashTest) VerifySignatureHelpPresent(t *testing.T, context *lsproto.SignatureHelpContext) {
2324+
t.Helper()
2325+
prefix := f.getCurrentPositionPrefix()
2326+
params := &lsproto.SignatureHelpParams{
2327+
TextDocument: lsproto.TextDocumentIdentifier{
2328+
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
2329+
},
2330+
Position: f.currentCaretPosition,
2331+
Context: context,
2332+
}
2333+
result := sendRequest(t, f, lsproto.TextDocumentSignatureHelpInfo, params)
2334+
if result.SignatureHelp == nil || len(result.SignatureHelp.Signatures) == 0 {
2335+
t.Errorf("%sExpected signature help to be present, but got none", prefix)
2336+
}
2337+
}
2338+
2339+
// VerifySignatureHelpPresentForMarkers verifies that signature help is available at the given markers with a given context.
2340+
func (f *FourslashTest) VerifySignatureHelpPresentForMarkers(t *testing.T, context *lsproto.SignatureHelpContext, markers ...string) {
2341+
t.Helper()
2342+
for _, marker := range markers {
2343+
f.GoToMarker(t, marker)
2344+
f.VerifySignatureHelpPresent(t, context)
2345+
}
2346+
}
2347+
2348+
// VerifyNoSignatureHelpForMarkers verifies that no signature help is available at the given markers.
2349+
func (f *FourslashTest) VerifyNoSignatureHelpForMarkers(t *testing.T, markers ...string) {
2350+
t.Helper()
2351+
for _, marker := range markers {
2352+
f.GoToMarker(t, marker)
2353+
f.VerifyNoSignatureHelp(t)
2354+
}
2355+
}
2356+
20862357
type SignatureHelpCase struct {
20872358
Context *lsproto.SignatureHelpContext
20882359
MarkerInput MarkerInput
20892360
Expected *lsproto.SignatureHelp
20902361
}
20912362

2092-
func (f *FourslashTest) VerifySignatureHelp(t *testing.T, signatureHelpCases ...*SignatureHelpCase) {
2363+
// VerifySignatureHelpWithCases verifies signature help using detailed SignatureHelpCase structs.
2364+
// This is useful for more complex tests that need to verify the full signature help response.
2365+
func (f *FourslashTest) VerifySignatureHelpWithCases(t *testing.T, signatureHelpCases ...*SignatureHelpCase) {
20932366
for _, option := range signatureHelpCases {
20942367
switch marker := option.MarkerInput.(type) {
20952368
case string:

0 commit comments

Comments
 (0)