提交 912d33da 编写于 作者: H Heejae Chang

move down diagnostic analyzer executor down to workspace layer since all...

move down diagnostic analyzer executor down to workspace layer since all requires one now lives in workspace layer.
上级 e0c398c5
......@@ -34,7 +34,7 @@ public static Type[] GetLanguageNeutralTypes()
typeof(Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent.SmartIndentProvider),
typeof(Microsoft.CodeAnalysis.Editor.Implementation.ForegroundNotification.ForegroundNotificationService),
typeof(IncrementalCaches.SymbolTreeInfoIncrementalAnalyzerProvider),
typeof(CodeAnalysis.Diagnostics.EngineV2.InProcCodeAnalysisDiagnosticAnalyzerExecutor)
typeof(CodeAnalysis.Diagnostics.EngineV2.DiagnosticAnalyzerExecutor)
};
return MinimalTestExportProvider.GetLanguageNeutralTypes().Concat(types).Distinct().ToArray();
......
......@@ -6,14 +6,12 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics
namespace Microsoft.CodeAnalysis.Diagnostics
{
[Shared]
[ExportIncrementalAnalyzerProvider(WellKnownSolutionCrawlerAnalyzers.Diagnostic, workspaceKinds: null)]
......
......@@ -3,7 +3,7 @@
using System.Collections.Immutable;
using System.Linq;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// helper type to package diagnostic arguments to pass around between remote hosts
......
......@@ -11,7 +11,7 @@
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal static class DiagnosticResultSerializer
{
......
// 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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2
{
[ExportWorkspaceServiceFactory(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor)), Shared]
internal class DiagnosticAnalyzerExecutor : IWorkspaceServiceFactory
{
private readonly IDiagnosticAnalyzerService _analyzerServiceOpt;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSourceOpt;
[ImportingConstructor]
public DiagnosticAnalyzerExecutor(
[Import(AllowDefault = true)]IDiagnosticAnalyzerService analyzerService,
[Import(AllowDefault = true)]AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
// analyzerService, hostDiagnosticUpdateSource can be null in unit test
_analyzerServiceOpt = analyzerService;
_hostDiagnosticUpdateSourceOpt = hostDiagnosticUpdateSource;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new AnalyzerExecutor(_analyzerServiceOpt, _hostDiagnosticUpdateSourceOpt);
}
private class AnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
{
private readonly IDiagnosticAnalyzerService _analyzerServiceOpt;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSourceOpt;
// TODO: this should be removed once we move options down to compiler layer
private readonly ConcurrentDictionary<string, ValueTuple<OptionSet, CustomAsset>> _lastOptionSetPerLanguage;
public AnalyzerExecutor(
IDiagnosticAnalyzerService analyzerService,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
_analyzerServiceOpt = analyzerService;
_hostDiagnosticUpdateSourceOpt = hostDiagnosticUpdateSource;
// currently option is a bit wierd since it is not part of snapshot and
// we can't load all options without loading all language specific dlls.
// we have tracking issue for this.
// https://github.com/dotnet/roslyn/issues/13643
_lastOptionSetPerLanguage = new ConcurrentDictionary<string, ValueTuple<OptionSet, CustomAsset>>();
}
public async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var service = project.Solution.Workspace.Services.GetService<IRemoteHostClientService>();
if (service == null)
{
// host doesn't support RemoteHostService such as under unit test
return await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
}
var remoteHostClient = await service.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
}
var outOfProcResult = await AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, cancellationToken).ConfigureAwait(false);
// make sure things are not cancelled
cancellationToken.ThrowIfCancellationRequested();
return DiagnosticAnalysisResultMap.Create(outOfProcResult.AnalysisResult, outOfProcResult.TelemetryInfo);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeInProcAsync(
CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
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);
// 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);
return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeOutOfProcAsync(
RemoteHostClient client, CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var solution = project.Solution;
var snapshotService = solution.Workspace.Services.GetService<ISolutionSynchronizationService>();
// TODO: this should be moved out
var analyzerMap = CreateAnalyzerMap(analyzerDriver.Analyzers);
if (analyzerMap.Count == 0)
{
return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty);
}
var optionAsset = GetOptionsAsset(solution, project.Language, cancellationToken);
var hostChecksums = GetHostAnalyzerReferences(snapshotService, project.Language, _analyzerServiceOpt?.GetHostAnalyzerReferences(), cancellationToken);
var argument = new DiagnosticArguments(
analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
project.Id, optionAsset.Checksum, hostChecksums, analyzerMap.Keys.ToArray());
// TODO: send telemetry on session
using (var session = await client.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
session.AddAdditionalAssets(optionAsset);
var result = await session.InvokeAsync(
WellKnownServiceHubServices.CodeAnalysisService_CalculateDiagnosticsAsync,
new object[] { argument },
(s, c) => GetCompilerAnalysisResultAsync(s, analyzerMap, project, c)).ConfigureAwait(false);
ReportAnalyzerExceptions(project, result.Exceptions);
return result;
}
}
private CustomAsset GetOptionsAsset(Solution solution, string language, CancellationToken cancellationToken)
{
// TODO: we need better way to deal with options. optionSet itself is green node but
// it is not part of snapshot and can't save option to solution since we can't use language
// specific option without loading related language specific dlls
var options = solution.Options;
// we have cached options
if (_lastOptionSetPerLanguage.TryGetValue(language, out var value) && value.Item1 == options)
{
return value.Item2;
}
// otherwise, we need to build one.
var assetBuilder = new CustomAssetBuilder(solution);
var asset = assetBuilder.Build(options, language, cancellationToken);
_lastOptionSetPerLanguage[language] = ValueTuple.Create(options, asset);
return asset;
}
private CompilationWithAnalyzers CreateAnalyzerDriver(CompilationWithAnalyzers analyzerDriver, Func<DiagnosticAnalyzer, bool> predicate)
{
var analyzers = analyzerDriver.Analyzers.Where(predicate).ToImmutableArray();
if (analyzers.Length == 0)
{
// we can't create analyzer driver with 0 analyzers
return null;
}
return analyzerDriver.Compilation.WithAnalyzers(analyzers, analyzerDriver.AnalysisOptions);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> GetCompilerAnalysisResultAsync(Stream stream, Dictionary<string, DiagnosticAnalyzer> analyzerMap, Project project, CancellationToken cancellationToken)
{
// handling of cancellation and exception
var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
using (var reader = StreamObjectReader.TryGetReader(stream))
{
Debug.Assert(reader != null,
@"We only ge a reader for data transmitted between live processes.
This data should always be correct as we're never persisting the data between sessions.");
return DiagnosticResultSerializer.Deserialize(reader, analyzerMap, project, version, cancellationToken);
}
}
private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>> exceptions)
{
foreach (var kv in exceptions)
{
var analyzer = kv.Key;
foreach (var diagnostic in kv.Value)
{
_hostDiagnosticUpdateSourceOpt?.ReportAnalyzerDiagnostic(analyzer, diagnostic, project);
}
}
}
private ImmutableArray<Checksum> GetHostAnalyzerReferences(
ISolutionSynchronizationService snapshotService, string language, IEnumerable<AnalyzerReference> references, CancellationToken cancellationToken)
{
if (references == null)
{
return ImmutableArray<Checksum>.Empty;
}
// TODO: cache this to somewhere
var builder = ImmutableArray.CreateBuilder<Checksum>();
foreach (var reference in references)
{
var analyzers = reference.GetAnalyzers(language);
if (analyzers.Length == 0)
{
// skip reference that doesn't contain any analyzers for the given language
// we do this so that we don't load analyzer dlls that MEF exported from vsix
// not related to this solution
continue;
}
var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
builder.Add(asset.Checksum);
}
return builder.ToImmutable();
}
private Dictionary<string, DiagnosticAnalyzer> CreateAnalyzerMap(IEnumerable<DiagnosticAnalyzer> analyzers)
{
// TODO: this needs to be cached. we can have 300+ analyzers
return analyzers.ToDictionary(a => a.GetAnalyzerIdAndVersion().Item1, a => a);
}
}
}
}
// 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.Collections.Immutable;
using System.Composition;
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
{
[ExportWorkspaceServiceFactory(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor)), Shared]
internal class InProcCodeAnalysisDiagnosticAnalyzerExecutor : IWorkspaceServiceFactory
{
public static readonly ICodeAnalysisDiagnosticAnalyzerExecutor Instance = new AnalyzerExecutor();
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return Instance;
}
private class AnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
{
public async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
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);
// 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);
return DiagnosticAnalysisResultMap.Create(builderMap.ToImmutableDictionary(kv => kv.Key, kv => new DiagnosticAnalysisResult(kv.Value)), analysisResult.AnalyzerTelemetryInfo);
}
}
}
}
......@@ -114,6 +114,8 @@
<Compile Include="Completion\Providers\AbstractCrefCompletionProvider.cs" />
<Compile Include="ConvertToInterpolatedString\AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs" />
<Compile Include="Diagnostics\Analyzers\NamingStyleDiagnosticAnalyzerBase.cs" />
<Compile Include="Diagnostics\DiagnosticArguments.cs" />
<Compile Include="Diagnostics\DiagnosticResultSerializer.cs" />
<Compile Include="Diagnostics\SymbolAnalysisContextExtensions.cs" />
<Compile Include="EncapsulateField\EncapsulateFieldRefactoringProvider.cs" />
<Compile Include="ExtractInterface\ExtractInterfaceCodeRefactoringProvider.cs" />
......@@ -327,7 +329,7 @@
<Compile Include="FindUsages\DefinitionsAndReferences.cs" />
<Compile Include="FindUsages\IDefinitionsAndReferencesFactory.cs" />
<Compile Include="FindUsages\SourceReferenceItem.cs" />
<Compile Include="Diagnostics\EngineV2\InProcCodeAnalysisDiagnosticAnalyzerExecutor.cs" />
<Compile Include="Diagnostics\EngineV2\DiagnosticAnalyzerExecutor.cs" />
<Compile Include="Diagnostics\EngineV2\ICodeAnalysisDiagnosticAnalyzerExecutor.cs" />
<Compile Include="MakeMethodAsynchronous\AbstractMakeMethodAsynchronousCodeFixProvider.cs" />
<Compile Include="ReplacePropertyWithMethods\AbstractReplacePropertyWithMethodsService.cs" />
......
// 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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics
{
[ExportWorkspaceService(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor), layer: ServiceLayer.Host), Shared]
internal class VisualStudioDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
{
private readonly IDiagnosticAnalyzerService _analyzerService;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSource;
// TODO: this should be removed once we move options down to compiler layer
private readonly ConcurrentDictionary<string, ValueTuple<OptionSet, CustomAsset>> _lastOptionSetPerLanguage;
[ImportingConstructor]
public VisualStudioDiagnosticAnalyzerExecutor(
IDiagnosticAnalyzerService analyzerService,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
_analyzerService = analyzerService;
_hostDiagnosticUpdateSource = hostDiagnosticUpdateSource;
// currently option is a bit wierd since it is not part of snapshot and
// we can't load all options without loading all language specific dlls.
// we have tracking issue for this.
// https://github.com/dotnet/roslyn/issues/13643
_lastOptionSetPerLanguage = new ConcurrentDictionary<string, ValueTuple<OptionSet, CustomAsset>>();
}
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);
}
var outOfProcResult = await AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, cancellationToken).ConfigureAwait(false);
// make sure things are not cancelled
cancellationToken.ThrowIfCancellationRequested();
return DiagnosticAnalysisResultMap.Create(outOfProcResult.AnalysisResult, outOfProcResult.TelemetryInfo);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> AnalyzeOutOfProcAsync(
RemoteHostClient client, CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
{
var solution = project.Solution;
var snapshotService = solution.Workspace.Services.GetService<ISolutionSynchronizationService>();
// TODO: this should be moved out
var analyzerMap = CreateAnalyzerMap(analyzerDriver.Analyzers);
if (analyzerMap.Count == 0)
{
return DiagnosticAnalysisResultMap.Create(ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty, ImmutableDictionary<DiagnosticAnalyzer, AnalyzerTelemetryInfo>.Empty);
}
var optionAsset = GetOptionsAsset(solution, project.Language, cancellationToken);
var hostChecksums = GetHostAnalyzerReferences(snapshotService, project.Language, _analyzerService.GetHostAnalyzerReferences(), cancellationToken);
var argument = new DiagnosticArguments(
analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
project.Id, optionAsset.Checksum, hostChecksums, analyzerMap.Keys.ToArray());
// TODO: send telemetry on session
using (var session = await client.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
session.AddAdditionalAssets(optionAsset);
var result = await session.InvokeAsync(
WellKnownServiceHubServices.CodeAnalysisService_CalculateDiagnosticsAsync,
new object[] { argument },
(s, c) => GetCompilerAnalysisResultAsync(s, analyzerMap, project, c)).ConfigureAwait(false);
ReportAnalyzerExceptions(project, result.Exceptions);
return result;
}
}
private CustomAsset GetOptionsAsset(Solution solution, string language, CancellationToken cancellationToken)
{
// TODO: we need better way to deal with options. optionSet itself is green node but
// it is not part of snapshot and can't save option to solution since we can't use language
// specific option without loading related language specific dlls
var options = solution.Options;
// we have cached options
if (_lastOptionSetPerLanguage.TryGetValue(language, out var value) && value.Item1 == options)
{
return value.Item2;
}
// otherwise, we need to build one.
var assetBuilder = new CustomAssetBuilder(solution);
var asset = assetBuilder.Build(options, language, cancellationToken);
_lastOptionSetPerLanguage[language] = ValueTuple.Create(options, asset);
return asset;
}
private CompilationWithAnalyzers CreateAnalyzerDriver(CompilationWithAnalyzers analyzerDriver, Func<DiagnosticAnalyzer, bool> predicate)
{
var analyzers = analyzerDriver.Analyzers.Where(predicate).ToImmutableArray();
if (analyzers.Length == 0)
{
// we can't create analyzer driver with 0 analyzers
return null;
}
return analyzerDriver.Compilation.WithAnalyzers(analyzers, analyzerDriver.AnalysisOptions);
}
private async Task<DiagnosticAnalysisResultMap<DiagnosticAnalyzer, DiagnosticAnalysisResult>> GetCompilerAnalysisResultAsync(Stream stream, Dictionary<string, DiagnosticAnalyzer> analyzerMap, Project project, CancellationToken cancellationToken)
{
// handling of cancellation and exception
var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
using (var reader = StreamObjectReader.TryGetReader(stream))
{
Debug.Assert(reader != null,
@"We only ge a reader for data transmitted between live processes.
This data should always be correct as we're never persisting the data between sessions.");
return DiagnosticResultSerializer.Deserialize(reader, analyzerMap, project, version, cancellationToken);
}
}
private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>> exceptions)
{
foreach (var kv in exceptions)
{
var analyzer = kv.Key;
foreach (var diagnostic in kv.Value)
{
_hostDiagnosticUpdateSource.ReportAnalyzerDiagnostic(analyzer, diagnostic, project);
}
}
}
private ImmutableArray<Checksum> GetHostAnalyzerReferences(
ISolutionSynchronizationService snapshotService, string language, IEnumerable<AnalyzerReference> references, CancellationToken cancellationToken)
{
// TODO: cache this to somewhere
var builder = ImmutableArray.CreateBuilder<Checksum>();
foreach (var reference in references)
{
var analyzers = reference.GetAnalyzers(language);
if (analyzers.Length == 0)
{
// skip reference that doesn't contain any analyzers for the given language
// we do this so that we don't load analyzer dlls that MEF exported from vsix
// not related to this solution
continue;
}
var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
builder.Add(asset.Checksum);
}
return builder.ToImmutable();
}
private Dictionary<string, DiagnosticAnalyzer> CreateAnalyzerMap(IEnumerable<DiagnosticAnalyzer> analyzers)
{
// TODO: this needs to be cached. we can have 300+ analyzers
return analyzers.ToDictionary(a => a.GetAnalyzerIdAndVersion().Item1, a => a);
}
}
}
......@@ -47,12 +47,6 @@
<Compile Include="..\..\..\Compilers\Shared\ShadowCopyAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Diagnostics\DiagnosticArguments.cs">
<Link>Implementation\Diagnostics\DiagnosticArguments.cs</Link>
</Compile>
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Diagnostics\DiagnosticResultSerializer.cs">
<Link>Implementation\Diagnostics\DiagnosticResultSerializer.cs</Link>
</Compile>
<Compile Include="Experimentation\IVsExperimentationService.cs" />
<Compile Include="Experimentation\VisualStudioExperimentationService.cs" />
<Compile Include="Implementation\AnalyzerDependency\AnalyzerDependencyResults.cs" />
......@@ -64,7 +58,6 @@
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNameList.cs" />
<Compile Include="Implementation\AnalyzerDependency\IgnorableAssemblyNamePrefixList.cs" />
<Compile Include="Implementation\CompilationErrorTelemetry\CompilationErrorTelemetryIncrementalAnalyzer.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" />
......@@ -704,4 +697,4 @@
</ItemGroup>
<Import Project="..\..\..\Dependencies\CodeAnalysis.Metadata\Microsoft.CodeAnalysis.Metadata.projitems" Label="Shared" />
<Import Project="..\..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
......@@ -7,7 +7,7 @@
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
using Roslyn.Test.Utilities;
......@@ -44,7 +44,7 @@ public void TestDocumentId()
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestDiagnosticArguments()
{
var arguments = new hub::Microsoft.CodeAnalysis.Remote.Diagnostics.DiagnosticArguments(
var arguments = new DiagnosticArguments(
reportSuppressedDiagnostics: true,
logAnalyzerExecutionTime: false,
projectId: ProjectId.CreateNewId("project"),
......
......@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
......@@ -12,13 +11,13 @@
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Diagnostics.TypeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Remote;
using Moq;
using Roslyn.Test.Utilities;
......@@ -155,7 +154,7 @@ void Method()
// run analysis
var project = workspace.CurrentSolution.Projects.First();
var executor = new VisualStudioDiagnosticAnalyzerExecutor(mockAnalyzerService, new MyUpdateSource(workspace));
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(mockAnalyzerService, new MyUpdateSource(workspace)).CreateService(workspace.Services);
var analyzerDriver = (await project.GetCompilationAsync()).WithAnalyzers(analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType).ToImmutableArray());
var result = await executor.AnalyzeAsync(analyzerDriver, project, CancellationToken.None);
......@@ -170,7 +169,7 @@ void Method()
private static async Task<DiagnosticAnalysisResult> AnalyzeAsync(TestWorkspace workspace, ProjectId projectId, Type analyzerType, CancellationToken cancellationToken = default(CancellationToken))
{
var diagnosticService = workspace.ExportProvider.GetExportedValue<IDiagnosticAnalyzerService>();
var executor = new VisualStudioDiagnosticAnalyzerExecutor(diagnosticService, new MyUpdateSource(workspace));
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(diagnosticService, new MyUpdateSource(workspace)).CreateService(workspace.Services);
var analyzerReference = new AnalyzerFileReference(analyzerType.Assembly.Location, new TestAnalyzerAssemblyLoader());
var project = workspace.CurrentSolution.GetProject(projectId).AddAnalyzerReference(analyzerReference);
......
......@@ -60,8 +60,6 @@
<Compile Include="Services\RemoteSymbolSearchUpdateEngine.cs" />
<Compile Include="Services\CodeAnalysisService_NavigateTo.cs" />
<Compile Include="Services\SnapshotService.JsonRpcAssetSource.cs" />
<Compile Include="Diagnostics\DiagnosticResultSerializer.cs" />
<Compile Include="Diagnostics\DiagnosticArguments.cs" />
<Compile Include="Services\CodeAnalysisService.cs" />
<Compile Include="Services\CodeAnalysisService_Diagnostics.cs" />
<Compile Include="Services\RemoteHostService.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册