Skip to content

Commit 3daf73a

Browse files
Merge pull request #147 from OmniSharp/fix/gh141
Added a fix for #141 with test validating that it works
2 parents 59204cd + 53d33d9 commit 3daf73a

File tree

7 files changed

+97
-18
lines changed

7 files changed

+97
-18
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ tools/*/
4141
coverage.*.xml
4242
coverage.json
4343
coverage.info
44+
/codealike.json

LSP.sln

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
2-
# Visual Studio 15
3-
VisualStudioVersion = 15.0.27130.2003
2+
# Visual Studio Version 16
3+
VisualStudioVersion = 16.0.29025.244
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D764E024-3D3F-4112-B932-2DB722A1BACC}"
66
ProjectSection(SolutionItems) = preProject

src/JsonRpc/IRequestRouter.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55

66
namespace OmniSharp.Extensions.JsonRpc
77
{
8-
public interface IRequestRouter<TDescriptor>
8+
public interface IRequestRouter
9+
{
10+
Task RouteNotification(Notification notification, CancellationToken token);
11+
Task<ErrorResponse> RouteRequest(Request request, CancellationToken token);
12+
void CancelRequest(object id);
13+
}
14+
15+
public interface IRequestRouter<TDescriptor> : IRequestRouter
916
{
1017
TDescriptor GetDescriptor(Notification notification);
1118
TDescriptor GetDescriptor(Request request);
12-
13-
Task RouteNotification(Notification notification, CancellationToken token);
1419
Task RouteNotification(TDescriptor descriptor, Notification notification, CancellationToken token);
15-
Task<ErrorResponse> RouteRequest(Request request, CancellationToken token);
1620
Task<ErrorResponse> RouteRequest(TDescriptor descriptor, Request request, CancellationToken token);
17-
18-
void CancelRequest(object id);
1921
}
2022
}

src/JsonRpc/RequestRouterBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,12 @@ private string GetId(object id)
198198
return id?.ToString();
199199
}
200200

201-
Task IRequestRouter<TDescriptor>.RouteNotification(Notification notification, CancellationToken token)
201+
Task IRequestRouter.RouteNotification(Notification notification, CancellationToken token)
202202
{
203203
return RouteNotification(GetDescriptor(notification), notification, token);
204204
}
205205

206-
Task<ErrorResponse> IRequestRouter<TDescriptor>.RouteRequest(Request request, CancellationToken token)
206+
Task<ErrorResponse> IRequestRouter.RouteRequest(Request request, CancellationToken token)
207207
{
208208
return RouteRequest(GetDescriptor(request), request, token);
209209
}

src/Server/LanguageServer.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,14 @@ public static Task<ILanguageServer> From(Action<LanguageServerOptions> optionsAc
6161
{
6262
var options = new LanguageServerOptions();
6363
optionsAction(options);
64-
return From(options);
64+
return From(options, token);
65+
}
66+
67+
public static ILanguageServer PreInit(Action<LanguageServerOptions> optionsAction)
68+
{
69+
var options = new LanguageServerOptions();
70+
optionsAction(options);
71+
return PreInit(options);
6572
}
6673

6774
public static async Task<ILanguageServer> From(LanguageServerOptions options, CancellationToken token)
@@ -91,6 +98,38 @@ public static async Task<ILanguageServer> From(LanguageServerOptions options, Ca
9198
return server;
9299
}
93100

101+
/// <summary>
102+
/// Create the server without connecting to the client
103+
///
104+
/// Mainly used for unit testing
105+
/// </summary>
106+
/// <param name="options"></param>
107+
/// <returns></returns>
108+
public static ILanguageServer PreInit(LanguageServerOptions options)
109+
{
110+
var server = new LanguageServer(
111+
options.Input,
112+
options.Output,
113+
options.Reciever,
114+
options.RequestProcessIdentifier,
115+
options.LoggerFactory,
116+
options.Serializer,
117+
options.Services,
118+
options.HandlerTypes.Select(x => x.Assembly)
119+
.Distinct().Concat(options.HandlerAssemblies),
120+
options.Handlers,
121+
options.NamedHandlers,
122+
options.NamedServiceHandlers,
123+
options.InitializeDelegates,
124+
options.InitializedDelegates
125+
);
126+
127+
if (options.AddDefaultLoggingProvider)
128+
options.LoggerFactory.AddProvider(new LanguageServerLoggerProvider(server));
129+
130+
return server;
131+
}
132+
94133
internal LanguageServer(
95134
Stream input,
96135
Stream output,
@@ -132,7 +171,9 @@ internal LanguageServer(
132171
services.AddSingleton<ILanguageServer>(this);
133172
services.AddTransient<IHandlerMatcher, ExecuteCommandMatcher>();
134173
services.AddTransient<IHandlerMatcher, ResolveCommandMatcher>();
135-
services.AddSingleton<IRequestRouter<ILspHandlerDescriptor>, LspRequestRouter>();
174+
services.AddSingleton<LspRequestRouter>();
175+
services.AddSingleton<IRequestRouter<ILspHandlerDescriptor>>(_ => _.GetRequiredService<LspRequestRouter>());
176+
services.AddSingleton<IRequestRouter<IHandlerDescriptor>>(_ => _.GetRequiredService<LspRequestRouter>());
136177
services.AddSingleton<IResponseRouter, ResponseRouter>();
137178
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ResolveCommandPipeline<,>));
138179

@@ -285,7 +326,7 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
285326
MinimumLogLevel = LogLevel.Trace;
286327
}
287328

288-
_clientVersion = request.Capabilities.GetClientVersion();
329+
_clientVersion = request.Capabilities?.GetClientVersion() ?? ClientVersion.Lsp2;
289330
_serializer.SetClientCapabilities(_clientVersion.Value, request.Capabilities);
290331

291332
var supportedCapabilities = new List<ISupports>();
@@ -312,8 +353,8 @@ async Task<InitializeResult> IRequestHandler<InitializeParams, InitializeResult>
312353

313354
await Task.WhenAll(_initializeDelegates.Select(c => c(this, request)));
314355

315-
var textDocumentCapabilities = ClientSettings.Capabilities.TextDocument;
316-
var workspaceCapabilities = ClientSettings.Capabilities.Workspace;
356+
var textDocumentCapabilities = ClientSettings.Capabilities?.TextDocument ?? new TextDocumentClientCapabilities();
357+
var workspaceCapabilities = ClientSettings.Capabilities?.Workspace ?? new WorkspaceClientCapabilities();
317358

318359
var ccp = new ClientCapabilityProvider(_collection);
319360

src/Server/LspRequestRouter.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
namespace OmniSharp.Extensions.LanguageServer.Server
2121
{
22-
internal class LspRequestRouter : RequestRouterBase<ILspHandlerDescriptor>
22+
internal class LspRequestRouter : RequestRouterBase<ILspHandlerDescriptor>, IRequestRouter<IHandlerDescriptor>
2323
{
2424
private readonly IEnumerable<ILspHandlerDescriptor> _collection;
2525
private readonly IEnumerable<IHandlerMatcher> _handlerMatchers;
@@ -68,6 +68,18 @@ private ILspHandlerDescriptor FindDescriptor(string method, JToken @params)
6868

6969
return _handlerMatchers.SelectMany(strat => strat.FindHandler(paramsValue, lspHandlerDescriptors)).FirstOrDefault() ?? descriptor;
7070
}
71-
71+
72+
IHandlerDescriptor IRequestRouter<IHandlerDescriptor>.GetDescriptor(Notification notification) => GetDescriptor(notification);
73+
IHandlerDescriptor IRequestRouter<IHandlerDescriptor>.GetDescriptor(Request request) => GetDescriptor(request);
74+
Task IRequestRouter<IHandlerDescriptor>.RouteNotification(IHandlerDescriptor descriptor, Notification notification, CancellationToken token) =>
75+
RouteNotification(
76+
descriptor is ILspHandlerDescriptor d ? d : throw new Exception("This should really never happen, seriously, only hand this correct descriptors"),
77+
notification,
78+
token);
79+
Task<ErrorResponse> IRequestRouter<IHandlerDescriptor>.RouteRequest(IHandlerDescriptor descriptor, Request request, CancellationToken token) =>
80+
RouteRequest(
81+
descriptor is ILspHandlerDescriptor d ? d : throw new Exception("This should really never happen, seriously, only hand this correct descriptors"),
82+
request,
83+
token);
7284
}
7385
}

test/Lsp.Tests/LanguageServerTests.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
using System.IO;
33
using System.Threading;
44
using System.Threading.Tasks;
5+
using FluentAssertions;
56
using Microsoft.Extensions.Logging;
67
using NSubstitute;
8+
using OmniSharp.Extensions.Embedded.MediatR;
79
using OmniSharp.Extensions.LanguageServer.Client;
810
using OmniSharp.Extensions.LanguageServer.Client.Processes;
11+
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
12+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
913
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
1014
using OmniSharp.Extensions.LanguageServer.Server;
1115
using Xunit;
@@ -19,7 +23,7 @@ public LanguageServerTests(ITestOutputHelper testOutputHelper) : base(testOutput
1923
{
2024
}
2125

22-
[Fact(Skip="Disabled to see if build passes on ci")]
26+
[Fact(Skip = "Disabled to see if build passes on ci")]
2327
public async Task Works_With_IWorkspaceSymbolsHandler()
2428
{
2529
var process = new NamedPipeServerProcess(Guid.NewGuid().ToString("N"), LoggerFactory);
@@ -50,5 +54,24 @@ await Task.WhenAll(
5054
var server = await serverStart;
5155
server.AddHandlers(handler);
5256
}
57+
58+
[Fact]
59+
public async Task GH141_CrashesWithEmptyInitializeParams()
60+
{
61+
var process = new NamedPipeServerProcess(Guid.NewGuid().ToString("N"), LoggerFactory);
62+
await process.Start();
63+
var server = LanguageServer.PreInit(x => x
64+
.WithInput(process.ClientOutputStream)
65+
.WithOutput(process.ClientInputStream)
66+
.WithLoggerFactory(LoggerFactory)
67+
.AddDefaultLoggingProvider()
68+
.WithMinimumLogLevel(LogLevel.Trace)
69+
) as IRequestHandler<InitializeParams, InitializeResult>;
70+
71+
var handler = server as IRequestHandler<InitializeParams, InitializeResult>;
72+
73+
Func<Task> a = async () => await handler.Handle(new InitializeParams() { }, CancellationToken.None);
74+
a.Should().NotThrow();
75+
}
5376
}
5477
}

0 commit comments

Comments
 (0)