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);
            }
        }
Example #2
0
 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);
            }
Example #4
0
 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);
 }
Example #7
0
        /// <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);
            }
Example #9
0
        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);
        }
Example #11
0
        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;
                }
            }
Example #13
0
        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));
        }
Example #14
0
        /// <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);
 }
Example #20
0
        /// <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));
        }
Example #21
0
        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);
        }
Example #25
0
        /// <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);                
 }
Example #27
0
        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;
        }
Example #29
0
        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);
        }
Example #30
0
 /// <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);
        }
Example #33
0
        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);
        }
Example #34
0
        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();
        }
Example #35
0
 private Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeTask(
     DiagnosticAnalyzer analyzer,
     AnalyzerExecutor analyzerExecutor)
 {
     lock (_sessionScopeMap)
     {
         return GetSessionAnalysisScopeTask_NoLock(analyzer, analyzerExecutor);
     }
 }
Example #36
0
        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);
            }
        }
Example #37
0
        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;
        }
Example #38
0
        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);
        }
Example #39
0
        /// <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);
        }
Example #40
0
        /// <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());
                            }
                        }
                    }
                }
            }