Skip to content
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
20 changes: 20 additions & 0 deletions _extension/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,26 @@ export class Client implements vscode.Disposable {
textDocument: { uri },
}, token);
}

async findFileReferences(uri: string, token?: vscode.CancellationToken): Promise<{ uri: string; range: vscode.Range; }[] | null> {
if (!this.client) {
throw new Error("Language client is not initialized");
}
type LspLocation = { uri: string; range: { start: { line: number; character: number; }; end: { line: number; character: number; }; }; };
const locations = await this.client.sendRequest<LspLocation[] | null>("custom/findFileReferences", {
textDocument: { uri },
}, token);
if (!locations) {
return null;
}
return locations.map(loc => ({
uri: loc.uri,
range: new vscode.Range(
new vscode.Position(loc.range.start.line, loc.range.start.character),
new vscode.Position(loc.range.end.line, loc.range.end.character),
),
}));
}
}

// Adapted from the default error handler in vscode-languageclient.
Expand Down
35 changes: 35 additions & 0 deletions _extension/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,38 @@ export function registerCodeLensShowLocationsCommand(): vscode.Disposable {
vscode.commands.executeCommand("editor.action.showReferences", editorUri, editorPosition, editorLocations);
}
}

export function registerFindFileReferencesCommand(getClient: () => Client | undefined): vscode.Disposable {
return vscode.commands.registerCommand("_typescript.findAllFileReferences", async (uri?: vscode.Uri) => {
const client = getClient();
if (!client) {
return;
}

const targetUri = uri ?? vscode.window.activeTextEditor?.document.uri;
if (!targetUri) {
return;
}

const locations = await client.findFileReferences(targetUri.toString());
if (!locations || locations.length === 0) {
vscode.window.showInformationMessage("No references found.");
return;
}

const vscodeLocs = locations.map(loc =>
new vscode.Location(
vscode.Uri.parse(loc.uri),
loc.range,
)
);

// Show references in the references view using position 0,0 of the target file
await vscode.commands.executeCommand(
"editor.action.showReferences",
targetUri,
new vscode.Position(0, 0),
vscodeLocs,
);
});
}
3 changes: 2 additions & 1 deletion _extension/src/session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from "vscode";
import { ActiveJsTsEditorTracker } from "./activeJsTsEditorTracker";
import { Client } from "./client";
import { registerCodeLensShowLocationsCommand } from "./commands";
import { registerCodeLensShowLocationsCommand, registerFindFileReferencesCommand } from "./commands";
import { ManagedFileContextManager } from "./managedFileContext";
import { ProjectStatus } from "./projectStatus";
import { setupStatusBar } from "./statusBar";
Expand Down Expand Up @@ -140,6 +140,7 @@ class Session implements vscode.Disposable {

registerCommands(): void {
this.disposables.push(registerCodeLensShowLocationsCommand());
this.disposables.push(registerFindFileReferencesCommand(() => this.client));

this.disposables.push(vscode.commands.registerCommand("typescript.native-preview.output.focus", () => {
this.outputChannel.show();
Expand Down
27 changes: 27 additions & 0 deletions internal/compiler/fileInclude.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"sync"

"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/diagnostics"
"github.com/microsoft/typescript-go/internal/module"
"github.com/microsoft/typescript-go/internal/scanner"
Expand Down Expand Up @@ -91,6 +92,32 @@ func (r *FileIncludeReason) isReferencedFile() bool {
return r != nil && r.kind <= fileIncludeKindLibReferenceDirective
}

// GetSpanInReferrer returns the file name and text range of this file-include reason
// within the referring file. Returns ok=false if the reason is not a referenced-file
// include (e.g. it is a root file, lib file, or automatic type directive), or if the
// location is synthetic (not present in the source text).
func (r *FileIncludeReason) GetSpanInReferrer(program *Program) (fileName string, textRange core.TextRange, ok bool) {
if !r.isReferencedFile() {
return "", core.TextRange{}, false
}
loc := program.includeProcessor.getReferenceLocation(r, program)
if loc.isSynthetic {
return "", core.TextRange{}, false
}
var tr core.TextRange
if loc.node != nil {
// Skip leading trivia so the span starts at the actual token text,
// matching TypeScript's skipTrivia(file.text, importLiteral.pos).
pos := scanner.SkipTrivia(loc.file.Text(), loc.node.Pos())
tr = core.NewTextRange(pos, loc.node.End())
} else if loc.ref != nil {
tr = loc.ref.TextRange
} else {
return "", core.TextRange{}, false
}
return loc.file.FileName(), tr, true
}

func (r *FileIncludeReason) asReferencedFileData() *referencedFileData {
return r.data.(*referencedFileData)
}
Expand Down
46 changes: 42 additions & 4 deletions internal/fourslash/_scripts/convertFourslash.mts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,20 @@ function parseTypeScriptFiles(manualTests: Set<string>, folder: string): void {
files.forEach(file => {
const filePath = path.join(folder, file);
const stat = fs.statSync(filePath);
if (inputFileSet && !inputFileSet.has(file)) {
return;
}

if (stat.isDirectory()) {
// Always recurse into subdirectories regardless of inputFileSet,
// so that e.g. "server/getFileReferences_server1.ts" is reachable
// when the user specifies only the basename in the filter list.
parseTypeScriptFiles(manualTests, filePath);
return;
}
else if (hasTSExtension(file) && !manualTests.has(file.slice(0, -3)) && file !== "fourslash.ts") {

if (inputFileSet && !inputFileSet.has(file)) {
return;
}

if (hasTSExtension(file) && !manualTests.has(file.slice(0, -3)) && file !== "fourslash.ts") {
const content = fs.readFileSync(filePath, "utf-8");
const isServer = filePath.split(path.sep).includes("server");
try {
Expand Down Expand Up @@ -231,6 +237,9 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] {
case "baselineFindAllReferences":
// `verify.baselineFindAllReferences(...)`
return parseBaselineFindAllReferencesArgs(callExpression.arguments);
case "baselineGetFileReferences":
// `verify.baselineGetFileReferences(...)`
return parseBaselineGetFileReferencesArgs(callExpression.arguments);
case "baselineDocumentHighlights":
return parseBaselineDocumentHighlightsArgs(callExpression.arguments);
case "baselineQuickInfo":
Expand Down Expand Up @@ -1258,6 +1267,23 @@ function parseBaselineFindAllReferencesArgs(args: readonly ts.Expression[]): [Ve
}];
}

function parseBaselineGetFileReferencesArgs(args: readonly ts.Expression[]): [VerifyBaselineGetFileReferencesCmd] {
const fileNames: string[] = [];
for (const arg of args) {
const strArg = getStringLiteralLike(arg);
if (strArg) {
fileNames.push(getGoStringLiteral(strArg.text));
}
else {
throw new Error(`Unrecognized argument in verify.baselineGetFileReferences: ${arg.getText()}`);
}
}
return [{
kind: "verifyBaselineGetFileReferences",
fileNames,
}];
}

function parseBaselineDocumentHighlightsArgs(args: readonly ts.Expression[]): [VerifyBaselineDocumentHighlightsCmd] {
const newArgs: string[] = [];
let preferences: string | undefined;
Expand Down Expand Up @@ -2985,6 +3011,11 @@ interface VerifyBaselineFindAllReferencesCmd {
ranges?: boolean;
}

interface VerifyBaselineGetFileReferencesCmd {
kind: "verifyBaselineGetFileReferences";
fileNames: string[];
}

interface VerifyBaselineGoToDefinitionCmd {
kind: "verifyBaselineGoToDefinition" | "verifyBaselineGoToType" | "verifyBaselineGoToImplementation";
markers: string[];
Expand Down Expand Up @@ -3195,6 +3226,7 @@ type Cmd =
| VerifyCompletionsCmd
| VerifyApplyCodeActionFromCompletionCmd
| VerifyBaselineFindAllReferencesCmd
| VerifyBaselineGetFileReferencesCmd
| VerifyBaselineDocumentHighlightsCmd
| VerifyBaselineGoToDefinitionCmd
| VerifyBaselineQuickInfoCmd
Expand Down Expand Up @@ -3288,6 +3320,10 @@ function generateBaselineFindAllReferences({ markers, ranges }: VerifyBaselineFi
return `f.VerifyBaselineFindAllReferences(t, ${markers.join(", ")})`;
}

function generateBaselineGetFileReferences({ fileNames }: VerifyBaselineGetFileReferencesCmd): string {
return `f.VerifyBaselineFindFileReferences(t, ${fileNames.join(", ")})`;
}

function generateBaselineDocumentHighlights({ args, preferences }: VerifyBaselineDocumentHighlightsCmd): string {
return `f.VerifyBaselineDocumentHighlights(t, ${preferences}, ${args.join(", ")})`;
}
Expand Down Expand Up @@ -3497,6 +3533,8 @@ function generateCmd(cmd: Cmd): string {
return generateVerifyApplyCodeActionFromCompletion(cmd);
case "verifyBaselineFindAllReferences":
return generateBaselineFindAllReferences(cmd);
case "verifyBaselineGetFileReferences":
return generateBaselineGetFileReferences(cmd);
case "verifyBaselineDocumentHighlights":
return generateBaselineDocumentHighlights(cmd);
case "verifyBaselineGoToDefinition":
Expand Down
1 change: 1 addition & 0 deletions internal/fourslash/_scripts/manualTests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ exhaustiveCaseCompletions6
exhaustiveCaseCompletions7
exhaustiveCaseCompletions8
formatOnEnterInComment
getFileReferences_deduplicate
getOutliningSpans
importNameCodeFix_uriStyleNodeCoreModules1
importNameCodeFixDefaultExport7
Expand Down
1 change: 1 addition & 0 deletions internal/fourslash/baselineutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
closingTagCmd baselineCommand = "Closing Tag"
documentHighlightsCmd baselineCommand = "documentHighlights"
findAllReferencesCmd baselineCommand = "findAllReferences"
findFileReferencesCmd baselineCommand = "findFileReferences"
goToDefinitionCmd baselineCommand = "goToDefinition"
goToImplementationCmd baselineCommand = "goToImplementation"
goToTypeDefinitionCmd baselineCommand = "goToType"
Expand Down
19 changes: 19 additions & 0 deletions internal/fourslash/fourslash.go
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,25 @@ func (f *FourslashTest) VerifyBaselineFindAllReferences(
}
}

// VerifyBaselineFindFileReferences calls the custom/findFileReferences request for the given file
// and baselines the result.
func (f *FourslashTest) VerifyBaselineFindFileReferences(t *testing.T, fileName string) {
t.Helper()
params := &lsproto.FindFileReferencesParams{
TextDocument: lsproto.TextDocumentIdentifier{
Uri: lsconv.FileNameToDocumentURI(fileName),
},
}
result := sendRequest(t, f, lsproto.CustomFindFileReferencesInfo, params)
var locations []lsproto.Location
if result.Locations != nil {
locations = *result.Locations
}
f.addResultToBaseline(t, findFileReferencesCmd, f.getBaselineForLocationsWithFileContents(locations, baselineFourslashLocationsOptions{
markerName: "/*FIND FILE REFS*/",
}))
}

func (f *FourslashTest) VerifyBaselineCodeLens(t *testing.T, preferences *lsutil.UserPreferences) {
if preferences != nil {
reset := f.ConfigureWithReset(t, preferences)
Expand Down
43 changes: 43 additions & 0 deletions internal/fourslash/tests/findFileReferences_test.go
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update convertfourslash.mts to add any existing tests that need to be ported.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 38e7195. Added baselineGetFileReferences support to convertFourslash.mts (parser + generator + interface + union type membership), and generated TestGetFileReferences1 and TestGetFileReferences2 from the existing TypeScript fourslash tests.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)

func TestFindFileReferences(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
export const a = {};

// @Filename: /b.ts
import "./a";

// @Filename: /c.ts
import {} from "./a";

// @Filename: /d.ts
import { a } from "/a";
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineFindFileReferences(t, "/a.ts")
}

func TestFindFileReferencesNonModule(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @Filename: /a.ts
const x = 1;

// @Filename: /b.ts
/// <reference path="./a.ts" />
const y = 2;
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineFindFileReferences(t, "/a.ts")
}
29 changes: 29 additions & 0 deletions internal/fourslash/tests/gen/getFileReferences1_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions internal/fourslash/tests/gen/getFileReferences2_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions internal/fourslash/tests/gen/getFileReferences_server1_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading