diff --git a/Extension/src/LanguageServer/Providers/callHierarchyProvider.ts b/Extension/src/LanguageServer/Providers/callHierarchyProvider.ts index 7fdb95c00f..0abb04a5d3 100644 --- a/Extension/src/LanguageServer/Providers/callHierarchyProvider.ts +++ b/Extension/src/LanguageServer/Providers/callHierarchyProvider.ts @@ -4,9 +4,10 @@ * ------------------------------------------------------------------------------------------ */ import * as path from 'path'; import * as vscode from 'vscode'; -import { Position, Range, RequestType, TextDocumentIdentifier } from 'vscode-languageclient'; +import { Position, Range, RequestType, ResponseError, TextDocumentIdentifier } from 'vscode-languageclient'; import * as Telemetry from '../../telemetry'; import { DefaultClient, workspaceReferences } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CancellationSender } from '../references'; import { makeVscodeRange } from '../utils'; @@ -127,8 +128,15 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider { textDocument: { uri: document.uri.toString() }, position: Position.create(position.line, position.character) }; - const response: CallHierarchyItemResult = await this.client.languageClient.sendRequest(CallHierarchyItemRequest, params, cancelSource.token); - + let response: CallHierarchyItemResult; + try { + response = await this.client.languageClient.sendRequest(CallHierarchyItemRequest, params, cancelSource.token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + return undefined; + } + throw e; + } cancellationTokenListener.dispose(); requestCanceledListener.dispose(); @@ -176,8 +184,16 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider { textDocument: { uri: item.uri.toString() }, position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character) }; - const response: CallHierarchyCallsItemResult = await this.client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, cancelSource.token); - + let response: CallHierarchyCallsItemResult | undefined; + let cancelled: boolean = false; + try { + response = await this.client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, cancelSource.token); + } catch (e: any) { + cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled); + if (!cancelled) { + throw e; + } + } // Reset anything that can be cleared before processing the result. const progressBarDuration: number | undefined = workspaceReferences.getCallHierarchyProgressBarDuration(); workspaceReferences.resetProgressBar(); @@ -186,12 +202,12 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider { requestCanceledListener.dispose(); // Process the result. - if (cancelSource.token.isCancellationRequested || response.calls === undefined || requestCanceled !== undefined) { + if (cancelSource.token.isCancellationRequested || cancelled || requestCanceled !== undefined) { const requestStatus: CallHierarchyRequestStatus = requestCanceled === CancellationSender.User ? CallHierarchyRequestStatus.CanceledByUser : CallHierarchyRequestStatus.Canceled; this.logTelemetry(CallHierarchyCallsToEvent, requestStatus, progressBarDuration); throw new vscode.CancellationError(); - } else if (response.calls.length !== 0) { + } else if (response && response.calls.length !== 0) { result = this.createIncomingCalls(response.calls); } @@ -214,12 +230,20 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider { textDocument: { uri: item.uri.toString() }, position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character) }; - const response: CallHierarchyCallsItemResult = await this.client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token); - - if (token.isCancellationRequested || response.calls === undefined) { + let response: CallHierarchyCallsItemResult | undefined; + let cancelled: boolean = false; + try { + await this.client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token); + } catch (e: any) { + cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled); + if (!cancelled) { + throw e; + } + } + if (token.isCancellationRequested || cancelled) { this.logTelemetry(CallHierarchyCallsFromEvent, CallHierarchyRequestStatus.Canceled); throw new vscode.CancellationError(); - } else if (response.calls.length !== 0) { + } else if (response && response.calls.length !== 0) { result = this.createOutgoingCalls(response.calls); } diff --git a/Extension/src/LanguageServer/Providers/codeActionProvider.ts b/Extension/src/LanguageServer/Providers/codeActionProvider.ts index 6de47e15b9..8611f8a4a1 100644 --- a/Extension/src/LanguageServer/Providers/codeActionProvider.ts +++ b/Extension/src/LanguageServer/Providers/codeActionProvider.ts @@ -3,13 +3,14 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient'; +import { Position, Range, RequestType, ResponseError, TextEdit } from 'vscode-languageclient'; import * as nls from 'vscode-nls'; import { DefaultClient } from '../client'; import { CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions } from '../codeAnalysis'; import { LocalizeStringParams, getLocalizedString } from '../localization'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings } from '../settings'; import { makeVscodeRange } from '../utils'; @@ -70,14 +71,21 @@ export class CodeActionProvider implements vscode.CodeActionProvider { uri: document.uri.toString() }; - let response: GetCodeActionsResult = await this.client.languageClient.sendRequest( - GetCodeActionsRequest, params, token); + let response: GetCodeActionsResult; + try { + response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } - const resultCodeActions: vscode.CodeAction[] = []; - if (token.isCancellationRequested || response.commands === undefined) { + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } + const resultCodeActions: vscode.CodeAction[] = []; let hasSelectIntelliSenseConfiguration: boolean = false; const settings: CppSettings = new CppSettings(this.client.RootUri); const hasConfigurationSet: boolean = settings.defaultCompilerPath !== null || @@ -254,8 +262,15 @@ export class CodeActionProvider implements vscode.CodeActionProvider { if (!hoverResult.value.includes(localize("expands.to", "Expands to:"))) { return false; } - response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token); - if (token.isCancellationRequested || response.commands === undefined) { + try { + response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + return false; + } + throw e; + } + if (token.isCancellationRequested) { return false; } for (const command of response.commands) { diff --git a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts index 5a0df58b39..529c3e4db0 100644 --- a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts @@ -3,7 +3,9 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { DefaultClient, FormatDocumentRequest, FormatParams, FormatResult } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings, OtherSettings, getEditorConfigSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -66,12 +68,16 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting }, onChanges: options.onChanges === true }; - // We do not currently pass the CancellationToken to sendRequest - // because there is not currently cancellation logic for formatting - // in the native process. Formatting is currently done directly in - // message handling thread. - const response: FormatResult = await this.client.languageClient.sendRequest(FormatDocumentRequest, params, token); - if (token.isCancellationRequested || response.edits === undefined) { + let response: FormatResult; + try { + response = await this.client.languageClient.sendRequest(FormatDocumentRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } const results: vscode.TextEdit[] = makeVscodeTextEdits(response.edits); diff --git a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts index e95312d1d3..6d9bd8ed79 100644 --- a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts @@ -3,7 +3,9 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { DefaultClient, FormatParams, FormatRangeRequest, FormatResult } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings, getEditorConfigSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -42,12 +44,16 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange }, onChanges: false }; - // We do not currently pass the CancellationToken to sendRequest - // because there is not currently cancellation logic for formatting - // in the native process. Formatting is currently done directly in - // message handling thread. - const response: FormatResult = await this.client.languageClient.sendRequest(FormatRangeRequest, params, token); - if (token.isCancellationRequested || response.edits === undefined) { + let response: FormatResult; + try { + response = await this.client.languageClient.sendRequest(FormatRangeRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } return makeVscodeTextEdits(response.edits); diff --git a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts index 819775a5b2..4d4c3019da 100644 --- a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts @@ -3,9 +3,11 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { Client, DefaultClient, GetDocumentSymbolRequest, GetDocumentSymbolRequestParams, GetDocumentSymbolResult, LocalizeDocumentSymbol, SymbolScope } from '../client'; import { clients } from '../extension'; import { getLocalizedString, getLocalizedSymbolScope } from '../localization'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { makeVscodeRange } from '../utils'; export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { @@ -61,8 +63,16 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { const params: GetDocumentSymbolRequestParams = { uri: document.uri.toString() }; - const response: GetDocumentSymbolResult = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token); - if (token.isCancellationRequested || response.symbols === undefined) { + let response: GetDocumentSymbolResult; + try { + response = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } const resultSymbols: vscode.DocumentSymbol[] = this.getChildrenSymbols(response.symbols); diff --git a/Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts b/Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts index 306165d1f3..01b2dc18e2 100644 --- a/Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts +++ b/Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts @@ -3,8 +3,9 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { Position, RequestType } from 'vscode-languageclient'; +import { Position, RequestType, ResponseError } from 'vscode-languageclient'; import { DefaultClient, workspaceReferences } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, ReferencesResult } from '../references'; const FindAllReferencesRequest: RequestType = @@ -34,7 +35,16 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider { position: Position.create(position.line, position.character), textDocument: { uri: document.uri.toString() } }; - const response: ReferencesResult = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token); + let response: ReferencesResult | undefined; + let cancelled: boolean = false; + 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; + } + } // Reset anything that can be cleared before processing the result. workspaceReferences.resetProgressBar(); @@ -42,14 +52,14 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider { requestCanceledListener.dispose(); // Process the result. - if (cancelSource.token.isCancellationRequested || response.referenceInfos === null || response.isCanceled) { + if (cancelSource.token.isCancellationRequested || cancelled || (response && response.isCanceled)) { // 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.referenceInfos.length > 0) { + } 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); diff --git a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts index be2a571aa5..c7065122a0 100644 --- a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts +++ b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts @@ -3,8 +3,10 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { ManualPromise } from '../../Utility/Async/manualPromise'; import { CppFoldingRange, DefaultClient, FoldingRangeKind, GetFoldingRangesParams, GetFoldingRangesRequest, GetFoldingRangesResult } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings } from '../settings'; interface FoldingRangeRequestInfo { @@ -62,8 +64,16 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider { uri }; - const response: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token); - if (token.isCancellationRequested || response.ranges === undefined) { + let response: GetFoldingRangesResult; + try { + response = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } const result: vscode.FoldingRange[] = []; diff --git a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts index 7a219d8440..d4725c13eb 100644 --- a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts @@ -3,7 +3,9 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { DefaultClient, FormatOnTypeRequest, FormatParams, FormatResult } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CppSettings, getEditorConfigSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -41,12 +43,16 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit }, onChanges: false }; - // We do not currently pass the CancellationToken to sendRequest - // because there is not currently cancellation logic for formatting - // in the native process. Formatting is currently done directly in - // message handling thread. - const response: FormatResult = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params, token); - if (token.isCancellationRequested || response.edits === undefined) { + let response: FormatResult; + try { + response = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } + if (token.isCancellationRequested) { throw new vscode.CancellationError(); } return makeVscodeTextEdits(response.edits); diff --git a/Extension/src/LanguageServer/Providers/renameProvider.ts b/Extension/src/LanguageServer/Providers/renameProvider.ts index 4ee347df18..8a46d81c8c 100644 --- a/Extension/src/LanguageServer/Providers/renameProvider.ts +++ b/Extension/src/LanguageServer/Providers/renameProvider.ts @@ -3,10 +3,11 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { Position, RequestType } from 'vscode-languageclient'; +import { Position, RequestType, ResponseError } from 'vscode-languageclient'; import * as nls from 'vscode-nls'; import * as util from '../../common'; import { DefaultClient, workspaceReferences } from '../client'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { CancellationSender, ReferenceType, ReferencesParams, ReferencesResult, getReferenceItemIconPath, getReferenceTagString } from '../references'; import { CppSettings } from '../settings'; @@ -47,7 +48,15 @@ export class RenameProvider implements vscode.RenameProvider { position: Position.create(position.line, position.character), textDocument: { uri: document.uri.toString() } }; - const response: ReferencesResult = await this.client.languageClient.sendRequest(RenameRequest, params, cancelSource.token); + let response: ReferencesResult; + try { + response = await this.client.languageClient.sendRequest(RenameRequest, params, cancelSource.token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } // Reset anything that can be cleared before processing the result. workspaceReferences.resetProgressBar(); @@ -55,7 +64,7 @@ export class RenameProvider implements vscode.RenameProvider { requestCanceledListener.dispose(); // Process the result. - if (cancelSource.token.isCancellationRequested || response.referenceInfos === null || response.isCanceled) { + if (cancelSource.token.isCancellationRequested || response.isCanceled) { throw new vscode.CancellationError(); } else if (response.referenceInfos.length === 0) { void vscode.window.showErrorMessage(localize("unable.to.locate.selected.symbol", "A definition for the selected symbol could not be located.")); diff --git a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts index 80d41dcaa1..041c7a2593 100644 --- a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts @@ -3,9 +3,11 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; +import { ResponseError } from 'vscode-languageclient'; import { isExperimentEnabled } from '../../telemetry'; import { DefaultClient, GetSymbolInfoRequest, LocalizeSymbolInformation, SymbolScope, WorkspaceSymbolParams } from '../client'; import { getLocalizedString, getLocalizedSymbolScope } from '../localization'; +import { RequestCancelled, ServerCancelled } from '../protocolFilter'; import { makeVscodeLocation } from '../utils'; export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { @@ -25,7 +27,15 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { experimentEnabled: await isExperimentEnabled('CppTools1') }; - const symbols: LocalizeSymbolInformation[] = await this.client.languageClient.sendRequest(GetSymbolInfoRequest, params, token); + let symbols: LocalizeSymbolInformation[]; + try { + symbols = await this.client.languageClient.sendRequest(GetSymbolInfoRequest, params, token); + } catch (e: any) { + if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) { + throw new vscode.CancellationError(); + } + throw e; + } const resultSymbols: vscode.SymbolInformation[] = []; if (token.isCancellationRequested) { throw new vscode.CancellationError(); diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index e161d8f566..4bc3e45fe5 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -12,6 +12,9 @@ import { Client } from './client'; import { clients } from './extension'; import { shouldChangeFromCToCpp } from './utils'; +export const RequestCancelled: number = -32800; +export const ServerCancelled: number = -32802; + let anyFileOpened: boolean = false; export function createProtocolFilter(): Middleware {