Skip to content

Commit a0f863c

Browse files
authored
Fix LSP cancellation (#12592)
1 parent 818f7c6 commit a0f863c

11 files changed

+157
-48
lines changed

Extension/src/LanguageServer/Providers/callHierarchyProvider.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
* ------------------------------------------------------------------------------------------ */
55
import * as path from 'path';
66
import * as vscode from 'vscode';
7-
import { Position, Range, RequestType, TextDocumentIdentifier } from 'vscode-languageclient';
7+
import { Position, Range, RequestType, ResponseError, TextDocumentIdentifier } from 'vscode-languageclient';
88
import * as Telemetry from '../../telemetry';
99
import { DefaultClient, workspaceReferences } from '../client';
10+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
1011
import { CancellationSender } from '../references';
1112
import { makeVscodeRange } from '../utils';
1213

@@ -127,8 +128,15 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
127128
textDocument: { uri: document.uri.toString() },
128129
position: Position.create(position.line, position.character)
129130
};
130-
const response: CallHierarchyItemResult = await this.client.languageClient.sendRequest(CallHierarchyItemRequest, params, cancelSource.token);
131-
131+
let response: CallHierarchyItemResult;
132+
try {
133+
response = await this.client.languageClient.sendRequest(CallHierarchyItemRequest, params, cancelSource.token);
134+
} catch (e: any) {
135+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
136+
return undefined;
137+
}
138+
throw e;
139+
}
132140
cancellationTokenListener.dispose();
133141
requestCanceledListener.dispose();
134142

@@ -176,8 +184,16 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
176184
textDocument: { uri: item.uri.toString() },
177185
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
178186
};
179-
const response: CallHierarchyCallsItemResult = await this.client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, cancelSource.token);
180-
187+
let response: CallHierarchyCallsItemResult | undefined;
188+
let cancelled: boolean = false;
189+
try {
190+
response = await this.client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, cancelSource.token);
191+
} catch (e: any) {
192+
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
193+
if (!cancelled) {
194+
throw e;
195+
}
196+
}
181197
// Reset anything that can be cleared before processing the result.
182198
const progressBarDuration: number | undefined = workspaceReferences.getCallHierarchyProgressBarDuration();
183199
workspaceReferences.resetProgressBar();
@@ -186,12 +202,12 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
186202
requestCanceledListener.dispose();
187203

188204
// Process the result.
189-
if (cancelSource.token.isCancellationRequested || response.calls === undefined || requestCanceled !== undefined) {
205+
if (cancelSource.token.isCancellationRequested || cancelled || requestCanceled !== undefined) {
190206
const requestStatus: CallHierarchyRequestStatus = requestCanceled === CancellationSender.User ?
191207
CallHierarchyRequestStatus.CanceledByUser : CallHierarchyRequestStatus.Canceled;
192208
this.logTelemetry(CallHierarchyCallsToEvent, requestStatus, progressBarDuration);
193209
throw new vscode.CancellationError();
194-
} else if (response.calls.length !== 0) {
210+
} else if (response && response.calls.length !== 0) {
195211
result = this.createIncomingCalls(response.calls);
196212
}
197213

@@ -214,12 +230,20 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
214230
textDocument: { uri: item.uri.toString() },
215231
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
216232
};
217-
const response: CallHierarchyCallsItemResult = await this.client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token);
218-
219-
if (token.isCancellationRequested || response.calls === undefined) {
233+
let response: CallHierarchyCallsItemResult | undefined;
234+
let cancelled: boolean = false;
235+
try {
236+
await this.client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token);
237+
} catch (e: any) {
238+
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
239+
if (!cancelled) {
240+
throw e;
241+
}
242+
}
243+
if (token.isCancellationRequested || cancelled) {
220244
this.logTelemetry(CallHierarchyCallsFromEvent, CallHierarchyRequestStatus.Canceled);
221245
throw new vscode.CancellationError();
222-
} else if (response.calls.length !== 0) {
246+
} else if (response && response.calls.length !== 0) {
223247
result = this.createOutgoingCalls(response.calls);
224248
}
225249

Extension/src/LanguageServer/Providers/codeActionProvider.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6-
import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient';
6+
import { Position, Range, RequestType, ResponseError, TextEdit } from 'vscode-languageclient';
77
import * as nls from 'vscode-nls';
88
import { DefaultClient } from '../client';
99
import {
1010
CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions
1111
} from '../codeAnalysis';
1212
import { LocalizeStringParams, getLocalizedString } from '../localization';
13+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
1314
import { CppSettings } from '../settings';
1415
import { makeVscodeRange } from '../utils';
1516

