提交 ab0ce610 编写于 作者: H Heejae Chang

added abstraction in remote host and diagnostic service to prevent VS.Next dll...

added abstraction in remote host and diagnostic service to prevent VS.Next dll from loading if remote host option is off.

the abstraction I added here is specific to diagnostic service feature. that abstract solely exist to prevent VS.Next dll from loading if remote host option is off.

this is different than IHostSpecificService abstraction I used to have that is generalized form of this abstraction which automatically figure out what to load based on option and layering/MEF composition of roslyn.

in this model, each feature need to take care of this kind of issue.
上级 368aeb95
......@@ -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<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> 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<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
// quick bail out
return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty);
}
if (analyzerDriver.Analyzers.Length == 0)
{
// quick bail out
return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.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);
}
}
}
}
// 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
{
/// <summary>
/// This interface is solely here to prevent VS.Next dll from loading
/// when RemoteHost option is off
/// </summary>
internal interface IRemoteHostDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
{
}
}
// 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<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var remoteHostClient = await project.Solution.Workspace.Services.GetService<IRemoteHostClientService>().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<IRemoteHostDiagnosticAnalyzerExecutor>();
return await executor.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -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<IRemoteHostClientService>()?.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<IRemoteHostClientService>()?.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<IRemoteHostClientService>()).Enable();
}
private void DisableRemoteHostClientService()
{
((RemoteHostClientServiceFactory.RemoteHostClientService)this.Workspace.Services.GetService<IRemoteHostClientService>()).Disable();
}
}
}
// 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
{
/// <summary>
/// Create new <see cref="RemoteHostClient"/>.
///
/// <see cref="IRemoteHostClientFactory"/> will use this to create new <see cref="RemoteHostClient"/>
/// </summary>
internal interface IRemoteHostClientFactory : IWorkspaceService
{
Task<RemoteHostClient> CreateAsync(Workspace workspace, CancellationToken cancellationToken);
}
}
......@@ -4,17 +4,13 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Remote
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
/// <summary>
/// Returns a <see cref="RemoteHostClient"/> that a user can use to communicate with a remote host (i.e. ServiceHub)
/// </summary>
internal interface IRemoteHostClientService : IWorkspaceService
{
// TODO: split service to registration service and one that return RemoteHostClient
void Enable();
void Disable();
Task<RemoteHostClient> GetRemoteHostClientAsync(CancellationToken cancellationToken);
}
}
......@@ -9,7 +9,7 @@
using Microsoft.CodeAnalysis.Execution;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Remote
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
/// <summary>
/// This lets users create a session to communicate with remote host (i.e. ServiceHub)
......
......@@ -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<IRemoteHostClientFactory>();
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<RemoteHostClient> GetRemoteHostClientAsync(CancellationToken cancell
{
cancellationToken.ThrowIfCancellationRequested();
Task<RemoteHostClient> instance;
Task<RemoteHostClient> instanceTask;
lock (_gate)
{
instance = _instanceTask;
instanceTask = _instanceTask;
}
if (instance == null)
if (instanceTask == null)
{
// service is in shutdown mode or not enabled
return SpecializedTasks.Default<RemoteHostClient>();
}
return instance;
return instanceTask;
}
private async Task<RemoteHostClient> 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<IRemoteHostClientFactory>().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)
{
......
......@@ -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;
......
......@@ -58,6 +58,8 @@
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNameList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNamePrefixList.cs" />
<Compile Include="Implementation\CompilationErrorTelemetry\CompilationErrorTelemetryIncrementalAnalyzer.cs" />
<Compile Include="Implementation\Diagnostics\IRemoteHostDiagnosticAnalyzerExecutor.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioDiagnosticAnalyzerExecutor.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioVenusSpanMappingService.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioWorkspaceDiagnosticAnalyzerProviderService.AnalyzerAssemblyLoader.cs" />
<Compile Include="Implementation\EditAndContinue\Interop\NativeMethods.cs" />
......@@ -111,8 +113,12 @@
<Compile Include="Implementation\Options\ExportLanguageSpecificOptionSerializerAttribute.cs" />
<Compile Include="Implementation\Options\ExportOptionSerializerAttribute.cs" />
<Compile Include="Implementation\ProjectSystem\Interop\IVsUndoState.cs" />
<Compile Include="Implementation\Remote\IRemoteHostClientFactory.cs" />
<Compile Include="Implementation\Remote\IRemoteHostClientService.cs" />
<Compile Include="Implementation\Remote\RemoteHostClient.cs" />
<Compile Include="Implementation\Remote\RemoteHostClientServiceFactory.cs" />
<Compile Include="Implementation\Remote\RemoteHostClientServiceFactory.RemoteHostClientService.cs" />
<Compile Include="Implementation\Remote\RemoteHostOptions.cs" />
<Compile Include="Implementation\Serialization\AssemblySerializationInfoService.cs" />
<Compile Include="Implementation\SolutionSize\SolutionSizeTracker.cs" />
<Compile Include="Implementation\TableDataSource\DiagnosticTableControlEventProcessorProvider.AggregateDiagnosticTableControlEventProcessor.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<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> 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<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeOutOfProcAsync(
......
// 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<RemoteHostClient> 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);
}
}
}
......@@ -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<ServiceHubRemoteHostClient> CreateAsync(Workspace workspace, CancellationToken cancellationToken)
public static async Task<RemoteHostClient> 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);
......
......@@ -82,10 +82,8 @@
<Link>Shared\WellKnownServiceHubServices.cs</Link>
</Compile>
<Compile Include="Diagnostics\OutOfProcDiagnosticAnalyzerExecutor.cs" />
<Compile Include="Remote\RemoteHostClientServiceFactory.RemoteHostClientService.cs" />
<Compile Include="Remote\RemoteHostClientServiceFactory.cs" />
<Compile Include="Remote\JsonRpcClient.cs" />
<Compile Include="Remote\RemoteHostOptions.cs" />
<Compile Include="Remote\RemoteHostClientFactory.cs" />
<Compile Include="Remote\ServiceHubRemoteHostClient.JsonRpcSnapshot.cs" />
<Compile Include="Remote\ServiceHubRemoteHostClient.cs" />
</ItemGroup>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册