提交 ec618933 编写于 作者: H Heejae Chang 提交者: GitHub

Merge pull request #12921 from heejaechang/nonext

added abstraction in remote host and diagnostic service to prevent VS…
......@@ -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);
......
......@@ -78,10 +78,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.
先完成此消息的编辑!
想要评论请 注册