@@ -70,14 +71,21 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
7071
uri: document.uri.toString()
7172
};
7273

73-
let response: GetCodeActionsResult = await this.client.languageClient.sendRequest(
74-
GetCodeActionsRequest, params, token);
74+
let response: GetCodeActionsResult;
75+
try {
76+
response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token);
77+
} catch (e: any) {
78+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
79+
throw new vscode.CancellationError();
80+
}
81+
throw e;
82+
}
7583

76-
const resultCodeActions: vscode.CodeAction[] = [];
77-
if (token.isCancellationRequested || response.commands === undefined) {
84+
if (token.isCancellationRequested) {
7885
throw new vscode.CancellationError();
7986
}
8087

88+
const resultCodeActions: vscode.CodeAction[] = [];
8189
let hasSelectIntelliSenseConfiguration: boolean = false;
8290
const settings: CppSettings = new CppSettings(this.client.RootUri);
8391
const hasConfigurationSet: boolean = settings.defaultCompilerPath !== null ||
@@ -254,8 +262,15 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
254262
if (!hoverResult.value.includes(localize("expands.to", "Expands to:"))) {
255263
return false;
256264
}
257-
response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token);
258-
if (token.isCancellationRequested || response.commands === undefined) {
265+
try {
266+
response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token);
267+
} catch (e: any) {
268+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
269+
return false;
270+
}
271+
throw e;
272+
}
273+
if (token.isCancellationRequested) {
259274
return false;
260275
}
261276
for (const command of response.commands) {

Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6+
import { ResponseError } from 'vscode-languageclient';
67
import { DefaultClient, FormatDocumentRequest, FormatParams, FormatResult } from '../client';
8+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
79
import { CppSettings, OtherSettings, getEditorConfigSettings } from '../settings';
810
import { makeVscodeTextEdits } from '../utils';
911

@@ -66,12 +68,16 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting
6668
},
6769
onChanges: options.onChanges === true
6870
};
69-
// We do not currently pass the CancellationToken to sendRequest
70-
// because there is not currently cancellation logic for formatting
71-
// in the native process. Formatting is currently done directly in
72-
// message handling thread.
73-
const response: FormatResult = await this.client.languageClient.sendRequest(FormatDocumentRequest, params, token);
74-
if (token.isCancellationRequested || response.edits === undefined) {
71+
let response: FormatResult;
72+
try {
73+
response = await this.client.languageClient.sendRequest(FormatDocumentRequest, params, token);
74+
} catch (e: any) {
75+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
76+
throw new vscode.CancellationError();
77+
}
78+
throw e;
79+
}
80+
if (token.isCancellationRequested) {
7581
throw new vscode.CancellationError();
7682
}
7783
const results: vscode.TextEdit[] = makeVscodeTextEdits(response.edits);

Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6+
import { ResponseError } from 'vscode-languageclient';
67
import { DefaultClient, FormatParams, FormatRangeRequest, FormatResult } from '../client';
8+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
79
import { CppSettings, getEditorConfigSettings } from '../settings';
810
import { makeVscodeTextEdits } from '../utils';
911

@@ -42,12 +44,16 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange
4244
},
4345
onChanges: false
4446
};
45-
// We do not currently pass the CancellationToken to sendRequest
46-
// because there is not currently cancellation logic for formatting
47-
// in the native process. Formatting is currently done directly in
48-
// message handling thread.
49-
const response: FormatResult = await this.client.languageClient.sendRequest(FormatRangeRequest, params, token);
50-
if (token.isCancellationRequested || response.edits === undefined) {
47+
let response: FormatResult;
48+
try {
49+
response = await this.client.languageClient.sendRequest(FormatRangeRequest, params, token);
50+
} catch (e: any) {
51+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
52+
throw new vscode.CancellationError();
53+
}
54+
throw e;
55+
}
56+
if (token.isCancellationRequested) {
5157
throw new vscode.CancellationError();
5258
}
5359
return makeVscodeTextEdits(response.edits);

Extension/src/LanguageServer/Providers/documentSymbolProvider.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6+
import { ResponseError } from 'vscode-languageclient';
67
import { Client, DefaultClient, GetDocumentSymbolRequest, GetDocumentSymbolRequestParams, GetDocumentSymbolResult, LocalizeDocumentSymbol, SymbolScope } from '../client';
78
import { clients } from '../extension';
89
import { getLocalizedString, getLocalizedSymbolScope } from '../localization';
10+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
911
import { makeVscodeRange } from '../utils';
1012

