提交 e92d57a6 编写于 作者: M Manish Vasani

Few more fixes:

1) Make AnalyzerManager.GetAnalyzerActions async
2) Switch AnalyzerDriver to use the AnalyzerManager for computing actions. Also, move the execution of Initialize method and CompilationStartActions to the background thread.
上级 db9a6dc7
......@@ -7,6 +7,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Diagnostics
{
......@@ -24,13 +25,13 @@ internal class AnalyzerManager
// Session wide analyzer actions map that stores HostSessionStartAnalysisScope registered by running the Initialize method on every DiagnosticAnalyzer.
// These are run only once per every analyzer.
private ImmutableDictionary<DiagnosticAnalyzer, HostSessionStartAnalysisScope> _sessionScopeMap =
ImmutableDictionary<DiagnosticAnalyzer, HostSessionStartAnalysisScope>.Empty;
private ImmutableDictionary<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> _sessionScopeMap =
ImmutableDictionary<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>>.Empty;
// This map stores the per-compilation 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.
private readonly ConditionalWeakTable<Compilation, ConcurrentDictionary<DiagnosticAnalyzer, HostCompilationStartAnalysisScope>> _compilationScopeMap =
new ConditionalWeakTable<Compilation, ConcurrentDictionary<DiagnosticAnalyzer, HostCompilationStartAnalysisScope>>();
private readonly ConditionalWeakTable<Compilation, ConcurrentDictionary<DiagnosticAnalyzer, Task<HostCompilationStartAnalysisScope>>> _compilationScopeMap =
new ConditionalWeakTable<Compilation, ConcurrentDictionary<DiagnosticAnalyzer, Task<HostCompilationStartAnalysisScope>>>();
/// <summary>
/// Cache descriptors for each diagnostic analyzer. We do this since <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/> is
......@@ -40,7 +41,7 @@ internal class AnalyzerManager
private readonly ConditionalWeakTable<DiagnosticAnalyzer, IReadOnlyList<DiagnosticDescriptor>> _descriptorCache =
new ConditionalWeakTable<DiagnosticAnalyzer, IReadOnlyList<DiagnosticDescriptor>>();
internal HostCompilationStartAnalysisScope GetCompilationAnalysisScope(
private Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeAsync(
DiagnosticAnalyzer analyzer,
HostSessionStartAnalysisScope sessionScope,
Compilation compilation,
......@@ -49,46 +50,49 @@ internal class AnalyzerManager
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
var sessionActions = sessionScope.GetAnalyzerActions(analyzer);
Debug.Assert(sessionActions.CompilationStartActionsCount > 0);
var compilationActionsMap = _compilationScopeMap.GetOrCreateValue(compilation);
HostCompilationStartAnalysisScope result;
if (compilationActionsMap.TryGetValue(analyzer, out result))
{
return result;
}
result = new HostCompilationStartAnalysisScope(sessionScope);
AnalyzerDriverHelper.ExecuteCompilationStartActions(sessionActions.CompilationStartActions, result, compilation,
analyzerOptions, addDiagnostic, continueOnAnalyzerException, cancellationToken);
if (!compilationActionsMap.TryAdd(analyzer, result))
{
return compilationActionsMap[analyzer];
}
return result;
return compilationActionsMap.GetOrAdd(analyzer,
Task.Run(() =>
{
var compilationAnalysisScope = new HostCompilationStartAnalysisScope(sessionScope);
AnalyzerDriverHelper.ExecuteCompilationStartActions(sessionScope.CompilationStartActions, compilationAnalysisScope, compilation,
analyzerOptions, addDiagnostic, continueOnAnalyzerException, cancellationToken);
return compilationAnalysisScope;
}, cancellationToken));
}
internal HostSessionStartAnalysisScope GetSessionAnalysisScope(
private Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeAsync(
DiagnosticAnalyzer analyzer,
Action<Diagnostic> addDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
return ImmutableInterlocked.GetOrAdd(ref _sessionScopeMap, analyzer, _ =>
Func<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> getTask = a =>
{
var sessionScope = new HostSessionStartAnalysisScope();
AnalyzerDriverHelper.ExecuteInitializeMethod(analyzer, sessionScope, addDiagnostic, continueOnAnalyzerException, cancellationToken);
return sessionScope;
});
return Task.Run(() =>
{
var sessionScope = new HostSessionStartAnalysisScope();
AnalyzerDriverHelper.ExecuteInitializeMethod(a, sessionScope, addDiagnostic, continueOnAnalyzerException, cancellationToken);
return sessionScope;
}, cancellationToken);
};
var task = ImmutableInterlocked.GetOrAdd(ref _sessionScopeMap, analyzer, getTask);
// Retry cancelled task.
if (task.Status == TaskStatus.Canceled)
{
ImmutableInterlocked.TryUpdate(ref _sessionScopeMap, analyzer, getTask(analyzer), task);
return _sessionScopeMap[analyzer];
}
return task;
}
/// <summary>
/// Get all the analyzer actions to execute for the given analyzer against a given compilation.
/// </summary>
public AnalyzerActions GetAnalyzerActions(
public async Task<AnalyzerActions> GetAnalyzerActionsAsync(
DiagnosticAnalyzer analyzer,
Compilation compilation,
Action<Diagnostic> addDiagnostic,
......@@ -96,21 +100,15 @@ internal class AnalyzerManager
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
var sessionScope = GetSessionAnalysisScope(analyzer, addDiagnostic, continueOnAnalyzerException, cancellationToken);
var sessionActions = sessionScope.GetAnalyzerActions(analyzer);
if (sessionActions != null && sessionActions.CompilationStartActionsCount > 0 && compilation != null)
var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, addDiagnostic, continueOnAnalyzerException, cancellationToken).ConfigureAwait(false);
if (sessionScope.CompilationStartActions.Length > 0 && compilation != null)
{
var compilationScope = GetCompilationAnalysisScope(analyzer, sessionScope,
compilation, addDiagnostic, analyzerOptions, continueOnAnalyzerException, cancellationToken);
var compilationActions = compilationScope.GetAnalyzerActions(analyzer);
if (compilationActions != null)
{
return sessionActions.Append(compilationActions);
}
var compilationScope = await GetCompilationAnalysisScopeAsync(analyzer, sessionScope,
compilation, addDiagnostic, analyzerOptions, continueOnAnalyzerException, cancellationToken).ConfigureAwait(false);
return compilationScope.GetAnalyzerActions(analyzer);
}
return sessionActions;
return sessionScope.GetAnalyzerActions(analyzer);
}
/// <summary>
......
......@@ -33,7 +33,7 @@ internal abstract class AnalyzerDriver : IDisposable
// Lazy fields initialized in Initialize() API
private Compilation _compilation;
internal HostCompilationStartAnalysisScope compilationAnalysisScope;
internal AnalyzerActions analyzerActions;
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<ImmutableArray<SymbolAnalyzerAction>>> _symbolActionsByKind;
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<SemanticModelAnalyzerAction>> _semanticModelActionsMap;
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<CompilationEndAnalyzerAction>> _compilationEndActionsMap;
......@@ -61,7 +61,7 @@ public AsyncQueue<Diagnostic> DiagnosticQueue
/// <summary>
/// Initializes the compilation for the analyzer driver.
/// It also computes and initializes <see cref="compilationAnalysisScope"/> and <see cref="_symbolActionsByKind"/>.
/// It also computes and initializes <see cref="analyzerActions"/> and <see cref="_symbolActionsByKind"/>.
/// Finally, it initializes and starts the <see cref="_primaryTask"/> for the driver.
/// </summary>
/// <remarks>
......@@ -77,16 +77,20 @@ private void Initialize(Compilation comp, CancellationToken cancellationToken)
_compilation = comp;
// Compute the set of effective actions based on suppression, and running the initial analyzers
var sessionAnalysisScope = GetSessionAnalysisScope(_analyzers, _analyzerManager, comp.Options, _addDiagnostic, continueOnAnalyzerException, cancellationToken);
this.compilationAnalysisScope = GetCompilationAnalysisScope(_analyzers, _analyzerManager, sessionAnalysisScope, comp, analyzerOptions, _addDiagnostic, continueOnAnalyzerException, cancellationToken);
_symbolActionsByKind = MakeSymbolActionsByKind();
_semanticModelActionsMap = MakeSemanticModelActionsByAnalyzer();
_compilationEndActionsMap = MakeCompilationEndActionsByAnalyzer();
var analyzerActionsTask = GetAnalyzerActionsAsync(_analyzers, _analyzerManager, comp, analyzerOptions, _addDiagnostic, continueOnAnalyzerException, cancellationToken);
var initializeTask = analyzerActionsTask.ContinueWith(t =>
{
this.analyzerActions = t.Result;
_symbolActionsByKind = MakeSymbolActionsByKind();
_semanticModelActionsMap = MakeSemanticModelActionsByAnalyzer();
_compilationEndActionsMap = MakeCompilationEndActionsByAnalyzer();
}, cancellationToken);
// create the primary driver task.
cancellationToken.ThrowIfCancellationRequested();
_primaryTask = Task.Run(async () =>
{
await initializeTask.ConfigureAwait(false);
await ProcessCompilationEventsAsync(cancellationToken).ConfigureAwait(false);
await ExecuteSyntaxTreeActions(cancellationToken).ConfigureAwait(false);
}, cancellationToken)
......@@ -113,7 +117,7 @@ private Task ExecuteSyntaxTreeActions(CancellationToken cancellationToken)
var tasks = ArrayBuilder<Task>.GetInstance();
foreach (var tree in _compilation.SyntaxTrees)
{
var actionsByAnalyzers = this.compilationAnalysisScope.SyntaxTreeActions.GroupBy(action => action.Analyzer);
var actionsByAnalyzers = this.analyzerActions.SyntaxTreeActions.GroupBy(action => action.Analyzer);
foreach (var analyzerAndActions in actionsByAnalyzers)
{
var task = Task.Run(() =>
......@@ -248,7 +252,7 @@ public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync()
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<ImmutableArray<SymbolAnalyzerAction>>> MakeSymbolActionsByKind()
{
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<ImmutableArray<SymbolAnalyzerAction>>>();
var actionsByAnalyzers = this.compilationAnalysisScope.SymbolActions.GroupBy(action => action.Analyzer);
var actionsByAnalyzers = this.analyzerActions.SymbolActions.GroupBy(action => action.Analyzer);
foreach (var analyzerAndActions in actionsByAnalyzers)
{
var actionsByKindBuilder = new List<ArrayBuilder<SymbolAnalyzerAction>>();
......@@ -277,7 +281,7 @@ public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync()
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<SemanticModelAnalyzerAction>> MakeSemanticModelActionsByAnalyzer()
{
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<SemanticModelAnalyzerAction>>();
var actionsByAnalyzers = this.compilationAnalysisScope.SemanticModelActions.GroupBy(action => action.Analyzer);
var actionsByAnalyzers = this.analyzerActions.SemanticModelActions.GroupBy(action => action.Analyzer);
foreach (var analyzerAndActions in actionsByAnalyzers)
{
builder.Add(analyzerAndActions.Key, analyzerAndActions.ToImmutableArray());
......@@ -289,7 +293,7 @@ public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync()
private ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<CompilationEndAnalyzerAction>> MakeCompilationEndActionsByAnalyzer()
{
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<CompilationEndAnalyzerAction>>();
var actionsByAnalyzers = this.compilationAnalysisScope.CompilationEndActions.GroupBy(action => action.Analyzer);
var actionsByAnalyzers = this.analyzerActions.CompilationEndActions.GroupBy(action => action.Analyzer);
foreach (var analyzerAndActions in actionsByAnalyzers)
{
builder.Add(analyzerAndActions.Key, analyzerAndActions.ToImmutableArray());
......@@ -551,29 +555,6 @@ internal protected Action<Diagnostic> GetDiagnosticSinkWithSuppression(ISymbol s
};
}
private static HostSessionStartAnalysisScope GetSessionAnalysisScope(
IEnumerable<DiagnosticAnalyzer> analyzers,
AnalyzerManager analyzerManager,
CompilationOptions compilationOptions,
Action<Diagnostic> addDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
HostSessionStartAnalysisScope sessionScope = new HostSessionStartAnalysisScope();
foreach (DiagnosticAnalyzer analyzer in analyzers)
{
cancellationToken.ThrowIfCancellationRequested();
if (!IsDiagnosticAnalyzerSuppressed(analyzer, analyzerManager, compilationOptions, addDiagnostic, continueOnAnalyzerException, cancellationToken))
{
var analyzerSessionScope = analyzerManager.GetSessionAnalysisScope(analyzer, addDiagnostic, continueOnAnalyzerException, cancellationToken);
sessionScope.RegisterAnalyzerActions(analyzer, analyzerSessionScope.GetAnalyzerActions(analyzer));
}
}
return sessionScope;
}
private static void VerifyArguments(
IEnumerable<ISymbol> symbols,
Compilation compilation,
......@@ -717,25 +698,30 @@ internal protected Action<Diagnostic> GetDiagnosticSinkWithSuppression(ISymbol s
}
}
private static HostCompilationStartAnalysisScope GetCompilationAnalysisScope(
private static Task<AnalyzerActions> GetAnalyzerActionsAsync(
ImmutableArray<DiagnosticAnalyzer> analyzers,
AnalyzerManager analyzerManager,
HostSessionStartAnalysisScope session,
Compilation compilation,
AnalyzerOptions analyzerOptions,
Action<Diagnostic> addDiagnostic,
Action<Diagnostic> addDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
HostCompilationStartAnalysisScope compilationScope = new HostCompilationStartAnalysisScope(session);
foreach (var analyzer in analyzers)
return Task.Run(async () =>
{
var analyzerCompilationScope = analyzerManager.GetCompilationAnalysisScope(analyzer, session, compilation,
addDiagnostic, analyzerOptions, continueOnAnalyzerException, cancellationToken);
compilationScope.RegisterAnalyzerActions(analyzer, analyzerCompilationScope.GetAnalyzerActions(analyzer));
}
AnalyzerActions allAnalyzerActions = new AnalyzerActions();
foreach (var analyzer in analyzers)
{
if (!IsDiagnosticAnalyzerSuppressed(analyzer, analyzerManager, compilation.Options, addDiagnostic, continueOnAnalyzerException, cancellationToken))
{
var analyzerActions = await analyzerManager.GetAnalyzerActionsAsync(analyzer,
compilation, addDiagnostic, analyzerOptions, continueOnAnalyzerException, cancellationToken).ConfigureAwait(false);
allAnalyzerActions = allAnalyzerActions.Append(analyzerActions);
}
}
return compilationScope;
return allAnalyzerActions;
}, cancellationToken);
}
/// <summary>
......@@ -831,7 +817,7 @@ internal AnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, Func<Synta
{
if (_lazyNodeActionsByKind == null)
{
var nodeActions = this.compilationAnalysisScope.GetSyntaxNodeActions<TLanguageKindEnum>();
var nodeActions = this.analyzerActions.GetSyntaxNodeActions<TLanguageKindEnum>();
ImmutableDictionary<DiagnosticAnalyzer, ImmutableDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>>> analyzerActionsByKind;
if (nodeActions.Any())
{
......@@ -874,7 +860,7 @@ internal AnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, Func<Synta
if (_lazyCodeBlockStartActionsByAnalyzer == null)
{
ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<CodeBlockStartAnalyzerAction<TLanguageKindEnum>>> codeBlockStartActionsByAnalyzer;
var codeBlockStartActions = this.compilationAnalysisScope.GetCodeBlockStartActions<TLanguageKindEnum>();
var codeBlockStartActions = this.analyzerActions.GetCodeBlockStartActions<TLanguageKindEnum>();
if (codeBlockStartActions.Any())
{
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<CodeBlockStartAnalyzerAction<TLanguageKindEnum>>>();
......@@ -905,7 +891,7 @@ internal AnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, Func<Synta
if (_lazyCodeBlockEndActionsByAnalyzer == null)
{
ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<CodeBlockEndAnalyzerAction>> codeBlockEndActionsByAnalyzer;
var codeBlockEndActions = this.compilationAnalysisScope.CodeBlockEndActions;
var codeBlockEndActions = this.analyzerActions.CodeBlockEndActions;
if (codeBlockEndActions.Any())
{
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ImmutableArray<CodeBlockEndAnalyzerAction>>();
......
......@@ -312,7 +312,7 @@ public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer an
Contract.ThrowIfFalse(_project.SupportsCompilation);
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
var analyzerActions = AnalyzerManager.Default.GetAnalyzerActions(analyzer, compilation, addDiagnostic, _analyzerOptions, CatchAnalyzerException, _cancellationToken);
var analyzerActions = await AnalyzerManager.Default.GetAnalyzerActionsAsync(analyzer, compilation, addDiagnostic, _analyzerOptions, CatchAnalyzerException, _cancellationToken).ConfigureAwait(false);
DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator);
return analyzerActions;
}
......
......@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.EngineV1;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Extensions
{
......@@ -25,13 +26,12 @@ public static DiagnosticAnalyzerCategory GetDiagnosticAnalyzerCategory(this Diag
// 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.
bool cantSupportSemanticSpanAnalysis = false;
var analyzerActions = AnalyzerManager.Default.GetAnalyzerActions(analyzer,
var analyzerActions = AnalyzerManager.Default.GetAnalyzerActionsAsync(analyzer,
null,
_ => { },
null,
driver.CatchAnalyzerExceptionHandler,
driver.CancellationToken);
driver.CancellationToken).WaitAndGetResult(driver.CancellationToken);
if (analyzerActions != null)
{
if (analyzerActions.SyntaxTreeActionsCount > 0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册