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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,50 @@ import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, Ref
const FindAllReferencesRequest: RequestType<ReferencesParams, ReferencesResult, void> =
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/findAllReferences');

export interface FindAllReferencesResult {
referencesResult: ReferencesResult;
locations: vscode.Location[];
}

function convertConfirmedReferencesToLocations(referencesResult: ReferencesResult): vscode.Location[] {
const locationsResult: vscode.Location[] = [];
referencesResult.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
if (referenceInfo.type === ReferenceType.Confirmed) {
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
referenceInfo.position.line, referenceInfo.position.character + referencesResult.text.length);
locationsResult.push(new vscode.Location(uri, range));
}
});
return locationsResult;
}

export async function sendFindAllReferencesRequest(client: DefaultClient, uri: vscode.Uri, position: vscode.Position, token: vscode.CancellationToken): Promise<FindAllReferencesResult | undefined> {
const params: ReferencesParams = {
newName: "",
position: Position.create(position.line, position.character),
textDocument: { uri: uri.toString() }
};
let response: ReferencesResult;
try {
response = await client.languageClient.sendRequest(FindAllReferencesRequest, params, token);
} catch (e: any) {
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
return undefined;
}
throw e;
}

if (token.isCancellationRequested || response.isCanceled) {
return undefined;
}

return {
referencesResult: response,
locations: convertConfirmedReferencesToLocations(response)
};
}

export class FindAllReferencesProvider implements vscode.ReferenceProvider {
private client: DefaultClient;

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

// Send the request to the language server.
const locationsResult: vscode.Location[] = [];
const params: ReferencesParams = {
newName: "",
position: Position.create(position.line, position.character),
textDocument: { uri: document.uri.toString() }
};
let response: ReferencesResult | undefined;
let cancelled: boolean = false;
let result: FindAllReferencesResult | undefined;
try {
response = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token);
} catch (e: any) {
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
if (!cancelled) {
throw e;
}
}
finally {
result = await sendFindAllReferencesRequest(this.client, document.uri, position, cancelSource.token);
} finally {
// Reset anything that can be cleared before processing the result.
workspaceReferences.resetProgressBar();
cancellationTokenListener.dispose();
requestCanceledListener.dispose();
}

// Process the result.
if (cancelSource.token.isCancellationRequested || cancelled || (response && response.isCanceled)) {
if (cancelSource.token.isCancellationRequested || !result) {
// Return undefined instead of vscode.CancellationError to avoid the following error message from VS Code:
// "Cannot destructure property 'range' of 'e.location' as it is undefined."
// TODO: per issue https://github.com/microsoft/vscode/issues/169698
// vscode.CancellationError is expected, so when VS Code fixes the error use vscode.CancellationError again.
workspaceReferences.resetReferences();
return undefined;
} else if (response && response.referenceInfos.length > 0) {
response.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
if (referenceInfo.type === ReferenceType.Confirmed) {
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
referenceInfo.position.line, referenceInfo.position.character + response.text.length);
locationsResult.push(new vscode.Location(uri, range));
}
});

} else if (result.referencesResult.referenceInfos.length > 0) {
// Display other reference types in panel or channel view.
// Note: ReferencesManager.resetReferences is called in ReferencesManager.showResultsInPanelView
workspaceReferences.showResultsInPanelView(response);
workspaceReferences.showResultsInPanelView(result.referencesResult);
} else {
workspaceReferences.resetReferences();
}

return locationsResult;
return result.locations;
}
}
17 changes: 17 additions & 0 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { getCrashCallStacksChannel } from '../logger';
import { PlatformInformation } from '../platform';
import * as telemetry from '../telemetry';
import { CopilotHoverProvider } from './Providers/CopilotHoverProvider';
import { sendFindAllReferencesRequest } from './Providers/findAllReferencesProvider';
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, openFileVersions } from './client';
import { ClientCollection } from './clientCollection';
import { CodeActionDiagnosticInfo, CodeAnalysisDiagnosticIdentifiersAndUri, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions } from './codeAnalysis';
Expand Down Expand Up @@ -397,6 +398,7 @@ export async function registerCommands(enabled: boolean): Promise<void> {
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowActiveCodeAnalysisCommands', enabled ? onShowActiveCodeAnalysisCommands : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowIdleCodeAnalysisCommands', enabled ? onShowIdleCodeAnalysisCommands : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowReferencesProgress', enabled ? onShowReferencesProgress : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.FindAllReferences', enabled ? onFindAllReferences : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.TakeSurvey', enabled ? onTakeSurvey : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.LogDiagnostics', enabled ? onLogDiagnostics : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RescanWorkspace', enabled ? onRescanWorkspace : onDisabledCommand));
Expand Down Expand Up @@ -808,6 +810,21 @@ function onShowReferencesProgress(): void {
void clients.ActiveClient.handleReferencesIcon().catch(logAndReturn.undefined);
}

async function onFindAllReferences(uri: vscode.Uri, position: vscode.Position, token?: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
if (!uri || !position) {
throw new Error("C_Cpp.FindAllReferences requires both a uri and position.");
}

const client: Client = clients.getClientFor(uri);
if (!(client instanceof DefaultClient)) {
return undefined;
}

await client.ready;
const result = await sendFindAllReferencesRequest(client, uri, position, token ?? CancellationToken.None);
return result?.locations;
}

function onToggleRefGroupView(): void {
// Set context to switch icons
const client: Client = getActiveClient();
Expand Down
Loading