Skip to content

Commit

Permalink
Merge pull request #73207 from dibarbet/lsp_stj
Browse files Browse the repository at this point in the history
Switch Roslyn protocol types to System.Text.Json serialization
  • Loading branch information
dibarbet committed May 15, 2024
2 parents fd9a371 + c1fd7b3 commit e5d344a
Show file tree
Hide file tree
Showing 436 changed files with 3,166 additions and 3,644 deletions.
6 changes: 3 additions & 3 deletions eng/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
Visual Studio
-->
<PackageVersion Include="Microsoft.VisualStudio.SDK" Version="17.10.234-preview.1" />
<PackageVersion Include="Microsoft.Internal.VisualStudio.Shell.Framework" Version="17.9.35796-preview.1" />
<PackageVersion Include="Microsoft.Internal.VisualStudio.Shell.Framework" Version="17.9.36524" />
<PackageVersion Include="Microsoft.ServiceHub.Client" Version="4.2.1017" />
<PackageVersion Include="Microsoft.VisualStudio.Extensibility" Version="$(MicrosoftVisualStudioExtensibilityVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="$(MicrosoftVisualStudioExtensibilityVersion)" />
Expand Down Expand Up @@ -100,7 +100,7 @@
<PackageVersion Include="Microsoft.VisualStudio.Language" Version="$(MicrosoftVisualStudioCoreVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.Language.NavigateTo.Interfaces" Version="$(MicrosoftVisualStudioCoreVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.Language.StandardClassification" Version="$(MicrosoftVisualStudioCoreVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.LanguageServer.Client" Version="17.10.11-preview" />
<PackageVersion Include="Microsoft.VisualStudio.LanguageServer.Client" Version="17.10.72-preview" />
<PackageVersion Include="Microsoft.VisualStudio.RemoteControl" Version="16.3.52" />
<PackageVersion Include="Microsoft.VisualStudio.RpcContracts" Version="17.10.3-preview" />
<PackageVersion Include="Microsoft.VisualStudio.Shell.15.0" Version="17.10.234-preview.1" />
Expand Down Expand Up @@ -139,7 +139,7 @@
<!--
Language Server
-->
<PackageVersion Include="Microsoft.VisualStudio.LanguageServer.Client.Implementation" Version="17.9.25-preview" />
<PackageVersion Include="Microsoft.VisualStudio.LanguageServer.Client.Implementation" Version="17.10.72-preview" />
<PackageVersion Include="NuGet.ProjectModel" Version="6.8.0-rc.112" />
<PackageVersion Include="Microsoft.TestPlatform.TranslationLayer" Version="$(MicrosoftTestPlatformVersion)" />
<PackageVersion Include="Microsoft.TestPlatform.ObjectModel" Version="$(MicrosoftTestPlatformVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
Expand All @@ -19,8 +20,6 @@
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Threading;
using Nerdbank.Streams;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Roslyn.LanguageServer.Protocol;
using StreamJsonRpc;

