Skip to content

Commit 3fae7ba

Browse files
authored
Port document symbol tests + fixes (#2207)
1 parent 828e64b commit 3fae7ba

File tree

166 files changed

+4230
-72
lines changed

Some content is hidden

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

166 files changed

+4230
-72
lines changed

internal/fourslash/_scripts/convertFourslash.mts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ function parseFileContent(filename: string, content: string): GoTest | undefined
9494
goTest.commands.push(...result);
9595
}
9696
}
97+
if (goTest.commands.length === 0) {
98+
console.error(`No commands parsed in file: ${filename}`);
99+
unparsedFiles.push(filename);
100+
return undefined;
101+
}
97102
return goTest;
98103
}
99104

@@ -237,6 +242,10 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined {
237242
case "outliningSpansInCurrentFile":
238243
case "outliningHintSpansInCurrentFile":
239244
return parseOutliningSpansArgs(callExpression.arguments);
245+
case "navigationTree":
246+
return parseVerifyNavTree(callExpression.arguments);
247+
case "navigationBar":
248+
return []; // Deprecated.
240249
}
241250
}
242251
// `goTo....`
@@ -2273,6 +2282,13 @@ function parseVerifyNavigateToArg(arg: ts.Expression): string | undefined {
22732282
}`;
22742283
}
22752284

2285+
function parseVerifyNavTree(args: readonly ts.Expression[]): [VerifyNavTreeCmd] | undefined {
2286+
// Ignore arguments and use baseline tests intead.
2287+
return [{
2288+
kind: "verifyNavigationTree",
2289+
}];
2290+
}
2291+
22762292
function parseNavToItem(arg: ts.Expression): string | undefined {
22772293
let item = getNodeOfKind(arg, ts.isObjectLiteralExpression);
22782294
if (!item) {
@@ -2348,11 +2364,15 @@ function getSymbolKind(kind: ts.Expression): string | undefined {
23482364
console.error(`Expected string literal for symbol kind, got ${kind.getText()}`);
23492365
return undefined;
23502366
}
2351-
switch (result.text) {
2367+
return getSymbolKindWorker(result.text);
2368+
}
2369+
2370+
function getSymbolKindWorker(kind: string): string {
2371+
switch (kind) {
23522372
case "script":
23532373
return "SymbolKindFile";
23542374
case "module":
2355-
return "SymbolKindModule";
2375+
return "SymbolKindNamespace";
23562376
case "class":
23572377
case "local class":
23582378
return "SymbolKindClass";
@@ -2400,6 +2420,8 @@ function getSymbolKind(kind: ts.Expression): string | undefined {
24002420
return "SymbolKindModule";
24012421
case "string":
24022422
return "SymbolKindString";
2423+
case "type":
2424+
return "SymbolKindClass";
24032425
default:
24042426
return "SymbolKindVariable";
24052427
}
@@ -2567,6 +2589,10 @@ interface VerifyOutliningSpansCmd {
25672589
foldingRangeKind?: string;
25682590
}
25692591

2592+
interface VerifyNavTreeCmd {
2593+
kind: "verifyNavigationTree";
2594+
}
2595+
25702596
type Cmd =
25712597
| VerifyCompletionsCmd
25722598
| VerifyApplyCodeActionFromCompletionCmd
@@ -2587,6 +2613,7 @@ type Cmd =
25872613
| VerifyBaselineRenameCmd
25882614
| VerifyRenameInfoCmd
25892615
| VerifyNavToCmd
2616+
| VerifyNavTreeCmd
25902617
| VerifyBaselineInlayHintsCmd
25912618
| VerifyImportFixAtPositionCmd
25922619
| VerifyDiagnosticsCmd
@@ -2894,6 +2921,8 @@ function generateCmd(cmd: Cmd): string {
28942921
return generateNoSignatureHelpForTriggerReason(cmd);
28952922
case "verifyOutliningSpans":
28962923
return generateVerifyOutliningSpans(cmd);
2924+
case "verifyNavigationTree":
2925+
return `f.VerifyBaselineDocumentSymbol(t)`;
28972926
default:
28982927
let neverCommand: never = cmd;
28992928
throw new Error(`Unknown command kind: ${neverCommand as Cmd["kind"]}`);

internal/fourslash/_scripts/manualTests.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ completionListInClosedFunction05
22
completionsAtIncompleteObjectLiteralProperty
33
completionsSelfDeclaring1
44
completionsWithDeprecatedTag4
5+
navigationBarFunctionPrototype
6+
navigationBarFunctionPrototype2
7+
navigationBarFunctionPrototype3
8+
navigationBarFunctionPrototype4
9+
navigationBarFunctionPrototypeBroken
10+
navigationBarFunctionPrototypeInterlaced
11+
navigationBarFunctionPrototypeNested
12+
navigationBarJsDoc
513
navigationItemsExactMatch2
614
navigationItemsSpecialPropertyAssignment
715
navto_excludeLib1

internal/fourslash/baselineutil.go

Lines changed: 105 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const (
3535
signatureHelpCmd baselineCommand = "SignatureHelp"
3636
smartSelectionCmd baselineCommand = "Smart Selection"
3737
codeLensesCmd baselineCommand = "Code Lenses"
38+
documentSymbolsCmd baselineCommand = "Document Symbols"
3839
)
3940

4041
type baselineCommand string
@@ -71,7 +72,7 @@ func getBaselineFileName(t *testing.T, command baselineCommand) string {
7172

7273
func getBaselineExtension(command baselineCommand) string {
7374
switch command {
74-
case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd:
75+
case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd, documentSymbolsCmd:
7576
return "baseline"
7677
case callHierarchyCmd:
7778
return "callHierarchy.txt"
@@ -472,11 +473,49 @@ func (f *FourslashTest) textOfFile(fileName string) (string, bool) {
472473
return f.vfs.ReadFile(fileName)
473474
}
474475

476+
type detailKind int
477+
478+
const (
479+
detailKindMarker detailKind = iota // /*MARKER*/
480+
detailKindContextStart // <|
481+
detailKindTextStart // [|
482+
detailKindTextEnd // |]
483+
detailKindContextEnd // |>
484+
)
485+
486+
func (k detailKind) isEnd() bool {
487+
return k == detailKindContextEnd || k == detailKindTextEnd
488+
}
489+
490+
func (k detailKind) isStart() bool {
491+
return k == detailKindContextStart || k == detailKindTextStart
492+
}
493+
475494
type baselineDetail struct {
476495
pos lsproto.Position
477496
positionMarker string
478497
span *documentSpan
479-
kind string
498+
kind detailKind
499+
}
500+
501+
func (d *baselineDetail) getRange() lsproto.Range {
502+
switch d.kind {
503+
case detailKindContextStart:
504+
return *d.span.contextSpan
505+
case detailKindContextEnd:
506+
return *d.span.contextSpan
507+
case detailKindTextStart:
508+
return d.span.textSpan
509+
case detailKindTextEnd:
510+
return d.span.textSpan
511+
case detailKindMarker:
512+
return lsproto.Range{
513+
Start: d.pos,
514+
End: d.pos,
515+
}
516+
default:
517+
panic("unknown detail kind")
518+
}
480519
}
481520

482521
func (f *FourslashTest) getBaselineContentForFile(
@@ -504,7 +543,7 @@ func (f *FourslashTest) getBaselineContentForFile(
504543
pos: span.contextSpan.Start,
505544
positionMarker: "<|",
506545
span: &span,
507-
kind: "contextStart",
546+
kind: detailKindContextStart,
508547
})
509548

510549
// Check if context span starts after text span
@@ -519,16 +558,16 @@ func (f *FourslashTest) getBaselineContentForFile(
519558
startMarker += options.getLocationData(span)
520559
}
521560
details = append(details,
522-
&baselineDetail{pos: span.textSpan.Start, positionMarker: startMarker, span: &span, kind: "textStart"},
523-
&baselineDetail{pos: span.textSpan.End, positionMarker: core.OrElse(options.endMarker, "|]"), span: &span, kind: "textEnd"},
561+
&baselineDetail{pos: span.textSpan.Start, positionMarker: startMarker, span: &span, kind: detailKindTextStart},
562+
&baselineDetail{pos: span.textSpan.End, positionMarker: core.OrElse(options.endMarker, "|]"), span: &span, kind: detailKindTextEnd},
524563
)
525564

526565
if span.contextSpan != nil {
527566
details = append(details, &baselineDetail{
528567
pos: span.contextSpan.End,
529568
positionMarker: "|>",
530569
span: &span,
531-
kind: "contextEnd",
570+
kind: detailKindContextEnd,
532571
})
533572
}
534573

@@ -566,37 +605,69 @@ func (f *FourslashTest) getBaselineContentForFile(
566605
}
567606
}
568607

569-
slices.SortStableFunc(details, func(d1, d2 *baselineDetail) int {
570-
return lsproto.ComparePositions(d1.pos, d2.pos)
571-
})
572-
// !!! if canDetermineContextIdInline
573-
574-
textWithContext := newTextWithContext(fileName, content)
575-
576-
// Our preferred way to write marker is
608+
// Our preferred way to write markers is
577609
// /*MARKER*/[| some text |]
578610
// [| some /*MARKER*/ text |]
579611
// [| some text |]/*MARKER*/
580-
// Stable sort should handle first two cases but with that marker will be before rangeEnd if locations match
581-
// So we will defer writing marker in this case by checking and finding index of rangeEnd if same
582-
var deferredMarkerIndex *int
612+
slices.SortStableFunc(details, func(d1, d2 *baselineDetail) int {
613+
c := lsproto.ComparePositions(d1.pos, d2.pos)
614+
if c != 0 || d1.kind == detailKindMarker && d2.kind == detailKindMarker {
615+
return c
616+
}
583617

584-
for index, detail := range details {
585-
if detail.span == nil && deferredMarkerIndex == nil {
586-
// If this is marker position and its same as textEnd and/or contextEnd we want to write marker after those
587-
for matchingEndPosIndex := index + 1; matchingEndPosIndex < len(details); matchingEndPosIndex++ {
588-
// Defer after the location if its same as rangeEnd
589-
if details[matchingEndPosIndex].pos == detail.pos && strings.HasSuffix(details[matchingEndPosIndex].kind, "End") {
590-
deferredMarkerIndex = ptrTo(matchingEndPosIndex)
591-
}
592-
// Dont defer further than already determined
593-
break
618+
// /*MARKER*/[| some text |]
619+
if d1.kind == detailKindMarker && d2.kind.isStart() {
620+
return -1
621+
}
622+
if d2.kind == detailKindMarker && d1.kind.isStart() {
623+
return 1
624+
}
625+
626+
// [| some text |]/*MARKER*/
627+
if d1.kind == detailKindMarker && d2.kind.isEnd() {
628+
return 1
629+
}
630+
if d2.kind == detailKindMarker && d1.kind.isEnd() {
631+
return -1
632+
}
633+
634+
// [||] or <||>
635+
if d1.span == d2.span {
636+
return int(d1.kind - d2.kind)
637+
}
638+
639+
// ...|><|...
640+
if d1.kind.isStart() && d2.kind.isEnd() {
641+
return 1
642+
}
643+
if d1.kind.isEnd() && d2.kind.isStart() {
644+
return -1
645+
}
646+
647+
// <| ... [| ... |]|>
648+
if d1.kind.isEnd() && d2.kind.isEnd() {
649+
c := lsproto.ComparePositions(d2.getRange().Start, d1.getRange().Start)
650+
if c != 0 {
651+
return c
594652
}
595-
// Defer writing marker position to deffered marker index
596-
if deferredMarkerIndex != nil {
597-
continue
653+
return int(d1.kind - d2.kind)
654+
}
655+
656+
// <|[| ... |] ... |>
657+
if d1.kind.isStart() && d2.kind.isStart() {
658+
c := lsproto.ComparePositions(d2.getRange().End, d2.getRange().End)
659+
if c != 0 {
660+
return c
598661
}
662+
return int(d1.kind - d2.kind)
599663
}
664+
665+
return 0
666+
})
667+
// !!! if canDetermineContextIdInline
668+
669+
textWithContext := newTextWithContext(fileName, content)
670+
for index, detail := range details {
600671
textWithContext.add(detail)
601672
textWithContext.pos = detail.pos
602673
// Prefix
@@ -607,13 +678,13 @@ func (f *FourslashTest) getBaselineContentForFile(
607678
textWithContext.newContent.WriteString(detail.positionMarker)
608679
if detail.span != nil {
609680
switch detail.kind {
610-
case "textStart":
681+
case detailKindTextStart:
611682
var text string
612683
if contextId, ok := spanToContextId[*detail.span]; ok {
613684
isAfterContextStart := false
614685
for textStartIndex := index - 1; textStartIndex >= 0; textStartIndex-- {
615686
textStartDetail := details[textStartIndex]
616-
if textStartDetail.kind == "contextStart" && textStartDetail.span == detail.span {
687+
if textStartDetail.kind == detailKindContextStart && textStartDetail.span == detail.span {
617688
isAfterContextStart = true
618689
break
619690
}
@@ -634,18 +705,11 @@ func (f *FourslashTest) getBaselineContentForFile(
634705
if text != "" {
635706
textWithContext.newContent.WriteString(`{ ` + text + ` |}`)
636707
}
637-
case "contextStart":
708+
case detailKindContextStart:
638709
if canDetermineContextIdInline {
639710
spanToContextId[*detail.span] = len(spanToContextId)
640711
}
641712
}
642-
643-
if deferredMarkerIndex != nil && *deferredMarkerIndex == index {
644-
// Write the marker
645-
textWithContext.newContent.WriteString(options.markerName)
646-
deferredMarkerIndex = nil
647-
detail = details[0] // Marker detail
648-
}
649713
}
650714
if suffix, ok := detailSuffixes[detail]; ok {
651715
textWithContext.newContent.WriteString(suffix)
@@ -714,7 +778,7 @@ func (t *textWithContext) add(detail *baselineDetail) {
714778
if t.content == "" && detail == nil {
715779
panic("Unsupported")
716780
}
717-
if detail == nil || (detail.kind != "textEnd" && detail.kind != "contextEnd") {
781+
if detail == nil || (detail.kind != detailKindTextEnd && detail.kind != detailKindContextEnd) {
718782
// Calculate pos to location number of lines
719783
posLineIndex := t.lineInfo
720784
if t.posInfo == nil || *t.posInfo != t.pos {

0 commit comments

Comments
 (0)