Skip to content

Commit 55fccf5

Browse files
committed
Add internal silent find-all-references command
Introduce an internal C_Cpp.FindAllReferences command that issues the existing cpptools/findAllReferences request without joining the workspaceReferences single-flight cancellation path. Extract the shared request and confirmed-location mapping logic from FindAllReferencesProvider so the existing vscode.executeReferenceProvider flow and the new silent command use the same request translation and cancellation handling for server-side cancel responses. Keep the interactive provider behavior unchanged: user-invoked references still cancel prior work, reset reference progress state, and update the ReferencesManager UI. The new command resolves the owning client from the target URI and returns locations without progress UI, preview notifications, or references panel updates, enabling concurrent silent callers such as Copilot.
1 parent 61b53bc commit 55fccf5

File tree

2 files changed

+68
-29
lines changed

2 files changed

+68
-29
lines changed

Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,50 @@ import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, Ref
1111
const FindAllReferencesRequest: RequestType<ReferencesParams, ReferencesResult, void> =
1212
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/findAllReferences');
1313

14+
export interface FindAllReferencesResult {
15+
referencesResult: ReferencesResult;
16+
locations: vscode.Location[];
17+
}
18+
19+
function convertConfirmedReferencesToLocations(referencesResult: ReferencesResult): vscode.Location[] {
20+
const locationsResult: vscode.Location[] = [];
21+
referencesResult.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
22+
if (referenceInfo.type === ReferenceType.Confirmed) {
23+
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
24+
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
25+
referenceInfo.position.line, referenceInfo.position.character + referencesResult.text.length);
26+
locationsResult.push(new vscode.Location(uri, range));
27+
}
28+
});
29+
return locationsResult;
30+
}
31+
32+
export async function sendFindAllReferencesRequest(client: DefaultClient, uri: vscode.Uri, position: vscode.Position, token: vscode.CancellationToken): Promise<FindAllReferencesResult | undefined> {
33+
const params: ReferencesParams = {
34+
newName: "",
35+
position: Position.create(position.line, position.character),
36+
textDocument: { uri: uri.toString() }
37+
};
38+
let response: ReferencesResult;
39+
try {
40+
response = await client.languageClient.sendRequest(FindAllReferencesRequest, params, token);
41+
} catch (e: any) {
42+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
43+
return undefined;
44+
}
45+
throw e;
46+
}
47+
48+
if (token.isCancellationRequested || response.isCanceled) {
49+
return undefined;
50+
}
51+
52+
return {
53+
referencesResult: response,
54+
locations: convertConfirmedReferencesToLocations(response)
55+
};
56+
}
57+
1458
export class FindAllReferencesProvider implements vscode.ReferenceProvider {
1559
private client: DefaultClient;
1660

@@ -29,54 +73,32 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
2973
const requestCanceledListener: vscode.Disposable = workspaceReferences.onCancellationRequested(_sender => { cancelSource.cancel(); });
3074

3175
// Send the request to the language server.
32-
const locationsResult: vscode.Location[] = [];
33-
const params: ReferencesParams = {
34-
newName: "",
35-
position: Position.create(position.line, position.character),
36-
textDocument: { uri: document.uri.toString() }
37-
};
38-
let response: ReferencesResult | undefined;
39-
let cancelled: boolean = false;
76+
let result: FindAllReferencesResult | undefined;
4077
try {
41-
response = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token);
42-
} catch (e: any) {
43-
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
44-
if (!cancelled) {
45-
throw e;
46-
}
47-
}
48-
finally {
78+
result = await sendFindAllReferencesRequest(this.client, document.uri, position, cancelSource.token);
79+
} finally {
4980
// Reset anything that can be cleared before processing the result.
5081
workspaceReferences.resetProgressBar();
5182
cancellationTokenListener.dispose();
5283
requestCanceledListener.dispose();
5384
}
5485

