Skip to content

Commit 94f31f3

Browse files
authored
Add classified text output for VS Find All References (#4030)
1 parent 898015c commit 94f31f3

52 files changed

Lines changed: 10952 additions & 6315 deletions

File tree

Some content is hidden

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

internal/fourslash/baselineutil.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const (
2626
closingTagCmd baselineCommand = "Closing Tag"
2727
documentHighlightsCmd baselineCommand = "documentHighlights"
2828
findAllReferencesCmd baselineCommand = "findAllReferences"
29+
vsFindAllReferencesCmd baselineCommand = "vsFindAllReferences"
2930
goToDefinitionCmd baselineCommand = "goToDefinition"
3031
goToImplementationCmd baselineCommand = "goToImplementation"
3132
goToSourceDefinitionCmd baselineCommand = "goToSourceDefinition"
@@ -78,7 +79,7 @@ func getBaselineFileName(t *testing.T, command baselineCommand) string {
7879

7980
func getBaselineExtension(command baselineCommand) string {
8081
switch command {
81-
case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd, documentSymbolsCmd, closingTagCmd:
82+
case quickInfoCmd, signatureHelpCmd, smartSelectionCmd, inlayHintsCmd, nonSuggestionDiagnosticsCmd, documentSymbolsCmd, closingTagCmd, vsFindAllReferencesCmd:
8283
return "baseline"
8384
case callHierarchyCmd:
8485
return "callHierarchy.txt"

internal/fourslash/fourslash.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2330,6 +2330,86 @@ func (f *FourslashTest) VerifyBaselineFindAllReferences(
23302330
}
23312331
}
23322332

2333+
func (f *FourslashTest) VerifyBaselineVsFindAllReferences(
2334+
t *testing.T,
2335+
markers ...string,
2336+
) {
2337+
referenceLocations := f.lookupMarkersOrGetRanges(t, markers)
2338+
2339+
for _, markerOrRange := range referenceLocations {
2340+
f.GoToMarkerOrRange(t, markerOrRange)
2341+
2342+
params := &lsproto.ReferenceParams{
2343+
TextDocument: lsproto.TextDocumentIdentifier{
2344+
Uri: lsconv.FileNameToDocumentURI(f.activeFilename),
2345+
},
2346+
Position: f.currentCaretPosition,
2347+
Context: &lsproto.ReferenceContext{
2348+
IncludeDeclaration: true,
2349+
},
2350+
}
2351+
result := sendRequest(t, f, lsproto.TextDocumentVSReferencesInfo, params)
2352+
// Sort cross-project results for deterministic baselines
2353+
if result.VsReferenceItems != nil && len(*result.VsReferenceItems) > 0 {
2354+
items := *result.VsReferenceItems
2355+
slices.SortStableFunc(items, func(a, b *lsproto.VsReferenceItem) int {
2356+
ap, bp := "", ""
2357+
if a.VSProjectName != nil {
2358+
ap = *a.VSProjectName
2359+
}
2360+
if b.VSProjectName != nil {
2361+
bp = *b.VSProjectName
2362+
}
2363+
if ap != bp {
2364+
if ap < bp {
2365+
return -1
2366+
}
2367+
return 1
2368+
}
2369+
if a.VSLocation.Uri != b.VSLocation.Uri {
2370+
if string(a.VSLocation.Uri) < string(b.VSLocation.Uri) {
2371+
return -1
2372+
}
2373+
return 1
2374+
}
2375+
if a.VSLocation.Range.Start.Line != b.VSLocation.Range.Start.Line {
2376+
return int(a.VSLocation.Range.Start.Line) - int(b.VSLocation.Range.Start.Line)
2377+
}
2378+
return int(a.VSLocation.Range.Start.Character) - int(b.VSLocation.Range.Start.Character)
2379+
})
2380+
// Re-number IDs sequentially after sort
2381+
idRemap := make(map[int32]int32, len(items))
2382+
for i, item := range items {
2383+
idRemap[item.VSId] = int32(i)
2384+
item.VSId = int32(i)
2385+
}
2386+
for _, item := range items {
2387+
if item.VSDefinitionId != nil {
2388+
newDefId := idRemap[*item.VSDefinitionId]
2389+
item.VSDefinitionId = &newDefId
2390+
}
2391+
}
2392+
}
2393+
// Include file contents with markers
2394+
var locations []lsproto.Location
2395+
if result.VsReferenceItems != nil {
2396+
for _, item := range *result.VsReferenceItems {
2397+
locations = append(locations, item.VSLocation)
2398+
}
2399+
}
2400+
fileContents := f.getBaselineForLocationsWithFileContents(locations, baselineFourslashLocationsOptions{
2401+
marker: markerOrRange,
2402+
markerName: "/*FIND ALL REFS*/",
2403+
})
2404+
2405+
if jsonStr, err := core.StringifyJson(result, "", " "); err == nil {
2406+
f.addResultToBaseline(t, vsFindAllReferencesCmd, fileContents+"\n\n"+jsonStr)
2407+
} else {
2408+
t.Fatalf("Failed to stringify VS references result for baseline: %v", err)
2409+
}
2410+
}
2411+
}
2412+
23332413
func (f *FourslashTest) VerifyBaselineCodeLens(t *testing.T, preferences *lsutil.UserPreferences) {
23342414
if preferences != nil {
23352415
reset := f.ConfigureWithReset(t, *preferences)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/testutil"
9+
)
10+
11+
func TestConstructorFindAllReferences1VS(t *testing.T) {
12+
t.Parallel()
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `export class C {
15+
/**/public constructor() { }
16+
public foo() { }
17+
}
18+
19+
new C().foo();`
20+
f, done := fourslash.NewFourslash(t, &lsproto.ClientCapabilities{VSSupportsVisualStudioExtensions: new(true)}, content)
21+
defer done()
22+
f.VerifyBaselineVsFindAllReferences(t, "")
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/testutil"
9+
)
10+
11+
func TestFindAllRefsForDefaultExportVS(t *testing.T) {
12+
t.Parallel()
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @Filename: a.ts
15+
export default function /*def*/f() {}
16+
// @Filename: b.ts
17+
import /*deg*/g from "./a";
18+
[|/*ref*/g|]();
19+
// @Filename: c.ts
20+
import { f } from "./a";`
21+
f, done := fourslash.NewFourslash(t, &lsproto.ClientCapabilities{VSSupportsVisualStudioExtensions: new(true)}, content)
22+
defer done()
23+
f.VerifyBaselineVsFindAllReferences(t, "def", "deg")
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/testutil"
9+
)
10+
11+
func TestFindAllRefsInheritedProperties1VS(t *testing.T) {
12+
t.Parallel()
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `class class1 extends class1 {
15+
/*1*/doStuff() { }
16+
/*2*/propName: string;
17+
}
18+
19+
var v: class1;
20+
v./*3*/doStuff();
21+
v./*4*/propName;`
22+
f, done := fourslash.NewFourslash(t, &lsproto.ClientCapabilities{VSSupportsVisualStudioExtensions: new(true)}, content)
23+
defer done()
24+
f.VerifyBaselineVsFindAllReferences(t, "1", "2", "3", "4")
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/testutil"
9+
)
10+
11+
func TestFindReferencesAcrossMultipleProjectsVS(t *testing.T) {
12+
t.Parallel()
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `//@Filename: a.ts
15+
/*1*/var /*2*/x: number;
16+
//@Filename: b.ts
17+
/// <reference path="a.ts" />
18+
/*3*/x++;
19+
//@Filename: c.ts
20+
/// <reference path="a.ts" />
21+
/*4*/x++;`
22+
f, done := fourslash.NewFourslash(t, &lsproto.ClientCapabilities{VSSupportsVisualStudioExtensions: new(true)}, content)
23+
defer done()
24+
f.VerifyBaselineVsFindAllReferences(t, "1", "2", "3", "4")
25+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
8+
"github.com/microsoft/typescript-go/internal/testutil"
9+
)
10+
11+
func TestTsxFindAllReferences1VS(t *testing.T) {
12+
t.Parallel()
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `//@Filename: file.tsx
15+
declare namespace JSX {
16+
interface Element { }
17+
interface IntrinsicElements {
18+
/*1*/div: {
19+
name?: string;
20+
isOpen?: boolean;
21+
};
22+
span: { n: string; };
23+
}
24+
}
25+
var x = /*2*/</*3*/div />;`
26+
f, done := fourslash.NewFourslash(t, &lsproto.ClientCapabilities{VSSupportsVisualStudioExtensions: new(true)}, content)
27+
defer done()
28+
f.VerifyBaselineVsFindAllReferences(t, "1", "2", "3")
29+
}

internal/ls/crossproject.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,34 @@ func combineReferences(results iter.Seq[lsproto.ReferencesResponse]) lsproto.Ref
308308
return lsproto.LocationsOrNull{Locations: combineResponseLocations(results)}
309309
}
310310

311+
func combineVsReferences(results iter.Seq[lsproto.VsReferencesResponse]) lsproto.VsReferencesResponse {
312+
var combined []*lsproto.VsReferenceItem
313+
// Re-number IDs across projects to maintain unique IDs and correct definition references
314+
nextId := int32(0)
315+
for resp := range results {
316+
if resp.VsReferenceItems == nil {
317+
continue
318+
}
319+
// Map old IDs to new IDs for this batch
320+
idMap := make(map[int32]int32)
321+
for _, item := range *resp.VsReferenceItems {
322+
oldId := item.VSId
323+
newId := nextId
324+
idMap[oldId] = newId
325+
nextId++
326+
327+
newItem := *item
328+
newItem.VSId = newId
329+
if item.VSDefinitionId != nil {
330+
newDefId := idMap[*item.VSDefinitionId]
331+
newItem.VSDefinitionId = &newDefId
332+
}
333+
combined = append(combined, &newItem)
334+
}
335+
}
336+
return lsproto.VsReferencesResponse{VsReferenceItems: &combined}
337+
}
338+
311339
func combineImplementations(results iter.Seq[lsproto.ImplementationResponse]) lsproto.ImplementationResponse {
312340
var combined []*lsproto.LocationLink
313341
var seenLocations collections.Set[lsproto.Location]

internal/ls/displaypartswriter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func (w *displayPartsWriter) addRun(classification lsproto.ClassificationTypeNam
3535
w.runs = append(w.runs, &lsproto.ClassifiedTextRun{
3636
ClassificationTypeName: string(classification),
3737
Text: text,
38+
VSType: "ClassifiedTextRun",
3839
})
3940
}
4041
w.lastWritten = text

0 commit comments

Comments
 (0)