Skip to content

Commit 6c9c959

Browse files
committed
Merge branch 'dev/evgenyt/improve_complex_edit' of https://github.com/etvorun/vscode-csharp into dev/evgenyt/improve_complex_edit
2 parents 324b354 + 0320ad8 commit 6c9c959

File tree

9 files changed

+460
-21
lines changed

9 files changed

+460
-21
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
## Known Issues
22

3-
- In version 2.15.30 only, .NET 6.0 projects fail to load if only the 6.0 SDK is installed [#6801](https://github.com/dotnet/vscode-csharp/issues/6801)
4-
- If you are trying to load a project that uses the 6.0 SDK, and you do not have any higher SDKs installed, you might get an error message like "Exception thrown while loading (project name) System.Exception: The server disconnected unexpectedly." In that case, try installing a 7.0 SDK as well, which should mitigate the issue. Other workarounds are available in the bug link if needed.
53
- Diagnostics related feature requests and improvements [#5951](https://github.com/dotnet/vscode-csharp/issues/5951)
6-
- [O# Parity] Nested code code action support for code fixes and refactorings [#5735](https://github.com/dotnet/vscode-csharp/issues/5735)
7-
- [O# Parity] Nuget restore [#5725](https://github.com/dotnet/vscode-csharp/issues/5725)
84
- Debug from .csproj and .sln [#5876](https://github.com/dotnet/vscode-csharp/issues/5876)
95

6+
## Latest
7+
* Update Roslyn to 4.10.0-1.24066.17 (PR: [#6816](https://github.com/dotnet/vscode-csharp/pull/6816))
8+
* Fix issue loading .NET 6.0 projects when only the 6.0 SDK is installed (PR: [#71597](https://github.com/dotnet/roslyn/pull/71597))
9+
1010
## 2.15.30
1111
* Update Roslyn to 4.10.0-1.24058.1 (PR: [#6791](https://github.com/dotnet/vscode-csharp/pull/6791))
1212
* Fix error when a source generated file was present in find references or go to definition requests (PR: [#71395](https://github.com/dotnet/roslyn/pull/71395))

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
}
3838
},
3939
"defaults": {
40-
"roslyn": "4.10.0-1.24058.1",
40+
"roslyn": "4.10.0-1.24066.17",
4141
"omniSharp": "1.39.11",
4242
"razor": "7.0.0-preview.23627.2",
4343
"razorOmnisharp": "7.0.0-preview.23363.1",

src/lsptoolshost/onAutoInsert.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,15 @@ export function registerOnAutoInsert(languageServer: RoslynLanguageServer) {
4040

4141
source.cancel();
4242
source = new vscode.CancellationTokenSource();
43-
await applyAutoInsertEdit(e, changeTrimmed, languageServer, source.token);
43+
try {
44+
await applyAutoInsertEdit(e, changeTrimmed, languageServer, source.token);
45+
} catch (e) {
46+
if (e instanceof vscode.CancellationError) {
47+
return;
48+
}
49+
50+
throw e;
51+
}
4452
}
4553
});
4654
}

src/lsptoolshost/restore.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,19 @@ async function chooseProjectAndRestore(
4141
languageServer: RoslynLanguageServer,
4242
restoreChannel: vscode.OutputChannel
4343
): Promise<void> {
44-
const projects = await languageServer.sendRequest0(
45-
RestorableProjects.type,
46-
new vscode.CancellationTokenSource().token
47-
);
44+
let projects: string[];
45+
try {
46+
projects = await languageServer.sendRequest0(
47+
RestorableProjects.type,
48+
new vscode.CancellationTokenSource().token
49+
);
50+
} catch (e) {
51+
if (e instanceof vscode.CancellationError) {
52+
return;
53+
}
54+
55+
throw e;
56+
}
4857

4958
const items = projects.map((p) => {
5059
const projectName = path.basename(p);

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
RAL,
2929
CancellationToken,
3030
RequestHandler,
31+
ResponseError,
3132
} from 'vscode-languageclient/node';
3233
import { PlatformInformation } from '../shared/platform';
3334
import { readConfigurations } from './configurationMiddleware';
@@ -270,8 +271,12 @@ export class RoslynLanguageServer {
270271
throw new Error('Tried to send request while server is not started.');
271272
}
272273

273-
const response = await this._languageClient.sendRequest(type, params, token);
274-
return response;
274+
try {
275+
const response = await this._languageClient.sendRequest(type, params, token);
276+
return response;
277+
} catch (e) {
278+
throw this.convertServerError(type.method, e);
279+
}
275280
}
276281

277282
/**
@@ -285,8 +290,12 @@ export class RoslynLanguageServer {
285290
throw new Error('Tried to send request while server is not started.');
286291
}
287292

288-
const response = await this._languageClient.sendRequest(type, token);
289-
return response;
293+
try {
294+
const response = await this._languageClient.sendRequest(type, token);
295+
return response;
296+
} catch (e) {
297+
throw this.convertServerError(type.method, e);
298+
}
290299
}
291300

292301
public async sendRequestWithProgress<P extends PartialResultParams, R, PR, E, RO>(
@@ -302,10 +311,15 @@ export class RoslynLanguageServer {
302311
const disposable = this._languageClient.onProgress(type, partialResultToken, async (partialResult) => {
303312
await onProgress(partialResult);
304313
});
305-
const response = await this._languageClient
306-
.sendRequest(type, params, cancellationToken)
307-
.finally(() => disposable.dispose());
308-
return response;
314+
315+
try {
316+
const response = await this._languageClient.sendRequest(type, params, cancellationToken);
317+
return response;
318+
} catch (e) {
319+
throw this.convertServerError(type.method, e);
320+
} finally {
321+
disposable.dispose();
322+
}
309323
}
310324

311325
/**
@@ -368,6 +382,25 @@ export class RoslynLanguageServer {
368382
}
369383
}
370384

385+
private convertServerError(request: string, e: any): Error {
386+
let error: Error;
387+
if (e instanceof ResponseError && e.code === -32800) {
388+
// Convert the LSP RequestCancelled error (code -32800) to a CancellationError so we can handle cancellation uniformly.
389+
error = new vscode.CancellationError();
390+
} else if (e instanceof Error) {
391+
error = e;
392+
} else if (typeof e === 'string') {
393+
error = new Error(e);
394+
} else {
395+
error = new Error(`Unknown error: ${e.toString()}`);
396+
}
397+
398+
if (!(error instanceof vscode.CancellationError)) {
399+
_channel.appendLine(`Error making ${request} request: ${error.message}`);
400+
}
401+
return error;
402+
}
403+
371404
private async openDefaultSolutionOrProjects(): Promise<void> {
372405
// If Dev Kit isn't installed, then we are responsible for picking the solution to open, assuming the user hasn't explicitly
373406
// disabled it.
@@ -723,8 +756,19 @@ export class RoslynLanguageServer {
723756
// When a file is opened process any build diagnostics that may be shown
724757
this._languageClient.addDisposable(
725758
vscode.workspace.onDidOpenTextDocument(async (event) => {
726-
const buildIds = await this.getBuildOnlyDiagnosticIds(CancellationToken.None);
727-
this._buildDiagnosticService._onFileOpened(event, buildIds);
759+
try {
760+
const buildIds = await this.getBuildOnlyDiagnosticIds(CancellationToken.None);
761+
this._buildDiagnosticService._onFileOpened(event, buildIds);
762+
} catch (e) {
763+
if (e instanceof vscode.CancellationError) {
764+
// The request was cancelled (not due to us) - this means the server is no longer accepting requests
765+
// so there is nothing for us to do here.
766+
return;
767+
}
768+
769+
// Let non-cancellation errors bubble up.
770+
throw e;
771+
}
728772
})
729773
);
730774
}

test/artifactTests/vsix.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('Vscode VSIX', () => {
1818
vsixFiles.forEach((element) => {
1919
// We're packaging the platform specific Roslyn server with ready to run in the vsix, so the size should be roughly ~50MB
2020
// We also publish the Razor server, which is roughly ~75MB
21-
const sizeInMB = 230;
21+
const sizeInMB = 240;
2222
const maximumVsixSizeInBytes = sizeInMB * 1024 * 1024;
2323

2424
describe(`Given ${element}`, () => {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import * as vscode from 'vscode';
6+
import { expect } from '@jest/globals';
7+
import { restartLanguageServer } from './integrationHelpers';
8+
9+
function sortDiagnostics(diagnostics: vscode.Diagnostic[]): vscode.Diagnostic[] {
10+
return diagnostics.sort((a, b) => {
11+
const rangeCompare = a.range.start.compareTo(b.range.start);
12+
if (rangeCompare !== 0) {
13+
return rangeCompare;
14+
}
15+
16+
return getCode(a).localeCompare(getCode(b));
17+
});
18+
}
19+
20+
export async function waitForExpectedDiagnostics(
21+
assertExpectedDiagnostics: (input: [vscode.Uri, vscode.Diagnostic[]][]) => void,
22+
file?: vscode.Uri
23+
): Promise<void> {
24+
let duration = 30 * 1000;
25+
const step = 500;
26+
let error: any = undefined;
27+
while (duration > 0) {
28+
const diagnostics: [vscode.Uri, vscode.Diagnostic[]][] = [];
29+
if (file) {
30+
diagnostics.push([file, sortDiagnostics(vscode.languages.getDiagnostics(file))]);
31+
} else {
32+
const allDiagnostics = vscode.languages.getDiagnostics();
33+
for (const [uri, uriDiagnostics] of allDiagnostics) {
34+
diagnostics.push([uri, sortDiagnostics(uriDiagnostics)]);
35+
}
36+
}
37+
38+
try {
39+
assertExpectedDiagnostics(diagnostics);
40+
return;
41+
} catch (e) {
42+
error = e;
43+
// Wait for a bit and try again.
44+
await new Promise((r) => setTimeout(r, step));
45+
duration -= step;
46+
}
47+
}
48+
49+
throw new Error(`Polling did not succeed within the alotted duration: ${error}`);
50+
}
51+
52+
export async function setBackgroundAnalysisScopes(scopes: { compiler: string; analyzer: string }): Promise<void> {
53+
const dotnetConfig = vscode.workspace.getConfiguration('dotnet');
54+
await dotnetConfig.update('backgroundAnalysis.compilerDiagnosticsScope', scopes.compiler);
55+
await dotnetConfig.update('backgroundAnalysis.analyzerDiagnosticsScope', scopes.analyzer);
56+
57+
// Restart the language server to ensure diagnostics are reported with the correct configuration.
58+
// While in normal user scenarios it isn't necessary to restart the server to pickup diagnostic config changes,
59+
// we need to do it in integration tests for two reasons:
60+
// 1. We don't know when the server finishes processing the config change (its sent as a notification from client -> server).
61+
// 2. Even if we processed the config change, the VSCode API does not provide a way to re-request diagnostics after the config change.
62+
await restartLanguageServer();
63+
}
64+
65+
export function getCode(diagnostic: vscode.Diagnostic): string {
66+
const code: {
67+
value: string | number;
68+
target: vscode.Uri;
69+
} = diagnostic.code as any;
70+
expect(code).toBeDefined();
71+
return code.value.toString();
72+
}

0 commit comments

Comments
 (0)