Skip to content

Commit 95be1ea

Browse files
committed
Add roslyn language client to dispose of registrations on language client dispose
1 parent 8e4471d commit 95be1ea

File tree

2 files changed

+55
-20
lines changed

2 files changed

+55
-20
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
6+
import { LanguageClient, LanguageClientOptions, ServerOptions } from "vscode-languageclient/node";
7+
import CompositeDisposable from "../CompositeDisposable";
8+
import { IDisposable } from "../Disposable";
9+
10+
export class RoslynLanguageClientInstance extends LanguageClient {
11+
12+
private readonly _disposables: CompositeDisposable;
13+
14+
constructor(
15+
id: string,
16+
name: string,
17+
serverOptions: ServerOptions,
18+
clientOptions: LanguageClientOptions,
19+
forceDebug?: boolean) {
20+
super(id, name, serverOptions, clientOptions, forceDebug);
21+
this._disposables = new CompositeDisposable();
22+
}
23+
24+
override async dispose(timeout?: number | undefined): Promise<void> {
25+
this._disposables.dispose();
26+
return super.dispose(timeout);
27+
}
28+
29+
/**
30+
* Adds a disposable that should be disposed of when the LanguageClient instance gets disposed.
31+
*/
32+
public addDisposable(disposable: IDisposable) {
33+
this._disposables.add(disposable);
34+
}
35+
}

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { UriConverter } from './uriConverter';
1414
import {
1515
DidChangeTextDocumentNotification,
1616
DidCloseTextDocumentNotification,
17-
LanguageClient,
1817
LanguageClientOptions,
1918
ServerOptions,
2019
DidCloseTextDocumentParams,
@@ -56,6 +55,7 @@ import TelemetryReporter from '@vscode/extension-telemetry';
5655
import CSharpIntelliCodeExports from '../CSharpIntelliCodeExports';
5756
import { csharpDevkitExtensionId, getCSharpDevKit } from '../utils/getCSharpDevKit';
5857
import { randomUUID } from 'crypto';
58+
import { RoslynLanguageClientInstance } from './roslynLanguageClient';
5959

6060
let _languageServer: RoslynLanguageServer;
6161
let _channel: vscode.OutputChannel;
@@ -89,7 +89,7 @@ export class RoslynLanguageServer {
8989
* The timeout for stopping the language server (in ms).
9090
*/
9191
private static _stopTimeout: number = 10000;
92-
private _languageClient: LanguageClient | undefined;
92+
private _languageClient: RoslynLanguageClientInstance | undefined;
9393

9494
/**
9595
* Flag indicating if C# Devkit was installed the last time we activated.
@@ -192,7 +192,7 @@ export class RoslynLanguageServer {
192192
};
193193

194194
// Create the language client and start the client.
195-
let client = new LanguageClient(
195+
let client = new RoslynLanguageClientInstance(
196196
'microsoft-codeanalysis-languageserver',
197197
'Microsoft.CodeAnalysis.LanguageServer',
198198
serverOptions,
@@ -460,7 +460,7 @@ export class RoslynLanguageServer {
460460
return childProcess;
461461
}
462462

463-
private registerRazor(client: LanguageClient) {
463+
private registerRazor(client: RoslynLanguageClientInstance) {
464464
// When the Roslyn language server sends a request for Razor dynamic file info, we forward that request along to Razor via
465465
// a command.
466466
client.onRequest(
@@ -472,40 +472,40 @@ export class RoslynLanguageServer {
472472

473473
// Razor will call into us (via command) for generated file didChange/didClose notifications. We'll then forward these
474474
// notifications along to Roslyn. didOpen notifications are handled separately via the vscode.openTextDocument method.
475-
vscode.commands.registerCommand(RoslynLanguageServer.roslynDidChangeCommand, (notification: DidChangeTextDocumentParams) => {
475+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.roslynDidChangeCommand, (notification: DidChangeTextDocumentParams) => {
476476
client.sendNotification(DidChangeTextDocumentNotification.method, notification);
477-
});
478-
vscode.commands.registerCommand(RoslynLanguageServer.roslynDidCloseCommand, (notification: DidCloseTextDocumentParams) => {
477+
}));
478+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.roslynDidCloseCommand, (notification: DidCloseTextDocumentParams) => {
479479
client.sendNotification(DidCloseTextDocumentNotification.method, notification);
480-
});
481-
vscode.commands.registerCommand(RoslynLanguageServer.roslynPullDiagnosticCommand, async (request: DocumentDiagnosticParams) => {
480+
}));
481+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.roslynPullDiagnosticCommand, async (request: DocumentDiagnosticParams) => {
482482
let diagnosticRequestType = new RequestType<DocumentDiagnosticParams, DocumentDiagnosticReport, any>(DocumentDiagnosticRequest.method);
483483
return await this.sendRequest(diagnosticRequestType, request, CancellationToken.None);
484-
});
484+
}));
485485

486486
// The VS Code API for code actions (and the vscode.CodeAction type) doesn't support everything that LSP supports,
487487
// namely the data property, which Razor needs to identify which code actions are on their allow list, so we need
488488
// to expose a command for them to directly invoke our code actions LSP endpoints, rather than use built-in commands.
489-
vscode.commands.registerCommand(RoslynLanguageServer.provideCodeActionsCommand, async (request: CodeActionParams) => {
489+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.provideCodeActionsCommand, async (request: CodeActionParams) => {
490490
return await this.sendRequest(CodeActionRequest.type, request, CancellationToken.None);
491-
});
492-
vscode.commands.registerCommand(RoslynLanguageServer.resolveCodeActionCommand, async (request: CodeAction) => {
491+
}));
492+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.resolveCodeActionCommand, async (request: CodeAction) => {
493493
return await this.sendRequest(CodeActionResolveRequest.type, request, CancellationToken.None);
494-
});
494+
}));
495495

496-
vscode.commands.registerCommand(RoslynLanguageServer.provideCompletionsCommand, async (request: CompletionParams) => {
496+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.provideCompletionsCommand, async (request: CompletionParams) => {
497497
return await this.sendRequest(CompletionRequest.type, request, CancellationToken.None);
498-
});
499-
vscode.commands.registerCommand(RoslynLanguageServer.resolveCompletionsCommand, async (request: CompletionItem) => {
498+
}));
499+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.resolveCompletionsCommand, async (request: CompletionItem) => {
500500
return await this.sendRequest(CompletionResolveRequest.type, request, CancellationToken.None);
501-
});
501+
}));
502502

503503
// Roslyn is responsible for producing a json file containing information for Razor, that comes from the compilation for
504504
// a project. We want to defer this work until necessary, so this command is called by the Razor document manager to tell
505505
// us when they need us to initialize the Razor things.
506-
vscode.commands.registerCommand(RoslynLanguageServer.razorInitializeCommand, () => {
506+
client.addDisposable(vscode.commands.registerCommand(RoslynLanguageServer.razorInitializeCommand, () => {
507507
client.sendNotification("razor/initialize", { });
508-
});
508+
}));
509509
}
510510

511511
private getServerFileName() {

0 commit comments

Comments
 (0)