diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/InProcCodeAnalysisDiagnosticAnalyzerExecutor.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/InProcCodeAnalysisDiagnosticAnalyzerExecutor.cs index afa14a19e3809f741939e975768328bcffbeb279..464758622619b90a5565a2a35a5cc19e719dd2c2 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/InProcCodeAnalysisDiagnosticAnalyzerExecutor.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/InProcCodeAnalysisDiagnosticAnalyzerExecutor.cs @@ -5,31 +5,42 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics.Telemetry; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Workspaces.Diagnostics; namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 { - [ExportWorkspaceService(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor)), Shared] - internal class InProcCodeAnalysisDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor + [ExportWorkspaceServiceFactory(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor)), Shared] + internal class InProcCodeAnalysisDiagnosticAnalyzerExecutor : IWorkspaceServiceFactory { - public async Task> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) + public static readonly ICodeAnalysisDiagnosticAnalyzerExecutor Instance = new AnalyzerExecutor(); + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + { + return Instance; + } + + private class AnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor { - if (analyzerDriver.Analyzers.Length == 0) + public async Task> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { - // quick bail out - return DiagnosticAnalysisResultMap.Create(ImmutableDictionary.Empty, ImmutableDictionary.Empty); - } + if (analyzerDriver.Analyzers.Length == 0) + { + // quick bail out + return DiagnosticAnalysisResultMap.Create(ImmutableDictionary.Empty, ImmutableDictionary.Empty); + } - var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); + var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); - // PERF: Run all analyzers at once using the new GetAnalysisResultAsync API. - var analysisResult = await analyzerDriver.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); + // PERF: Run all analyzers at once using the new GetAnalysisResultAsync API. + var analysisResult = await analyzerDriver.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); - // get compiler result builder map - var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken); + // get compiler result builder map + var builderMap = analysisResult.ToResultBuilderMap(project, version, analyzerDriver.Compilation, analyzerDriver.Analyzers, cancellationToken); - return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo); + return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo); + } } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/IRemoteHostDiagnosticAnalyzerExecutor.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/IRemoteHostDiagnosticAnalyzerExecutor.cs new file mode 100644 index 0000000000000000000000000000000000000000..2a2b498d78803ca0e2ada89b3928613da622b2f2 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/IRemoteHostDiagnosticAnalyzerExecutor.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Diagnostics.EngineV2; + +namespace Microsoft.VisualStudio.LanguageServices.Diagnostics +{ + /// + /// This interface is solely here to prevent VS.Next dll from loading + /// when RemoteHost option is off + /// + internal interface IRemoteHostDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor + { + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerExecutor.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerExecutor.cs new file mode 100644 index 0000000000000000000000000000000000000000..771097fc9d0ca93b31d05a03183a5cdda8b11e64 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerExecutor.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics.EngineV2; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Workspaces.Diagnostics; +using Microsoft.VisualStudio.LanguageServices.Diagnostics; +using Microsoft.VisualStudio.LanguageServices.Remote; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics +{ + [ExportWorkspaceService(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor), layer: ServiceLayer.Host), Shared] + internal class VisualStudioDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor + { + public async Task> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) + { + var remoteHostClient = await project.Solution.Workspace.Services.GetService().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); + if (remoteHostClient == null) + { + // remote host is not running. this can happen if remote host is disabled. + return await InProcCodeAnalysisDiagnosticAnalyzerExecutor.Instance.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false); + } + + // this will let VS.Next dll to be loaded + var executor = project.Solution.Workspace.Services.GetService(); + return await executor.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false); + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs index b0adde67368d6154756a5b2bf3448ab9eb3aa68b..4e7110ae473f324e839f60a19c647c6778643856 100644 --- a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs +++ b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs @@ -3,13 +3,12 @@ using System; using System.Collections.Generic; using System.ComponentModel.Design; -using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -using Microsoft.VisualStudio.LanguageServices.Implementation.Remote; using Microsoft.VisualStudio.LanguageServices.Packaging; +using Microsoft.VisualStudio.LanguageServices.Remote; using Microsoft.VisualStudio.LanguageServices.SymbolSearch; using Microsoft.VisualStudio.Shell.Interop; @@ -75,7 +74,7 @@ protected override void Initialize() this.Workspace.StartSolutionCrawler(); // start remote host - this.Workspace.Services.GetService()?.Enable(); + EnableRemoteHostClientService(); } // Ensure services that must be created on the UI thread have been. @@ -138,7 +137,8 @@ protected override void Dispose(bool disposing) if (this.Workspace != null) { this.Workspace.StopSolutionCrawler(); - this.Workspace.Services.GetService()?.Disable(); + + DisableRemoteHostClientService(); } // If we've created the language service then tell it it's time to clean itself up now. @@ -152,5 +152,15 @@ protected override void Dispose(bool disposing) } protected abstract string RoslynLanguageName { get; } + + private void EnableRemoteHostClientService() + { + ((RemoteHostClientServiceFactory.RemoteHostClientService)this.Workspace.Services.GetService()).Enable(); + } + + private void DisableRemoteHostClientService() + { + ((RemoteHostClientServiceFactory.RemoteHostClientService)this.Workspace.Services.GetService()).Disable(); + } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientFactory.cs b/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..6795214b5f2a242ce66963dc8be1611eefdf9245 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientFactory.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.VisualStudio.LanguageServices.Remote +{ + /// + /// Create new . + /// + /// will use this to create new + /// + internal interface IRemoteHostClientFactory : IWorkspaceService + { + Task CreateAsync(Workspace workspace, CancellationToken cancellationToken); + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientService.cs b/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientService.cs index 1d5f6836da070b0a8508b7dd97a974a11a9a33ff..630768dfb7af6afd8eb131fd6903dbb03200709f 100644 --- a/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/IRemoteHostClientService.cs @@ -4,17 +4,13 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Remote +namespace Microsoft.VisualStudio.LanguageServices.Remote { /// /// Returns a that a user can use to communicate with a remote host (i.e. ServiceHub) /// internal interface IRemoteHostClientService : IWorkspaceService { - // TODO: split service to registration service and one that return RemoteHostClient - void Enable(); - void Disable(); - Task GetRemoteHostClientAsync(CancellationToken cancellationToken); } } diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClient.cs b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClient.cs index 97dde8a01340f01b924ef07f8141a775c1111a7c..c4132c3aacdd3522b6f3c79f34b3ec763cbeece5 100644 --- a/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClient.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClient.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Execution; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Remote +namespace Microsoft.VisualStudio.LanguageServices.Remote { /// /// This lets users create a session to communicate with remote host (i.e. ServiceHub) diff --git a/src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs similarity index 85% rename from src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs rename to src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs index 4b87d6adfefb444dd7fbfe7035cb97833563c088..de2dd889f72d0a6fbca6c5e261f11d2349482693 100644 --- a/src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.RemoteHostClientService.cs @@ -7,15 +7,13 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Execution; -using Microsoft.CodeAnalysis.Extensions; -using Microsoft.VisualStudio.LanguageServices.Implementation.Remote; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Remote { internal partial class RemoteHostClientServiceFactory { - private class RemoteHostClientService : IRemoteHostClientService + public class RemoteHostClientService : IRemoteHostClientService { private readonly Workspace _workspace; private readonly IDiagnosticAnalyzerService _analyzerService; @@ -49,6 +47,13 @@ public void Enable() return; } + var remoteHostClientFactory = _workspace.Services.GetService(); + if (remoteHostClientFactory == null) + { + // dev14 doesn't have remote host client factory + return; + } + // make sure we run it on background thread _shutdownCancellationTokenSource = new CancellationTokenSource(); @@ -91,27 +96,28 @@ public Task GetRemoteHostClientAsync(CancellationToken cancell { cancellationToken.ThrowIfCancellationRequested(); - Task instance; + Task instanceTask; lock (_gate) { - instance = _instanceTask; + instanceTask = _instanceTask; } - if (instance == null) + if (instanceTask == null) { // service is in shutdown mode or not enabled return SpecializedTasks.Default(); } - return instance; + return instanceTask; } private async Task EnableAsync(CancellationToken cancellationToken) { await AddGlobalAssetsAsync(cancellationToken).ConfigureAwait(false); - // TODO: abstract this out so that we can have more host than service hub - var instance = await ServiceHubRemoteHostClient.CreateAsync(_workspace, cancellationToken).ConfigureAwait(false); + // if we reached here, IRemoteHostClientFactory must exist. + // this will make VS.Next dll to be loaded + var instance = await _workspace.Services.GetRequiredService().CreateAsync(_workspace, cancellationToken).ConfigureAwait(false); instance.ConnectionChanged += OnConnectionChanged; return instance; @@ -147,7 +153,7 @@ private void OnConnectionChanged(object sender, bool connected) return; } - lock(_gate) + lock (_gate) { if (_shutdownCancellationTokenSource.IsCancellationRequested) { diff --git a/src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.cs similarity index 92% rename from src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.cs rename to src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.cs index f8ecd4473ce9831590915e2f9438e725766ce618..b60864dd1582966b680d5a73479acba6e4898716 100644 --- a/src/VisualStudio/Next/Remote/RemoteHostClientServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostClientServiceFactory.cs @@ -4,11 +4,10 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.VisualStudio.LanguageServices.Implementation.Remote; namespace Microsoft.VisualStudio.LanguageServices.Remote { - [ExportWorkspaceServiceFactory(typeof(IRemoteHostClientService)), Shared] + [ExportWorkspaceServiceFactory(typeof(IRemoteHostClientService), layer: ServiceLayer.Host), Shared] internal partial class RemoteHostClientServiceFactory : IWorkspaceServiceFactory { private readonly IDiagnosticAnalyzerService _analyzerService; diff --git a/src/VisualStudio/Next/Remote/RemoteHostOptions.cs b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs similarity index 100% rename from src/VisualStudio/Next/Remote/RemoteHostOptions.cs rename to src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj index 4b36f37d02339c51429ac1f463b1fe31b53754db..364cc17ef3fce54041caeab39496d0a3a2fe506f 100644 --- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj +++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj @@ -58,6 +58,8 @@ + + @@ -111,8 +113,12 @@ + + + + diff --git a/src/VisualStudio/Next/Diagnostics/OutOfProcDiagnosticAnalyzerExecutor.cs b/src/VisualStudio/Next/Diagnostics/OutOfProcDiagnosticAnalyzerExecutor.cs index a87b577d2eae6415180e905c93a42fd13587e9eb..9ccd851dab1b7ca016812d6a29e2d1f3c49635dd 100644 --- a/src/VisualStudio/Next/Diagnostics/OutOfProcDiagnosticAnalyzerExecutor.cs +++ b/src/VisualStudio/Next/Diagnostics/OutOfProcDiagnosticAnalyzerExecutor.cs @@ -17,16 +17,14 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Remote.Diagnostics; using Microsoft.CodeAnalysis.Workspaces.Diagnostics; -using Microsoft.VisualStudio.LanguageServices.Implementation.Remote; +using Microsoft.VisualStudio.LanguageServices.Remote; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Diagnostics { - [ExportWorkspaceService(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor), layer: ServiceLayer.Host), Shared] - internal class OutOfProcDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor + [ExportWorkspaceService(typeof(IRemoteHostDiagnosticAnalyzerExecutor), layer: ServiceLayer.Host), Shared] + internal class OutOfProcDiagnosticAnalyzerExecutor : IRemoteHostDiagnosticAnalyzerExecutor { - private static readonly ICodeAnalysisDiagnosticAnalyzerExecutor _inProcAnalyzer = new InProcCodeAnalysisDiagnosticAnalyzerExecutor(); - private readonly IDiagnosticAnalyzerService _analyzerService; private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSource; @@ -70,7 +68,7 @@ internal class OutOfProcDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnal private async Task> AnalyzeInProcAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { - return await _inProcAnalyzer.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false); + return await InProcCodeAnalysisDiagnosticAnalyzerExecutor.Instance.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false); } private async Task> AnalyzeOutOfProcAsync( diff --git a/src/VisualStudio/Next/Remote/RemoteHostClientFactory.cs b/src/VisualStudio/Next/Remote/RemoteHostClientFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..eb9994e30c18bee3e0f9b0e9d7c517a38625095a --- /dev/null +++ b/src/VisualStudio/Next/Remote/RemoteHostClientFactory.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.VisualStudio.LanguageServices.Remote +{ + [ExportWorkspaceService(typeof(IRemoteHostClientFactory)), Shared] + internal class RemoteHostClientFactory : IRemoteHostClientFactory + { + public Task CreateAsync(Workspace workspace, CancellationToken cancellationToken) + { + // this is the point where we can create different kind of remote host client in future (cloud or etc) + return ServiceHubRemoteHostClient.CreateAsync(workspace, cancellationToken); + } + } +} diff --git a/src/VisualStudio/Next/Remote/ServiceHubRemoteHostClient.cs b/src/VisualStudio/Next/Remote/ServiceHubRemoteHostClient.cs index b85794b3936ccffdfc33ebff9febe65cf43d84f9..610db69348568d36264e779cd53371f61363d665 100644 --- a/src/VisualStudio/Next/Remote/ServiceHubRemoteHostClient.cs +++ b/src/VisualStudio/Next/Remote/ServiceHubRemoteHostClient.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.Execution; using Microsoft.CodeAnalysis.Remote; using Microsoft.ServiceHub.Client; -using Microsoft.VisualStudio.LanguageServices.Implementation.Remote; using Roslyn.Utilities; using StreamJsonRpc; @@ -20,9 +19,9 @@ internal partial class ServiceHubRemoteHostClient : RemoteHostClient private readonly Stream _stream; private readonly JsonRpc _rpc; - public static async Task CreateAsync(Workspace workspace, CancellationToken cancellationToken) + public static async Task CreateAsync(Workspace workspace, CancellationToken cancellationToken) { - var primary = new HubClient("RoslynPrimaryHubClient"); + var primary = new HubClient("ManagedLanguage.IDE.RemoteHostClient"); var remoteHostStream = await primary.RequestServiceAsync(WellKnownServiceHubServices.RemoteHostService, cancellationToken).ConfigureAwait(false); var instance = new ServiceHubRemoteHostClient(workspace, primary, remoteHostStream); diff --git a/src/VisualStudio/Next/ServicesVisualStudio.Next.csproj b/src/VisualStudio/Next/ServicesVisualStudio.Next.csproj index f6f476f2148a8c021d28ff59f0620153cd41a52f..b5b6506cb7bb6de5fed7d8325751540c0c9338e1 100644 --- a/src/VisualStudio/Next/ServicesVisualStudio.Next.csproj +++ b/src/VisualStudio/Next/ServicesVisualStudio.Next.csproj @@ -78,10 +78,8 @@ Shared\WellKnownServiceHubServices.cs - - - +