Files
2026-08-27 10:56:38 -06:00

1016 lines
59 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.FlowAnalysis;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics;
internal class AnalyzerExecutor
{
private sealed class AnalyzerDiagnosticReporter
{
public readonly Action<Diagnostic> AddDiagnosticAction;
private static readonly ObjectPool<AnalyzerDiagnosticReporter> s_objectPool = new ObjectPool<AnalyzerDiagnosticReporter>(() => new AnalyzerDiagnosticReporter(), 10);
private SourceOrAdditionalFile? _contextFile;
private Compilation _compilation;
private DiagnosticAnalyzer _analyzer;
private bool _isSyntaxDiagnostic;
private Action<Diagnostic, CancellationToken>? _addNonCategorizedDiagnostic;
private Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? _addCategorizedLocalDiagnostic;
private Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? _addCategorizedNonLocalDiagnostic;
private Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> _shouldSuppressGeneratedCodeDiagnostic;
private CancellationToken _cancellationToken;
public TextSpan? FilterSpanForLocalDiagnostics;
public static AnalyzerDiagnosticReporter GetInstance(SourceOrAdditionalFile contextFile, TextSpan? span, Compilation compilation, DiagnosticAnalyzer analyzer, bool isSyntaxDiagnostic, Action<Diagnostic, CancellationToken>? addNonCategorizedDiagnostic, Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? addCategorizedLocalDiagnostic, Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? addCategorizedNonLocalDiagnostic, Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> shouldSuppressGeneratedCodeDiagnostic, CancellationToken cancellationToken)
{
AnalyzerDiagnosticReporter analyzerDiagnosticReporter = s_objectPool.Allocate();
analyzerDiagnosticReporter._contextFile = contextFile;
analyzerDiagnosticReporter.FilterSpanForLocalDiagnostics = span;
analyzerDiagnosticReporter._compilation = compilation;
analyzerDiagnosticReporter._analyzer = analyzer;
analyzerDiagnosticReporter._isSyntaxDiagnostic = isSyntaxDiagnostic;
analyzerDiagnosticReporter._addNonCategorizedDiagnostic = addNonCategorizedDiagnostic;
analyzerDiagnosticReporter._addCategorizedLocalDiagnostic = addCategorizedLocalDiagnostic;
analyzerDiagnosticReporter._addCategorizedNonLocalDiagnostic = addCategorizedNonLocalDiagnostic;
analyzerDiagnosticReporter._shouldSuppressGeneratedCodeDiagnostic = shouldSuppressGeneratedCodeDiagnostic;
analyzerDiagnosticReporter._cancellationToken = cancellationToken;
return analyzerDiagnosticReporter;
}
public void Free()
{
_contextFile = null;
FilterSpanForLocalDiagnostics = null;
_compilation = null;
_analyzer = null;
_isSyntaxDiagnostic = false;
_addNonCategorizedDiagnostic = null;
_addCategorizedLocalDiagnostic = null;
_addCategorizedNonLocalDiagnostic = null;
_shouldSuppressGeneratedCodeDiagnostic = null;
_cancellationToken = default(CancellationToken);
s_objectPool.Free(this);
}
private AnalyzerDiagnosticReporter()
{
AddDiagnosticAction = AddDiagnostic;
}
private void AddDiagnostic(Diagnostic diagnostic)
{
if (!_shouldSuppressGeneratedCodeDiagnostic(diagnostic, _analyzer, _compilation, _cancellationToken))
{
if (_addCategorizedLocalDiagnostic == null)
{
_addNonCategorizedDiagnostic(diagnostic, _cancellationToken);
}
else if (isLocalDiagnostic(diagnostic) && (!FilterSpanForLocalDiagnostics.HasValue || FilterSpanForLocalDiagnostics.Value.IntersectsWith(diagnostic.Location.SourceSpan)))
{
_addCategorizedLocalDiagnostic(diagnostic, _analyzer, _isSyntaxDiagnostic, _cancellationToken);
}
else
{
_addCategorizedNonLocalDiagnostic(diagnostic, _analyzer, _cancellationToken);
}
}
bool isLocalDiagnostic(Diagnostic diagnostic2)
{
if (diagnostic2.Location.IsInSource)
{
if (_contextFile?.SourceTree != null)
{
return _contextFile.Value.SourceTree == diagnostic2.Location.SourceTree;
}
return false;
}
if (_contextFile?.AdditionalFile != null && diagnostic2.Location is ExternalFileLocation externalFileLocation)
{
return PathUtilities.Comparer.Equals(_contextFile.Value.AdditionalFile.Path, externalFileLocation.GetLineSpan().Path);
}
return false;
}
}
}
private const string DiagnosticCategory = "Compiler";
internal const string AnalyzerExceptionDiagnosticId = "AD0001";
internal const string AnalyzerDriverExceptionDiagnosticId = "AD0002";
private readonly Action<Diagnostic, CancellationToken>? _addNonCategorizedDiagnostic;
private readonly Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? _addCategorizedLocalDiagnostic;
private readonly Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? _addCategorizedNonLocalDiagnostic;
private readonly Action<Suppression>? _addSuppression;
private readonly Func<Exception, bool>? _analyzerExceptionFilter;
private readonly AnalyzerManager _analyzerManager;
private readonly Func<DiagnosticAnalyzer, bool> _isCompilerAnalyzer;
private readonly Func<DiagnosticAnalyzer, object?> _getAnalyzerGate;
private readonly Func<SyntaxTree, SemanticModel> _getSemanticModel;
private readonly Func<DiagnosticAnalyzer, bool> _shouldSkipAnalysisOnGeneratedCode;
private readonly Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> _shouldSuppressGeneratedCodeDiagnostic;
private readonly Func<SyntaxTree, TextSpan, CancellationToken, bool> _isGeneratedCodeLocation;
private readonly Func<DiagnosticAnalyzer, SyntaxTree, SyntaxTreeOptionsProvider?, CancellationToken, bool> _isAnalyzerSuppressedForTree;
private readonly ConcurrentDictionary<DiagnosticAnalyzer, StrongBox<long>>? _analyzerExecutionTimeMap;
private readonly CompilationAnalysisValueProviderFactory _compilationAnalysisValueProviderFactory;
private Func<IOperation, ControlFlowGraph>? _lazyGetControlFlowGraph;
private ConcurrentDictionary<IOperation, ControlFlowGraph>? _lazyControlFlowGraphMap;
private Func<IOperation, ControlFlowGraph> GetControlFlowGraph => GetControlFlowGraphImpl;
internal Compilation Compilation { get; }
internal AnalyzerOptions AnalyzerOptions { get; }
internal Action<Exception, DiagnosticAnalyzer, Diagnostic, CancellationToken> OnAnalyzerException { get; }
internal ImmutableDictionary<DiagnosticAnalyzer, TimeSpan> AnalyzerExecutionTimes => _analyzerExecutionTimeMap.ToImmutableDictionary<KeyValuePair<DiagnosticAnalyzer, StrongBox<long>>, DiagnosticAnalyzer, TimeSpan>((KeyValuePair<DiagnosticAnalyzer, StrongBox<long>> pair) => pair.Key, (KeyValuePair<DiagnosticAnalyzer, StrongBox<long>> pair) => TimeSpan.FromTicks(pair.Value.Value));
private bool IsAnalyzerSuppressedForTree(DiagnosticAnalyzer analyzer, SyntaxTree tree, CancellationToken cancellationToken)
{
return _isAnalyzerSuppressedForTree(analyzer, tree, Compilation.Options.SyntaxTreeOptionsProvider, cancellationToken);
}
public static AnalyzerExecutor Create(Compilation compilation, AnalyzerOptions analyzerOptions, Action<Diagnostic, CancellationToken>? addNonCategorizedDiagnostic, Action<Exception, DiagnosticAnalyzer, Diagnostic, CancellationToken> onAnalyzerException, Func<Exception, bool>? analyzerExceptionFilter, Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer, AnalyzerManager analyzerManager, Func<DiagnosticAnalyzer, bool> shouldSkipAnalysisOnGeneratedCode, Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> shouldSuppressGeneratedCodeDiagnostic, Func<SyntaxTree, TextSpan, CancellationToken, bool> isGeneratedCodeLocation, Func<DiagnosticAnalyzer, SyntaxTree, SyntaxTreeOptionsProvider?, CancellationToken, bool> isAnalyzerSuppressedForTree, Func<DiagnosticAnalyzer, object?> getAnalyzerGate, Func<SyntaxTree, SemanticModel> getSemanticModel, bool logExecutionTime = false, Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? addCategorizedLocalDiagnostic = null, Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? addCategorizedNonLocalDiagnostic = null, Action<Suppression>? addSuppression = null)
{
ConcurrentDictionary<DiagnosticAnalyzer, StrongBox<long>> analyzerExecutionTimeMap = (logExecutionTime ? new ConcurrentDictionary<DiagnosticAnalyzer, StrongBox<long>>() : null);
return new AnalyzerExecutor(compilation, analyzerOptions, addNonCategorizedDiagnostic, onAnalyzerException, analyzerExceptionFilter, isCompilerAnalyzer, analyzerManager, shouldSkipAnalysisOnGeneratedCode, shouldSuppressGeneratedCodeDiagnostic, isGeneratedCodeLocation, isAnalyzerSuppressedForTree, getAnalyzerGate, getSemanticModel, analyzerExecutionTimeMap, addCategorizedLocalDiagnostic, addCategorizedNonLocalDiagnostic, addSuppression);
}
private AnalyzerExecutor(Compilation compilation, AnalyzerOptions analyzerOptions, Action<Diagnostic, CancellationToken>? addNonCategorizedDiagnosticOpt, Action<Exception, DiagnosticAnalyzer, Diagnostic, CancellationToken> onAnalyzerException, Func<Exception, bool>? analyzerExceptionFilter, Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer, AnalyzerManager analyzerManager, Func<DiagnosticAnalyzer, bool> shouldSkipAnalysisOnGeneratedCode, Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> shouldSuppressGeneratedCodeDiagnostic, Func<SyntaxTree, TextSpan, CancellationToken, bool> isGeneratedCodeLocation, Func<DiagnosticAnalyzer, SyntaxTree, SyntaxTreeOptionsProvider?, CancellationToken, bool> isAnalyzerSuppressedForTree, Func<DiagnosticAnalyzer, object?> getAnalyzerGate, Func<SyntaxTree, SemanticModel> getSemanticModel, ConcurrentDictionary<DiagnosticAnalyzer, StrongBox<long>>? analyzerExecutionTimeMap, Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? addCategorizedLocalDiagnostic, Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? addCategorizedNonLocalDiagnostic, Action<Suppression>? addSuppression)
{
Compilation = compilation;
AnalyzerOptions = analyzerOptions;
_addNonCategorizedDiagnostic = addNonCategorizedDiagnosticOpt;
OnAnalyzerException = onAnalyzerException;
_analyzerExceptionFilter = analyzerExceptionFilter;
_isCompilerAnalyzer = isCompilerAnalyzer;
_analyzerManager = analyzerManager;
_shouldSkipAnalysisOnGeneratedCode = shouldSkipAnalysisOnGeneratedCode;
_shouldSuppressGeneratedCodeDiagnostic = shouldSuppressGeneratedCodeDiagnostic;
_isGeneratedCodeLocation = isGeneratedCodeLocation;
_isAnalyzerSuppressedForTree = isAnalyzerSuppressedForTree;
_getAnalyzerGate = getAnalyzerGate;
_getSemanticModel = getSemanticModel;
_analyzerExecutionTimeMap = analyzerExecutionTimeMap;
_addCategorizedLocalDiagnostic = addCategorizedLocalDiagnostic;
_addCategorizedNonLocalDiagnostic = addCategorizedNonLocalDiagnostic;
_addSuppression = addSuppression;
_compilationAnalysisValueProviderFactory = new CompilationAnalysisValueProviderFactory();
}
public void ExecuteInitializeMethod(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope, CancellationToken cancellationToken)
{
AnalyzerAnalysisContext item = new AnalyzerAnalysisContext(analyzer, sessionScope);
ExecuteAndCatchIfThrows(analyzer, delegate((DiagnosticAnalyzer analyzer, AnalyzerAnalysisContext context) data)
{
data.analyzer.Initialize(data.context);
}, (analyzer, item), null, cancellationToken);
}
public void ExecuteCompilationStartActions(ImmutableArray<CompilationStartAnalyzerAction> actions, HostCompilationStartAnalysisScope compilationScope, CancellationToken cancellationToken)
{
ImmutableArray<CompilationStartAnalyzerAction>.Enumerator enumerator = actions.GetEnumerator();
while (enumerator.MoveNext())
{
CompilationStartAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
AnalyzerCompilationStartAnalysisContext item = new AnalyzerCompilationStartAnalysisContext(current.Analyzer, compilationScope, Compilation, AnalyzerOptions, _compilationAnalysisValueProviderFactory, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<CompilationStartAnalysisContext> action, AnalyzerCompilationStartAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(Compilation), cancellationToken);
}
}
public void ExecuteSymbolStartActions(ISymbol symbol, DiagnosticAnalyzer analyzer, ImmutableArray<SymbolStartAnalyzerAction> actions, HostSymbolStartAnalysisScope symbolScope, bool isGeneratedCodeSymbol, SyntaxTree? filterTree, TextSpan? filterSpan, CancellationToken cancellationToken)
{
if ((isGeneratedCodeSymbol && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForSymbol(analyzer, symbol, cancellationToken))
{
return;
}
ImmutableArray<SymbolStartAnalyzerAction>.Enumerator enumerator = actions.GetEnumerator();
while (enumerator.MoveNext())
{
SymbolStartAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
AnalyzerSymbolStartAnalysisContext item = new AnalyzerSymbolStartAnalysisContext(current.Analyzer, symbolScope, symbol, Compilation, AnalyzerOptions, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<SymbolStartAnalysisContext> action, AnalyzerSymbolStartAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(Compilation, symbol), cancellationToken);
}
}
public void ExecuteSuppressionAction(DiagnosticSuppressor suppressor, ImmutableArray<Diagnostic> reportedDiagnostics, CancellationToken cancellationToken)
{
if (!reportedDiagnostics.IsEmpty)
{
cancellationToken.ThrowIfCancellationRequested();
Func<SuppressionDescriptor, bool> isSupportedSuppressionDescriptor = _analyzerManager.GetSupportedSuppressionDescriptors(suppressor, this, cancellationToken).Contains;
Action<SuppressionAnalysisContext> item = suppressor.ReportSuppressions;
ExecuteAndCatchIfThrows(argument: (item, new SuppressionAnalysisContext(Compilation, AnalyzerOptions, reportedDiagnostics, _addSuppression, isSupportedSuppressionDescriptor, _getSemanticModel, cancellationToken)), analyzer: suppressor, analyze: delegate((Action<SuppressionAnalysisContext> action, SuppressionAnalysisContext context) data)
{
data.action(data.context);
}, contextInfo: new AnalysisContextInfo(Compilation), cancellationToken: cancellationToken);
}
}
public void ExecuteCompilationActions(ImmutableArray<CompilationAnalyzerAction> compilationActions, DiagnosticAnalyzer analyzer, CompilationEvent compilationEvent, CancellationToken cancellationToken)
{
Action<Diagnostic> addCompilationDiagnostic = GetAddCompilationDiagnostic(analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<CompilationAnalyzerAction>.Enumerator enumerator = compilationActions.GetEnumerator();
while (enumerator.MoveNext())
{
CompilationAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
CompilationAnalysisContext item = new CompilationAnalysisContext(Compilation, AnalyzerOptions, addCompilationDiagnostic, boundFunction, _compilationAnalysisValueProviderFactory, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<CompilationAnalysisContext> action, CompilationAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(Compilation), cancellationToken);
}
}
}
public void ExecuteSymbolActions(ImmutableArray<SymbolAnalyzerAction> symbolActions, DiagnosticAnalyzer analyzer, SymbolDeclaredCompilationEvent symbolDeclaredEvent, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, bool isGeneratedCodeSymbol, SyntaxTree? filterTree, TextSpan? filterSpan, CancellationToken cancellationToken)
{
if ((isGeneratedCodeSymbol && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForSymbol(analyzer, symbolDeclaredEvent.Symbol, cancellationToken))
{
return;
}
ISymbol symbol = symbolDeclaredEvent.Symbol;
Action<Diagnostic> addDiagnostic = GetAddDiagnostic(symbol, symbolDeclaredEvent.DeclaringSyntaxReferences, analyzer, getTopMostNodeForAnalysis, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<SymbolAnalyzerAction>.Enumerator enumerator = symbolActions.GetEnumerator();
while (enumerator.MoveNext())
{
SymbolAnalyzerAction current = enumerator.Current;
Action<SymbolAnalysisContext> action = current.Action;
if (current.Kinds.Contains(symbol.Kind))
{
cancellationToken.ThrowIfCancellationRequested();
ExecuteAndCatchIfThrows(argument: (action, new SymbolAnalysisContext(symbol, Compilation, AnalyzerOptions, addDiagnostic, boundFunction, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken)), analyzer: current.Analyzer, analyze: delegate((Action<SymbolAnalysisContext> action, SymbolAnalysisContext context) data)
{
data.action(data.context);
}, contextInfo: new AnalysisContextInfo(Compilation, symbol), cancellationToken: cancellationToken);
}
}
}
}
public bool TryExecuteSymbolEndActionsForContainer(INamespaceOrTypeSymbol containingSymbol, ISymbol processedMemberSymbol, DiagnosticAnalyzer analyzer, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, bool isGeneratedCode, SyntaxTree? filterTree, TextSpan? filterSpan, CancellationToken cancellationToken, [NotNullWhen(true)] out SymbolDeclaredCompilationEvent? containingSymbolDeclaredEvent)
{
containingSymbolDeclaredEvent = null;
if (!_analyzerManager.TryProcessCompletedMemberAndGetPendingSymbolEndActionsForContainer(containingSymbol, processedMemberSymbol, analyzer, out (ImmutableArray<SymbolEndAnalyzerAction>, SymbolDeclaredCompilationEvent) containerEndActionsAndEvent))
{
return false;
}
ImmutableArray<SymbolEndAnalyzerAction> symbolEndActions;
(symbolEndActions, containingSymbolDeclaredEvent) = containerEndActionsAndEvent;
ExecuteSymbolEndActionsCore(symbolEndActions, analyzer, containingSymbolDeclaredEvent, getTopMostNodeForAnalysis, isGeneratedCode, filterTree, filterSpan, cancellationToken);
return true;
}
public bool TryExecuteSymbolEndActions(ImmutableArray<SymbolEndAnalyzerAction> symbolEndActions, DiagnosticAnalyzer analyzer, SymbolDeclaredCompilationEvent symbolDeclaredEvent, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, bool isGeneratedCode, SyntaxTree? filterTree, TextSpan? filterSpan, CancellationToken cancellationToken)
{
if (!_analyzerManager.TryStartExecuteSymbolEndActions(symbolEndActions, analyzer, symbolDeclaredEvent))
{
return false;
}
ExecuteSymbolEndActionsCore(symbolEndActions, analyzer, symbolDeclaredEvent, getTopMostNodeForAnalysis, isGeneratedCode, filterTree, filterSpan, cancellationToken);
return true;
}
private void ExecuteSymbolEndActionsCore(ImmutableArray<SymbolEndAnalyzerAction> symbolEndActions, DiagnosticAnalyzer analyzer, SymbolDeclaredCompilationEvent symbolDeclaredEvent, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, bool isGeneratedCode, SyntaxTree? filterTree, TextSpan? filterSpan, CancellationToken cancellationToken)
{
ISymbol symbol = symbolDeclaredEvent.Symbol;
Action<Diagnostic> addDiagnostic = GetAddDiagnostic(symbol, symbolDeclaredEvent.DeclaringSyntaxReferences, analyzer, getTopMostNodeForAnalysis, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<SymbolEndAnalyzerAction>.Enumerator enumerator = symbolEndActions.GetEnumerator();
while (enumerator.MoveNext())
{
SymbolEndAnalyzerAction current = enumerator.Current;
Action<SymbolAnalysisContext> action = current.Action;
cancellationToken.ThrowIfCancellationRequested();
ExecuteAndCatchIfThrows(argument: (action, new SymbolAnalysisContext(symbol, Compilation, AnalyzerOptions, addDiagnostic, boundFunction, isGeneratedCode, filterTree, filterSpan, cancellationToken)), analyzer: current.Analyzer, analyze: delegate((Action<SymbolAnalysisContext> action, SymbolAnalysisContext context) data)
{
data.action(data.context);
}, contextInfo: new AnalysisContextInfo(Compilation, symbol), cancellationToken: cancellationToken);
}
_analyzerManager.MarkSymbolEndAnalysisComplete(symbol, analyzer);
}
}
public void ExecuteSemanticModelActions(ImmutableArray<SemanticModelAnalyzerAction> semanticModelActions, DiagnosticAnalyzer analyzer, SemanticModel semanticModel, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken)
{
if ((isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForTree(analyzer, semanticModel.SyntaxTree, cancellationToken))
{
return;
}
AnalyzerDiagnosticReporter addSemanticDiagnostic = GetAddSemanticDiagnostic(semanticModel.SyntaxTree, analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<SemanticModelAnalyzerAction>.Enumerator enumerator = semanticModelActions.GetEnumerator();
while (enumerator.MoveNext())
{
SemanticModelAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
SemanticModelAnalysisContext item = new SemanticModelAnalysisContext(semanticModel, AnalyzerOptions, addSemanticDiagnostic.AddDiagnosticAction, boundFunction, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<SemanticModelAnalysisContext> action, SemanticModelAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(semanticModel), cancellationToken);
}
addSemanticDiagnostic.Free();
}
}
public void ExecuteSyntaxTreeActions(ImmutableArray<SyntaxTreeAnalyzerAction> syntaxTreeActions, DiagnosticAnalyzer analyzer, SourceOrAdditionalFile file, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken)
{
SyntaxTree sourceTree = file.SourceTree;
if ((isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForTree(analyzer, sourceTree, cancellationToken))
{
return;
}
AnalyzerDiagnosticReporter addSyntaxDiagnostic = GetAddSyntaxDiagnostic(file, analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<SyntaxTreeAnalyzerAction>.Enumerator enumerator = syntaxTreeActions.GetEnumerator();
while (enumerator.MoveNext())
{
SyntaxTreeAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
SyntaxTreeAnalysisContext item = new SyntaxTreeAnalysisContext(sourceTree, AnalyzerOptions, addSyntaxDiagnostic.AddDiagnosticAction, boundFunction, Compilation, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<SyntaxTreeAnalysisContext> action, SyntaxTreeAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(Compilation, file), cancellationToken);
}
addSyntaxDiagnostic.Free();
}
}
public void ExecuteAdditionalFileActions(ImmutableArray<AdditionalFileAnalyzerAction> additionalFileActions, DiagnosticAnalyzer analyzer, SourceOrAdditionalFile file, TextSpan? filterSpan, CancellationToken cancellationToken)
{
AdditionalText additionalFile = file.AdditionalFile;
AnalyzerDiagnosticReporter addSyntaxDiagnostic = GetAddSyntaxDiagnostic(file, analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ImmutableArray<AdditionalFileAnalyzerAction>.Enumerator enumerator = additionalFileActions.GetEnumerator();
while (enumerator.MoveNext())
{
AdditionalFileAnalyzerAction current = enumerator.Current;
cancellationToken.ThrowIfCancellationRequested();
AdditionalFileAnalysisContext item = new AdditionalFileAnalysisContext(additionalFile, AnalyzerOptions, addSyntaxDiagnostic.AddDiagnosticAction, boundFunction, Compilation, filterSpan, cancellationToken);
ExecuteAndCatchIfThrows(current.Analyzer, delegate((Action<AdditionalFileAnalysisContext> action, AdditionalFileAnalysisContext context) data)
{
data.action(data.context);
}, (current.Action, item), new AnalysisContextInfo(Compilation, file), cancellationToken);
}
addSyntaxDiagnostic.Free();
}
}
private void ExecuteSyntaxNodeAction<TLanguageKindEnum>(SyntaxNodeAnalyzerAction<TLanguageKindEnum> syntaxNodeAction, SyntaxNode node, ISymbol containingSymbol, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken) where TLanguageKindEnum : struct
{
SyntaxNodeAnalysisContext item = new SyntaxNodeAnalysisContext(node, containingSymbol, semanticModel, AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(syntaxNodeAction.Analyzer, delegate((Action<SyntaxNodeAnalysisContext> action, SyntaxNodeAnalysisContext context) data)
{
data.action(data.context);
}, (syntaxNodeAction.Action, item), new AnalysisContextInfo(Compilation, node), cancellationToken);
}
private void ExecuteOperationAction(OperationAnalyzerAction operationAction, IOperation operation, ISymbol containingSymbol, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken)
{
OperationAnalysisContext item = new OperationAnalysisContext(operation, containingSymbol, semanticModel.Compilation, AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, GetControlFlowGraph, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(operationAction.Analyzer, delegate((Action<OperationAnalysisContext> action, OperationAnalysisContext context) data)
{
data.action(data.context);
}, (operationAction.Action, item), new AnalysisContextInfo(Compilation, operation), cancellationToken);
}
public void ExecuteCodeBlockActions<TLanguageKindEnum>(IEnumerable<CodeBlockStartAnalyzerAction<TLanguageKindEnum>> codeBlockStartActions, IEnumerable<CodeBlockAnalyzerAction> codeBlockActions, IEnumerable<CodeBlockAnalyzerAction> codeBlockEndActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray<SyntaxNode> executableCodeBlocks, SemanticModel semanticModel, Func<SyntaxNode, TLanguageKindEnum> getKind, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken) where TLanguageKindEnum : struct
{
ExecuteBlockActionsCore<CodeBlockStartAnalyzerAction<TLanguageKindEnum>, CodeBlockAnalyzerAction, SyntaxNodeAnalyzerAction<TLanguageKindEnum>, SyntaxNode, TLanguageKindEnum>(codeBlockStartActions, codeBlockActions, codeBlockEndActions, analyzer, declaredNode, declaredSymbol, executableCodeBlocks, (ImmutableArray<SyntaxNode> codeBlocks) => codeBlocks.SelectMany(delegate(SyntaxNode cb)
{
Func<SyntaxNode, bool> syntaxNodesToAnalyzeFilter = semanticModel.GetSyntaxNodesToAnalyzeFilter(cb, declaredSymbol);
return (syntaxNodesToAnalyzeFilter != null) ? cb.DescendantNodesAndSelf(syntaxNodesToAnalyzeFilter).Where(syntaxNodesToAnalyzeFilter) : cb.DescendantNodesAndSelf();
}), semanticModel, getKind, filterSpan, isGeneratedCode, cancellationToken);
}
public void ExecuteOperationBlockActions(IEnumerable<OperationBlockStartAnalyzerAction> operationBlockStartActions, IEnumerable<OperationBlockAnalyzerAction> operationBlockActions, IEnumerable<OperationBlockAnalyzerAction> operationBlockEndActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray<IOperation> operationBlocks, ImmutableArray<IOperation> operations, SemanticModel semanticModel, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken)
{
ExecuteBlockActionsCore<OperationBlockStartAnalyzerAction, OperationBlockAnalyzerAction, OperationAnalyzerAction, IOperation, int>(operationBlockStartActions, operationBlockActions, operationBlockEndActions, analyzer, declaredNode, declaredSymbol, operationBlocks, (ImmutableArray<IOperation> blocks) => operations, semanticModel, null, filterSpan, isGeneratedCode, cancellationToken);
}
private void ExecuteBlockActionsCore<TBlockStartAction, TBlockAction, TNodeAction, TNode, TLanguageKindEnum>(IEnumerable<TBlockStartAction> startActions, IEnumerable<TBlockAction> actions, IEnumerable<TBlockAction> endActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray<TNode> executableBlocks, Func<ImmutableArray<TNode>, IEnumerable<TNode>> getNodesToAnalyze, SemanticModel semanticModel, Func<SyntaxNode, TLanguageKindEnum>? getKind, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken) where TBlockStartAction : AnalyzerAction where TBlockAction : AnalyzerAction where TNodeAction : AnalyzerAction where TLanguageKindEnum : struct
{
if ((isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForTree(analyzer, declaredNode.SyntaxTree, cancellationToken))
{
return;
}
PooledHashSet<TBlockAction> instance = PooledHashSet<TBlockAction>.GetInstance();
PooledHashSet<TBlockAction> instance2 = PooledHashSet<TBlockAction>.GetInstance();
ArrayBuilder<TNodeAction> instance3 = ArrayBuilder<TNodeAction>.GetInstance();
ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> arrayBuilder = instance3 as ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>;
ArrayBuilder<OperationAnalyzerAction> arrayBuilder2 = instance3 as ArrayBuilder<OperationAnalyzerAction>;
ImmutableArray<IOperation> operationBlocks = ((executableBlocks[0] is IOperation) ? ((ImmutableArray<IOperation>)(object)executableBlocks) : ImmutableArray<IOperation>.Empty);
instance2.AddAll(actions);
instance.AddAll(endActions);
AnalyzerDiagnosticReporter addSemanticDiagnostic = GetAddSemanticDiagnostic(semanticModel.SyntaxTree, declaredNode.FullSpan, analyzer, cancellationToken);
foreach (TBlockStartAction startAction in startActions)
{
if (startAction is CodeBlockStartAnalyzerAction<TLanguageKindEnum> codeBlockStartAnalyzerAction)
{
PooledHashSet<CodeBlockAnalyzerAction> item = instance as PooledHashSet<CodeBlockAnalyzerAction>;
HostCodeBlockStartAnalysisScope<TLanguageKindEnum> hostCodeBlockStartAnalysisScope = new HostCodeBlockStartAnalysisScope<TLanguageKindEnum>();
AnalyzerCodeBlockStartAnalysisContext<TLanguageKindEnum> item2 = new AnalyzerCodeBlockStartAnalysisContext<TLanguageKindEnum>(startAction.Analyzer, hostCodeBlockStartAnalysisScope, declaredNode, declaredSymbol, semanticModel, AnalyzerOptions, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(startAction.Analyzer, delegate((Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action, AnalyzerCodeBlockStartAnalysisContext<TLanguageKindEnum> context, HostCodeBlockStartAnalysisScope<TLanguageKindEnum> scope, PooledHashSet<CodeBlockAnalyzerAction> blockEndActions, ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> syntaxNodeActions) data)
{
data.action(data.context);
data.blockEndActions?.AddAll(data.scope.CodeBlockEndActions);
data.syntaxNodeActions?.AddRange(data.scope.SyntaxNodeActions);
}, (codeBlockStartAnalyzerAction.Action, item2, hostCodeBlockStartAnalysisScope, item, arrayBuilder), new AnalysisContextInfo(Compilation, declaredSymbol, declaredNode), cancellationToken);
}
else if (startAction is OperationBlockStartAnalyzerAction operationBlockStartAnalyzerAction)
{
PooledHashSet<OperationBlockAnalyzerAction> item3 = instance as PooledHashSet<OperationBlockAnalyzerAction>;
HostOperationBlockStartAnalysisScope hostOperationBlockStartAnalysisScope = new HostOperationBlockStartAnalysisScope();
AnalyzerOperationBlockStartAnalysisContext item4 = new AnalyzerOperationBlockStartAnalysisContext(startAction.Analyzer, hostOperationBlockStartAnalysisScope, operationBlocks, declaredSymbol, semanticModel.Compilation, AnalyzerOptions, GetControlFlowGraph, declaredNode.SyntaxTree, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(startAction.Analyzer, delegate((Action<OperationBlockStartAnalysisContext> action, AnalyzerOperationBlockStartAnalysisContext context, HostOperationBlockStartAnalysisScope scope, PooledHashSet<OperationBlockAnalyzerAction> blockEndActions, ArrayBuilder<OperationAnalyzerAction> operationActions) data)
{
data.action(data.context);
data.blockEndActions?.AddAll(data.scope.OperationBlockEndActions);
data.operationActions?.AddRange(data.scope.OperationActions);
}, (operationBlockStartAnalyzerAction.Action, item4, hostOperationBlockStartAnalysisScope, item3, arrayBuilder2), new AnalysisContextInfo(Compilation, declaredSymbol), cancellationToken);
}
}
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
if (instance3.Any())
{
if (arrayBuilder != null)
{
ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind = GetNodeActionsByKind(arrayBuilder);
IEnumerable<SyntaxNode> nodesToAnalyze = (IEnumerable<SyntaxNode>)getNodesToAnalyze(executableBlocks);
ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, analyzer, declaredSymbol, semanticModel, getKind, addSemanticDiagnostic, boundFunction, filterSpan, isGeneratedCode, startActions.Any(), cancellationToken);
}
else if (arrayBuilder2 != null)
{
ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind = GetOperationActionsByKind(arrayBuilder2);
IEnumerable<IOperation> operationsToAnalyze = (IEnumerable<IOperation>)getNodesToAnalyze(executableBlocks);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, semanticModel, addSemanticDiagnostic, boundFunction, filterSpan, isGeneratedCode, startActions.Any(), cancellationToken);
}
}
instance3.Free();
ExecuteBlockActions(instance2, declaredNode, declaredSymbol, analyzer, semanticModel, operationBlocks, addSemanticDiagnostic.AddDiagnosticAction, boundFunction, filterSpan, isGeneratedCode, cancellationToken);
ExecuteBlockActions(instance, declaredNode, declaredSymbol, analyzer, semanticModel, operationBlocks, addSemanticDiagnostic.AddDiagnosticAction, boundFunction, filterSpan, isGeneratedCode, cancellationToken);
addSemanticDiagnostic.Free();
}
}
private void ExecuteBlockActions<TBlockAction>(PooledHashSet<TBlockAction> blockActions, SyntaxNode declaredNode, ISymbol declaredSymbol, DiagnosticAnalyzer analyzer, SemanticModel semanticModel, ImmutableArray<IOperation> operationBlocks, Action<Diagnostic> addDiagnostic, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, TextSpan? filterSpan, bool isGeneratedCode, CancellationToken cancellationToken) where TBlockAction : AnalyzerAction
{
foreach (TBlockAction blockAction in blockActions)
{
if (blockAction is CodeBlockAnalyzerAction codeBlockAnalyzerAction)
{
CodeBlockAnalysisContext item = new CodeBlockAnalysisContext(declaredNode, declaredSymbol, semanticModel, AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(codeBlockAnalyzerAction.Analyzer, delegate((Action<CodeBlockAnalysisContext> action, CodeBlockAnalysisContext context) data)
{
data.action(data.context);
}, (codeBlockAnalyzerAction.Action, item), new AnalysisContextInfo(Compilation, declaredSymbol, declaredNode), cancellationToken);
}
else if (blockAction is OperationBlockAnalyzerAction operationBlockAnalyzerAction)
{
OperationBlockAnalysisContext item2 = new OperationBlockAnalysisContext(operationBlocks, declaredSymbol, semanticModel.Compilation, AnalyzerOptions, addDiagnostic, isSupportedDiagnostic, GetControlFlowGraph, declaredNode.SyntaxTree, filterSpan, isGeneratedCode, cancellationToken);
ExecuteAndCatchIfThrows(operationBlockAnalyzerAction.Analyzer, delegate((Action<OperationBlockAnalysisContext> action, OperationBlockAnalysisContext context) data)
{
data.action(data.context);
}, (operationBlockAnalyzerAction.Action, item2), new AnalysisContextInfo(Compilation, declaredSymbol), cancellationToken);
}
}
blockActions.Free();
}
internal static ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> GetNodeActionsByKind<TLanguageKindEnum>(IEnumerable<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> nodeActions) where TLanguageKindEnum : struct
{
PooledDictionary<TLanguageKindEnum, ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> instance = PooledDictionary<TLanguageKindEnum, ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>>.GetInstance();
foreach (SyntaxNodeAnalyzerAction<TLanguageKindEnum> nodeAction in nodeActions)
{
ImmutableArray<TLanguageKindEnum>.Enumerator enumerator2 = nodeAction.Kinds.GetEnumerator();
while (enumerator2.MoveNext())
{
TLanguageKindEnum current2 = enumerator2.Current;
if (!instance.TryGetValue(current2, out var value))
{
instance.Add(current2, value = ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.GetInstance());
}
value.Add(nodeAction);
}
}
ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> result = ImmutableSegmentedDictionary.CreateRange(instance.Select((KeyValuePair<TLanguageKindEnum, ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> kvp) => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree())));
instance.Free();
return result;
}
public void ExecuteSyntaxNodeActions<TLanguageKindEnum>(IEnumerable<SyntaxNode> nodesToAnalyze, ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind, DiagnosticAnalyzer analyzer, SemanticModel model, Func<SyntaxNode, TLanguageKindEnum> getKind, TextSpan spanForContainingTopmostNodeForAnalysis, ISymbol declaredSymbol, TextSpan? filterSpan, bool isGeneratedCode, bool hasCodeBlockStartOrSymbolStartActions, CancellationToken cancellationToken) where TLanguageKindEnum : struct
{
if ((isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForTree(analyzer, model.SyntaxTree, cancellationToken))
{
return;
}
AnalyzerDiagnosticReporter addSemanticDiagnostic = GetAddSemanticDiagnostic(model.SyntaxTree, spanForContainingTopmostNodeForAnalysis, analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, analyzer, declaredSymbol, model, getKind, addSemanticDiagnostic, boundFunction, filterSpan, isGeneratedCode, hasCodeBlockStartOrSymbolStartActions, cancellationToken);
addSemanticDiagnostic.Free();
}
}
private void ExecuteSyntaxNodeActions<TLanguageKindEnum>(IEnumerable<SyntaxNode> nodesToAnalyze, ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind, DiagnosticAnalyzer analyzer, ISymbol containingSymbol, SemanticModel model, Func<SyntaxNode, TLanguageKindEnum> getKind, AnalyzerDiagnosticReporter diagReporter, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, TextSpan? filterSpan, bool isGeneratedCode, bool hasCodeBlockStartOrSymbolStartActions, CancellationToken cancellationToken) where TLanguageKindEnum : struct
{
foreach (SyntaxNode item in nodesToAnalyze)
{
if (nodeActionsByKind.TryGetValue(getKind(item), out ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> value) && ShouldExecuteNode(item, analyzer, cancellationToken))
{
if (!hasCodeBlockStartOrSymbolStartActions)
{
diagReporter.FilterSpanForLocalDiagnostics = item.FullSpan;
}
ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.Enumerator enumerator2 = value.GetEnumerator();
while (enumerator2.MoveNext())
{
SyntaxNodeAnalyzerAction<TLanguageKindEnum> current2 = enumerator2.Current;
ExecuteSyntaxNodeAction(current2, item, containingSymbol, model, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken);
}
}
}
}
internal static ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> GetOperationActionsByKind(IEnumerable<OperationAnalyzerAction> operationActions)
{
PooledDictionary<OperationKind, ArrayBuilder<OperationAnalyzerAction>> instance = PooledDictionary<OperationKind, ArrayBuilder<OperationAnalyzerAction>>.GetInstance();
foreach (OperationAnalyzerAction operationAction in operationActions)
{
ImmutableArray<OperationKind>.Enumerator enumerator2 = operationAction.Kinds.GetEnumerator();
while (enumerator2.MoveNext())
{
OperationKind current2 = enumerator2.Current;
if (!instance.TryGetValue(current2, out var value))
{
instance.Add(current2, value = ArrayBuilder<OperationAnalyzerAction>.GetInstance());
}
value.Add(operationAction);
}
}
ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> result = ImmutableSegmentedDictionary.CreateRange(instance.Select((KeyValuePair<OperationKind, ArrayBuilder<OperationAnalyzerAction>> kvp) => KeyValuePairUtil.Create(kvp.Key, kvp.Value.ToImmutableAndFree())));
instance.Free();
return result;
}
public void ExecuteOperationActions(IEnumerable<IOperation> operationsToAnalyze, ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind, DiagnosticAnalyzer analyzer, SemanticModel model, TextSpan spanForContainingOperationBlock, ISymbol declaredSymbol, TextSpan? filterSpan, bool isGeneratedCode, bool hasOperationBlockStartOrSymbolStartActions, CancellationToken cancellationToken)
{
if ((isGeneratedCode && _shouldSkipAnalysisOnGeneratedCode(analyzer)) || IsAnalyzerSuppressedForTree(analyzer, model.SyntaxTree, cancellationToken))
{
return;
}
AnalyzerDiagnosticReporter addSemanticDiagnostic = GetAddSemanticDiagnostic(model.SyntaxTree, spanForContainingOperationBlock, analyzer, cancellationToken);
Func<Diagnostic, CancellationToken, bool> boundFunction;
using (PooledDelegates.GetPooledFunction((Diagnostic d, CancellationToken ct, (AnalyzerExecutor self, DiagnosticAnalyzer analyzer) arg) => arg.self.IsSupportedDiagnostic(arg.analyzer, d, ct), (this, analyzer), out boundFunction))
{
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, model, addSemanticDiagnostic, boundFunction, filterSpan, isGeneratedCode, hasOperationBlockStartOrSymbolStartActions, cancellationToken);
addSemanticDiagnostic.Free();
}
}
private void ExecuteOperationActions(IEnumerable<IOperation> operationsToAnalyze, ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind, DiagnosticAnalyzer analyzer, ISymbol containingSymbol, SemanticModel model, AnalyzerDiagnosticReporter diagReporter, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, TextSpan? filterSpan, bool isGeneratedCode, bool hasOperationBlockStartOrSymbolStartActions, CancellationToken cancellationToken)
{
foreach (IOperation item in operationsToAnalyze)
{
if (operationActionsByKind.TryGetValue(item.Kind, out ImmutableArray<OperationAnalyzerAction> value) && ShouldExecuteOperation(item, analyzer, cancellationToken))
{
if (!hasOperationBlockStartOrSymbolStartActions)
{
diagReporter.FilterSpanForLocalDiagnostics = item.Syntax.FullSpan;
}
ImmutableArray<OperationAnalyzerAction>.Enumerator enumerator2 = value.GetEnumerator();
while (enumerator2.MoveNext())
{
OperationAnalyzerAction current2 = enumerator2.Current;
ExecuteOperationAction(current2, item, containingSymbol, model, diagReporter.AddDiagnosticAction, isSupportedDiagnostic, filterSpan, isGeneratedCode, cancellationToken);
}
}
}
}
internal static bool CanHaveExecutableCodeBlock(ISymbol symbol)
{
switch (symbol.Kind)
{
case SymbolKind.Event:
case SymbolKind.Method:
case SymbolKind.NamedType:
case SymbolKind.Namespace:
case SymbolKind.Property:
return true;
case SymbolKind.Field:
return true;
default:
return false;
}
}
internal void ExecuteAndCatchIfThrows<TArg>(DiagnosticAnalyzer analyzer, Action<TArg> analyze, TArg argument, AnalysisContextInfo? contextInfo, CancellationToken cancellationToken)
{
SharedStopwatch sharedStopwatch = default(SharedStopwatch);
if (_analyzerExecutionTimeMap != null)
{
sharedStopwatch = SharedStopwatch.StartNew();
}
object obj = _getAnalyzerGate(analyzer);
if (obj != null)
{
lock (obj)
{
ExecuteAndCatchIfThrows_NoLock(analyzer, analyze, argument, contextInfo, cancellationToken);
}
}
else
{
ExecuteAndCatchIfThrows_NoLock(analyzer, analyze, argument, contextInfo, cancellationToken);
}
if (_analyzerExecutionTimeMap != null)
{
long ticks = sharedStopwatch.Elapsed.Ticks;
Interlocked.Add(ref _analyzerExecutionTimeMap.GetOrAdd(analyzer, (DiagnosticAnalyzer _) => new StrongBox<long>(0L)).Value, ticks);
}
}
private void ExecuteAndCatchIfThrows_NoLock<TArg>(DiagnosticAnalyzer analyzer, Action<TArg> analyze, TArg argument, AnalysisContextInfo? info, CancellationToken cancellationToken)
{
try
{
cancellationToken.ThrowIfCancellationRequested();
analyze(argument);
}
catch (Exception exception) when (HandleAnalyzerException(exception, analyzer, info, OnAnalyzerException, _analyzerExceptionFilter, cancellationToken))
{
}
}
internal static bool HandleAnalyzerException(Exception exception, DiagnosticAnalyzer analyzer, AnalysisContextInfo? info, Action<Exception, DiagnosticAnalyzer, Diagnostic, CancellationToken> onAnalyzerException, Func<Exception, bool>? analyzerExceptionFilter, CancellationToken cancellationToken)
{
if (!ExceptionFilter(exception, analyzerExceptionFilter, cancellationToken))
{
return false;
}
Diagnostic arg = CreateAnalyzerExceptionDiagnostic(analyzer, exception, info);
try
{
onAnalyzerException(exception, analyzer, arg, cancellationToken);
}
catch (Exception)
{
}
return true;
static bool ExceptionFilter(Exception ex2, Func<Exception, bool>? func, CancellationToken cancellationToken2)
{
OperationCanceledException obj = ex2 as OperationCanceledException;
if (obj != null && obj.CancellationToken == cancellationToken2)
{
return false;
}
return func?.Invoke(ex2) ?? true;
}
}
internal static Diagnostic CreateAnalyzerExceptionDiagnostic(DiagnosticAnalyzer analyzer, Exception e, AnalysisContextInfo? info = null)
{
string text = analyzer.ToString();
string compilerAnalyzerFailure = CodeAnalysisResources.CompilerAnalyzerFailure;
string compilerAnalyzerThrows = CodeAnalysisResources.CompilerAnalyzerThrows;
string text2 = string.Join(Environment.NewLine, new string[2]
{
CreateDiagnosticDescription(info, e),
CreateDisablingMessage(analyzer, text)
}).Trim();
string[] array = new string[4]
{
text,
e.GetType().ToString(),
e.Message,
text2
};
DiagnosticDescriptor analyzerExceptionDiagnosticDescriptor = GetAnalyzerExceptionDiagnosticDescriptor("AD0001", compilerAnalyzerFailure, compilerAnalyzerThrows);
Location none = Location.None;
object[] messageArgs = array;
return Diagnostic.Create(analyzerExceptionDiagnosticDescriptor, none, messageArgs);
}
private static string CreateDiagnosticDescription(AnalysisContextInfo? info, Exception e)
{
if (!info.HasValue)
{
return e.CreateDiagnosticDescription();
}
return string.Join(Environment.NewLine, new string[2]
{
string.Format(CodeAnalysisResources.ExceptionContext, info?.GetContext()),
e.CreateDiagnosticDescription()
});
}
private static string CreateDisablingMessage(DiagnosticAnalyzer analyzer, string analyzerName)
{
ImmutableSortedSet<string> immutableSortedSet = ImmutableSortedSet<string>.Empty.WithComparer(StringComparer.OrdinalIgnoreCase);
try
{
ImmutableArray<DiagnosticDescriptor>.Enumerator enumerator = analyzer.SupportedDiagnostics.GetEnumerator();
while (enumerator.MoveNext())
{
DiagnosticDescriptor current = enumerator.Current;
if (current != null)
{
immutableSortedSet = immutableSortedSet.Add(current.Id);
}
}
}
catch (Exception ex)
{
return string.Format(CodeAnalysisResources.CompilerAnalyzerThrows, new object[4]
{
analyzerName,
ex.GetType().ToString(),
ex.Message,
ex.CreateDiagnosticDescription()
});
}
if (immutableSortedSet.IsEmpty)
{
return "";
}
return string.Format(CodeAnalysisResources.DisableAnalyzerDiagnosticsMessage, string.Join(", ", immutableSortedSet));
}
internal static Diagnostic CreateDriverExceptionDiagnostic(Exception e)
{
string analyzerDriverFailure = CodeAnalysisResources.AnalyzerDriverFailure;
string analyzerDriverThrows = CodeAnalysisResources.AnalyzerDriverThrows;
string[] array = new string[3]
{
e.GetType().ToString(),
e.Message,
e.CreateDiagnosticDescription()
};
DiagnosticDescriptor analyzerExceptionDiagnosticDescriptor = GetAnalyzerExceptionDiagnosticDescriptor("AD0002", analyzerDriverFailure, analyzerDriverThrows);
Location none = Location.None;
object[] messageArgs = array;
return Diagnostic.Create(analyzerExceptionDiagnosticDescriptor, none, messageArgs);
}
internal static DiagnosticDescriptor GetAnalyzerExceptionDiagnosticDescriptor(string? id = null, string? title = null, string? messageFormat = null)
{
if (id == null)
{
id = "AD0001";
}
if (title == null)
{
title = CodeAnalysisResources.CompilerAnalyzerFailure;
}
if (messageFormat == null)
{
messageFormat = CodeAnalysisResources.CompilerAnalyzerThrows;
}
return new DiagnosticDescriptor(id, title, messageFormat, "Compiler", DiagnosticSeverity.Warning, true, null, null, "AnalyzerException");
}
internal static bool IsAnalyzerExceptionDiagnostic(Diagnostic diagnostic)
{
if (diagnostic.Id == "AD0001" || diagnostic.Id == "AD0002")
{
ImmutableArray<string>.Enumerator enumerator = diagnostic.Descriptor.ImmutableCustomTags.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current == "AnalyzerException")
{
return true;
}
}
}
return false;
}
internal static bool AreEquivalentAnalyzerExceptionDiagnostics(Diagnostic exceptionDiagnostic, Diagnostic other)
{
if (!IsAnalyzerExceptionDiagnostic(other))
{
return false;
}
if (exceptionDiagnostic.Id == other.Id && exceptionDiagnostic.Severity == other.Severity)
{
return exceptionDiagnostic.GetMessage() == other.GetMessage();
}
return false;
}
private bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, CancellationToken cancellationToken)
{
if (diagnostic is DiagnosticWithInfo)
{
return true;
}
return _analyzerManager.IsSupportedDiagnostic(analyzer, diagnostic, _isCompilerAnalyzer, this, cancellationToken);
}
private Action<Diagnostic> GetAddDiagnostic(ISymbol contextSymbol, ImmutableArray<SyntaxReference> cachedDeclaringReferences, DiagnosticAnalyzer analyzer, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, CancellationToken cancellationToken)
{
return GetAddDiagnostic(contextSymbol, cachedDeclaringReferences, Compilation, analyzer, _addNonCategorizedDiagnostic, _addCategorizedLocalDiagnostic, _addCategorizedNonLocalDiagnostic, getTopMostNodeForAnalysis, _shouldSuppressGeneratedCodeDiagnostic, cancellationToken);
}
private static Action<Diagnostic> GetAddDiagnostic(ISymbol contextSymbol, ImmutableArray<SyntaxReference> cachedDeclaringReferences, Compilation compilation, DiagnosticAnalyzer analyzer, Action<Diagnostic, CancellationToken>? addNonCategorizedDiagnostic, Action<Diagnostic, DiagnosticAnalyzer, bool, CancellationToken>? addCategorizedLocalDiagnostic, Action<Diagnostic, DiagnosticAnalyzer, CancellationToken>? addCategorizedNonLocalDiagnostic, Func<ISymbol, SyntaxReference, Compilation, CancellationToken, SyntaxNode> getTopMostNodeForAnalysis, Func<Diagnostic, DiagnosticAnalyzer, Compilation, CancellationToken, bool> shouldSuppressGeneratedCodeDiagnostic, CancellationToken cancellationToken)
{
return delegate(Diagnostic diagnostic)
{
if (!shouldSuppressGeneratedCodeDiagnostic(diagnostic, analyzer, compilation, cancellationToken))
{
if (addCategorizedLocalDiagnostic == null)
{
addNonCategorizedDiagnostic(diagnostic, cancellationToken);
}
else
{
if (diagnostic.Location.IsInSource)
{
ImmutableArray<SyntaxReference>.Enumerator enumerator = cachedDeclaringReferences.GetEnumerator();
while (enumerator.MoveNext())
{
SyntaxReference current = enumerator.Current;
if (current.SyntaxTree == diagnostic.Location.SourceTree)
{
SyntaxNode syntaxNode = getTopMostNodeForAnalysis(contextSymbol, current, compilation, cancellationToken);
if (diagnostic.Location.SourceSpan.IntersectsWith(syntaxNode.FullSpan))
{
addCategorizedLocalDiagnostic(diagnostic, analyzer, arg3: false, cancellationToken);
return;
}
}
}
}
addCategorizedNonLocalDiagnostic(diagnostic, analyzer, cancellationToken);
}
}
};
}
private Action<Diagnostic> GetAddCompilationDiagnostic(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return delegate(Diagnostic diagnostic)
{
if (!_shouldSuppressGeneratedCodeDiagnostic(diagnostic, analyzer, Compilation, cancellationToken))
{
if (_addCategorizedNonLocalDiagnostic == null)
{
_addNonCategorizedDiagnostic(diagnostic, cancellationToken);
}
else
{
_addCategorizedNonLocalDiagnostic(diagnostic, analyzer, cancellationToken);
}
}
};
}
private AnalyzerDiagnosticReporter GetAddSemanticDiagnostic(SyntaxTree tree, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return AnalyzerDiagnosticReporter.GetInstance(new SourceOrAdditionalFile(tree), null, Compilation, analyzer, isSyntaxDiagnostic: false, _addNonCategorizedDiagnostic, _addCategorizedLocalDiagnostic, _addCategorizedNonLocalDiagnostic, _shouldSuppressGeneratedCodeDiagnostic, cancellationToken);
}
private AnalyzerDiagnosticReporter GetAddSemanticDiagnostic(SyntaxTree tree, TextSpan? span, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return AnalyzerDiagnosticReporter.GetInstance(new SourceOrAdditionalFile(tree), span, Compilation, analyzer, isSyntaxDiagnostic: false, _addNonCategorizedDiagnostic, _addCategorizedLocalDiagnostic, _addCategorizedNonLocalDiagnostic, _shouldSuppressGeneratedCodeDiagnostic, cancellationToken);
}
private AnalyzerDiagnosticReporter GetAddSyntaxDiagnostic(SourceOrAdditionalFile file, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return AnalyzerDiagnosticReporter.GetInstance(file, null, Compilation, analyzer, isSyntaxDiagnostic: true, _addNonCategorizedDiagnostic, _addCategorizedLocalDiagnostic, _addCategorizedNonLocalDiagnostic, _shouldSuppressGeneratedCodeDiagnostic, cancellationToken);
}
private bool ShouldExecuteNode(SyntaxNode node, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
if (_shouldSkipAnalysisOnGeneratedCode(analyzer) && _isGeneratedCodeLocation(node.SyntaxTree, node.Span, cancellationToken))
{
return false;
}
return true;
}
private bool ShouldExecuteOperation(IOperation operation, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
if (operation.Syntax != null && _shouldSkipAnalysisOnGeneratedCode(analyzer) && _isGeneratedCodeLocation(operation.Syntax.SyntaxTree, operation.Syntax.Span, cancellationToken))
{
return false;
}
return true;
}
internal TimeSpan ResetAnalyzerExecutionTime(DiagnosticAnalyzer analyzer)
{
if (!_analyzerExecutionTimeMap.TryRemove(analyzer, out StrongBox<long> value))
{
return TimeSpan.Zero;
}
return TimeSpan.FromTicks(value.Value);
}
private ControlFlowGraph GetControlFlowGraphImpl(IOperation operation)
{
if (_lazyControlFlowGraphMap == null)
{
Interlocked.CompareExchange(ref _lazyControlFlowGraphMap, new ConcurrentDictionary<IOperation, ControlFlowGraph>(), null);
}
return _lazyControlFlowGraphMap.GetOrAdd(operation, (IOperation op) => ControlFlowGraphBuilder.Create(op, null, null, null, default(ControlFlowGraphBuilder.Context)));
}
private bool IsAnalyzerSuppressedForSymbol(DiagnosticAnalyzer analyzer, ISymbol symbol, CancellationToken cancellationToken)
{
ImmutableArray<Location>.Enumerator enumerator = symbol.Locations.GetEnumerator();
while (enumerator.MoveNext())
{
Location current = enumerator.Current;
if (current.SourceTree != null && !IsAnalyzerSuppressedForTree(analyzer, current.SourceTree, cancellationToken))
{
return false;
}
}
return true;
}
public void OnOperationBlockActionsExecuted(ImmutableArray<IOperation> operationBlocks)
{
ConcurrentDictionary<IOperation, ControlFlowGraph>? lazyControlFlowGraphMap = _lazyControlFlowGraphMap;
if (lazyControlFlowGraphMap != null && lazyControlFlowGraphMap.Count > 0)
{
ImmutableArray<IOperation>.Enumerator enumerator = operationBlocks.GetEnumerator();
while (enumerator.MoveNext())
{
IOperation rootOperation = enumerator.Current.GetRootOperation();
_lazyControlFlowGraphMap.TryRemove(rootOperation, out ControlFlowGraph _);
}
}
}
}