private async Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeAsync( DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope, AnalyzerExecutor analyzerExecutor) { var analyzerAndOptions = new AnalyzerAndOptions(analyzer, analyzerExecutor.AnalyzerOptions); try { return await GetCompilationAnalysisScopeCoreAsync(analyzerAndOptions, sessionScope, analyzerExecutor).ConfigureAwait(false); } catch (OperationCanceledException) { // Task to compute the scope was cancelled. // Clear the entry in scope map for analyzer, so we can attempt a retry. ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>> compilationActionsMap; if (_compilationScopeMap.TryGetValue(analyzerAndOptions, out compilationActionsMap)) { compilationActionsMap.Remove(analyzerExecutor.Compilation); } analyzerExecutor.CancellationToken.ThrowIfCancellationRequested(); return await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor).ConfigureAwait(false); } }
private async Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeAsync( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var analyzerExecutionContext = _analyzerExecutionContextMap.GetOrCreateValue(analyzer); return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor, analyzerExecutionContext).ConfigureAwait(false); }
public DiagnosticIncrementalAnalyzer(DiagnosticAnalyzerService owner, int correlationId, Workspace workspace, AnalyzerManager analyzerManager) { _owner = owner; _correlationId = correlationId; _memberRangeMap = new MemberRangeMap(); _analyzersAndState = new DiagnosticAnalyzersAndStates(this, workspace, analyzerManager); _executor = new AnalyzerExecutor(this); _diagnosticLogAggregator = new DiagnosticLogAggregator(_owner); }
private void ClearCompilationScopeMap(AnalyzerAndOptions analyzerAndOptions, AnalyzerExecutor analyzerExecutor) { ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>> compilationActionsCache; lock (_compilationScopeMap) { if (_compilationScopeMap.TryGetValue(analyzerAndOptions, out compilationActionsCache)) { compilationActionsCache.Remove(analyzerExecutor.Compilation); } } }
public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService owner, int correlationId, Workspace workspace, HostAnalyzerManager analyzerManager, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : base(owner, workspace, analyzerManager, hostDiagnosticUpdateSource) { _correlationId = correlationId; _memberRangeMap = new MemberRangeMap(); _executor = new AnalyzerExecutor(this); _stateManager = new StateManager(analyzerManager); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; }
public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService owner, int correlationId, Workspace workspace, HostAnalyzerManager analyzerManager, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : base(owner, workspace, analyzerManager, hostDiagnosticUpdateSource) { _correlationId = correlationId; _memberRangeMap = new MemberRangeMap(); _executor = new AnalyzerExecutor(this); _eventQueue = new SimpleTaskQueue(TaskScheduler.Default); _stateManager = new StateManager(analyzerManager); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; _solutionCrawlerAnalysisState = new SolutionCrawlerAnalysisState(analyzerManager); }
/// <summary> /// Initializes the compilation for the analyzer driver. /// It also computes and initializes <see cref="analyzerActions"/> and <see cref="_symbolActionsByKind"/>. /// Finally, it initializes and starts the <see cref="_primaryTask"/> for the driver. /// </summary> /// <remarks> /// NOTE: This method must only be invoked from <see cref="AnalyzerDriver.Create(Compilation, ImmutableArray{DiagnosticAnalyzer}, AnalyzerOptions, AnalyzerManager, Action{Diagnostic}, out Compilation, CancellationToken)"/>. /// </remarks> private void Initialize(Compilation comp, AnalyzerExecutor analyzerExecutor, CancellationToken cancellationToken) { try { Debug.Assert(_compilation == null); Debug.Assert(comp.EventQueue == this.CompilationEventQueue); _compilation = comp; this.analyzerExecutor = analyzerExecutor; // Compute the set of effective actions based on suppression, and running the initial analyzers var analyzerActionsTask = GetAnalyzerActionsAsync(_analyzers, analyzerManager, analyzerExecutor); var initializeTask = analyzerActionsTask.ContinueWith(t => { this.analyzerActions = t.Result; _symbolActionsByKind = MakeSymbolActionsByKind(); _semanticModelActionsMap = MakeSemanticModelActionsByAnalyzer(); _compilationActionsMap = MakeCompilationActionsByAnalyzer(this.analyzerActions.CompilationActions); _compilationEndActionsMap = MakeCompilationActionsByAnalyzer(this.analyzerActions.CompilationEndActions); }, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Default); // create the primary driver task. cancellationToken.ThrowIfCancellationRequested(); _primaryTask = Task.Run(async () => { await initializeTask.ConfigureAwait(false); await ProcessCompilationEventsAsync(cancellationToken).ConfigureAwait(false); }, cancellationToken) .ContinueWith(c => DiagnosticQueue.TryComplete(), cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } finally { if (_primaryTask == null) { // Set primaryTask to be a cancelled task. var tcs = new TaskCompletionSource<int>(); tcs.SetCanceled(); _primaryTask = tcs.Task; // Try to set the DiagnosticQueue to be complete. this.DiagnosticQueue.TryComplete(); } } }
public Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeAsync( HostSessionStartAnalysisScope sessionScope, AnalyzerExecutor analyzerExecutor) { Func<Compilation, Task<HostCompilationStartAnalysisScope>> getTask = comp => { return Task.Run(() => { var compilationAnalysisScope = new HostCompilationStartAnalysisScope(sessionScope); analyzerExecutor.ExecuteCompilationStartActions(sessionScope.CompilationStartActions, compilationAnalysisScope); return compilationAnalysisScope; }, analyzerExecutor.CancellationToken); }; var callback = new ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>>.CreateValueCallback(getTask); var compilationActionsCache = GetOrCreateCompilationActionsCache(analyzerExecutor.AnalyzerOptions); return compilationActionsCache.GetValue(analyzerExecutor.Compilation, callback); }
private async Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeCoreAsync( HostSessionStartAnalysisScope sessionScope, AnalyzerExecutor analyzerExecutor, AnalyzerExecutionContext analyzerExecutionContext) { try { return await analyzerExecutionContext.GetCompilationAnalysisScopeAsync(sessionScope, analyzerExecutor).ConfigureAwait(false); } catch (OperationCanceledException) { // Task to compute the scope was cancelled. // Clear the entry in scope map for analyzer, so we can attempt a retry. analyzerExecutionContext.ClearCompilationScopeMap(analyzerExecutor.AnalyzerOptions, analyzerExecutor.Compilation); analyzerExecutor.CancellationToken.ThrowIfCancellationRequested(); return await GetCompilationAnalysisScopeCoreAsync(sessionScope, analyzerExecutor, analyzerExecutionContext).ConfigureAwait(false); } }
private Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeCoreAsync( AnalyzerAndOptions analyzerAndOptions, HostSessionStartAnalysisScope sessionScope, AnalyzerExecutor analyzerExecutor) { Func<Compilation, Task<HostCompilationStartAnalysisScope>> getTask = comp => { return Task.Run(() => { var compilationAnalysisScope = new HostCompilationStartAnalysisScope(sessionScope); analyzerExecutor.ExecuteCompilationStartActions(sessionScope.CompilationStartActions, compilationAnalysisScope); return compilationAnalysisScope; }, analyzerExecutor.CancellationToken); }; var callback = new ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>>.CreateValueCallback(getTask); var compilationActionsMap = _compilationScopeMap.GetOrAdd(analyzerAndOptions, new ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>>()); return compilationActionsMap.GetValue(analyzerExecutor.Compilation, callback); }
private async Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeCoreAsync( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor, AnalyzerExecutionContext analyzerExecutionContext) { try { var task = analyzerExecutionContext.GetSessionAnalysisScopeTask(analyzer, analyzerExecutor); return await task.ConfigureAwait(false); } catch (OperationCanceledException) { // Task to compute the scope was cancelled. // Clear the entry in scope map for analyzer, so we can attempt a retry. analyzerExecutionContext.ClearSessionScopeTask(); analyzerExecutor.CancellationToken.ThrowIfCancellationRequested(); return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor, analyzerExecutionContext).ConfigureAwait(false); } }
public Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeTask(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { lock (_gate) { Task<HostSessionStartAnalysisScope> task; if (_lazySessionScopeTask != null) { return _lazySessionScopeTask; } task = Task.Run(() => { var sessionScope = new HostSessionStartAnalysisScope(); analyzerExecutor.ExecuteInitializeMethod(analyzer, sessionScope); return sessionScope; }, analyzerExecutor.CancellationToken); _lazySessionScopeTask = task; return task; } }
public async ValueTask <AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); if (sessionScope.GetAnalyzerActions(analyzer).CompilationStartActions.Length > 0 && analyzerExecutor.Compilation != null) { var compilationScope = await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor).ConfigureAwait(false); return(compilationScope.GetAnalyzerActions(analyzer)); } return(sessionScope.GetAnalyzerActions(analyzer)); }
/// <summary> /// Return <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/> of given <paramref name="analyzer"/>. /// </summary> public ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnosticDescriptors( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { // Check if the value has already been computed and stored. Tuple<ImmutableArray<DiagnosticDescriptor>, EventHandler<Exception>> value; lock (_descriptorMap) { // REVIEW: how one knows exception handler is same as the one cached? if (_descriptorMap.TryGetValue(analyzer, out value)) { return value.Item1; } } // Otherwise, compute the value. // We do so outside the lock statement as we are calling into user code, which may be a long running operation. value = ComputeDescriptorsAndHandler(analyzer, analyzerExecutor); lock (_descriptorMap) { // Check if another thread already stored the computed value. Tuple<ImmutableArray<DiagnosticDescriptor>, EventHandler<Exception>> storedValue; if (_descriptorMap.TryGetValue(analyzer, out storedValue)) { // If so, we return the stored value. value = storedValue; } else { // Otherwise, store the value computed here. _descriptorMap.Add(analyzer, value); } } return value.Item1; }
private AnalyzerExecutor GetAnalyzerExecutor(DiagnosticAnalyzer analyzer, Compilation compilation, Action <Diagnostic> addDiagnostic) { return(AnalyzerExecutor.Create(compilation, _analyzerOptions, addDiagnostic, _onAnalyzerException, AnalyzerHelper.IsCompilerAnalyzer, AnalyzerManager.Instance, cancellationToken: _cancellationToken)); }
private AnalyzerExecutor GetAnalyzerExecutor(DiagnosticAnalyzer analyzer, Compilation compilation, Action <Diagnostic> addDiagnostic) { return(AnalyzerExecutor.Create(compilation, _analyzerOptions, addDiagnostic, _onAnalyzerException, _cancellationToken)); }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// </summary> internal bool IsDiagnosticAnalyzerSuppressed( DiagnosticAnalyzer analyzer, CompilationOptions options, Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer, AnalyzerExecutor analyzerExecutor) { if (isCompilerAnalyzer(analyzer)) { // Compiler analyzer must always be executed for compiler errors, which cannot be suppressed or filtered. return false; } var supportedDiagnostics = GetSupportedDiagnosticDescriptors(analyzer, analyzerExecutor); var diagnosticOptions = options.SpecificDiagnosticOptions; foreach (var diag in supportedDiagnostics) { if (HasNotConfigurableTag(diag.CustomTags)) { if (diag.IsEnabledByDefault) { // Diagnostic descriptor is not configurable, so the diagnostics created through it cannot be suppressed. return false; } else { // NotConfigurable disabled diagnostic can be ignored as it is never reported. continue; } } // Is this diagnostic suppressed by default (as written by the rule author) var isSuppressed = !diag.IsEnabledByDefault; // If the user said something about it, that overrides the author. if (diagnosticOptions.ContainsKey(diag.Id)) { isSuppressed = diagnosticOptions[diag.Id] == ReportDiagnostic.Suppress; } if (!isSuppressed) { return false; } } return true; }
/// <summary> /// Return <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/> of given <paramref name="analyzer"/>. /// </summary> public ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnosticDescriptors( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var descriptors = _descriptorCache.GetOrAdd(analyzer, key => { var supportedDiagnostics = ImmutableArray<DiagnosticDescriptor>.Empty; // Catch Exception from 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; if (onAnalyzerException != null) { handler = new EventHandler<Exception>((sender, ex) => { var diagnostic = AnalyzerExecutor.CreateAnalyzerExceptionDiagnostic(analyzer, ex); onAnalyzerException(ex, analyzer, diagnostic); }); // Subscribe for exceptions from lazily evaluated localizable strings in the descriptors. foreach (var descriptor in supportedDiagnostics) { descriptor.Title.OnException += handler; descriptor.MessageFormat.OnException += handler; descriptor.Description.OnException += handler; } } return Tuple.Create(supportedDiagnostics, handler); }); return descriptors.Item1; }
/// <summary> /// Returns true if the given analyzer has enabled concurrent execution by invoking <see cref="AnalysisContext.EnableConcurrentExecution"/>. /// </summary> public async Task<bool> IsConcurrentAnalyzerAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); return sessionScope.IsConcurrentAnalyzer(analyzer); }
/// <summary> /// Returns <see cref="GeneratedCodeAnalysisFlags"/> for the given analyzer. /// If an analyzer hasn't configured generated code analysis, returns <see cref="AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags"/>. /// </summary> public async Task <GeneratedCodeAnalysisFlags> GetGeneratedCodeAnalysisFlagsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); return(sessionScope.GetGeneratedCodeAnalysisFlags(analyzer)); }
private async Task <AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var analyzerActions = await AnalyzerManager.Instance.GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); DiagnosticAnalyzerLogger.UpdateAnalyzerTypeCount(analyzer, analyzerActions, (DiagnosticLogAggregator)_logAggregator); return(analyzerActions); }
public async Task <ImmutableArray <Diagnostic> > GetSemanticDiagnosticsAsync(DiagnosticAnalyzer analyzer) { var model = await _document.GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false); var compilation = model?.Compilation; Contract.ThrowIfNull(_document); using (var pooledObject = SharedPools.Default <List <Diagnostic> >().GetPooledObject()) { var diagnostics = pooledObject.Object; // Stateless semantic analyzers: // 1) ISemanticModelAnalyzer/IDocumentBasedDiagnosticAnalyzer // 2) ISymbolAnalyzer // 3) ISyntaxNodeAnalyzer _cancellationToken.ThrowIfCancellationRequested(); var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer; if (documentAnalyzer != null) { try { await documentAnalyzer.AnalyzeSemanticsAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false); } catch (Exception e) when(!AnalyzerExecutor.IsCanceled(e, _cancellationToken)) { OnAnalyzerException(e, analyzer, compilation); return(ImmutableArray <Diagnostic> .Empty); } } else { var analyzerExecutor = GetAnalyzerExecutor(analyzer, compilation, diagnostics.Add); var analyzerActions = await GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); if (analyzerActions != null) { // SemanticModel actions. if (analyzerActions.SemanticModelActionsCount > 0) { analyzerExecutor.ExecuteSemanticModelActions(analyzerActions, model); } // Symbol actions. if (analyzerActions.SymbolActionsCount > 0) { var symbols = this.GetSymbolsToAnalyze(model); analyzerExecutor.ExecuteSymbolActions(analyzerActions, symbols); } if (this.SyntaxNodeAnalyzerService != null) { // SyntaxNode actions. if (analyzerActions.SyntaxNodeActionsCount > 0) { this.SyntaxNodeAnalyzerService.ExecuteSyntaxNodeActions(analyzerActions, GetSyntaxNodesToAnalyze(), model, analyzerExecutor); } // CodeBlockStart, CodeBlock, CodeBlockEnd, and generated SyntaxNode actions. if (analyzerActions.CodeBlockStartActionsCount > 0 || analyzerActions.CodeBlockActionsCount > 0 || analyzerActions.CodeBlockEndActionsCount > 0) { this.SyntaxNodeAnalyzerService.ExecuteCodeBlockActions(analyzerActions, this.GetDeclarationInfos(model), model, analyzerExecutor); } } } } return(GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray()); } }
private async Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeAsync( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { try { return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor).ConfigureAwait(false); } catch (OperationCanceledException) { // Task to compute the scope was cancelled. // Clear the entry in scope map for analyzer, so we can attempt a retry. Task<HostSessionStartAnalysisScope> cancelledTask; _sessionScopeMap.TryRemove(analyzer, out cancelledTask); analyzerExecutor.CancellationToken.ThrowIfCancellationRequested(); return await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); } }
/// <summary> /// Get all the analyzer actions to execute for the given analyzer against a given compilation. /// The returned actions include the actions registered during <see cref="DiagnosticAnalyzer.Initialize(AnalysisContext)"/> method as well as /// the actions registered during <see cref="CompilationStartAnalyzerAction"/> for the given compilation. /// </summary> public async Task<AnalyzerActions> GetAnalyzerActionsAsync(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); return compilationScope.GetAnalyzerActions(analyzer); } return sessionScope.GetAnalyzerActions(analyzer); }
/// <summary> /// Returns true if the given analyzer has enabled concurrent execution by invoking <see cref="AnalysisContext.EnableConcurrentExecution"/>. /// </summary> public async Task <bool> IsConcurrentAnalyzerAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); return(sessionScope.IsConcurrentAnalyzer(analyzer)); }
/// <summary> /// Returns <see cref="GeneratedCodeAnalysisFlags"/> for the given analyzer. /// If an analyzer hasn't configured generated code analysis, returns <see cref="GeneratedCodeAnalysisFlags.Default"/>. /// </summary> public async Task<GeneratedCodeAnalysisFlags> GetGeneratedCodeAnalysisFlagsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false); return sessionScope.GetGeneratedCodeAnalysisFlags(analyzer); }
public async ValueTask <AnalyzerActions> GetPerSymbolAnalyzerActionsAsync(ISymbol symbol, DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var analyzerActions = await GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); if (analyzerActions.SymbolStartActionsCount > 0) { var filteredSymbolStartActions = getFilteredActionsByKind(analyzerActions.SymbolStartActions); if (filteredSymbolStartActions.Length > 0) { var symbolScope = await GetSymbolAnalysisScopeAsync(symbol, analyzer, filteredSymbolStartActions, analyzerExecutor).ConfigureAwait(false); return(symbolScope.GetAnalyzerActions(analyzer)); } } return(null); ImmutableArray <SymbolStartAnalyzerAction> getFilteredActionsByKind(ImmutableArray <SymbolStartAnalyzerAction> symbolStartActions) { ArrayBuilder <SymbolStartAnalyzerAction> filteredActionsBuilderOpt = null; for (int i = 0; i < symbolStartActions.Length; i++) { var symbolStartAction = symbolStartActions[i]; if (symbolStartAction.Kind != symbol.Kind) { if (filteredActionsBuilderOpt == null) { filteredActionsBuilderOpt = ArrayBuilder <SymbolStartAnalyzerAction> .GetInstance(); filteredActionsBuilderOpt.AddRange(symbolStartActions, i); } } else if (filteredActionsBuilderOpt != null) { filteredActionsBuilderOpt.Add(symbolStartAction); } } return(filteredActionsBuilderOpt != null?filteredActionsBuilderOpt.ToImmutableAndFree() : symbolStartActions); } }
internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer, AnalyzerExecutor analyzerExecutor) { // Avoid realizing all the descriptors for all compiler diagnostics by assuming that compiler analyzer doesn't report unsupported diagnostics. if (isCompilerAnalyzer(analyzer)) { return true; } // Get all the supported diagnostics and scan them linearly to see if the reported diagnostic is supported by the analyzer. // The linear scan is okay, given that this runs only if a diagnostic is being reported and a given analyzer is quite unlikely to have hundreds of thousands of supported diagnostics. var supportedDescriptors = GetSupportedDiagnosticDescriptors(analyzer, analyzerExecutor); foreach (var descriptor in supportedDescriptors) { if (descriptor.Id.Equals(diagnostic.Id, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; }
private static void OnDriverException(Task faultedTask, AnalyzerExecutor analyzerExecutor, ImmutableArray<DiagnosticAnalyzer> analyzers) { Debug.Assert(faultedTask.IsFaulted); var innerException = faultedTask.Exception?.InnerException; if (innerException == null || innerException is OperationCanceledException) { return; } var diagnostic = AnalyzerExecutor.CreateDriverExceptionDiagnostic(innerException); // Just pick the first analyzer from the scope for the onAnalyzerException callback. // The exception diagnostic's message and description will not include the analyzer, but explicitly state its a driver exception. var analyzer = analyzers[0]; analyzerExecutor.OnAnalyzerException(innerException, analyzer, diagnostic); }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// </summary> internal static bool IsDiagnosticAnalyzerSuppressed( DiagnosticAnalyzer analyzer, CompilationOptions options, AnalyzerManager analyzerManager, AnalyzerExecutor analyzerExecutor) { return analyzerManager.IsDiagnosticAnalyzerSuppressed(analyzer, options, IsCompilerAnalyzer, analyzerExecutor); }
public ImmutableArray <DiagnosticDescriptor> GetOrComputeDescriptors(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { lock (_gate) { if (!_lazyDescriptors.IsDefault) { return(_lazyDescriptors); } } // Otherwise, compute the value. // We do so outside the lock statement as we are calling into user code, which may be a long running operation. var descriptors = ComputeDescriptors(analyzer, analyzerExecutor); lock (_gate) { // Check if another thread already stored the computed value. if (!_lazyDescriptors.IsDefault) { // If so, we return the stored value. descriptors = _lazyDescriptors; } else { // Otherwise, store the value computed here. _lazyDescriptors = descriptors; } } return(descriptors); }
private Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeCoreAsync( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { Func<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> getTask = a => { return Task.Run(() => { var sessionScope = new HostSessionStartAnalysisScope(); analyzerExecutor.ExecuteInitializeMethod(a, sessionScope); return sessionScope; }, analyzerExecutor.CancellationToken); }; return _sessionScopeMap.GetOrAdd(analyzer, getTask); }
internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Func <DiagnosticAnalyzer, bool> isCompilerAnalyzer, AnalyzerExecutor analyzerExecutor) { // Avoid realizing all the descriptors for all compiler diagnostics by assuming that compiler analyzer doesn't report unsupported diagnostics. if (isCompilerAnalyzer(analyzer)) { return(true); } // Get all the supported diagnostics and scan them linearly to see if the reported diagnostic is supported by the analyzer. // The linear scan is okay, given that this runs only if a diagnostic is being reported and a given analyzer is quite unlikely to have hundreds of thousands of supported diagnostics. var supportedDescriptors = GetSupportedDiagnosticDescriptors(analyzer, analyzerExecutor); foreach (var descriptor in supportedDescriptors) { if (descriptor.Id.Equals(diagnostic.Id, StringComparison.OrdinalIgnoreCase)) { return(true); } } return(false); }
private static async Task<ImmutableDictionary<DiagnosticAnalyzer, SemaphoreSlim>> GetAnalyzerGateMapAsync( ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, AnalyzerExecutor analyzerExecutor) { var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, SemaphoreSlim>(); foreach (var analyzer in analyzers) { var isConcurrent = await analyzerManager.IsConcurrentAnalyzerAsync(analyzer, analyzerExecutor).ConfigureAwait(false); if (!isConcurrent) { // Non-concurrent analyzers need their action callbacks from the analyzer driver to be guarded by a gate. var gate = new SemaphoreSlim(initialCount: 1); builder.Add(analyzer, gate); } } return builder.ToImmutable(); }
private Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeTask( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { lock (_sessionScopeMap) { return GetSessionAnalysisScopeTask_NoLock(analyzer, analyzerExecutor); } }
private async Task ExecutePrimaryAnalysisTaskAsync(AnalysisScope analysisScope, AnalysisState analysisStateOpt, bool usingPrePopulatedEventQueue, CancellationToken cancellationToken) { Debug.Assert(analysisScope != null); Debug.Assert(WhenInitializedTask != null); await WhenInitializedTask.ConfigureAwait(false); if (WhenInitializedTask.IsFaulted) { OnDriverException(WhenInitializedTask, this.analyzerExecutor, analysisScope.Analyzers); } else if (!WhenInitializedTask.IsCanceled) { this.analyzerExecutor = this.analyzerExecutor.WithCancellationToken(cancellationToken); await ProcessCompilationEventsAsync(analysisScope, analysisStateOpt, usingPrePopulatedEventQueue, cancellationToken).ConfigureAwait(false); } }
private Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeTask_NoLock( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { Task<HostSessionStartAnalysisScope> task; if (_sessionScopeMap.TryGetValue(analyzer, out task)) { return task; } task = Task.Run(() => { var sessionScope = new HostSessionStartAnalysisScope(); analyzerExecutor.ExecuteInitializeMethod(analyzer, sessionScope); return sessionScope; }, analyzerExecutor.CancellationToken); _sessionScopeMap.Add(analyzer, task); return task; }
private static Task<AnalyzerActions> GetAnalyzerActionsAsync( ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, AnalyzerExecutor analyzerExecutor) { return Task.Run(async () => { AnalyzerActions allAnalyzerActions = new AnalyzerActions(); foreach (var analyzer in analyzers) { if (!IsDiagnosticAnalyzerSuppressed(analyzer, analyzerExecutor.Compilation.Options, analyzerManager, analyzerExecutor)) { var analyzerActions = await analyzerManager.GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false); if (analyzerActions != null) { allAnalyzerActions = allAnalyzerActions.Append(analyzerActions); } } } return allAnalyzerActions; }, analyzerExecutor.CancellationToken); }
/// <summary> /// Compute <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/> and exception handler for the given <paramref name="analyzer"/>. /// </summary> private static Tuple<ImmutableArray<DiagnosticDescriptor>, EventHandler<Exception>> ComputeDescriptorsAndHandler( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var supportedDiagnostics = ImmutableArray<DiagnosticDescriptor>.Empty; // Catch Exception from 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; if (onAnalyzerException != null) { handler = new EventHandler<Exception>((sender, ex) => { var diagnostic = AnalyzerExecutor.CreateAnalyzerExceptionDiagnostic(analyzer, ex); onAnalyzerException(ex, analyzer, diagnostic); }); // Subscribe for exceptions from lazily evaluated localizable strings in the descriptors. // REVIEW: find out better way to handle these exception handlers. right now, it can leak // so easily unless ClearAnalyzerState is called from host properly foreach (var descriptor in supportedDiagnostics) { descriptor.Title.OnException += handler; descriptor.MessageFormat.OnException += handler; descriptor.Description.OnException += handler; } } return Tuple.Create(supportedDiagnostics, handler); }
/// <summary> /// Initializes the <see cref="analyzerActions"/> and related actions maps for the analyzer driver. /// It kicks off the <see cref="WhenInitializedTask"/> task for initialization. /// Note: This method must be invoked exactly once on the driver. /// </summary> private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagnosticQueue, CancellationToken cancellationToken) { try { Debug.Assert(_initializeTask == null); this.analyzerExecutor = analyzerExecutor; this.DiagnosticQueue = diagnosticQueue; // Compute the set of effective actions based on suppression, and running the initial analyzers var analyzerActionsTask = GetAnalyzerActionsAsync(analyzers, analyzerManager, analyzerExecutor); _initializeTask = analyzerActionsTask.ContinueWith(t => { this.analyzerActions = t.Result; _symbolActionsByKind = MakeSymbolActionsByKind(); _semanticModelActionsMap = MakeSemanticModelActionsByAnalyzer(); _syntaxTreeActionsMap = MakeSyntaxTreeActionsByAnalyzer(); _compilationActionsMap = MakeCompilationActionsByAnalyzer(this.analyzerActions.CompilationActions); _compilationEndActionsMap = MakeCompilationActionsByAnalyzer(this.analyzerActions.CompilationEndActions); }, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Default); // create the primary driver task. cancellationToken.ThrowIfCancellationRequested(); _initializeSucceeded = true; } finally { if (_initializeTask == null) { // Set initializeTask to be a cancelled task. var tcs = new TaskCompletionSource<int>(); tcs.SetCanceled(); _initializeTask = tcs.Task; // Set primaryTask to be a cancelled task. tcs = new TaskCompletionSource<int>(); tcs.SetCanceled(); _primaryTask = tcs.Task; // Try to set the DiagnosticQueue to be complete. this.DiagnosticQueue.TryComplete(); } } }
public Task <HostSymbolStartAnalysisScope> GetSymbolAnalysisScopeAsync( ISymbol symbol, ImmutableArray <SymbolStartAnalyzerAction> symbolStartActions, AnalyzerExecutor analyzerExecutor) { lock (_gate) { _lazySymbolScopeTasks = _lazySymbolScopeTasks ?? new Dictionary <ISymbol, Task <HostSymbolStartAnalysisScope> >(); if (!_lazySymbolScopeTasks.TryGetValue(symbol, out var symbolScopeTask)) { symbolScopeTask = Task.Run(() => getSymbolAnalysisScopeCore(), analyzerExecutor.CancellationToken); _lazySymbolScopeTasks.Add(symbol, symbolScopeTask); } return(symbolScopeTask); HostSymbolStartAnalysisScope getSymbolAnalysisScopeCore() { var symbolAnalysisScope = new HostSymbolStartAnalysisScope(); analyzerExecutor.ExecuteSymbolStartActions(symbol, _analyzer, symbolStartActions, symbolAnalysisScope); var symbolEndActions = symbolAnalysisScope.GetAnalyzerActions(_analyzer); if (symbolEndActions.SymbolEndActionsCount > 0) { var dependentSymbols = getDependentSymbols(); lock (_gate) { _lazyPendingMemberSymbolsMapOpt = _lazyPendingMemberSymbolsMapOpt ?? new Dictionary <ISymbol, HashSet <ISymbol> >(); // Guard against entry added from another thread. VerifyNewEntryForPendingMemberSymbolsMap(symbol, dependentSymbols); _lazyPendingMemberSymbolsMapOpt[symbol] = dependentSymbols; } } return(symbolAnalysisScope); } } HashSet <ISymbol> getDependentSymbols() { HashSet <ISymbol> memberSet = null; switch (symbol.Kind) { case SymbolKind.NamedType: processMembers(((INamedTypeSymbol)symbol).GetMembers()); break; case SymbolKind.Namespace: processMembers(((INamespaceSymbol)symbol).GetMembers()); break; } return(memberSet); void processMembers(IEnumerable <ISymbol> members) { foreach (var member in members) { if (!member.IsImplicitlyDeclared && member.IsInSource()) { memberSet = memberSet ?? new HashSet <ISymbol>(); memberSet.Add(member); // Ensure that we include symbols for both parts of partial methods. if (member is IMethodSymbol method && !(method.PartialImplementationPart is null)) { memberSet.Add(method.PartialImplementationPart); } } if (member.Kind != symbol.Kind && member is INamedTypeSymbol typeMember) { processMembers(typeMember.GetMembers()); } } } } }