Expand All @@ -35,7 +34,9 @@ internal abstract partial class AbstractInProcLanguageClient(
AbstractLanguageClientMiddleLayer? middleLayer = null) : ILanguageClient, ILanguageServerFactory, ICapabilitiesProvider, ILanguageClientCustomMessage2
{
private readonly IThreadingContext _threadingContext = threadingContext;
#pragma warning disable CS0618 // Type or member is obsolete - blocked on Razor switching to new APIs for STJ - https://github.com/dotnet/roslyn/issues/73317
private readonly ILanguageClientMiddleLayer? _middleLayer = middleLayer;
#pragma warning restore CS0618 // Type or member is obsolete
private readonly ILspServiceLoggerFactory _lspLoggerFactory = lspLoggerFactory;
private readonly ExportProvider _exportProvider = exportProvider;

Expand Down Expand Up @@ -200,10 +201,9 @@ public Task OnServerInitializedAsync()
ILspServiceLoggerFactory lspLoggerFactory,
CancellationToken cancellationToken)
{
var jsonMessageFormatter = new JsonMessageFormatter();
VSInternalExtensionUtilities.AddVSInternalExtensionConverters(jsonMessageFormatter.JsonSerializer);
var messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter();

var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, jsonMessageFormatter))
var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, messageFormatter))
{
ExceptionStrategy = ExceptionProcessing.ISerializable,
};
Expand All @@ -215,7 +215,7 @@ public Task OnServerInitializedAsync()
var hostServices = VisualStudioMefHostServices.Create(_exportProvider);
var server = Create(
jsonRpc,
jsonMessageFormatter.JsonSerializer,
messageFormatter.JsonSerializerOptions,
languageClient,
serverKind,
logger,
Expand All @@ -227,7 +227,7 @@ public Task OnServerInitializedAsync()

public virtual AbstractLanguageServer<RequestContext> Create(
JsonRpc jsonRpc,
JsonSerializer jsonSerializer,
JsonSerializerOptions options,
ICapabilitiesProvider capabilitiesProvider,
WellKnownLspServerKinds serverKind,
AbstractLspLogger logger,
Expand All @@ -236,7 +236,7 @@ public Task OnServerInitializedAsync()
var server = new RoslynLanguageServer(
LspServiceProvider,
jsonRpc,
jsonSerializer,
options,
capabilitiesProvider,
logger,
hostServices,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -9,11 +9,13 @@

namespace Microsoft.CodeAnalysis.Editor.Implementation.LanguageClient;

#pragma warning disable CS0618 // Type or member is obsolete - blocked on Razor switching to new APIs for STJ - https://github.com/dotnet/roslyn/issues/73317
internal abstract class AbstractLanguageClientMiddleLayer : ILanguageClientMiddleLayer
#pragma warning restore CS0618 // Type or member is obsolete
{
public abstract bool CanHandle(string methodName);

public abstract Task HandleNotificationAsync(string methodName, JToken methodParam, Func<JToken, Task> sendNotification);

public abstract Task<JToken?> HandleRequestAsync(string methodName, JToken methodParam, Func<JToken, Task<JToken?>> sendRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Options;
using StreamJsonRpc;
using LSP = Roslyn.LanguageServer.Protocol;

namespace Roslyn.Test.Utilities
Expand All @@ -22,10 +23,12 @@ public abstract partial class AbstractLanguageServerProtocolTests
internal LSP.ClientCapabilities ClientCapabilities { get; init; } = new LSP.ClientCapabilities();
internal WellKnownLspServerKinds ServerKind { get; init; } = WellKnownLspServerKinds.AlwaysActiveVSLspServer;
internal Action<IGlobalOptionService>? OptionUpdater { get; init; } = null;
internal bool CallInitialize { get; init; } = true;
internal bool CallInitialized { get; init; } = true;
internal object? ClientTarget { get; init; } = null;
internal string? Locale { get; init; } = null;
internal IEnumerable<DiagnosticAnalyzer>? AdditionalAnalyzers { get; init; } = null;
internal IJsonRpcMessageFormatter? ClientMessageFormatter { get; init; } = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -26,13 +28,11 @@
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Nerdbank.Streams;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Roslyn.LanguageServer.Protocol;
using Roslyn.Utilities;
using StreamJsonRpc;
using Xunit;
Expand All @@ -44,6 +44,8 @@ namespace Roslyn.Test.Utilities
[UseExportProvider]
public abstract partial class AbstractLanguageServerProtocolTests
{
private static readonly SystemTextJsonFormatter s_messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter();

private protected readonly AbstractLspLogger TestOutputLspLogger;
protected AbstractLanguageServerProtocolTests(ITestOutputHelper? testOutputHelper)
{
Expand Down Expand Up @@ -124,8 +126,8 @@ private protected static LSP.ClientCapabilities GetCapabilities(bool isVS)
/// <param name="actual">the actual object to be converted to JSON.</param>
public static void AssertJsonEquals<T1, T2>(T1 expected, T2 actual)
{
var expectedStr = JsonConvert.SerializeObject(expected);
var actualStr = JsonConvert.SerializeObject(actual);
var expectedStr = JsonSerializer.Serialize(expected, s_messageFormatter.JsonSerializerOptions);
var actualStr = JsonSerializer.Serialize(actual, s_messageFormatter.JsonSerializerOptions);
AssertEqualIgnoringWhitespace(expectedStr, actualStr);
}

Expand Down Expand Up @@ -269,7 +271,7 @@ private protected static LSP.MarkupContent CreateMarkupContent(LSP.MarkupKind ki
SortText = sortText,
InsertTextFormat = LSP.InsertTextFormat.Plaintext,
Kind = kind,
Data = JObject.FromObject(new CompletionResolveData(resultId, ProtocolConversions.DocumentToTextDocumentIdentifier(document))),
Data = JsonSerializer.SerializeToElement(new CompletionResolveData(resultId, ProtocolConversions.DocumentToTextDocumentIdentifier(document)), s_messageFormatter.JsonSerializerOptions),
Preselect = preselect,
VsResolveTextEditOnCommit = vsResolveTextEditOnCommit,
LabelDetails = labelDetails
Expand Down Expand Up @@ -512,13 +514,6 @@ private static LSP.DidCloseTextDocumentParams CreateDidCloseTextDocumentParams(U
}
};

internal static JsonMessageFormatter CreateJsonMessageFormatter()
{
var messageFormatter = new JsonMessageFormatter();
LSP.VSInternalExtensionUtilities.AddVSInternalExtensionConverters(messageFormatter.JsonSerializer);
return messageFormatter;
}

internal sealed class TestLspServer : IAsyncDisposable
{
public readonly EditorTestWorkspace TestWorkspace;
Expand All @@ -536,7 +531,8 @@ internal sealed class TestLspServer : IAsyncDisposable
LSP.ClientCapabilities clientCapabilities,
RoslynLanguageServer target,
Stream clientStream,
object? clientTarget = null)
object? clientTarget = null,
IJsonRpcMessageFormatter? clientMessageFormatter = null)
{
TestWorkspace = testWorkspace;
ClientCapabilities = clientCapabilities;
Expand All @@ -545,7 +541,9 @@ internal sealed class TestLspServer : IAsyncDisposable

LanguageServer = target;

_clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, CreateJsonMessageFormatter()), clientTarget)
clientMessageFormatter ??= RoslynLanguageServer.CreateJsonMessageFormatter();

_clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, clientMessageFormatter), clientTarget)
{
ExceptionStrategy = ExceptionProcessing.ISerializable,
};
Expand All @@ -571,13 +569,16 @@ internal static async Task<TestLspServer> CreateAsync(EditorTestWorkspace testWo
var (clientStream, serverStream) = FullDuplexStream.CreatePair();
var languageServer = CreateLanguageServer(serverStream, serverStream, testWorkspace, initializationOptions.ServerKind, logger);

var server = new TestLspServer(testWorkspace, locations, initializationOptions.ClientCapabilities, languageServer, clientStream, initializationOptions.ClientTarget);
var server = new TestLspServer(testWorkspace, locations, initializationOptions.ClientCapabilities, languageServer, clientStream, initializationOptions.ClientTarget, initializationOptions.ClientMessageFormatter);

await server.ExecuteRequestAsync<LSP.InitializeParams, LSP.InitializeResult>(LSP.Methods.InitializeName, new LSP.InitializeParams
if (initializationOptions.CallInitialize)
{
Capabilities = initializationOptions.ClientCapabilities,
Locale = initializationOptions.Locale,
}, CancellationToken.None);
await server.ExecuteRequestAsync<LSP.InitializeParams, LSP.InitializeResult>(LSP.Methods.InitializeName, new LSP.InitializeParams
{
Capabilities = initializationOptions.ClientCapabilities,
Locale = initializationOptions.Locale,
}, CancellationToken.None);
}

if (initializationOptions.CallInitialized)
{
Expand Down Expand Up @@ -607,13 +608,13 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str
var capabilitiesProvider = workspace.ExportProvider.GetExportedValue<ExperimentalCapabilitiesProvider>();
var factory = workspace.ExportProvider.GetExportedValue<ILanguageServerFactory>();

var jsonMessageFormatter = CreateJsonMessageFormatter();
var jsonMessageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter();
var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream, jsonMessageFormatter))
{
ExceptionStrategy = ExceptionProcessing.ISerializable,
};

var languageServer = (RoslynLanguageServer)factory.Create(jsonRpc, jsonMessageFormatter.JsonSerializer, capabilitiesProvider, serverKind, logger, workspace.Services.HostServices);
var languageServer = (RoslynLanguageServer)factory.Create(jsonRpc, jsonMessageFormatter.JsonSerializerOptions, capabilitiesProvider, serverKind, logger, workspace.Services.HostServices);

jsonRpc.StartListening();
return languageServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Concurrent;
using System.Text.Json;
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.FileWatching;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.LanguageServer.Protocol;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StreamJsonRpc;
using Xunit.Abstractions;
using FileSystemWatcher = Roslyn.LanguageServer.Protocol.FileSystemWatcher;
Expand Down Expand Up @@ -115,8 +114,8 @@ private static async Task WaitForFileWatcherAsync(TestLspServer testLspServer)

private static FileSystemWatcher GetSingleFileWatcher(DynamicCapabilitiesRpcTarget dynamicCapabilities)
{
var registrationJson = Assert.IsType<JObject>(Assert.Single(dynamicCapabilities.Registrations).Value.RegisterOptions);
var registration = registrationJson.ToObject<DidChangeWatchedFilesRegistrationOptions>()!;
var registrationJson = Assert.IsType<JsonElement>(Assert.Single(dynamicCapabilities.Registrations).Value.RegisterOptions);
var registration = JsonSerializer.Deserialize<DidChangeWatchedFilesRegistrationOptions>(registrationJson, ProtocolConversions.LspJsonSerializerOptions)!;

return Assert.Single(registration.Watchers);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ private TestLspServer(ExportProvider exportProvider, ILogger logger)
var (clientStream, serverStream) = FullDuplexStream.CreatePair();
LanguageServerHost = new LanguageServerHost(serverStream, serverStream, exportProvider, logger);

_clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, new JsonMessageFormatter()))
var messageFormatter = LanguageServerHost.CreateJsonMessageFormatter();
_clientRpc = new JsonRpc(new HeaderDelimitedMessageHandler(clientStream, clientStream, messageFormatter))
{
AllowModificationWhileListening = true,
ExceptionStrategy = ExceptionProcessing.ISerializable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Composition;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CommonLanguageServerProtocol.Framework;
Expand Down Expand Up @@ -32,10 +32,9 @@ public ServiceBrokerConnectHandler(ServiceBrokerFactory serviceBrokerFactory)
return _serviceBrokerFactory.CreateAndConnectAsync(request.PipeName);
}

[DataContract]
private class NotificationParams
{
[DataMember(Name = "pipeName")]
[JsonPropertyName("pipeName")]
public required string PipeName { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,40 @@
// See the LICENSE file in the project root for more information.

using System.Runtime.Serialization;
using Newtonsoft.Json;
using System.Text.Json.Serialization;

namespace Roslyn.LanguageServer.Protocol;

[DataContract]
internal class DidChangeWatchedFilesRegistrationOptions
{
[DataMember(Name = "watchers")]
[JsonPropertyName("watchers")]
public required FileSystemWatcher[] Watchers { get; set; }
}

[DataContract]
internal class FileSystemWatcher
{
[DataMember(Name = "globPattern")]
[JsonPropertyName("globPattern")]
public required RelativePattern GlobPattern { get; set; }

[DataMember(Name = "kind")]
[JsonPropertyName("kind")]
public WatchKind? Kind { get; set; }
}

[DataContract]
internal class RelativePattern
{
[DataMember(Name = "baseUri")]
[JsonPropertyName("baseUri")]
[JsonConverter(typeof(DocumentUriConverter))]
public required Uri BaseUri { get; set; }

[DataMember(Name = "pattern")]
[JsonPropertyName("pattern")]
public required string Pattern { get; set; }
}

// The LSP specification has a spelling error in the protocol, but Microsoft.VisualStudio.LanguageServer.Protocol
// didn't carry that error along. This corrects that.
[DataContract]
internal class UnregistrationParamsWithMisspelling
{
[DataMember(Name = "unregisterations")]
[JsonPropertyName("unregisterations")]
public required Unregistration[] Unregistrations { get; set; }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Composition;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CommonLanguageServerProtocol.Framework;
Expand Down Expand Up @@ -32,10 +32,9 @@ public OpenProjectHandler(LanguageServerProjectSystem projectSystem)
return _projectSystem.OpenProjectsAsync(request.Projects.SelectAsArray(p => p.LocalPath));
}

[DataContract]
private class NotificationParams
{
[DataMember(Name = "projects")]
[JsonPropertyName("projects")]
public required Uri[] Projects { get; set; }
}
}

0 comments on commit e5d344a

Please sign in to comment.