-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow more specific LSP services to override Any LSP services
- Loading branch information
Showing
6 changed files
with
247 additions
and
39 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
...ageServer/Microsoft.CodeAnalysis.LanguageServer/Telemetry/VSCodeRequestTelemetryLogger.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// 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. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Composition; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Internal.Log; | ||
using Microsoft.CodeAnalysis.LanguageServer.Handler; | ||
using Microsoft.CodeAnalysis.Telemetry; | ||
|
||
//namespace Microsoft.CodeAnalysis.LanguageServer.Telemetry; | ||
|
||
//internal class VSCodeRequestTelemetryLogger : RequestTelemetryLogger | ||
//{ | ||
// /// <summary> | ||
// /// Tracks whether or not the initial project load has completed so we can see | ||
// /// how often we get misc file requests after we've loaded. | ||
// /// </summary> | ||
// private static bool _initialProjectLoadCompleted = false; | ||
|
||
// private readonly ConcurrentDictionary<bool, ConcurrentDictionary<string, Counter>> _findDocumentCounters; | ||
|
||
// public VSCodeRequestTelemetryLogger(string serverTypeName) : base(serverTypeName) | ||
// { | ||
// } | ||
|
||
// public static void ReportProjectInitializationComplete() | ||
// { | ||
// _initialProjectLoadCompleted = true; | ||
// Logger.Log(FunctionId.VSCode_Projects_Load_Completed, logLevel: LogLevel.Information); | ||
// } | ||
|
||
// public static void ReportProjectLoadStarted() | ||
// { | ||
// Logger.Log(FunctionId.VSCode_Project_Load_Started, logLevel: LogLevel.Information); | ||
// } | ||
|
||
// protected override void IncreaseFindDocumentCount(string workspaceInfo) | ||
// { | ||
// TelemetryLogging.LogAggregated(FunctionId.LSP_FindDocumentInWorkspace, KeyValueLogMessage.Create(m => | ||
// { | ||
// m[TelemetryLogging.KeyName] = _serverTypeName; | ||
// m[TelemetryLogging.KeyValue] = (int)queuedDuration.TotalMilliseconds; | ||
// m[TelemetryLogging.KeyMetricName] = "Count"; | ||
// m["server"] = _serverTypeName; | ||
// m["method"] = methodName; | ||
// m["language"] = language; | ||
// })); | ||
|
||
// base.IncreaseFindDocumentCount(workspaceInfo); | ||
// } | ||
|
||
// protected override void ReportFindDocumentCounter() | ||
// { | ||
// base.ReportFindDocumentCounter(); | ||
// } | ||
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
src/LanguageServer/ProtocolUnitTests/LspServicesTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// 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. | ||
|
||
using System; | ||
using System.Composition; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Host.Mef; | ||
using Microsoft.CodeAnalysis.Test.Utilities; | ||
using Roslyn.Test.Utilities; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; | ||
|
||
[UseExportProvider] | ||
public class LspServicesTests(ITestOutputHelper testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) | ||
{ | ||
[Theory, CombinatorialData] | ||
public async Task ReturnsSpecificLspService(bool mutatingLspWorkspace) | ||
{ | ||
var composition = base.Composition.AddParts(typeof(CSharpLspService), typeof(CSharpLspServiceFactory)); | ||
await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace, initializationOptions: new() { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }, composition); | ||
|
||
var lspService = server.GetRequiredLspService<TestLspService>(); | ||
Assert.True(lspService is CSharpLspService); | ||
|
||
var lspServiceFromFactory = server.GetRequiredLspService<TestLspServiceFromFactory>(); | ||
Assert.Equal(typeof(CSharpLspServiceFactory).Name, lspServiceFromFactory.FactoryName); | ||
} | ||
|
||
[Theory, CombinatorialData] | ||
public async Task SpecificLspServiceOverridesAny(bool mutatingLspWorkspace) | ||
{ | ||
var composition = base.Composition.AddParts(typeof(CSharpLspService), typeof(AnyLspService), typeof(CSharpLspServiceFactory), typeof(AnyLspServiceFactory)); | ||
await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace, initializationOptions: new() { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }, composition); | ||
|
||
var lspService = server.GetRequiredLspService<TestLspService>(); | ||
Assert.True(lspService is CSharpLspService); | ||
|
||
var lspServiceFromFactory = server.GetRequiredLspService<TestLspServiceFromFactory>(); | ||
Assert.Equal(typeof(CSharpLspServiceFactory).Name, lspServiceFromFactory.FactoryName); | ||
} | ||
|
||
[Theory, CombinatorialData] | ||
public async Task ReturnsAnyLspService(bool mutatingLspWorkspace) | ||
{ | ||
var composition = base.Composition.AddParts(typeof(AnyLspService), typeof(AnyLspServiceFactory)); | ||
await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace, initializationOptions: new() { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }, composition); | ||
|
||
var lspService = server.GetRequiredLspService<TestLspService>(); | ||
Assert.True(lspService is AnyLspService); | ||
|
||
var lspServiceFromFactory = server.GetRequiredLspService<TestLspServiceFromFactory>(); | ||
Assert.Equal(typeof(AnyLspServiceFactory).Name, lspServiceFromFactory.FactoryName); | ||
} | ||
|
||
[Theory, CombinatorialData] | ||
public async Task DuplicateSpecificServicesThrow(bool mutatingLspWorkspace) | ||
{ | ||
var composition = base.Composition.AddParts(typeof(CSharpLspService), typeof(CSharpLspServiceFactory), typeof(DuplicateCSharpLspService), typeof(DuplicateCSharpLspServiceFactory)); | ||
await Assert.ThrowsAnyAsync<Exception>(async () => await CreateTestLspServerAsync("", mutatingLspWorkspace, initializationOptions: new() { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }, composition)); | ||
} | ||
|
||
[Theory, CombinatorialData] | ||
public async Task DuplicateAnyServicesThrow(bool mutatingLspWorkspace) | ||
{ | ||
var composition = base.Composition.AddParts(typeof(AnyLspService), typeof(AnyLspServiceFactory), typeof(DuplicateAnyLspService), typeof(DuplicateAnyLspServiceFactory)); | ||
await Assert.ThrowsAnyAsync<Exception>(async () => await CreateTestLspServerAsync("", mutatingLspWorkspace, initializationOptions: new() { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }, composition)); | ||
} | ||
|
||
internal class TestLspService : ILspService { } | ||
|
||
internal record class TestLspServiceFromFactory(string FactoryName) : ILspService { } | ||
|
||
internal class TestLspServiceFactory : ILspServiceFactory | ||
{ | ||
public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) => new TestLspServiceFromFactory(this.GetType().Name); | ||
} | ||
|
||
[ExportStatelessLspService(typeof(TestLspService), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.CSharpVisualBasicLspServer), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class CSharpLspService() : TestLspService { } | ||
|
||
[ExportLspServiceFactory(typeof(TestLspServiceFromFactory), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.CSharpVisualBasicLspServer), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class CSharpLspServiceFactory() : TestLspServiceFactory { } | ||
|
||
[ExportStatelessLspService(typeof(TestLspService), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class AnyLspService() : TestLspService { } | ||
|
||
[ExportLspServiceFactory(typeof(TestLspServiceFromFactory), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class AnyLspServiceFactory() : TestLspServiceFactory { } | ||
|
||
[ExportStatelessLspService(typeof(TestLspService), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.CSharpVisualBasicLspServer), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class DuplicateCSharpLspService() : TestLspService { } | ||
|
||
[ExportLspServiceFactory(typeof(TestLspServiceFromFactory), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.CSharpVisualBasicLspServer), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class DuplicateCSharpLspServiceFactory() : CSharpLspServiceFactory { } | ||
|
||
[ExportStatelessLspService(typeof(TestLspService), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class DuplicateAnyLspService() : TestLspService { } | ||
|
||
[ExportLspServiceFactory(typeof(TestLspServiceFromFactory), ProtocolConstants.RoslynLspLanguagesContract, WellKnownLspServerKinds.Any), Shared] | ||
[method: ImportingConstructor] | ||
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] | ||
internal class DuplicateAnyLspServiceFactory() : CSharpLspServiceFactory { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters