提交 8921fa9d 编写于 作者: M Manish Vasani

AnalyzerDiagnosticUpdateSource - Working implementation

上级 817a7ae1
...@@ -25,8 +25,8 @@ internal class AnalyzerManager ...@@ -25,8 +25,8 @@ internal class AnalyzerManager
// This map stores the tasks to compute HostSessionStartAnalysisScope for session wide analyzer actions, i.e. AnalyzerActions registered by analyzer's Initialize method. // This map stores the tasks to compute HostSessionStartAnalysisScope for session wide analyzer actions, i.e. AnalyzerActions registered by analyzer's Initialize method.
// These are run only once per every analyzer. // These are run only once per every analyzer.
private ImmutableDictionary<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> _sessionScopeMap = private ConditionalWeakTable<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> _sessionScopeMap =
ImmutableDictionary<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>>.Empty; new ConditionalWeakTable<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>>();
// This map stores the tasks to compute HostCompilationStartAnalysisScope for per-compilation analyzer actions, i.e. AnalyzerActions registered by analyzer's CompilationStartActions. // This map stores the tasks to compute HostCompilationStartAnalysisScope for per-compilation analyzer actions, i.e. AnalyzerActions registered by analyzer's CompilationStartActions.
// Compilation start actions will get executed once per-each compilation as user might want to return different set of custom actions for each compilation. // Compilation start actions will get executed once per-each compilation as user might want to return different set of custom actions for each compilation.
...@@ -75,16 +75,8 @@ internal class AnalyzerManager ...@@ -75,16 +75,8 @@ internal class AnalyzerManager
}, cancellationToken); }, cancellationToken);
}; };
var task = ImmutableInterlocked.GetOrAdd(ref _sessionScopeMap, analyzer, getTask); var callback = new ConditionalWeakTable<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>>.CreateValueCallback(getTask);
return _sessionScopeMap.GetValue(analyzer, callback);
// Retry cancelled task.
if (task.Status == TaskStatus.Canceled)
{
ImmutableInterlocked.TryUpdate(ref _sessionScopeMap, analyzer, getTask(analyzer), task);
return _sessionScopeMap[analyzer];
}
return task;
} }
/// <summary> /// <summary>
...@@ -115,7 +107,6 @@ internal class AnalyzerManager ...@@ -115,7 +107,6 @@ internal class AnalyzerManager
/// </summary> /// </summary>
public ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnosticDescriptors( public ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnosticDescriptors(
DiagnosticAnalyzer analyzer, DiagnosticAnalyzer analyzer,
Action<Diagnostic> addDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
......
...@@ -27,7 +27,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze ...@@ -27,7 +27,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze
var analyzer = analyzerOpt ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(project.Language); var analyzer = analyzerOpt ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(project.Language);
var exceptionDiagnostics = new List<Diagnostic>(); var exceptionDiagnostics = new List<Diagnostic>();
EventHandler<AnalyzerExceptionDiagnosticArgs> addExceptionDiagnostic = (sender, args) => EventHandler<WorkspaceAnalyzerExceptionDiagnosticArgs> addExceptionDiagnostic = (sender, args) =>
{ {
if (args.FaultedAnalyzer == analyzer) if (args.FaultedAnalyzer == analyzer)
{ {
...@@ -35,7 +35,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze ...@@ -35,7 +35,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze
} }
}; };
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic += addExceptionDiagnostic; DiagnosticAnalyzerDriver.AnalyzerExceptionDiagnostic += addExceptionDiagnostic;
if (getDocumentDiagnostics) if (getDocumentDiagnostics)
{ {
...@@ -101,7 +101,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze ...@@ -101,7 +101,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze
} }
} }
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic -= addExceptionDiagnostic; DiagnosticAnalyzerDriver.AnalyzerExceptionDiagnostic -= addExceptionDiagnostic;
return documentDiagnostics.Concat(projectDiagnostics).Concat(exceptionDiagnostics); return documentDiagnostics.Concat(projectDiagnostics).Concat(exceptionDiagnostics);
} }
......
...@@ -19,12 +19,16 @@ internal sealed class AnalyzerDiagnosticUpdateSource : IDiagnosticUpdateSource ...@@ -19,12 +19,16 @@ internal sealed class AnalyzerDiagnosticUpdateSource : IDiagnosticUpdateSource
[ImportingConstructor] [ImportingConstructor]
public AnalyzerDiagnosticUpdateSource() public AnalyzerDiagnosticUpdateSource()
{ {
BaseDiagnosticIncrementalAnalyzer.AnalyzerExceptionDiagnostic += OnAnalyzerExceptionDiagnostic; // Register for exception diagnostics from both engines.
EngineV1.DiagnosticAnalyzerDriver.AnalyzerExceptionDiagnostic += OnAnalyzerExceptionDiagnostic;
EngineV2.DiagnosticIncrementalAnalyzer.AnalyzerExceptionDiagnostic += OnAnalyzerExceptionDiagnostic;
} }
~AnalyzerDiagnosticUpdateSource() ~AnalyzerDiagnosticUpdateSource()
{ {
BaseDiagnosticIncrementalAnalyzer.AnalyzerExceptionDiagnostic -= OnAnalyzerExceptionDiagnostic; // Unregister for exception diagnostics from both engines.
EngineV1.DiagnosticAnalyzerDriver.AnalyzerExceptionDiagnostic -= OnAnalyzerExceptionDiagnostic;
EngineV2.DiagnosticIncrementalAnalyzer.AnalyzerExceptionDiagnostic -= OnAnalyzerExceptionDiagnostic;
} }
public bool SupportGetDiagnostics public bool SupportGetDiagnostics
...@@ -56,12 +60,33 @@ private void OnAnalyzerExceptionDiagnostic(object sender, WorkspaceAnalyzerExcep ...@@ -56,12 +60,33 @@ private void OnAnalyzerExceptionDiagnostic(object sender, WorkspaceAnalyzerExcep
Contract.ThrowIfFalse(AnalyzerDriverHelper.IsAnalyzerExceptionDiagnostic(args.Diagnostic)); Contract.ThrowIfFalse(AnalyzerDriverHelper.IsAnalyzerExceptionDiagnostic(args.Diagnostic));
var diagnosticData = DiagnosticData.Create(args.Workspace, args.Diagnostic); var diagnosticData = DiagnosticData.Create(args.Workspace, args.Diagnostic);
ImmutableArray<DiagnosticData> existingDiagnostics;
if (_analyzerExceptionDiagnosticsMap.TryGetValue(args.FaultedAnalyzer, out existingDiagnostics))
{
if (existingDiagnostics.Contains(diagnosticData))
{
// don't fire duplicate diagnostics.
return;
}
}
else
{
existingDiagnostics = ImmutableArray<DiagnosticData>.Empty;
}
var dxs = ImmutableInterlocked.AddOrUpdate(ref _analyzerExceptionDiagnosticsMap, var dxs = ImmutableInterlocked.AddOrUpdate(ref _analyzerExceptionDiagnosticsMap,
args.FaultedAnalyzer, args.FaultedAnalyzer,
ImmutableArray.Create(diagnosticData), ImmutableArray.Create(diagnosticData),
(a, existing) => existing.Add(diagnosticData).Distinct()); (a, existing) =>
{
var newDiags = existing.Add(diagnosticData).Distinct();
return newDiags.Length == existing.Length ? existing : newDiags;
});
RaiseDiagnosticsUpdated(MakeArgs(args.FaultedAnalyzer, dxs, args.Workspace)); if (dxs.Length > existingDiagnostics.Length)
{
RaiseDiagnosticsUpdated(MakeArgs(args.FaultedAnalyzer, dxs, args.Workspace, args.Project));
}
} }
public void ClearDiagnostics(DiagnosticAnalyzer analyzer, Workspace workspace) public void ClearDiagnostics(DiagnosticAnalyzer analyzer, Workspace workspace)
...@@ -69,19 +94,19 @@ public void ClearDiagnostics(DiagnosticAnalyzer analyzer, Workspace workspace) ...@@ -69,19 +94,19 @@ public void ClearDiagnostics(DiagnosticAnalyzer analyzer, Workspace workspace)
ImmutableArray<DiagnosticData> existing; ImmutableArray<DiagnosticData> existing;
if (ImmutableInterlocked.TryRemove(ref _analyzerExceptionDiagnosticsMap, analyzer, out existing)) if (ImmutableInterlocked.TryRemove(ref _analyzerExceptionDiagnosticsMap, analyzer, out existing))
{ {
RaiseDiagnosticsUpdated(MakeArgs(analyzer, ImmutableArray<DiagnosticData>.Empty, workspace)); RaiseDiagnosticsUpdated(MakeArgs(analyzer, ImmutableArray<DiagnosticData>.Empty, workspace, project: null));
} }
} }
private DiagnosticsUpdatedArgs MakeArgs(DiagnosticAnalyzer analyzer, ImmutableArray<DiagnosticData> items, Workspace workspace) private DiagnosticsUpdatedArgs MakeArgs(DiagnosticAnalyzer analyzer, ImmutableArray<DiagnosticData> items, Workspace workspace, Project project)
{ {
var id = WorkspaceAnalyzerManager.GetUniqueIdForAnalyzer(analyzer); var id = WorkspaceAnalyzerManager.GetUniqueIdForAnalyzer(analyzer);
return new DiagnosticsUpdatedArgs( return new DiagnosticsUpdatedArgs(
id: Tuple.Create(this, id), id: Tuple.Create(this, id),
workspace: workspace, workspace: workspace,
solution: null, solution: project?.Solution,
projectId: null, projectId: project?.Id,
documentId: null, documentId: null,
diagnostics: items); diagnostics: items);
} }
......
// 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.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
[Export(typeof(IDiagnosticUpdateSource))]
[Export(typeof(AnalyzerExceptionDiagnosticUpdateSource))]
[Shared]
internal sealed class AnalyzerExceptionDiagnosticUpdateSource : IDiagnosticUpdateSource
{
private static ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>> _analyzerExceptionDiagnosticsMap =
ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<DiagnosticData>>.Empty;
public bool SupportGetDiagnostics
{
get
{
return false;
}
}
public ImmutableArray<DiagnosticData> GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, CancellationToken cancellationToken)
{
return ImmutableArray<DiagnosticData>.Empty;
}
public event EventHandler<DiagnosticsUpdatedArgs> DiagnosticsUpdated;
private void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args)
{
var updated = this.DiagnosticsUpdated;
if (updated != null)
{
updated(this, args);
}
}
public void ReportDiagnostics(DiagnosticAnalyzer analyzer, ImmutableArray<Diagnostic> diagnostics, Project project)
{
Contract.ThrowIfFalse(diagnostics.All(AnalyzerDriverHelper.IsAnalyzerExceptionDiagnostic));
var dxs = diagnostics.Select(d => DiagnosticData.Create(project, d)).Distinct().ToImmutableArray();
dxs = ImmutableInterlocked.AddOrUpdate(ref _analyzerExceptionDiagnosticsMap,
analyzer,
dxs,
(a, existing) => existing.AddRange(dxs).Distinct());
RaiseDiagnosticsUpdated(MakeArgs(analyzer, dxs, project.Solution.Workspace, project));
}
public void ClearDiagnostics(DiagnosticAnalyzer analyzer, Workspace workspace)
{
ImmutableArray<DiagnosticData> existing;
if (ImmutableInterlocked.TryRemove(ref _analyzerExceptionDiagnosticsMap, analyzer, out existing))
{
RaiseDiagnosticsUpdated(MakeArgs(analyzer, ImmutableArray<DiagnosticData>.Empty, workspace, project: null));
}
}
private DiagnosticsUpdatedArgs MakeArgs(DiagnosticAnalyzer analyzer, ImmutableArray<DiagnosticData> items, Workspace workspace, Project project)
{
var id = WorkspaceAnalyzerManager.GetUniqueIdForAnalyzer(analyzer);
return new DiagnosticsUpdatedArgs(
id: Tuple.Create(this, id),
workspace: workspace,
solution: project != null ? project.Solution : workspace.CurrentSolution,
projectId: project?.Id,
documentId: null,
diagnostics: items);
}
internal ImmutableArray<DiagnosticData> TestOnly_GetExceptionDiagnostics(DiagnosticAnalyzer analyzer)
{
ImmutableArray<DiagnosticData> diagnostics;
if (!_analyzerExceptionDiagnosticsMap.TryGetValue(analyzer, out diagnostics))
{
diagnostics = ImmutableArray<DiagnosticData>.Empty;
}
return diagnostics;
}
}
}
...@@ -16,12 +16,6 @@ internal abstract class BaseDiagnosticIncrementalAnalyzer : IIncrementalAnalyzer ...@@ -16,12 +16,6 @@ internal abstract class BaseDiagnosticIncrementalAnalyzer : IIncrementalAnalyzer
protected BaseDiagnosticIncrementalAnalyzer(Workspace workspace) protected BaseDiagnosticIncrementalAnalyzer(Workspace workspace)
{ {
this.Workspace = workspace; this.Workspace = workspace;
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic += OnAnalyzerExceptionDiagnostic;
}
~BaseDiagnosticIncrementalAnalyzer()
{
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic -= OnAnalyzerExceptionDiagnostic;
} }
#region IIncrementalAnalyzer #region IIncrementalAnalyzer
...@@ -56,18 +50,5 @@ public virtual bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedE ...@@ -56,18 +50,5 @@ public virtual bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedE
public virtual void LogAnalyzerCountSummary() public virtual void LogAnalyzerCountSummary()
{ {
} }
internal static event EventHandler<WorkspaceAnalyzerExceptionDiagnosticArgs> AnalyzerExceptionDiagnostic;
private void OnAnalyzerExceptionDiagnostic(object sender, AnalyzerExceptionDiagnosticArgs args)
{
var workspaceArgs = new WorkspaceAnalyzerExceptionDiagnosticArgs(args, Workspace);
AnalyzerExceptionDiagnostic?.Invoke(this, workspaceArgs);
}
internal static void OnAnalyzerExceptionDiagnostic(object sender, WorkspaceAnalyzerExceptionDiagnosticArgs args)
{
AnalyzerExceptionDiagnostic?.Invoke(sender, args);
}
} }
} }
...@@ -294,6 +294,7 @@ public static DiagnosticData Create(Workspace workspace, Diagnostic diagnostic) ...@@ -294,6 +294,7 @@ public static DiagnosticData Create(Workspace workspace, Diagnostic diagnostic)
diagnostic.Descriptor.IsEnabledByDefault, diagnostic.Descriptor.IsEnabledByDefault,
diagnostic.WarningLevel, diagnostic.WarningLevel,
diagnostic.Descriptor.CustomTags.AsImmutableOrEmpty(), diagnostic.Descriptor.CustomTags.AsImmutableOrEmpty(),
diagnostic.Properties,
workspace, workspace,
projectId: null, projectId: null,
title: diagnostic.Descriptor.Title.ToString(CultureInfo.CurrentUICulture), title: diagnostic.Descriptor.Title.ToString(CultureInfo.CurrentUICulture),
......
...@@ -44,6 +44,8 @@ internal class DiagnosticAnalyzerDriver ...@@ -44,6 +44,8 @@ internal class DiagnosticAnalyzerDriver
private AnalyzerOptions _analyzerOptions = null; private AnalyzerOptions _analyzerOptions = null;
internal static event EventHandler<WorkspaceAnalyzerExceptionDiagnosticArgs> AnalyzerExceptionDiagnostic;
public DiagnosticAnalyzerDriver(Document document, TextSpan? span, SyntaxNode root, LogAggregator logAggregator, CancellationToken cancellationToken) public DiagnosticAnalyzerDriver(Document document, TextSpan? span, SyntaxNode root, LogAggregator logAggregator, CancellationToken cancellationToken)
: this(document, span, root, document.Project.LanguageServices.GetService<ISyntaxNodeAnalyzerService>(), cancellationToken) : this(document, span, root, document.Project.LanguageServices.GetService<ISyntaxNodeAnalyzerService>(), cancellationToken)
{ {
...@@ -134,6 +136,26 @@ public ISyntaxNodeAnalyzerService SyntaxNodeAnalyzerService ...@@ -134,6 +136,26 @@ public ISyntaxNodeAnalyzerService SyntaxNodeAnalyzerService
} }
} }
private EventHandler<AnalyzerExceptionDiagnosticArgs> RegisterAnalyzerExceptionDiagnosticHandler(DiagnosticAnalyzer analyzer)
{
EventHandler<AnalyzerExceptionDiagnosticArgs> handler = (sender, args) =>
{
if (args.FaultedAnalyzer == analyzer)
{
var workspaceArgs = new WorkspaceAnalyzerExceptionDiagnosticArgs(args, this.Project.Solution.Workspace, this.Project);
AnalyzerExceptionDiagnostic?.Invoke(this, workspaceArgs);
}
};
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic += handler;
return handler;
}
private void UnregisterAnalyzerExceptionDiagnosticHandler(EventHandler<AnalyzerExceptionDiagnosticArgs> handler)
{
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic -= handler;
}
private ImmutableArray<DeclarationInfo> GetDeclarationInfos(SemanticModel model) private ImmutableArray<DeclarationInfo> GetDeclarationInfos(SemanticModel model)
{ {
if (_lazyDeclarationInfos == null) if (_lazyDeclarationInfos == null)
...@@ -265,7 +287,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost ...@@ -265,7 +287,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost
} }
} }
var analyzerActions = await this.GetAnalyzerActionsAsync(analyzer).ConfigureAwait(false); var handler = RegisterAnalyzerExceptionDiagnosticHandler(analyzer);
var analyzerActions = await this.GetAnalyzerActionsCoreAsync(analyzer).ConfigureAwait(false);
DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator);
...@@ -283,6 +307,7 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost ...@@ -283,6 +307,7 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost
return ImmutableArray<Diagnostic>.Empty; return ImmutableArray<Diagnostic>.Empty;
} }
UnregisterAnalyzerExceptionDiagnosticHandler(handler);
return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray(); return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray();
} }
} }
...@@ -325,15 +350,23 @@ internal void ReportAnalyzerExceptionDiagnostic(DiagnosticAnalyzer analyzer, Dia ...@@ -325,15 +350,23 @@ internal void ReportAnalyzerExceptionDiagnostic(DiagnosticAnalyzer analyzer, Dia
} }
} }
var args = new WorkspaceAnalyzerExceptionDiagnosticArgs(analyzer, exceptionDiagnostic, this.Project.Solution.Workspace); var workspaceArgs = new WorkspaceAnalyzerExceptionDiagnosticArgs(analyzer, exceptionDiagnostic, this.Project.Solution.Workspace, this.Project);
DiagnosticIncrementalAnalyzer.OnAnalyzerExceptionDiagnostic(this, args); AnalyzerExceptionDiagnostic?.Invoke(this, workspaceArgs);
} }
public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer) public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer)
{ {
Contract.ThrowIfFalse(_project.SupportsCompilation); var handler = RegisterAnalyzerExceptionDiagnosticHandler(analyzer);
var actions = await GetAnalyzerActionsCoreAsync(analyzer).ConfigureAwait(false);
UnregisterAnalyzerExceptionDiagnosticHandler(handler);
return actions;
}
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false); private async Task<AnalyzerActions> GetAnalyzerActionsCoreAsync(DiagnosticAnalyzer analyzer)
{
var compilation = _project.SupportsCompilation ?
await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false) :
null;
var analyzerActions = await AnalyzerManager.Default.GetAnalyzerActionsAsync(analyzer, compilation, _analyzerOptions, CatchAnalyzerException, _cancellationToken).ConfigureAwait(false); var analyzerActions = await AnalyzerManager.Default.GetAnalyzerActionsAsync(analyzer, compilation, _analyzerOptions, CatchAnalyzerException, _cancellationToken).ConfigureAwait(false);
DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator);
return analyzerActions; return analyzerActions;
...@@ -373,8 +406,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno ...@@ -373,8 +406,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno
} }
else else
{ {
var analyzerActions = await GetAnalyzerActionsAsync(analyzer).ConfigureAwait(false); var handler = RegisterAnalyzerExceptionDiagnosticHandler(analyzer);
var analyzerActions = await GetAnalyzerActionsCoreAsync(analyzer).ConfigureAwait(false);
if (analyzerActions != null) if (analyzerActions != null)
{ {
// SemanticModel actions. // SemanticModel actions.
...@@ -409,6 +443,8 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno ...@@ -409,6 +443,8 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno
} }
} }
} }
UnregisterAnalyzerExceptionDiagnosticHandler(handler);
} }
return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray(); return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray();
...@@ -464,8 +500,10 @@ private async Task GetCompilationDiagnosticsAsync(DiagnosticAnalyzer analyzer, L ...@@ -464,8 +500,10 @@ private async Task GetCompilationDiagnosticsAsync(DiagnosticAnalyzer analyzer, L
{ {
var localDiagnostics = pooledObject.Object; var localDiagnostics = pooledObject.Object;
var handler = RegisterAnalyzerExceptionDiagnosticHandler(analyzer);
// Get all the analyzer actions, including the per-compilation actions. // Get all the analyzer actions, including the per-compilation actions.
var analyzerActions = await GetAnalyzerActionsAsync(analyzer).ConfigureAwait(false); var analyzerActions = await GetAnalyzerActionsCoreAsync(analyzer).ConfigureAwait(false);
if (analyzerActions.CompilationEndActionsCount > 0 && analyzerActions.CompilationStartActionsCount > 0 && forceAnalyzeAllDocuments != null) if (analyzerActions.CompilationEndActionsCount > 0 && analyzerActions.CompilationStartActionsCount > 0 && forceAnalyzeAllDocuments != null)
{ {
...@@ -485,6 +523,8 @@ private async Task GetCompilationDiagnosticsAsync(DiagnosticAnalyzer analyzer, L ...@@ -485,6 +523,8 @@ private async Task GetCompilationDiagnosticsAsync(DiagnosticAnalyzer analyzer, L
// CompilationEnd actions. // CompilationEnd actions.
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false); var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
AnalyzerDriverHelper.ExecuteCompilationEndActions(analyzerActions, compilation, _analyzerOptions, localDiagnostics.Add, CatchAnalyzerException, _cancellationToken); AnalyzerDriverHelper.ExecuteCompilationEndActions(analyzerActions, compilation, _analyzerOptions, localDiagnostics.Add, CatchAnalyzerException, _cancellationToken);
UnregisterAnalyzerExceptionDiagnosticHandler(handler);
var filteredDiagnostics = CompilationWithAnalyzers.GetEffectiveDiagnostics(localDiagnostics, compilation); var filteredDiagnostics = CompilationWithAnalyzers.GetEffectiveDiagnostics(localDiagnostics, compilation);
diagnostics.AddRange(filteredDiagnostics); diagnostics.AddRange(filteredDiagnostics);
} }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
...@@ -16,6 +17,8 @@ internal class DiagnosticIncrementalAnalyzer : BaseDiagnosticIncrementalAnalyzer ...@@ -16,6 +17,8 @@ internal class DiagnosticIncrementalAnalyzer : BaseDiagnosticIncrementalAnalyzer
private readonly DiagnosticAnalyzerService _owner; private readonly DiagnosticAnalyzerService _owner;
private readonly WorkspaceAnalyzerManager _workspaceAnalyzerManager; private readonly WorkspaceAnalyzerManager _workspaceAnalyzerManager;
internal static event EventHandler<WorkspaceAnalyzerExceptionDiagnosticArgs> AnalyzerExceptionDiagnostic;
public DiagnosticIncrementalAnalyzer(DiagnosticAnalyzerService owner, int correlationId, Workspace workspace, WorkspaceAnalyzerManager workspaceAnalyzerManager) public DiagnosticIncrementalAnalyzer(DiagnosticAnalyzerService owner, int correlationId, Workspace workspace, WorkspaceAnalyzerManager workspaceAnalyzerManager)
: base(workspace) : base(workspace)
{ {
...@@ -155,11 +158,37 @@ private async Task<ImmutableArray<DiagnosticData>> GetProjectDiagnosticsAsync(Pr ...@@ -155,11 +158,37 @@ private async Task<ImmutableArray<DiagnosticData>> GetProjectDiagnosticsAsync(Pr
var analyzers = _workspaceAnalyzerManager.CreateDiagnosticAnalyzers(project); var analyzers = _workspaceAnalyzerManager.CreateDiagnosticAnalyzers(project);
var handler = RegisterAnalyzerExceptionDiagnosticHandler(analyzers, project);
var compilationWithAnalyzer = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, cancellationToken); var compilationWithAnalyzer = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, cancellationToken);
// REVIEW: this API is a bit strange. // REVIEW: this API is a bit strange.
// if getting diagnostic is cancelled, it has to create new compilation and do everything from scretch again? // if getting diagnostic is cancelled, it has to create new compilation and do everything from scretch again?
return GetDiagnosticData(project, await compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false)).ToImmutableArrayOrEmpty(); var dxs = GetDiagnosticData(project, await compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false)).ToImmutableArrayOrEmpty();
UnregisterAnalyzerExceptionDiagnosticHandler(handler);
return dxs;
}
private EventHandler<AnalyzerExceptionDiagnosticArgs> RegisterAnalyzerExceptionDiagnosticHandler(ImmutableArray<DiagnosticAnalyzer> analyzers, Project project)
{
EventHandler<AnalyzerExceptionDiagnosticArgs> handler = (sender, args) =>
{
if (analyzers.Contains(args.FaultedAnalyzer))
{
var workspaceArgs = new WorkspaceAnalyzerExceptionDiagnosticArgs(args, project.Solution.Workspace, project);
AnalyzerExceptionDiagnostic?.Invoke(this, workspaceArgs);
}
};
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic += handler;
return handler;
}
private void UnregisterAnalyzerExceptionDiagnosticHandler(EventHandler<AnalyzerExceptionDiagnosticArgs> handler)
{
AnalyzerDriverHelper.AnalyzerExceptionDiagnostic -= handler;
} }
private IEnumerable<DiagnosticData> GetDiagnosticData(Project project, ImmutableArray<Diagnostic> diagnostics) private IEnumerable<DiagnosticData> GetDiagnosticData(Project project, ImmutableArray<Diagnostic> diagnostics)
......
...@@ -9,17 +9,19 @@ internal class WorkspaceAnalyzerExceptionDiagnosticArgs : EventArgs ...@@ -9,17 +9,19 @@ internal class WorkspaceAnalyzerExceptionDiagnosticArgs : EventArgs
public readonly Diagnostic Diagnostic; public readonly Diagnostic Diagnostic;
public readonly DiagnosticAnalyzer FaultedAnalyzer; public readonly DiagnosticAnalyzer FaultedAnalyzer;
public readonly Workspace Workspace; public readonly Workspace Workspace;
public readonly Project Project;
public WorkspaceAnalyzerExceptionDiagnosticArgs(AnalyzerExceptionDiagnosticArgs args, Workspace workspace) public WorkspaceAnalyzerExceptionDiagnosticArgs(AnalyzerExceptionDiagnosticArgs args, Workspace workspace, Project project)
: this(args.FaultedAnalyzer, args.Diagnostic, workspace) : this(args.FaultedAnalyzer, args.Diagnostic, workspace, project)
{ {
} }
public WorkspaceAnalyzerExceptionDiagnosticArgs(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Workspace workspace) public WorkspaceAnalyzerExceptionDiagnosticArgs(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Workspace workspace, Project project)
{ {
this.FaultedAnalyzer = analyzer; this.FaultedAnalyzer = analyzer;
this.Diagnostic = diagnostic; this.Diagnostic = diagnostic;
this.Workspace = workspace; this.Workspace = workspace;
this.Project = project;
} }
} }
} }
...@@ -77,10 +77,9 @@ public string GetAnalyzerReferenceIdentity(AnalyzerReference reference) ...@@ -77,10 +77,9 @@ public string GetAnalyzerReferenceIdentity(AnalyzerReference reference)
public ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors(DiagnosticAnalyzer analyzer) public ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors(DiagnosticAnalyzer analyzer)
{ {
// TODO: report diagnostics from exceptions thrown in DiagnosticAnalyzer.SupportedDiagnostics // TODO: report diagnostics from exceptions thrown in DiagnosticAnalyzer.SupportedDiagnostics
Action<Diagnostic> dummyAddDiagnostic = _ => { };
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = (ex, a) => !AnalyzerHelper.IsBuiltInAnalyzer(analyzer); Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = (ex, a) => !AnalyzerHelper.IsBuiltInAnalyzer(analyzer);
return AnalyzerManager.Default.GetSupportedDiagnosticDescriptors(analyzer, dummyAddDiagnostic, continueOnAnalyzerException, CancellationToken.None); return AnalyzerManager.Default.GetSupportedDiagnosticDescriptors(analyzer, continueOnAnalyzerException, CancellationToken.None);
} }
/// <summary> /// <summary>
......
...@@ -536,11 +536,13 @@ ...@@ -536,11 +536,13 @@
<Compile Include="CodeFixes\Suppression\SuppressionCodeAction.cs" /> <Compile Include="CodeFixes\Suppression\SuppressionCodeAction.cs" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<PublicAPI Include="PublicAPI.txt" />
</ItemGroup>
<Import Project="..\..\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems" Label="Shared" /> <Import Project="..\..\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems" Label="Shared" />
<ImportGroup Label="Targets"> <ImportGroup Label="Targets">
<Import Project="..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" /> <Import Project="..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\build\VSL.Imports.Closed.targets" /> <Import Project="..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup> </ImportGroup>
</Project> </Project>
\ No newline at end of file
...@@ -27,11 +27,7 @@ public static DiagnosticAnalyzerCategory GetDiagnosticAnalyzerCategory(this Diag ...@@ -27,11 +27,7 @@ public static DiagnosticAnalyzerCategory GetDiagnosticAnalyzerCategory(this Diag
// to be able to operate on a limited span of the document. In practical terms, no analyzer // to be able to operate on a limited span of the document. In practical terms, no analyzer
// can have both SemanticDocumentAnalysis and SemanticSpanAnalysis as categories. // can have both SemanticDocumentAnalysis and SemanticSpanAnalysis as categories.
bool cantSupportSemanticSpanAnalysis = false; bool cantSupportSemanticSpanAnalysis = false;
var analyzerActions = AnalyzerManager.Default.GetAnalyzerActionsAsync(analyzer, var analyzerActions = driver.GetAnalyzerActionsAsync(analyzer).WaitAndGetResult(driver.CancellationToken);
null,
null,
driver.CatchAnalyzerExceptionHandler,
driver.CancellationToken).WaitAndGetResult(driver.CancellationToken);
if (analyzerActions != null) if (analyzerActions != null)
{ {
if (analyzerActions.SyntaxTreeActionsCount > 0) if (analyzerActions.SyntaxTreeActionsCount > 0)
......
...@@ -125,6 +125,8 @@ public void Dispose() ...@@ -125,6 +125,8 @@ public void Dispose()
{ {
_hostDiagnosticUpdateSource.ClearDiagnosticsForProject(_projectId, this); _hostDiagnosticUpdateSource.ClearDiagnosticsForProject(_projectId, this);
} }
_hostDiagnosticUpdateSource.ClearAnalyzerSpecificDiagnostics((AnalyzerFileReference)_analyzerReference, _language);
} }
_analyzerLoadErrors = null; _analyzerLoadErrors = null;
......
...@@ -17,14 +17,17 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList ...@@ -17,14 +17,17 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
internal sealed class HostDiagnosticUpdateSource : IDiagnosticUpdateSource internal sealed class HostDiagnosticUpdateSource : IDiagnosticUpdateSource
{ {
private readonly VisualStudioWorkspaceImpl _workspace; private readonly VisualStudioWorkspaceImpl _workspace;
private readonly AnalyzerDiagnosticUpdateSource _analyzerDiagnosticsSource;
private readonly Dictionary<ProjectId, HashSet<object>> _diagnosticMap = new Dictionary<ProjectId, HashSet<object>>(); private readonly Dictionary<ProjectId, HashSet<object>> _diagnosticMap = new Dictionary<ProjectId, HashSet<object>>();
[ImportingConstructor] [ImportingConstructor]
public HostDiagnosticUpdateSource( public HostDiagnosticUpdateSource(
VisualStudioWorkspaceImpl workspace) VisualStudioWorkspaceImpl workspace,
AnalyzerDiagnosticUpdateSource analyzerDiagnosticsSource)
{ {
_workspace = workspace; _workspace = workspace;
_analyzerDiagnosticsSource = analyzerDiagnosticsSource;
} }
public event EventHandler<DiagnosticsUpdatedArgs> DiagnosticsUpdated; public event EventHandler<DiagnosticsUpdatedArgs> DiagnosticsUpdated;
...@@ -77,7 +80,7 @@ public void ClearAllDiagnosticsForProject(ProjectId projectId) ...@@ -77,7 +80,7 @@ public void ClearAllDiagnosticsForProject(ProjectId projectId)
{ {
RaiseDiagnosticsUpdatedForProject(projectId, key, SpecializedCollections.EmptyEnumerable<DiagnosticData>()); RaiseDiagnosticsUpdatedForProject(projectId, key, SpecializedCollections.EmptyEnumerable<DiagnosticData>());
} }
} }
} }
public void ClearDiagnosticsForProject(ProjectId projectId, object key) public void ClearDiagnosticsForProject(ProjectId projectId, object key)
...@@ -94,5 +97,13 @@ public void ClearDiagnosticsForProject(ProjectId projectId, object key) ...@@ -94,5 +97,13 @@ public void ClearDiagnosticsForProject(ProjectId projectId, object key)
} }
} }
} }
public void ClearAnalyzerSpecificDiagnostics(AnalyzerFileReference analyzerReference, string language)
{
foreach (var analyzer in analyzerReference.GetAnalyzers(language))
{
_analyzerDiagnosticsSource.ClearDiagnostics(analyzer, _workspace);
}
}
} }
} }
...@@ -22,7 +22,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim ...@@ -22,7 +22,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
<Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)> <Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub AnalyzerErrorsAreUpdated() Public Sub AnalyzerErrorsAreUpdated()
Dim hostDiagnosticUpdateSource = New HostDiagnosticUpdateSource(Nothing) Dim hostDiagnosticUpdateSource = New HostDiagnosticUpdateSource(Nothing, Nothing)
Dim file = Path.GetTempFileName() Dim file = Path.GetTempFileName()
Dim eventHandler = New EventHandlers(file) Dim eventHandler = New EventHandlers(file)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册