1113
export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
@@ -61,8 +63,16 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
6163
const params: GetDocumentSymbolRequestParams = {
6264
uri: document.uri.toString()
6365
};
64-
const response: GetDocumentSymbolResult = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
65-
if (token.isCancellationRequested || response.symbols === undefined) {
66+
let response: GetDocumentSymbolResult;
67+
try {
68+
response = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
69+
} catch (e: any) {
70+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
71+
throw new vscode.CancellationError();
72+
}
73+
throw e;
74+
}
75+
if (token.isCancellationRequested) {
6676
throw new vscode.CancellationError();
6777
}
6878
const resultSymbols: vscode.DocumentSymbol[] = this.getChildrenSymbols(response.symbols);

Extension/src/LanguageServer/Providers/findAllReferencesProvider.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6-
import { Position, RequestType } from 'vscode-languageclient';
6+
import { Position, RequestType, ResponseError } from 'vscode-languageclient';
77
import { DefaultClient, workspaceReferences } from '../client';
8+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
89
import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, ReferencesResult } from '../references';
910

1011
const FindAllReferencesRequest: RequestType<ReferencesParams, ReferencesResult, void> =
@@ -34,22 +35,31 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
3435
position: Position.create(position.line, position.character),
3536
textDocument: { uri: document.uri.toString() }
3637
};
37-
const response: ReferencesResult = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token);
38+
let response: ReferencesResult | undefined;
39+
let cancelled: boolean = false;
40+
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+
}
3848

3949
// Reset anything that can be cleared before processing the result.
4050
workspaceReferences.resetProgressBar();
4151
cancellationTokenListener.dispose();
4252
requestCanceledListener.dispose();
4353

4454
// Process the result.
45-
if (cancelSource.token.isCancellationRequested || response.referenceInfos === null || response.isCanceled) {
55+
if (cancelSource.token.isCancellationRequested || cancelled || (response && response.isCanceled)) {
4656
// Return undefined instead of vscode.CancellationError to avoid the following error message from VS Code:
4757
// "Cannot destructure property 'range' of 'e.location' as it is undefined."
4858
// TODO: per issue https://github.com/microsoft/vscode/issues/169698
4959
// vscode.CancellationError is expected, so when VS Code fixes the error use vscode.CancellationError again.
5060
workspaceReferences.resetReferences();
5161
return undefined;
52-
} else if (response.referenceInfos.length > 0) {
62+
} else if (response && response.referenceInfos.length > 0) {
5363
response.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
5464
if (referenceInfo.type === ReferenceType.Confirmed) {
5565
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);

Extension/src/LanguageServer/Providers/foldingRangeProvider.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6+
import { ResponseError } from 'vscode-languageclient';
67
import { ManualPromise } from '../../Utility/Async/manualPromise';
78
import { CppFoldingRange, DefaultClient, FoldingRangeKind, GetFoldingRangesParams, GetFoldingRangesRequest, GetFoldingRangesResult } from '../client';
9+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
810
import { CppSettings } from '../settings';
911

1012
interface FoldingRangeRequestInfo {
@@ -62,8 +64,16 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider {
6264
uri
6365
};
6466

65-
const response: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token);
66-
if (token.isCancellationRequested || response.ranges === undefined) {
67+
let response: GetFoldingRangesResult;
68+
try {
69+
response = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token);
70+
} catch (e: any) {
71+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
72+
throw new vscode.CancellationError();
73+
}
74+
throw e;
75+
}
76+
if (token.isCancellationRequested) {
6777
throw new vscode.CancellationError();
6878
}
6979
const result: vscode.FoldingRange[] = [];

Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* See 'LICENSE' in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import * as vscode from 'vscode';
6+
import { ResponseError } from 'vscode-languageclient';
67
import { DefaultClient, FormatOnTypeRequest, FormatParams, FormatResult } from '../client';
8+
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
79
import { CppSettings, getEditorConfigSettings } from '../settings';
810
import { makeVscodeTextEdits } from '../utils';
911

@@ -41,12 +43,16 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit
4143
},
4244
onChanges: false
4345
};
44-
// We do not currently pass the CancellationToken to sendRequest
45-
// because there is not currently cancellation logic for formatting
46-
// in the native process. Formatting is currently done directly in
47-
// message handling thread.
48-
const response: FormatResult = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params, token);
49-
if (token.isCancellationRequested || response.edits === undefined) {
46+
let response: FormatResult;
47+
try {
48+
response = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params, token);
49+
} catch (e: any) {
50+
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
51+
throw new vscode.CancellationError();
52+
}
53+
throw e;
54+
}
55+
if (token.isCancellationRequested) {
5056
throw new vscode.CancellationError();
5157
}
5258
return makeVscodeTextEdits(response.edits);

0 commit comments

Comments
 (0)