提交 9a4c2ab0 编写于 作者: M Manish Vasani

Merge pull request #4081 from mavasani/AnalyzerDriverV2

Implementation for Analyzer driver v2 for IDE analyzer host
......@@ -2884,9 +2884,9 @@ public override IEnumerable<ISymbol> GetSymbolsWithName(Func<string, bool> predi
#endregion
internal override AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, CancellationToken cancellationToken)
internal override AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager)
{
return new AnalyzerDriver<SyntaxKind>(analyzers, n => n.Kind(), analyzerManager, cancellationToken);
return new AnalyzerDriver<SyntaxKind>(analyzers, n => n.Kind(), analyzerManager);
}
internal void SymbolDeclaredEvent(Symbol symbol)
......
......@@ -40,11 +40,6 @@ internal sealed override bool HasComplete(CompletionPart part)
return state.HasComplete(part);
}
internal override void ForceComplete(SourceLocation locationOpt, CancellationToken cancellationToken)
{
state.DefaultForceComplete(this);
}
public abstract override string Name { get; }
protected abstract DeclarationModifiers Modifiers { get; }
......
......@@ -439,6 +439,38 @@ private void RegisterDeclaredCorTypes()
}
}
internal override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedWithinSpan, CancellationToken cancellationToken = default(CancellationToken))
{
if (this.IsGlobalNamespace)
{
return true;
}
// Check if any namespace declaration block intersects with the given tree/span.
foreach (var syntaxRef in this.DeclaringSyntaxReferences)
{
cancellationToken.ThrowIfCancellationRequested();
if (syntaxRef.SyntaxTree != tree)
{
continue;
}
if (!definedWithinSpan.HasValue)
{
return true;
}
var syntax = syntaxRef.GetSyntax(cancellationToken);
if (syntax.FullSpan.IntersectsWith(definedWithinSpan.Value))
{
return true;
}
}
return false;
}
private struct NameToSymbolMapBuilder
{
private readonly Dictionary<string, object> _dictionary;
......
......@@ -679,7 +679,13 @@ internal bool Dangerous_IsFromSomeCompilation
internal virtual bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedWithinSpan, CancellationToken cancellationToken = default(CancellationToken))
{
foreach (var syntaxRef in this.DeclaringSyntaxReferences)
var declaringReferences = this.DeclaringSyntaxReferences;
if (this.IsImplicitlyDeclared && declaringReferences.Length == 0)
{
return this.ContainingSymbol.IsDefinedInSourceTree(tree, definedWithinSpan, cancellationToken);
}
foreach (var syntaxRef in declaringReferences)
{
cancellationToken.ThrowIfCancellationRequested();
......
......@@ -45,6 +45,9 @@ internal void DefaultForceComplete(Symbol symbol)
{
symbol.GetAttributes();
}
// any other values are completion parts intended for other kinds of symbols
NotePartComplete(CompletionPart.All);
}
internal bool HasComplete(CompletionPart part)
......
......@@ -9,13 +9,7 @@
<Import_RootNamespace>AnalyzerDriver</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AnalyzerExecutor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AnalyzerManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DeclarationComputer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DeclarationInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DiagnosticAnalysisContextHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DiagnosticAnalyzerAction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DiagnosticStartAnalysisScope.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AnalyzerManager.AnalyzerAndOptions.cs" />
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -132,6 +132,28 @@
<Compile Include="Compilation.EmitStreamProvider.cs" />
<Compile Include="Compilation\SymbolFilter.cs" />
<Compile Include="CompilerPathUtilities.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisResult.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisScope.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisState.AnalyzerStateData.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisState.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisState.PerAnalyzerState.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisState.StateKind.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisState.SyntaxReferenceAnalyzerStateData.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerTelemetry.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerTelemetry.ActionCounts.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerExecutor.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerManager.AnalyzerAndOptions.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerManager.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationCompletedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationStartedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationUnitCompletedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationWithAnalyzersOptions.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticAnalysisContextHelpers.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticAnalyzerAction.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticQueue.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticStartAnalysisScope.cs" />
<Compile Include="DiagnosticAnalyzer\SymbolDeclaredCompilationEvent.cs" />
<Compile Include="InternalUtilities\CompilerOptionParseUtilities.cs" />
<Compile Include="InternalUtilities\ImmutableArrayInterop.cs" />
<Compile Include="InternalUtilities\ReflectionUtilities.cs" />
......@@ -203,12 +225,8 @@
<Compile Include="DiagnosticAnalyzer\AnalyzerImageReference.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerOptions.cs" />
<Compile Include="DiagnosticAnalyzer\AnalyzerReference.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationCompletedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationStartedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationUnitCompletedEvent.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationWithAnalyzers.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticAnalyzerExtensions.cs" />
<Compile Include="DiagnosticAnalyzer\SymbolDeclaredCompilationEvent.cs" />
<Compile Include="DiagnosticAnalyzer\UnresolvedAnalyzerReference.cs" />
<Compile Include="Diagnostic\CommonDiagnosticComparer.cs" />
<Compile Include="Diagnostic\CommonMessageProvider.cs" />
......@@ -233,7 +251,6 @@
<Compile Include="Diagnostic\ReportDiagnostic.cs" />
<Compile Include="Diagnostic\SourceLocation.cs" />
<Compile Include="Diagnostic\XmlLocation.cs" />
<Compile Include="DiagnosticAnalyzer\CompilationEvent.cs" />
<Compile Include="DiagnosticAnalyzer\AsyncQueue.cs" />
<Compile Include="DiagnosticAnalyzer\DiagnosticAnalyzerAttribute.cs" />
<Compile Include="DiagnosticAnalyzer\SuppressMessageAttributeState.cs" />
......
......@@ -332,6 +332,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Argument contains duplicate analyzer instances..
/// </summary>
internal static string DuplicateAnalyzerInstances {
get {
return ResourceManager.GetString("DuplicateAnalyzerInstances", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Empty or invalid file name.
/// </summary>
......@@ -611,6 +620,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Syntax tree doesn&apos;t belong to the underlying &apos;Compilation&apos;..
/// </summary>
internal static string InvalidTree {
get {
return ResourceManager.GetString("InvalidTree", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Argument to &apos;/keepalive&apos; option is not a 32-bit integer..
/// </summary>
......@@ -1043,6 +1061,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Argument contains an analyzer instance that does not belong to the &apos;Analyzers&apos; for this CompilationWithAnalyzers instance..
/// </summary>
internal static string UnsupportedAnalyzerInstance {
get {
return ResourceManager.GetString("UnsupportedAnalyzerInstance", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reported diagnostic with ID &apos;{0}&apos; is not supported by the analyzer..
/// </summary>
......
......@@ -460,4 +460,13 @@
<data name="NoAnalyzersFound" xml:space="preserve">
<value>No analyzers found</value>
</data>
<data name="DuplicateAnalyzerInstances" xml:space="preserve">
<value>Argument contains duplicate analyzer instances.</value>
</data>
<data name="UnsupportedAnalyzerInstance" xml:space="preserve">
<value>Argument contains an analyzer instance that does not belong to the 'Analyzers' for this CompilationWithAnalyzers instance.</value>
</data>
<data name="InvalidTree" xml:space="preserve">
<value>Syntax tree doesn't belong to the underlying 'Compilation'.</value>
</data>
</root>
\ No newline at end of file
......@@ -367,7 +367,7 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
analyzerExceptionDiagnostics = new ConcurrentSet<Diagnostic>();
Action<Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic);
var analyzerOptions = new AnalyzerOptions(ImmutableArray<AdditionalText>.CastUp(additionalTextFiles));
analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token);
analyzerDriver = AnalyzerDriver.CreateAndAttachToCompilation(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token);
getAnalyzerDiagnostics = () => analyzerDriver.GetDiagnosticsAsync().Result;
}
......
......@@ -113,7 +113,7 @@ public abstract partial class Compilation
return set;
}
internal abstract AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, CancellationToken cancellationToken);
internal abstract AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager);
/// <summary>
/// Gets the source language ("C#" or "Visual Basic").
......
// 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.Immutable;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// Stores the results of analyzer execution:
/// 1. Local and non-local diagnostics, per-analyzer.
/// 2. Analyzer execution times, if requested.
/// </summary>
internal partial class AnalysisResult
{
private readonly object _gate = new object();
private readonly Dictionary<DiagnosticAnalyzer, TimeSpan> _analyzerExecutionTimeOpt;
private Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> _localSemanticDiagnosticsOpt = null;
private Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> _localSyntaxDiagnosticsOpt = null;
private Dictionary<DiagnosticAnalyzer, List<Diagnostic>> _nonLocalDiagnosticsOpt = null;
public AnalysisResult(bool logAnalyzerExecutionTime, ImmutableArray<DiagnosticAnalyzer> analyzers)
{
_analyzerExecutionTimeOpt = logAnalyzerExecutionTime ? CreateAnalyzerExecutionTimeMap(analyzers) : null;
}
private static Dictionary<DiagnosticAnalyzer, TimeSpan> CreateAnalyzerExecutionTimeMap(ImmutableArray<DiagnosticAnalyzer> analyzers)
{
var map = new Dictionary<DiagnosticAnalyzer, TimeSpan>(analyzers.Length);
foreach (var analyzer in analyzers)
{
map[analyzer] = default(TimeSpan);
}
return map;
}
public TimeSpan GetAnalyzerExecutionTime(DiagnosticAnalyzer analyzer)
{
Debug.Assert(_analyzerExecutionTimeOpt != null);
lock (_gate)
{
return _analyzerExecutionTimeOpt[analyzer];
}
}
public void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver)
{
foreach (var analyzer in analysisScope.Analyzers)
{
// Dequeue reported analyzer diagnostics from the driver and store them in our maps.
var syntaxDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: true);
var semanticDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: false);
var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer);
lock (_gate)
{
if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0)
{
UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, ref _localSyntaxDiagnosticsOpt);
UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, ref _localSemanticDiagnosticsOpt);
UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics);
}
if (_analyzerExecutionTimeOpt != null)
{
_analyzerExecutionTimeOpt[analyzer] += driver.ResetAnalyzerExecutionTime(analyzer);
}
}
}
}
private void UpdateLocalDiagnostics_NoLock(DiagnosticAnalyzer analyzer, ImmutableArray<Diagnostic> diagnostics, ref Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> lazyLocalDiagnostics)
{
if (diagnostics.IsEmpty)
{
return;
}
lazyLocalDiagnostics = lazyLocalDiagnostics ?? new Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>>();
foreach (var diagsByTree in diagnostics.GroupBy(d => d.Location.SourceTree))
{
var tree = diagsByTree.Key;
Dictionary<DiagnosticAnalyzer, List<Diagnostic>> allDiagnostics;
if (!lazyLocalDiagnostics.TryGetValue(tree, out allDiagnostics))
{
allDiagnostics = new Dictionary<DiagnosticAnalyzer, List<Diagnostic>>();
lazyLocalDiagnostics[tree] = allDiagnostics;
}
List<Diagnostic> analyzerDiagnostics;
if (!allDiagnostics.TryGetValue(analyzer, out analyzerDiagnostics))
{
analyzerDiagnostics = new List<Diagnostic>();
allDiagnostics[analyzer] = analyzerDiagnostics;
}
analyzerDiagnostics.AddRange(diagsByTree);
}
}
private void UpdateNonLocalDiagnostics_NoLock(DiagnosticAnalyzer analyzer, ImmutableArray<Diagnostic> diagnostics)
{
if (diagnostics.IsEmpty)
{
return;
}
_nonLocalDiagnosticsOpt = _nonLocalDiagnosticsOpt ?? new Dictionary<DiagnosticAnalyzer, List<Diagnostic>>();
List<Diagnostic> currentDiagnostics;
if (!_nonLocalDiagnosticsOpt.TryGetValue(analyzer, out currentDiagnostics))
{
currentDiagnostics = new List<Diagnostic>();
_nonLocalDiagnosticsOpt[analyzer] = currentDiagnostics;
}
currentDiagnostics.AddRange(diagnostics);
}
public ImmutableArray<Diagnostic> GetDiagnostics(AnalysisScope analysisScope, bool getLocalDiagnostics, bool getNonLocalDiagnostics)
{
lock (_gate)
{
return GetDiagnostics_NoLock(analysisScope, getLocalDiagnostics, getNonLocalDiagnostics);
}
}
private ImmutableArray<Diagnostic> GetDiagnostics_NoLock(AnalysisScope analysisScope, bool getLocalDiagnostics, bool getNonLocalDiagnostics)
{
Debug.Assert(getLocalDiagnostics || getNonLocalDiagnostics);
var builder = ImmutableArray.CreateBuilder<Diagnostic>();
if (getLocalDiagnostics)
{
if (!analysisScope.IsTreeAnalysis)
{
AddAllLocalDiagnostics_NoLock(_localSyntaxDiagnosticsOpt, analysisScope, builder);
AddAllLocalDiagnostics_NoLock(_localSemanticDiagnosticsOpt, analysisScope, builder);
}
else if (analysisScope.IsSyntaxOnlyTreeAnalysis)
{
AddLocalDiagnosticsForPartialAnalysis_NoLock(_localSyntaxDiagnosticsOpt, analysisScope, builder);
}
else
{
AddLocalDiagnosticsForPartialAnalysis_NoLock(_localSemanticDiagnosticsOpt, analysisScope, builder);
}
}
if (getNonLocalDiagnostics && _nonLocalDiagnosticsOpt != null)
{
AddDiagnostics_NoLock(_nonLocalDiagnosticsOpt, analysisScope, builder);
}
return builder.ToImmutableArray();
}
private static void AddAllLocalDiagnostics_NoLock(
Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> localDiagnostics,
AnalysisScope analysisScope,
ImmutableArray<Diagnostic>.Builder builder)
{
if (localDiagnostics != null)
{
foreach (var localDiagsByTree in localDiagnostics.Values)
{
AddDiagnostics_NoLock(localDiagsByTree, analysisScope, builder);
}
}
}
private static void AddLocalDiagnosticsForPartialAnalysis_NoLock(
Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> localDiagnostics,
AnalysisScope analysisScope,
ImmutableArray<Diagnostic>.Builder builder)
{
Dictionary<DiagnosticAnalyzer, List<Diagnostic>> diagnosticsForTree;
if (localDiagnostics != null && localDiagnostics.TryGetValue(analysisScope.FilterTreeOpt, out diagnosticsForTree))
{
AddDiagnostics_NoLock(diagnosticsForTree, analysisScope, builder);
}
}
private static void AddDiagnostics_NoLock(
Dictionary<DiagnosticAnalyzer, List<Diagnostic>> diagnostics,
AnalysisScope analysisScope,
ImmutableArray<Diagnostic>.Builder builder)
{
Debug.Assert(diagnostics != null);
foreach (var analyzer in analysisScope.Analyzers)
{
List<Diagnostic> diagnosticsByAnalyzer;
if (diagnostics.TryGetValue(analyzer, out diagnosticsByAnalyzer))
{
builder.AddRange(diagnosticsByAnalyzer);
}
}
}
}
}
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// Scope for analyzer execution.
/// This scope could either be the entire compilation for all analyzers (command line build) or
/// could be scoped to a specific tree/span and/or a subset of analyzers (CompilationWithAnalyzers).
/// </summary>
internal class AnalysisScope
{
public SyntaxTree FilterTreeOpt { get; private set; }
public TextSpan? FilterSpanOpt { get; private set; }
public ImmutableArray<DiagnosticAnalyzer> Analyzers { get; private set; }
/// <summary>
/// Syntax trees on which we need to perform syntax analysis.
/// </summary>
public IEnumerable<SyntaxTree> SyntaxTrees { get; private set; }
public bool ConcurrentAnalysis { get; private set; }
/// <summary>
/// True if we need to categorize diagnostics into local and non-local diagnostics and track the analyzer reporting each diagnostic.
/// </summary>
public bool CategorizeDiagnostics { get; private set; }
/// <summary>
/// True if we need to perform only syntax analysis for a single tree.
/// </summary>
public bool IsSyntaxOnlyTreeAnalysis { get; private set; }
/// <summary>
/// True if we need to perform analysis for a single tree.
/// </summary>
public bool IsTreeAnalysis => FilterTreeOpt != null;
public AnalysisScope(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, bool concurrentAnalysis, bool categorizeDiagnostics)
{
SyntaxTrees = compilation.SyntaxTrees;
Analyzers = analyzers;
ConcurrentAnalysis = concurrentAnalysis;
CategorizeDiagnostics = categorizeDiagnostics;
FilterTreeOpt = null;
FilterSpanOpt = null;
IsSyntaxOnlyTreeAnalysis = false;
}
public AnalysisScope(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree filterTree, TextSpan? filterSpan, bool syntaxAnalysis, bool concurrentAnalysis, bool categorizeDiagnostics)
{
Debug.Assert(filterTree != null);
SyntaxTrees = SpecializedCollections.SingletonEnumerable(filterTree);
Analyzers = analyzers;
FilterTreeOpt = filterTree;
FilterSpanOpt = filterSpan;
IsSyntaxOnlyTreeAnalysis = syntaxAnalysis;
ConcurrentAnalysis = concurrentAnalysis;
CategorizeDiagnostics = categorizeDiagnostics;
}
public static bool ShouldSkipSymbolAnalysis(ISymbol symbol)
{
// Skip symbol actions for implicitly declared symbols and non-source symbols.
return symbol.IsImplicitlyDeclared || symbol.DeclaringSyntaxReferences.All(s => s.SyntaxTree == null);
}
public static bool ShouldSkipDeclarationAnalysis(ISymbol symbol)
{
// Skip syntax actions for implicitly declared symbols, except for implicitly declared global namespace symbols.
return symbol.IsImplicitlyDeclared &&
!((symbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)symbol).IsGlobalNamespace));
}
public bool ShouldAnalyze(SyntaxTree tree)
{
return FilterTreeOpt == null || FilterTreeOpt == tree;
}
public bool ShouldAnalyze(ISymbol symbol)
{
if (FilterTreeOpt == null)
{
return true;
}
foreach (var location in symbol.Locations)
{
if (location.SourceTree != null && FilterTreeOpt == location.SourceTree && ShouldInclude(location.SourceSpan))
{
return true;
}
}
return false;
}
public bool ShouldAnalyze(SyntaxNode node)
{
if (FilterTreeOpt == null)
{
return true;
}
return ShouldInclude(node.FullSpan);
}
private bool ShouldInclude(TextSpan filterSpan)
{
return !FilterSpanOpt.HasValue || FilterSpanOpt.Value.IntersectsWith(filterSpan);
}
public bool ContainsSpan(TextSpan filterSpan)
{
return !FilterSpanOpt.HasValue || FilterSpanOpt.Value.Contains(filterSpan);
}
public bool ShouldInclude(Diagnostic diagnostic)
{
if (FilterTreeOpt == null)
{
return true;
}
if (!diagnostic.Location.IsInSource || diagnostic.Location.SourceTree != FilterTreeOpt)
{
return false;
}
return ShouldInclude(diagnostic.Location.SourceSpan);
}
}
}
// 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.Generic;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class AnalysisState
{
/// <summary>
/// Stores the partial analysis state for a specific event/symbol/tree for a specific analyzer.
/// </summary>
internal class AnalyzerStateData
{
/// <summary>
/// Current state of analysis.
/// </summary>
public StateKind StateKind { get; private set; }
/// <summary>
/// Set of completed actions.
/// </summary>
public HashSet<AnalyzerAction> ProcessedActions { get; private set; }
public AnalyzerStateData()
{
StateKind = StateKind.InProcess;
ProcessedActions = new HashSet<AnalyzerAction>();
}
public virtual void SetStateKind(StateKind stateKind)
{
StateKind = stateKind;
}
/// <summary>
/// Resets the <see cref="StateKind"/> from <see cref="StateKind.InProcess"/> to <see cref="StateKind.ReadyToProcess"/>.
/// This method must be invoked after successful analysis completion AND on analysis cancellation.
/// </summary>
public void ResetToReadyState()
{
SetStateKind(StateKind.ReadyToProcess);
}
public virtual void Free()
{
this.StateKind = StateKind.ReadyToProcess;
this.ProcessedActions.Clear();
}
}
}
}
// 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.Generic;
using System.Diagnostics;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// Stores the current partial analysis state for an analyzer.
/// </summary>
internal partial class AnalysisState
{
private class PerAnalyzerState
{
private readonly object _gate = new object();
private readonly Dictionary<CompilationEvent, AnalyzerStateData> _pendingEvents = new Dictionary<CompilationEvent, AnalyzerStateData>();
private readonly Dictionary<ISymbol, AnalyzerStateData> _pendingSymbols = new Dictionary<ISymbol, AnalyzerStateData>();
private readonly Dictionary<SyntaxNode, DeclarationAnalyzerStateData> _pendingDeclarations = new Dictionary<SyntaxNode, DeclarationAnalyzerStateData>();
private Dictionary<SyntaxTree, AnalyzerStateData> _lazyPendingSyntaxAnalysisTrees = null;
private readonly ObjectPool<AnalyzerStateData> _analyzerStateDataPool = new ObjectPool<AnalyzerStateData>(() => new AnalyzerStateData());
private readonly ObjectPool<DeclarationAnalyzerStateData> _declarationAnalyzerStateDataPool = new ObjectPool<DeclarationAnalyzerStateData>(() => new DeclarationAnalyzerStateData());
public PerAnalyzerState(ObjectPool<AnalyzerStateData> analyzerStateDataPool, ObjectPool<DeclarationAnalyzerStateData> declarationAnalyzerStateDataPool)
{
_analyzerStateDataPool = analyzerStateDataPool;
_declarationAnalyzerStateDataPool = declarationAnalyzerStateDataPool;
}
public IEnumerable<CompilationEvent> PendingEvents_NoLock =>_pendingEvents.Keys;
public bool HasPendingSyntaxAnalysis(SyntaxTree treeOpt)
{
lock (_gate)
{
return _lazyPendingSyntaxAnalysisTrees != null &&
(treeOpt != null ? _lazyPendingSyntaxAnalysisTrees.ContainsKey(treeOpt) : _lazyPendingSyntaxAnalysisTrees.Count > 0);
}
}
public bool HasPendingSymbolAnalysis(ISymbol symbol)
{
lock (_gate)
{
return _pendingSymbols.ContainsKey(symbol);
}
}
private bool TryStartProcessingEntity<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, out TAnalyzerStateData newState)
where TAnalyzerStateData : AnalyzerStateData, new()
{
lock (_gate)
{
return TryStartProcessingEntity_NoLock(analysisEntity, pendingEntities, pool, out newState);
}
}
private static bool TryStartProcessingEntity_NoLock<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, out TAnalyzerStateData state)
where TAnalyzerStateData : AnalyzerStateData
{
if (pendingEntities.TryGetValue(analysisEntity, out state) &&
(state == null || state.StateKind == StateKind.ReadyToProcess))
{
if (state == null)
{
state = pool.Allocate();
}
state.SetStateKind(StateKind.InProcess);
Debug.Assert(state.StateKind == StateKind.InProcess);
pendingEntities[analysisEntity] = state;
return true;
}
state = null;
return false;
}
private void MarkEntityProcessed<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool)
where TAnalyzerStateData : AnalyzerStateData
{
lock (_gate)
{
MarkEntityProcessed_NoLock(analysisEntity, pendingEntities, pool);
}
}
private static void MarkEntityProcessed_NoLock<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool)
where TAnalyzerStateData : AnalyzerStateData
{
TAnalyzerStateData state;
if (pendingEntities.TryGetValue(analysisEntity, out state))
{
pendingEntities.Remove(analysisEntity);
if (state != null)
{
state.Free();
pool.Free(state);
}
}
}
private bool IsEntityFullyProcessed<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities)
where TAnalyzerStateData : AnalyzerStateData
{
lock (_gate)
{
return IsEntityFullyProcessed_NoLock(analysisEntity, pendingEntities);
}
}
private static bool IsEntityFullyProcessed_NoLock<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities)
where TAnalyzerStateData : AnalyzerStateData
{
return !pendingEntities.ContainsKey(analysisEntity);
}
public bool TryStartProcessingEvent(CompilationEvent compilationEvent, out AnalyzerStateData state)
{
return TryStartProcessingEntity(compilationEvent, _pendingEvents, _analyzerStateDataPool, out state);
}
public void MarkEventComplete(CompilationEvent compilationEvent)
{
MarkEntityProcessed(compilationEvent, _pendingEvents, _analyzerStateDataPool);
}
public bool TryStartAnalyzingSymbol(ISymbol symbol, out AnalyzerStateData state)
{
return TryStartProcessingEntity(symbol, _pendingSymbols, _analyzerStateDataPool, out state);
}
public void MarkSymbolComplete(ISymbol symbol)
{
MarkEntityProcessed(symbol, _pendingSymbols, _analyzerStateDataPool);
}
public bool TryStartAnalyzingDeclaration(SyntaxReference decl, out DeclarationAnalyzerStateData state)
{
return TryStartProcessingEntity(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool, out state);
}
public void MarkDeclarationComplete(SyntaxReference decl)
{
MarkEntityProcessed(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool);
}
public bool TryStartSyntaxAnalysis(SyntaxTree tree, out AnalyzerStateData state)
{
Debug.Assert(_lazyPendingSyntaxAnalysisTrees != null);
return TryStartProcessingEntity(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool, out state);
}
public void MarkSyntaxAnalysisComplete(SyntaxTree tree)
{
if (_lazyPendingSyntaxAnalysisTrees != null)
{
MarkEntityProcessed(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool);
}
}
public void MarkDeclarationsComplete(ISymbol symbol)
{
lock (_gate)
{
foreach (var syntaxRef in symbol.DeclaringSyntaxReferences)
{
MarkEntityProcessed_NoLock(syntaxRef.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool);
}
}
}
public void OnCompilationEventGenerated_NoLock(CompilationEvent compilationEvent, ActionCounts actionCounts)
{
var symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent;
if (symbolEvent != null)
{
var needsAnalysis = false;
var symbol = symbolEvent.Symbol;
if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbol) && actionCounts.SymbolActionsCount > 0)
{
needsAnalysis = true;
_pendingSymbols[symbol] = null;
}
if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol) &&
(actionCounts.SyntaxNodeActionsCount > 0 ||
actionCounts.CodeBlockActionsCount > 0 ||
actionCounts.CodeBlockStartActionsCount > 0))
{
foreach (var syntaxRef in symbol.DeclaringSyntaxReferences)
{
needsAnalysis = true;
_pendingDeclarations[syntaxRef.GetSyntax()]= null;
}
}
if (!needsAnalysis)
{
return;
}
}
else if (compilationEvent is CompilationStartedEvent)
{
if (actionCounts.SyntaxTreeActionsCount > 0)
{
var map = new Dictionary<SyntaxTree, AnalyzerStateData>();
foreach (var tree in compilationEvent.Compilation.SyntaxTrees)
{
map[tree] = null;
}
_lazyPendingSyntaxAnalysisTrees = map;
}
if (actionCounts.CompilationActionsCount == 0)
{
return;
}
}
_pendingEvents[compilationEvent] = null;
}
public bool IsEventAnalyzed(CompilationEvent compilationEvent)
{
return IsEntityFullyProcessed(compilationEvent, _pendingEvents);
}
public void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent)
{
lock (_gate)
{
OnSymbolDeclaredEventProcessed_NoLock(symbolDeclaredEvent);
}
}
private void OnSymbolDeclaredEventProcessed_NoLock(SymbolDeclaredCompilationEvent symbolDeclaredEvent)
{
// Check if the symbol event has been completely processed or not.
// Have the symbol actions executed?
if (!IsEntityFullyProcessed_NoLock(symbolDeclaredEvent.Symbol, _pendingSymbols))
{
return;
}
// Have the node/code block actions executed for all symbol declarations?
foreach (var syntaxRef in symbolDeclaredEvent.Symbol.DeclaringSyntaxReferences)
{
if (!IsEntityFullyProcessed_NoLock(syntaxRef.GetSyntax(), _pendingDeclarations))
{
return;
}
}
// Mark the symbol event completely processed.
MarkEntityProcessed_NoLock(symbolDeclaredEvent, _pendingEvents, _analyzerStateDataPool);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class AnalysisState
{
/// <summary>
/// State kind of per-analyzer <see cref="AnalyzerStateData"/> tracking an analyzer's partial analysis state.
/// An analysis state object can be in one of the following states:
/// 1. Completely unprocessed: <see cref="ReadyToProcess"/>
/// 2. Currently being processed: <see cref="InProcess"/>
/// 3. Partially processed by one or more older requests that was either completed or cancelled: <see cref="ReadyToProcess"/>
/// 4. Fully processed: We don't need a state kind to represent fully processed state as the analysis state object is discarded once fully processed.
/// </summary>
internal enum StateKind
{
/// <summary>
/// Ready for processing.
/// Indicates it is either completely unprocessed or partially processed by one or more older requests that was either completed or cancelled.
/// </summary>
ReadyToProcess,
/// <summary>
/// Currently being processed.
/// </summary>
InProcess
}
}
}
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class AnalysisState
{
/// <summary>
/// Stores the partial analysis state for a specific symbol declaration for a specific analyzer.
/// </summary>
internal sealed class DeclarationAnalyzerStateData : SyntaxNodeAnalyzerStateData
{
/// <summary>
/// Partial analysis state for code block actions executed on the declaration.
/// </summary>
public CodeBlockAnalyzerStateData CodeBlockAnalysisState { get; set; }
public DeclarationAnalyzerStateData()
{
CodeBlockAnalysisState = new CodeBlockAnalyzerStateData();
}
public override void SetStateKind(StateKind stateKind)
{
CodeBlockAnalysisState.SetStateKind(stateKind);
base.SetStateKind(stateKind);
}
public override void Free()
{
base.Free();
CodeBlockAnalysisState.Free();
}
}
/// <summary>
/// Stores the partial analysis state for syntax node actions executed on the declaration.
/// </summary>
internal class SyntaxNodeAnalyzerStateData : AnalyzerStateData
{
public HashSet<SyntaxNode> ProcessedNodes { get; set; }
public SyntaxNode CurrentNode { get; set; }
public SyntaxNodeAnalyzerStateData()
{
CurrentNode = null;
ProcessedNodes = new HashSet<SyntaxNode>();
}
public void ClearNodeAnalysisState()
{
CurrentNode = null;
ProcessedActions.Clear();
}
public override void Free()
{
base.Free();
CurrentNode = null;
ProcessedNodes.Clear();
}
}
/// <summary>
/// Stores the partial analysis state for code block actions executed on the declaration.
/// </summary>
internal sealed class CodeBlockAnalyzerStateData : AnalyzerStateData
{
public SyntaxNodeAnalyzerStateData ExecutableNodesAnalysisState { get; private set; }
public ImmutableHashSet<AnalyzerAction> CurrentCodeBlockEndActions { get; set; }
public ImmutableHashSet<AnalyzerAction> CurrentCodeBlockNodeActions { get; set; }
public CodeBlockAnalyzerStateData()
{
ExecutableNodesAnalysisState = new SyntaxNodeAnalyzerStateData();
CurrentCodeBlockEndActions = null;
CurrentCodeBlockNodeActions = null;
}
public override void SetStateKind(StateKind stateKind)
{
ExecutableNodesAnalysisState.SetStateKind(stateKind);
base.SetStateKind(stateKind);
}
public override void Free()
{
base.Free();
ExecutableNodesAnalysisState.Free();
CurrentCodeBlockEndActions = null;
CurrentCodeBlockNodeActions = null;
}
}
}
}
......@@ -20,8 +20,8 @@ namespace Microsoft.CodeAnalysis.Diagnostics
/// 3) <see cref="CompilationStartAnalyzerAction"/> registered during Initialize are invoked only once per-compilation per-<see cref="AnalyzerAndOptions"/>
/// </summary>
/// <remarks>
/// TODO: Consider moving <see cref="_compilationScopeMap"/> and relevant APIs <see cref="GetCompilationAnalysisScopeAsync(DiagnosticAnalyzer, HostSessionStartAnalysisScope, AnalyzerExecutor)"/> and
/// <see cref="GetAnalyzerHasDependentCompilationEndAsync(DiagnosticAnalyzer, AnalyzerExecutor)"/> out of the AnalyzerManager and into analyzer drivers.
/// TODO: Consider moving <see cref="_compilationScopeMap"/> and relevant APIs <see cref="GetCompilationAnalysisScopeAsync(DiagnosticAnalyzer, HostSessionStartAnalysisScope, AnalyzerExecutor)"/>
/// out of the AnalyzerManager and into analyzer drivers.
/// </remarks>
internal partial class AnalyzerManager
{
......@@ -148,30 +148,6 @@ public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer an
return sessionScope.GetAnalyzerActions(analyzer);
}
/// <summary>
/// Returns true if analyzer registered a compilation start action during <see cref="DiagnosticAnalyzer.Initialize(AnalysisContext)"/>
/// which registered a compilation end action and at least one other analyzer action, that the end action depends upon.
/// </summary>
public async Task<bool> GetAnalyzerHasDependentCompilationEndAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor)
{
var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false);
if (sessionScope.CompilationStartActions.Length > 0 && analyzerExecutor.Compilation != null)
{
var compilationScope = await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor).ConfigureAwait(false);
var compilationActions = compilationScope.GetCompilationOnlyAnalyzerActions(analyzer);
return compilationActions != null &&
compilationActions.CompilationEndActionsCount > 0 &&
(compilationActions.CodeBlockEndActionsCount > 0 ||
compilationActions.CodeBlockStartActionsCount > 0 ||
compilationActions.SemanticModelActionsCount > 0 ||
compilationActions.SymbolActionsCount > 0 ||
compilationActions.SyntaxNodeActionsCount > 0 ||
compilationActions.SyntaxTreeActionsCount > 0);
}
return false;
}
/// <summary>
/// Return <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/> of given <paramref name="analyzer"/>.
/// </summary>
......@@ -184,7 +160,14 @@ public async Task<bool> GetAnalyzerHasDependentCompilationEndAsync(DiagnosticAna
var supportedDiagnostics = ImmutableArray<DiagnosticDescriptor>.Empty;
// Catch Exception from analyzer.SupportedDiagnostics
analyzerExecutor.ExecuteAndCatchIfThrows(analyzer, () => { supportedDiagnostics = analyzer.SupportedDiagnostics; });
analyzerExecutor.ExecuteAndCatchIfThrows(analyzer, () =>
{
var supportedDiagnosticsLocal = analyzer.SupportedDiagnostics;
if (!supportedDiagnosticsLocal.IsDefaultOrEmpty)
{
supportedDiagnostics = supportedDiagnosticsLocal;
}
});
EventHandler<Exception> handler = null;
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = analyzerExecutor.OnAnalyzerException;
......@@ -192,7 +175,7 @@ public async Task<bool> GetAnalyzerHasDependentCompilationEndAsync(DiagnosticAna
{
handler = new EventHandler<Exception>((sender, ex) =>
{
var diagnostic = AnalyzerExecutor.GetAnalyzerExceptionDiagnostic(analyzer, ex);
var diagnostic = AnalyzerExecutor.CreateAnalyzerExceptionDiagnostic(analyzer, ex);
onAnalyzerException(ex, analyzer, diagnostic);
});
......@@ -217,10 +200,13 @@ public async Task<bool> GetAnalyzerHasDependentCompilationEndAsync(DiagnosticAna
/// </summary>
internal void ClearAnalyzerState(ImmutableArray<DiagnosticAnalyzer> analyzers)
{
foreach (var analyzer in analyzers)
if (!analyzers.IsDefaultOrEmpty)
{
ClearDescriptorState(analyzer);
ClearAnalysisScopeState(analyzer);
foreach (var analyzer in analyzers)
{
ClearDescriptorState(analyzer);
ClearAnalysisScopeState(analyzer);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Diagnostics.Telemetry
{
public static partial class AnalyzerTelemetry
{
/// <summary>
/// Contains the counts of registered actions for an analyzer.
/// </summary>
public class ActionCounts
{
internal ActionCounts(AnalyzerActions analyzerActions)
{
analyzerActions = analyzerActions ?? AnalyzerActions.Empty;
CompilationStartActionsCount = analyzerActions.CompilationStartActionsCount;
CompilationEndActionsCount = analyzerActions.CompilationEndActionsCount;
CompilationActionsCount = analyzerActions.CompilationActionsCount;
SyntaxTreeActionsCount = analyzerActions.SyntaxTreeActionsCount;
SemanticModelActionsCount = analyzerActions.SemanticModelActionsCount;
SymbolActionsCount = analyzerActions.SymbolActionsCount;
SyntaxNodeActionsCount = analyzerActions.SyntaxNodeActionsCount;
CodeBlockStartActionsCount = analyzerActions.CodeBlockStartActionsCount;
CodeBlockEndActionsCount = analyzerActions.CodeBlockEndActionsCount;
CodeBlockActionsCount = analyzerActions.CodeBlockActionsCount;
}
/// <summary>
/// Count of registered compilation start actions.
/// </summary>
public int CompilationStartActionsCount { get; private set; }
/// <summary>
/// Count of registered compilation end actions.
/// </summary>
public int CompilationEndActionsCount { get; private set; }
/// <summary>
/// Count of registered compilation actions.
/// </summary>
public int CompilationActionsCount { get; private set; }
/// <summary>
/// Count of registered syntax tree actions.
/// </summary>
public int SyntaxTreeActionsCount { get; private set; }
/// <summary>
/// Count of registered semantic model actions.
/// </summary>
public int SemanticModelActionsCount { get; private set; }
/// <summary>
/// Count of registered symbol actions.
/// </summary>
public int SymbolActionsCount { get; private set; }
/// <summary>
/// Count of registered syntax node actions.
/// </summary>
public int SyntaxNodeActionsCount { get; private set; }
/// <summary>
/// Count of code block start actions.
/// </summary>
public int CodeBlockStartActionsCount { get; private set; }
/// <summary>
/// Count of code block end actions.
/// </summary>
public int CodeBlockEndActionsCount { get; private set; }
/// <summary>
/// Count of code block actions.
/// </summary>
public int CodeBlockActionsCount { get; private set; }
}
}
}
// 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.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Diagnostics.Telemetry
{
public static partial class AnalyzerTelemetry
{
/// <summary>
/// Gets the count of registered actions for the analyzer for the given <see cref="CompilationWithAnalyzers"/>.
/// </summary>
public static async Task<ActionCounts> GetAnalyzerActionCountsAsync(this CompilationWithAnalyzers compilationWithAnalyzers, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return await compilationWithAnalyzers.GetAnalyzerActionCountsAsync(analyzer, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Gets the execution time for the given analyzer for the given <see cref="CompilationWithAnalyzers"/>.
/// </summary>
public static TimeSpan GetAnalyzerExecutionTime(this CompilationWithAnalyzers compilationWithAnalyzers, DiagnosticAnalyzer analyzer)
{
return compilationWithAnalyzers.GetAnalyzerExecutionTime(analyzer);
}
}
}
......@@ -11,6 +11,10 @@ public CompilationUnitCompletedEvent(Compilation compilation, SyntaxTree compila
{
this.CompilationUnit = compilationUnit;
}
public CompilationUnitCompletedEvent(CompilationUnitCompletedEvent original, SemanticModel newSemanticModel) : this(original.Compilation, original.CompilationUnit)
{
SemanticModel = newSemanticModel;
}
private WeakReference<SemanticModel> _weakModel;
public SemanticModel SemanticModel
{
......@@ -35,6 +39,10 @@ override public void FlushCache()
}
public SyntaxTree CompilationUnit { get; }
public CompilationUnitCompletedEvent WithSemanticModel(SemanticModel model)
{
return new CompilationUnitCompletedEvent(this, model);
}
public override string ToString()
{
return "CompilationUnitCompletedEvent(" + CompilationUnit.FilePath + ")";
......
// 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;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// Options to configure analyzer execution within <see cref="CompilationWithAnalyzers"/>.
/// </summary>
public class CompilationWithAnalyzersOptions
{
private readonly AnalyzerOptions _options;
private readonly Action<Exception, DiagnosticAnalyzer, Diagnostic> _onAnalyzerException;
private readonly bool _concurrentAnalysis;
private readonly bool _logAnalyzerExecutionTime;
/// <summary>
/// Options passed to <see cref="DiagnosticAnalyzer"/>s.
/// </summary>
public AnalyzerOptions AnalyzerOptions => _options;
/// <summary>
/// An optional delegate to be invoked when an analyzer throws an exception.
/// </summary>
public Action<Exception, DiagnosticAnalyzer, Diagnostic> OnAnalyzerException => _onAnalyzerException;
/// <summary>
/// Flag indicating whether analysis can be performed concurrently on multiple threads.
/// </summary>
public bool ConcurrentAnalysis => _concurrentAnalysis;
/// <summary>
/// Flag indicating whether analyzer execution time should be logged.
/// </summary>
public bool LogAnalyzerExecutionTime => _logAnalyzerExecutionTime;
/// <summary>
/// Creates a new <see cref="CompilationWithAnalyzersOptions"/>.
/// </summary>
/// <param name="options">Options that are passed to analyzers.</param>
/// <param name="onAnalyzerException">Action to invoke if an analyzer throws an exception.</param>
/// <param name="concurrentAnalysis">Flag indicating whether analysis can be performed concurrently on multiple threads.</param>
/// <param name="logAnalyzerExecutionTime">Flag indicating whether analyzer execution time should be logged.</param>
public CompilationWithAnalyzersOptions(AnalyzerOptions options, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, bool concurrentAnalysis, bool logAnalyzerExecutionTime)
{
_options = options;
_onAnalyzerException = onAnalyzerException;
_concurrentAnalysis = concurrentAnalysis;
_logAnalyzerExecutionTime = logAnalyzerExecutionTime;
}
}
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册