5586
// Process the result.
56-
if (cancelSource.token.isCancellationRequested || cancelled || (response && response.isCanceled)) {
87+
if (cancelSource.token.isCancellationRequested || !result) {
5788
// Return undefined instead of vscode.CancellationError to avoid the following error message from VS Code:
5889
// "Cannot destructure property 'range' of 'e.location' as it is undefined."
5990
// TODO: per issue https://github.com/microsoft/vscode/issues/169698
6091
// vscode.CancellationError is expected, so when VS Code fixes the error use vscode.CancellationError again.
6192
workspaceReferences.resetReferences();
6293
return undefined;
63-
} else if (response && response.referenceInfos.length > 0) {
64-
response.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
65-
if (referenceInfo.type === ReferenceType.Confirmed) {
66-
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
67-
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
68-
referenceInfo.position.line, referenceInfo.position.character + response.text.length);
69-
locationsResult.push(new vscode.Location(uri, range));
70-
}
71-
});
72-
94+
} else if (result.referencesResult.referenceInfos.length > 0) {
7395
// Display other reference types in panel or channel view.
7496
// Note: ReferencesManager.resetReferences is called in ReferencesManager.showResultsInPanelView
75-
workspaceReferences.showResultsInPanelView(response);
97+
workspaceReferences.showResultsInPanelView(result.referencesResult);
7698
} else {
7799
workspaceReferences.resetReferences();
78100
}
79101

80-
return locationsResult;
102+
return result.locations;
81103
}
82104
}

Extension/src/LanguageServer/extension.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { getCrashCallStacksChannel } from '../logger';
2323
import { PlatformInformation } from '../platform';
2424
import * as telemetry from '../telemetry';
2525
import { CopilotHoverProvider } from './Providers/CopilotHoverProvider';
26+
import { sendFindAllReferencesRequest } from './Providers/findAllReferencesProvider';
2627
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, openFileVersions } from './client';
2728
import { ClientCollection } from './clientCollection';
2829
import { CodeActionDiagnosticInfo, CodeAnalysisDiagnosticIdentifiersAndUri, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions } from './codeAnalysis';
@@ -397,6 +398,7 @@ export async function registerCommands(enabled: boolean): Promise<void> {
397398
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowActiveCodeAnalysisCommands', enabled ? onShowActiveCodeAnalysisCommands : onDisabledCommand));
398399
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowIdleCodeAnalysisCommands', enabled ? onShowIdleCodeAnalysisCommands : onDisabledCommand));
399400
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowReferencesProgress', enabled ? onShowReferencesProgress : onDisabledCommand));
401+
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.FindAllReferences', enabled ? onFindAllReferences : onDisabledCommand));
400402
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.TakeSurvey', enabled ? onTakeSurvey : onDisabledCommand));
401403
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.LogDiagnostics', enabled ? onLogDiagnostics : onDisabledCommand));
402404
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RescanWorkspace', enabled ? onRescanWorkspace : onDisabledCommand));
@@ -808,6 +810,21 @@ function onShowReferencesProgress(): void {
808810
void clients.ActiveClient.handleReferencesIcon().catch(logAndReturn.undefined);
809811
}
810812

813+
async function onFindAllReferences(uri: vscode.Uri, position: vscode.Position, token?: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
814+
if (!uri || !position) {
815+
throw new Error("C_Cpp.FindAllReferences requires both a uri and position.");
816+
}
817+
818+
const client: Client = clients.getClientFor(uri);
819+
if (!(client instanceof DefaultClient)) {
820+
return undefined;
821+
}
822+
823+
await client.ready;
824+
const result = await sendFindAllReferencesRequest(client, uri, position, token ?? CancellationToken.None);
825+
return result?.locations;
826+
}
827+
811828
function onToggleRefGroupView(): void {
812829
// Set context to switch icons
813830
const client: Client = getActiveClient();

0 commit comments

Comments
 (0)