예제 #1
0
        private async Task EnsureAnalyzerActionCountsInitializedAsync(
            AnalyzerDriver driver,
            CancellationToken cancellationToken
            )
        {
            if (_lazyAnalyzerActionCountsMap == null)
            {
                var builder = ImmutableDictionary.CreateBuilder <
                    DiagnosticAnalyzer,
                    AnalyzerActionCounts
                    >();
                foreach (var(analyzer, _) in _analyzerStateMap)
                {
                    var actionCounts = await driver
                                       .GetAnalyzerActionCountsAsync(
                        analyzer,
                        _compilationOptions,
                        cancellationToken
                        )
                                       .ConfigureAwait(false);

                    builder.Add(analyzer, actionCounts);
                }

                Interlocked.CompareExchange(
                    ref _lazyAnalyzerActionCountsMap,
                    builder.ToImmutable(),
                    null
                    );
            }
        }
예제 #2
0
        public void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver)
        {
            foreach (var analyzer in analysisScope.Analyzers)
            {
                // Dequeue reported analyzer diagnostics from the driver and store them in our maps.
                var syntaxDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: true);
                var semanticDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: false);
                var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer);

                lock (_gate)
                {
                    if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0)
                    {
                        UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, ref _localSyntaxDiagnosticsOpt);
                        UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, ref _localSemanticDiagnosticsOpt);
                        UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics);
                    }

                    if (_analyzerExecutionTimeOpt != null)
                    {
                        _analyzerExecutionTimeOpt[analyzer] += driver.ResetAnalyzerExecutionTime(analyzer);
                    }
                }
            }
        }
예제 #3
0
        private async Task <AnalyzerDriver> GetAnalyzerDriverAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Get instance of analyzer driver from the driver pool.
            AnalyzerDriver driver = _driverPool.Allocate();

            try
            {
                // Start the initialization task, if required.
                if (driver.WhenInitializedTask == null)
                {
                    driver.Initialize(_compilation, _analysisOptions, categorizeDiagnostics: true, cancellationToken: cancellationToken);
                }

                // Wait for driver initilization to complete: this executes the Initialize and CompilationStartActions to compute all registered actions per-analyzer.
                await driver.WhenInitializedTask.ConfigureAwait(false);
            }
            finally
            {
                if (driver.WhenInitializedTask.IsCanceled)
                {
                    // If the initialization task was cancelled, we retry again with our own cancellation token.
                    // This can happen if the task that started the initialization was cancelled by the callee, and the new request picked up this driver instance.
                    _driverPool.ForgetTrackedObject(driver);
                    driver = await GetAnalyzerDriverAsync(cancellationToken).ConfigureAwait(false);
                }
            }

            return(driver);
        }
예제 #4
0
        public void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver)
        {
            foreach (var analyzer in analysisScope.Analyzers)
            {
                // Dequeue reported analyzer diagnostics from the driver and store them in our maps.
                var syntaxDiagnostics      = driver.DequeueLocalDiagnostics(analyzer, syntax: true);
                var semanticDiagnostics    = driver.DequeueLocalDiagnostics(analyzer, syntax: false);
                var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer);

                lock (_gate)
                {
                    if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0)
                    {
                        UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, ref _localSyntaxDiagnosticsOpt);
                        UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, ref _localSemanticDiagnosticsOpt);
                        UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics);
                    }

                    if (_analyzerExecutionTimeOpt != null)
                    {
                        _analyzerExecutionTimeOpt[analyzer] += driver.ResetAnalyzerExecutionTime(analyzer);
                    }
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Invoke this method at completion of event processing for the given analysis scope.
        /// It updates the analysis state of this event for each analyzer and if the event has been fully processed for all analyzers, then removes it from our event cache.
        /// </summary>
        public void OnCompilationEventProcessed(CompilationEvent compilationEvent, AnalysisScope analysisScope)
        {
            // Analyze if the symbol and all its declaring syntax references are analyzed.
            var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;

            if (symbolDeclaredEvent != null)
            {
                OnSymbolDeclaredEventProcessed(symbolDeclaredEvent, analysisScope.Analyzers);
            }

            // Check if event is fully analyzed for all analyzers.
            foreach (var analyzerState in _analyzerStates)
            {
                if (!analyzerState.IsEventAnalyzed(compilationEvent))
                {
                    return;
                }
            }

            // Remove the event from event map.
            lock (_gate)
            {
                UpdateEventsMap_NoLock(compilationEvent, add: false);
            }

            if (symbolDeclaredEvent != null)
            {
                AnalyzerDriver.RemoveCachedDeclaringReferences(symbolDeclaredEvent.Symbol, symbolDeclaredEvent.Compilation);
            }
        }
예제 #6
0
        /// <summary>
        /// Invoke this method at completion of event processing for the given analysis scope.
        /// It updates the analysis state of this event for each analyzer and if the event has been fully processed for all analyzers, then removes it from our event cache.
        /// </summary>
        public async Task OnCompilationEventProcessedAsync(CompilationEvent compilationEvent, AnalysisScope analysisScope, CancellationToken cancellationToken)
        {
            // Analyze if the symbol and all its declaring syntax references are analyzed.
            var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;

            if (symbolDeclaredEvent != null)
            {
                await OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, analysisScope.Analyzers, cancellationToken).ConfigureAwait(false);
            }

            // Check if event is fully analyzed for all analyzers.
            foreach (var analyzerState in _analyzerStates)
            {
                var eventAnalyzed = await analyzerState.IsEventAnalyzedAsync(compilationEvent, cancellationToken).ConfigureAwait(false);

                if (!eventAnalyzed)
                {
                    return;
                }
            }

            // Remove the event from event map.
            using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
            {
                UpdateEventsMap_NoLock(compilationEvent, add: false);
            }

            if (symbolDeclaredEvent != null)
            {
                AnalyzerDriver.RemoveCachedDeclaringReferences(symbolDeclaredEvent.Symbol, symbolDeclaredEvent.Compilation);
            }
        }
예제 #7
0
        // internal for testing purposes
        internal static AnalyzerDriver Create(
            Compilation compilation,
            ImmutableArray <DiagnosticAnalyzer> analyzers,
            AnalyzerOptions options,
            AnalyzerManager analyzerManager,
            Action <Diagnostic> addExceptionDiagnostic,
            out Compilation newCompilation,
            Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
            CancellationToken cancellationToken)
        {
            options = options ?? AnalyzerOptions.Empty;
            AnalyzerDriver analyzerDriver = compilation.AnalyzerForLanguage(analyzers, analyzerManager, cancellationToken);

            newCompilation = compilation.WithEventQueue(analyzerDriver.CompilationEventQueue);

            continueOnAnalyzerException = continueOnAnalyzerException ?? ((exception, analyzer) => true);
            var addDiagnostic = GetDiagnosticSinkWithSuppression(analyzerDriver.DiagnosticQueue.Enqueue, newCompilation);

            addExceptionDiagnostic = addExceptionDiagnostic != null?
                                     GetDiagnosticSinkWithSuppression(addExceptionDiagnostic, newCompilation) :
                                         addDiagnostic;

            var analyzerExecutor = AnalyzerExecutor.Create(newCompilation, options, addDiagnostic, addExceptionDiagnostic, continueOnAnalyzerException, cancellationToken);

            analyzerDriver.Initialize(newCompilation, analyzerExecutor, cancellationToken);

            return(analyzerDriver);
        }
예제 #8
0
        private void GenerateSimulatedCompilationSourceEvents(
            SyntaxTree tree,
            Compilation compilation,
            Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            lock (_gate)
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }
            }

            var globalNs          = compilation.Assembly.GlobalNamespace;
            var symbols           = GetDeclaredSymbolsInTree(tree, compilation, getCachedSemanticModel, cancellationToken);
            var compilationEvents = CreateCompilationEventsForTree(symbols.Concat(globalNs), tree, compilation);

            lock (_gate)
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }

                OnCompilationEventsGenerated_NoLock(compilationEvents, tree, driver, cancellationToken);

                var added = _treesWithGeneratedSourceEvents.Add(tree);
                Debug.Assert(added);
            }
        }
예제 #9
0
        public async Task OnCompilationEventsGeneratedAsync(
            Func <
                AsyncQueue <CompilationEvent>,
                ImmutableArray <AdditionalText>,
                ImmutableArray <CompilationEvent>
                > getCompilationEvents,
            AsyncQueue <CompilationEvent> eventQueue,
            ImmutableArray <AdditionalText> additionalFiles,
            AnalyzerDriver driver,
            CancellationToken cancellationToken
            )
        {
            try
            {
                await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken)
                .ConfigureAwait(false);

                using (_gate.DisposableWait(cancellationToken))
                {
                    // Defer the call to 'getCompilationEvents' until we know cancellation is no longer possible
                    OnCompilationEventsGenerated_NoLock(
                        getCompilationEvents(eventQueue, additionalFiles)
                        );
                }
            }
            catch (Exception e)
                when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
                {
                    throw ExceptionUtilities.Unreachable;
                }
        }
예제 #10
0
        internal async Task <AnalyzerActionCounts> GetOrComputeAnalyzerActionCountsAsync(
            DiagnosticAnalyzer analyzer,
            AnalyzerDriver driver,
            CancellationToken cancellationToken
            )
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken)
            .ConfigureAwait(false);

            return(AnalyzerActionCountsMap[analyzer]);
        }
예제 #11
0
        /// <summary>
        /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options.
        /// <param name="analyzer">Analyzer to be checked for suppression.</param>
        /// <param name="options">Compilation options.</param>
        /// <param name="onAnalyzerException">
        /// Optional delegate which is invoked when an analyzer throws an exception.
        /// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc.
        /// </param>
        /// </summary>
        public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
        {
            VerifyAnalyzerArgumentForStaticApis(analyzer);

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(onAnalyzerException, AnalyzerManager.Instance);

            return(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, AnalyzerManager.Instance, analyzerExecutor));
        }
예제 #12
0
        /// <summary>
        /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
        /// </summary>
        /// <param name="compilation">The original compilation.</param>
        /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
        /// <param name="options">Options that are passed to analyzers.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort analysis.</param>
        public CompilationWithAnalyzers(Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            VerifyAnalyzersArgument(analyzers);

            _cancellationToken    = cancellationToken;
            _exceptionDiagnostics = new ConcurrentSet <Diagnostic>();
            _driver = AnalyzerDriver.Create(compilation, analyzers, options, AnalyzerManager.Instance, AddExceptionDiagnostic, false, out _compilation, _cancellationToken);
        }
        /// <summary>
        /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
        /// </summary>
        /// <param name="compilation">The original compilation.</param>
        /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
        /// <param name="options">Options that are passed to analyzers.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort analysis.</param>
        public CompilationWithAnalyzers(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }

            VerifyAnalyzersArgument(analyzers);

            _cancellationToken = cancellationToken;
            _exceptionDiagnostics = new ConcurrentSet<Diagnostic>();
            _driver = AnalyzerDriver.Create(compilation, analyzers, options, AnalyzerManager.Instance, AddExceptionDiagnostic, false, out _compilation, _cancellationToken);
        }
예제 #14
0
        private void AddPendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent compilationEvent)
        {
            HashSet <CompilationEvent> currentEvents;

            if (!_pendingSourceEvents.TryGetValue(tree, out currentEvents))
            {
                currentEvents = _compilationEventsPool.Allocate();
                _pendingSourceEvents[tree] = currentEvents;
                AnalyzerDriver.RemoveCachedSemanticModel(tree, compilationEvent.Compilation);
            }

            currentEvents.Add(compilationEvent);
        }
예제 #15
0
 private void FreeDriver(AnalyzerDriver driver)
 {
     if (driver != null)
     {
         if (driver.WhenInitializedTask.IsCanceled)
         {
             _driverPool.ForgetTrackedObject(driver);
         }
         else
         {
             _driverPool.Free(driver);
         }
     }
 }
예제 #16
0
        internal void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver, Compilation compilation, Func<DiagnosticAnalyzer, AnalyzerActionCounts> getAnalyzerActionCounts, bool fullAnalysisResultForAnalyzersInScope)
        {
            Debug.Assert(!fullAnalysisResultForAnalyzersInScope || analysisScope.FilterTreeOpt == null, "Full analysis result cannot come from partial (tree) analysis.");

            foreach (var analyzer in analysisScope.Analyzers)
            {
                // Dequeue reported analyzer diagnostics from the driver and store them in our maps.
                var syntaxDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: true, compilation: compilation);
                var semanticDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: false, compilation: compilation);
                var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer, compilation);

                lock (_gate)
                {
                    if (_completedAnalyzers.Contains(analyzer))
                    {
                        // Already stored full analysis result for this analyzer.
                        continue;
                    }

                    if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0 || fullAnalysisResultForAnalyzersInScope)
                    {
                        UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSyntaxDiagnosticsOpt);
                        UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSemanticDiagnosticsOpt);
                        UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics, fullAnalysisResultForAnalyzersInScope);
                    }

                    if (_analyzerExecutionTimeOpt != null)
                    {
                        var timeSpan = driver.ResetAnalyzerExecutionTime(analyzer);
                        _analyzerExecutionTimeOpt[analyzer] = fullAnalysisResultForAnalyzersInScope ?
                            timeSpan :
                            _analyzerExecutionTimeOpt[analyzer] + timeSpan;
                    }

                    if (!_analyzerActionCounts.ContainsKey(analyzer))
                    {
                        _analyzerActionCounts.Add(analyzer, getAnalyzerActionCounts(analyzer));
                    }

                    if (fullAnalysisResultForAnalyzersInScope)
                    {
                        _completedAnalyzers.Add(analyzer);
                    }
                }
            }
        }
예제 #17
0
        internal void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver, Compilation compilation, Func <DiagnosticAnalyzer, AnalyzerActionCounts> getAnalyzerActionCounts, bool fullAnalysisResultForAnalyzersInScope)
        {
            Debug.Assert(!fullAnalysisResultForAnalyzersInScope || analysisScope.FilterTreeOpt == null, "Full analysis result cannot come from partial (tree) analysis.");

            foreach (var analyzer in analysisScope.Analyzers)
            {
                // Dequeue reported analyzer diagnostics from the driver and store them in our maps.
                var syntaxDiagnostics      = driver.DequeueLocalDiagnostics(analyzer, syntax: true, compilation: compilation);
                var semanticDiagnostics    = driver.DequeueLocalDiagnostics(analyzer, syntax: false, compilation: compilation);
                var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer, compilation);

                lock (_gate)
                {
                    if (_completedAnalyzers.Contains(analyzer))
                    {
                        // Already stored full analysis result for this analyzer.
                        continue;
                    }

                    if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0 || fullAnalysisResultForAnalyzersInScope)
                    {
                        UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSyntaxDiagnosticsOpt);
                        UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSemanticDiagnosticsOpt);
                        UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics, fullAnalysisResultForAnalyzersInScope);
                    }

                    if (_analyzerExecutionTimeOpt != null)
                    {
                        var timeSpan = driver.ResetAnalyzerExecutionTime(analyzer);
                        _analyzerExecutionTimeOpt[analyzer] = fullAnalysisResultForAnalyzersInScope ?
                                                              timeSpan :
                                                              _analyzerExecutionTimeOpt[analyzer] + timeSpan;
                    }

                    if (!_analyzerActionCounts.ContainsKey(analyzer))
                    {
                        _analyzerActionCounts.Add(analyzer, getAnalyzerActionCounts(analyzer));
                    }

                    if (fullAnalysisResultForAnalyzersInScope)
                    {
                        _completedAnalyzers.Add(analyzer);
                    }
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Gets the count of registered actions for the analyzer.
        /// </summary>
        internal async Task <ActionCounts> GetAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
        {
            VerifyAnalyzerArgument(analyzer);

            AnalyzerDriver driver = null;

            try
            {
                driver = await GetAnalyzerDriverAsync(cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();
                return(await _analysisState.GetAnalyzerActionCountsAsync(analyzer, driver, cancellationToken).ConfigureAwait(false));
            }
            finally
            {
                FreeDriver(driver);
            }
        }
예제 #19
0
        /// <summary>
        /// Core method for executing analyzers.
        /// </summary>
        private async Task ComputeAnalyzerDiagnosticsCoreAsync(AnalyzerDriver driver, AsyncQueue <CompilationEvent> eventQueue, AnalysisScope analysisScope, CancellationToken cancellationToken)
        {
            Debug.Assert(!driver.WhenInitializedTask.IsCanceled);

            if (eventQueue.Count > 0 || _analysisState.HasPendingSyntaxAnalysis(analysisScope))
            {
                try
                {
                    // Perform analysis to compute new diagnostics.
                    Debug.Assert(!eventQueue.IsCompleted);
                    await driver.AttachQueueAndProcessAllEventsAsync(eventQueue, analysisScope, _analysisState, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
                finally
                {
                    // Update the diagnostic results based on the diagnostics reported on the driver.
                    _analysisResult.StoreAnalysisResult(analysisScope, driver);
                }
            }
        }
        /// <summary>
        /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options.
        /// <param name="analyzer">Analyzer to be checked for suppression.</param>
        /// <param name="options">Compilation options.</param>
        /// <param name="onAnalyzerException">
        /// Optional delegate which is invoked when an analyzer throws an exception.
        /// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc.
        /// </param>
        /// </summary>
        public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
        {
            if (analyzer == null)
            {
                throw new ArgumentNullException(nameof(analyzer));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            Action <Exception, DiagnosticAnalyzer, Diagnostic> voidHandler = (ex, a, diag) => { };

            onAnalyzerException = onAnalyzerException ?? voidHandler;
            var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(onAnalyzerException, CancellationToken.None);

            return(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, AnalyzerManager.Instance, analyzerExecutor));
        }
        public static Diagnostic ApplySourceSuppressions(Diagnostic diagnostic, Compilation compilation, ISymbol symbolOpt = null)
        {
            if (diagnostic.IsSuppressed)
            {
                // Diagnostic already has a source suppression.
                return(diagnostic);
            }

            var suppressMessageState = AnalyzerDriver.GetOrCreateCachedCompilationData(compilation).SuppressMessageAttributeState;

            SuppressMessageInfo info;

            if (suppressMessageState.IsDiagnosticSuppressed(diagnostic, out info))
            {
                // Attach the suppression info to the diagnostic.
                diagnostic = diagnostic.WithIsSuppressed(true);
            }

            return(diagnostic);
        }
예제 #22
0
        private async Task PopulateEventsCacheAsync(CancellationToken cancellationToken)
        {
            if (_compilation.EventQueue.Count > 0)
            {
                AnalyzerDriver driver = null;
                try
                {
                    driver = await GetAnalyzerDriverAsync(cancellationToken).ConfigureAwait(false);

                    cancellationToken.ThrowIfCancellationRequested();

                    var compilationEvents = DequeueGeneratedCompilationEvents();
                    await _analysisState.OnCompilationEventsGeneratedAsync(compilationEvents, driver, cancellationToken).ConfigureAwait(false);
                }
                finally
                {
                    FreeDriver(driver);
                }
            }
        }
        /// <summary>
        /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
        /// The returned diagnostics are then ordered by location in the source document.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the documents</param>
        /// <param name="documents">The Documents that the analyzer will be run on</param>
        /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param>
        /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns>
        protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents)
        {
            var projects = new HashSet<Project>();
            foreach (var document in documents)
            {
                projects.Add(document.Project);
            }

            var diagnostics = new List<Diagnostic>();
            foreach (var project in projects)
            {
                var compilation = project.GetCompilationAsync().Result;
                var driver = new AnalyzerDriver<SyntaxKind>((new[] { analyzer }).ToImmutableArray(), n => n.CSharpKind(), null, CancellationToken.None);
                compilation = compilation.WithEventQueue(driver.CompilationEventQueue);
                var discarded = compilation.GetDiagnostics();
                var diags = driver.GetDiagnosticsAsync().Result;
                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        for (int i = 0; i < documents.Length; i++)
                        {
                            var document = documents[i];
                            var tree = document.GetSyntaxTreeAsync().Result;
                            if (tree == diag.Location.SourceTree)
                            {
                                diagnostics.Add(diag);
                            }
                        }
                    }
                }
            }

            var results = SortDiagnostics(diagnostics);
            diagnostics.Clear();
            return results;
        }
예제 #24
0
        /// <summary>
        /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options.
        /// <paramref name="continueOnAnalyzerException"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled.
        /// </summary>
        public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException)
        {
            if (analyzer == null)
            {
                throw new ArgumentNullException(nameof(analyzer));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (continueOnAnalyzerException == null)
            {
                throw new ArgumentNullException(nameof(continueOnAnalyzerException));
            }

            Action <Diagnostic> dummy = _ => { };

            return(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, dummy, continueOnAnalyzerException, CancellationToken.None));
        }
예제 #25
0
        /// <summary>
        /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options.
        /// <paramref name="continueOnAnalyzerException"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled.
        /// </summary>
        public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException)
        {
            if (analyzer == null)
            {
                throw new ArgumentNullException(nameof(analyzer));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (continueOnAnalyzerException == null)
            {
                throw new ArgumentNullException(nameof(continueOnAnalyzerException));
            }

            // TODO: Public API change to surface exception diagnostics?
            Action <Diagnostic> addExceptionDiagnostic = diagnostic => { };
            var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(addExceptionDiagnostic, continueOnAnalyzerException, CancellationToken.None);

            return(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, AnalyzerManager.Instance, analyzerExecutor));
        }
예제 #26
0
        // internal for testing purposes
        internal static AnalyzerDriver Create(
            Compilation compilation,
            ImmutableArray <DiagnosticAnalyzer> analyzers,
            AnalyzerOptions options,
            AnalyzerManager analyzerManager,
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
            out Compilation newCompilation,
            CancellationToken cancellationToken)
        {
            options = options ?? AnalyzerOptions.Empty;
            AnalyzerDriver analyzerDriver = compilation.AnalyzerForLanguage(analyzers, analyzerManager, cancellationToken);

            newCompilation = compilation.WithEventQueue(analyzerDriver.CompilationEventQueue);

            var addDiagnostic = GetDiagnosticSinkWithSuppression(analyzerDriver.DiagnosticQueue.Enqueue, newCompilation);

            Action <Exception, DiagnosticAnalyzer, Diagnostic> newOnAnalyzerException;

            if (onAnalyzerException != null)
            {
                // Wrap onAnalyzerException to pass in filtered diagnostic.
                var comp = newCompilation;
                newOnAnalyzerException = (ex, analyzer, diagnostic) =>
                                         onAnalyzerException(ex, analyzer, GetFilteredDiagnostic(diagnostic, comp));
            }
            else
            {
                // Add exception diagnostic to regular diagnostic bag.
                newOnAnalyzerException = (ex, analyzer, diagnostic) => addDiagnostic(diagnostic);
            }

            var analyzerExecutor = AnalyzerExecutor.Create(newCompilation, options, addDiagnostic, newOnAnalyzerException, cancellationToken);

            analyzerDriver.Initialize(newCompilation, analyzerExecutor, cancellationToken);

            return(analyzerDriver);
        }
예제 #27
0
        public async Task GenerateSimulatedCompilationEventsAsync(
            AnalysisScope analysisScope,
            Compilation compilation,
            Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            // Compilation started event.
            GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: true, cancellationToken: cancellationToken);

            // Symbol declared and compilation unit completed events.
            foreach (var tree in analysisScope.SyntaxTrees)
            {
                GenerateSimulatedCompilationSourceEvents(tree, compilation, getCachedSemanticModel, driver, cancellationToken);
            }

            // Compilation ended event.
            if (analysisScope.FilterTreeOpt == null)
            {
                GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: false, cancellationToken: cancellationToken);
            }
        }
예제 #28
0
 private void FreeDriver(AnalyzerDriver driver)
 {
     if (driver != null)
     {
         // Throw away the driver instance if the initialization didn't succeed.
         if (driver.WhenInitializedTask == null || driver.WhenInitializedTask.IsCanceled)
         {
             _driverPool.ForgetTrackedObject(driver);
         }
         else
         {
             _driverPool.Free(driver);
         }
     }
 }
예제 #29
0
        private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add)
        {
            var symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent;

            if (symbolEvent != null)
            {
                // Add/remove symbol events.
                // Any diagnostics request for a tree should trigger symbol and syntax node analysis for symbols with at least one declaring reference in the tree.
                foreach (var location in symbolEvent.Symbol.Locations)
                {
                    if (location.SourceTree != null)
                    {
                        if (add)
                        {
                            AddPendingSourceEvent_NoLock(location.SourceTree, compilationEvent);
                        }
                        else
                        {
                            RemovePendingSourceEvent_NoLock(location.SourceTree, compilationEvent);
                        }
                    }
                }
            }
            else
            {
                // Add/remove compilation unit completed events.
                var compilationUnitCompletedEvent = compilationEvent as CompilationUnitCompletedEvent;
                if (compilationUnitCompletedEvent != null)
                {
                    var tree = compilationUnitCompletedEvent.SemanticModel.SyntaxTree;
                    if (add)
                    {
                        AddPendingSourceEvent_NoLock(tree, compilationEvent);
                    }
                    else
                    {
                        RemovePendingSourceEvent_NoLock(tree, compilationEvent);
                    }
                }
                else if (compilationEvent is CompilationStartedEvent || compilationEvent is CompilationCompletedEvent)
                {
                    // Add/remove compilation events.
                    if (add)
                    {
                        _pendingNonSourceEvents.Add(compilationEvent);
                    }
                    else
                    {
                        _pendingNonSourceEvents.Remove(compilationEvent);
                        _compilationEndAnalyzed |= compilationEvent is CompilationCompletedEvent;
                    }
                }
                else
                {
                    throw new InvalidOperationException("Unexpected compilation event of type " + compilationEvent.GetType().Name);
                }
            }

            if (_compilationEndAnalyzed && _pendingSourceEvents.Count == 0)
            {
                // Clear the per-compilation data cache if we finished analyzing this compilation.
                AnalyzerDriver.RemoveCachedCompilationData(compilationEvent.Compilation);
            }
        }
예제 #30
0
        public async Task OnCompilationEventsGeneratedAsync(ImmutableArray <CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            lock (_gate)
            {
                OnCompilationEventsGenerated_NoLock(compilationEvents, filterTreeOpt: null, driver: driver, cancellationToken: cancellationToken);
            }
        }
예제 #31
0
        private async Task OnCompilationEventsGenerated_NoLockAsync(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            Debug.Assert(_lazyAnalyzerActionCountsMap != null);

            // Add the events to our global pending events map.
            AddToEventsMap_NoLock(compilationEvents);

            // Mark the events for analysis for each analyzer.
            Debug.Assert(_pooledEventsWithAnyActionsSet.Count == 0);
            foreach (var kvp in _analyzerStateMap)
            {
                var analyzer = kvp.Key;
                var analyzerState = _analyzerStates[kvp.Value];
                var actionCounts = _lazyAnalyzerActionCountsMap[analyzer];

                foreach (var compilationEvent in compilationEvents)
                {
                    if (HasActionsForEvent(compilationEvent, actionCounts))
                    {
                        _pooledEventsWithAnyActionsSet.Add(compilationEvent);
                        await analyzerState.OnCompilationEventGeneratedAsync(compilationEvent, actionCounts, cancellationToken).ConfigureAwait(false);
                    }
                }
            }

            foreach (var compilationEvent in compilationEvents)
            {
                if (!_pooledEventsWithAnyActionsSet.Remove(compilationEvent))
                {
                    // Event has no relevant actions to execute, so mark it as complete.  
                    UpdateEventsMap_NoLock(compilationEvent, add: false);
                }
            }
        }
예제 #32
0
        public async Task OnCompilationEventsGeneratedAsync(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
            {
                await OnCompilationEventsGenerated_NoLockAsync(compilationEvents, driver, cancellationToken).ConfigureAwait(false);
            }
        }
예제 #33
0
        /// <summary>
        /// Core method for executing analyzers.
        /// </summary>
        private async Task ComputeAnalyzerDiagnosticsCoreAsync(AnalyzerDriver driver, AsyncQueue<CompilationEvent> eventQueue, AnalysisScope analysisScope, CancellationToken cancellationToken)
        {
            try
            {
                Debug.Assert(!driver.WhenInitializedTask.IsCanceled);

                if (eventQueue.Count > 0 || _analysisState.HasPendingSyntaxAnalysis(analysisScope))
                {
                    try
                    {
                        // Perform analysis to compute new diagnostics.
                        Debug.Assert(!eventQueue.IsCompleted);
                        await driver.AttachQueueAndProcessAllEventsAsync(eventQueue, analysisScope, _analysisState, cancellationToken: cancellationToken).ConfigureAwait(false);
                    }
                    finally
                    {
                        // Update the diagnostic results based on the diagnostics reported on the driver.
                        _analysisResult.StoreAnalysisResult(analysisScope, driver);
                    }
                }
            }
            catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
예제 #34
0
 internal async Task<ActionCounts> GetAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, AnalyzerDriver driver, CancellationToken cancellationToken)
 {
     await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);
     return _lazyAnalyzerActionCountsMap[analyzer];
 }
예제 #35
0
        private async Task EnsureAnalyzerActionCountsInitializedAsync(AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            if (_lazyAnalyzerActionCountsMap == null)
            {
                var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, ActionCounts>();
                foreach (var analyzer in _analyzerStateMap.Keys)
                {
                    var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, cancellationToken).ConfigureAwait(false);
                    builder.Add(analyzer, actionCounts);
                }

                Interlocked.CompareExchange(ref _lazyAnalyzerActionCountsMap, builder.ToImmutable(), null);
            }
        }
예제 #36
0
        private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            Debug.Assert(_lazyAnalyzerActionCountsMap != null);

            // Add the events to our global pending events map.
            AddToEventsMap_NoLock(compilationEvents);

            // Mark the events for analysis for each analyzer.
            foreach (var kvp in _analyzerStateMap)
            {
                var analyzer = kvp.Key;
                var analyzerState = kvp.Value;
                var actionCounts = _lazyAnalyzerActionCountsMap[analyzer];

                foreach (var compilationEvent in compilationEvents)
                {
                    if (HasActionsForEvent(compilationEvent, actionCounts))
                    {
                        analyzerState.OnCompilationEventGenerated_NoLock(compilationEvent, actionCounts);
                    }
                }
            }
        }
예제 #37
0
        private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent> compilationEvents, SyntaxTree filterTreeOpt, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            Debug.Assert(_lazyAnalyzerActionCountsMap != null);

            // Add the events to our global pending events map.
            AddToEventsMap_NoLock(compilationEvents, filterTreeOpt);

            // Mark the events for analysis for each analyzer.
            ArrayBuilder<ISymbol> newPartialSymbols = null;
            Debug.Assert(_pooledEventsWithAnyActionsSet.Count == 0);
            foreach (var kvp in _analyzerStateMap)
            {
                var analyzer = kvp.Key;
                var analyzerState = _analyzerStates[kvp.Value];
                var actionCounts = _lazyAnalyzerActionCountsMap[analyzer];

                foreach (var compilationEvent in compilationEvents)
                {
                    if (HasActionsForEvent(compilationEvent, actionCounts))
                    {
                        _pooledEventsWithAnyActionsSet.Add(compilationEvent);

                        var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;
                        if (symbolDeclaredEvent?.DeclaringSyntaxReferences.Length > 1)
                        {
                            if (_partialSymbolsWithGeneratedSourceEvents.Contains(symbolDeclaredEvent.Symbol))
                            {
                                // already processed.
                                continue;
                            }
                            else
                            {
                                newPartialSymbols = newPartialSymbols ?? ArrayBuilder<ISymbol>.GetInstance();
                                newPartialSymbols.Add(symbolDeclaredEvent.Symbol);
                            }
                        }

                        analyzerState.OnCompilationEventGenerated(compilationEvent, actionCounts);
                    }
                }
            }

            foreach (var compilationEvent in compilationEvents)
            {
                if (!_pooledEventsWithAnyActionsSet.Remove(compilationEvent))
                {
                    // Event has no relevant actions to execute, so mark it as complete.  
                    UpdateEventsMap_NoLock(compilationEvent, add: false);
                }
            }

            if (newPartialSymbols != null)
            {
                _partialSymbolsWithGeneratedSourceEvents.AddAll(newPartialSymbols);
                newPartialSymbols.Free();
            }
        }
 internal static Compilation AttachAnalyzerDriverToCompilation(Compilation compilation, ImmutableArray<IDiagnosticAnalyzer> analyzers, out AnalyzerDriver analyzerDriver3, AnalyzerOptions options, CancellationToken cancellationToken)
 {
     analyzerDriver3 = compilation.AnalyzerForLanguage(analyzers, options, cancellationToken);
     return compilation.WithEventQueue(analyzerDriver3.CompilationEventQueue);
 }
예제 #39
0
 /// <summary>
 /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
 /// </summary>
 /// <param name="compilation">The original compilation.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="options">Options that are passed to analyzers.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to abort analysis.</param>
 public CompilationWithAnalyzers(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
 {
     _cancellationToken = cancellationToken;
     _driver = AnalyzerDriver.Create(compilation, analyzers, options, out _compilation, _cancellationToken);
 }
 /// <summary>
 /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
 /// </summary>
 /// <param name="compilation">The original compilation.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="options">Options that are passed to analyzers.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to abort analysis.</param>
 public CompilationWithAnalyzers(Compilation compilation, ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
 {
     _cancellationToken = cancellationToken;
     _exceptionDiagnostics = new ConcurrentSet<Diagnostic>();
     _driver = AnalyzerDriver.Create(compilation, analyzers, options, AnalyzerManager.Instance, AddExceptionDiagnostic, out _compilation, _cancellationToken);
 }
예제 #41
0
 private void FreeDriver(AnalyzerDriver driver)
 {
     if (driver != null)
     {
         if (driver.WhenInitializedTask.IsCanceled)
         {
             _driverPool.ForgetTrackedObject(driver);
         }
         else
         {
             _driverPool.Free(driver);
         }
     }
 }
예제 #42
0
        public async Task OnCompilationEventsGeneratedAsync(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            lock (_gate)
            {
                OnCompilationEventsGenerated_NoLock(compilationEvents, driver, cancellationToken);
            }
        }
예제 #43
0
        public async Task OnCompilationEventsGeneratedAsync(ImmutableArray <CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            try
            {
                await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

                using (_gate.DisposableWait(cancellationToken))
                {
                    OnCompilationEventsGenerated_NoLock(compilationEvents);
                }
            }
            catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
예제 #44
0
        private async Task GenerateCompilationEventsAndPopulateEventsCacheAsync(AnalysisScope analysisScope, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
#if SIMULATED_EVENT_QUEUE
            await _analysisState.GenerateSimulatedCompilationEventsAsync(analysisScope, _compilation, _compilationData.GetOrCreateCachedSemanticModel, driver, cancellationToken).ConfigureAwait(false);
#else
            GenerateCompilationEvents(analysisScope, cancellationToken);
            await PopulateEventsCacheAsync(cancellationToken).ConfigureAwait(false);
#endif
        }
예제 #45
0
        private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, AnalyzerDriver analyzerDriver, CultureInfo culture, bool isConcurrentBuild)
        {
            Debug.Assert(analyzerDriver.AnalyzerExecutionTimes != null);
            if (analyzerDriver.AnalyzerExecutionTimes.IsEmpty)
            {
                return;
            }

            var totalAnalyzerExecutionTime = analyzerDriver.AnalyzerExecutionTimes.Sum(kvp => kvp.Value.TotalSeconds);
            Func<double, string> getFormattedTime = d => d.ToString("##0.000", culture);
            consoleOutput.WriteLine();
            consoleOutput.WriteLine(string.Format(CodeAnalysisResources.AnalyzerTotalExecutionTime, getFormattedTime(totalAnalyzerExecutionTime)));

            if (isConcurrentBuild)
            {
                consoleOutput.WriteLine(CodeAnalysisResources.MultithreadedAnalyzerExecutionNote);
            }

            var analyzersByAssembly = analyzerDriver.AnalyzerExecutionTimes
                .GroupBy(kvp => kvp.Key.GetType().GetTypeInfo().Assembly)
                .OrderByDescending(kvp => kvp.Sum(entry => entry.Value.Ticks));

            consoleOutput.WriteLine();

            getFormattedTime = d => d < 0.001 ?
                string.Format(culture, "{0,8:<0.000}", 0.001) :
                string.Format(culture, "{0,8:##0.000}", d);
            Func<int, string> getFormattedPercentage = i => string.Format("{0,5}", i < 1 ? "<1" : i.ToString());
            Func<string, string> getFormattedAnalyzerName = s => "   " + s;

            // Table header
            var analyzerTimeColumn = string.Format("{0,8}", CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader);
            var analyzerPercentageColumn = string.Format("{0,5}", "%");
            var analyzerNameColumn = getFormattedAnalyzerName(CodeAnalysisResources.AnalyzerNameColumnHeader);
            consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);

            // Table rows grouped by assembly.
            foreach (var analyzerGroup in analyzersByAssembly)
            {
                var executionTime = analyzerGroup.Sum(kvp => kvp.Value.TotalSeconds);
                var percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime);

                analyzerTimeColumn = getFormattedTime(executionTime);
                analyzerPercentageColumn = getFormattedPercentage(percentage);
                analyzerNameColumn = getFormattedAnalyzerName(analyzerGroup.Key.FullName);

                consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);

                // Rows for each diagnostic analyzer in the assembly.
                foreach (var kvp in analyzerGroup.OrderByDescending(kvp => kvp.Value))
                {
                    executionTime = kvp.Value.TotalSeconds;
                    percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime);

                    analyzerTimeColumn = getFormattedTime(executionTime);
                    analyzerPercentageColumn = getFormattedPercentage(percentage);
                    analyzerNameColumn = getFormattedAnalyzerName("   " + kvp.Key.ToString());

                    consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn);
                }

                consoleOutput.WriteLine();
            }
        }
예제 #46
0
        private void GenerateSimulatedCompilatioNonSourceEvent(Compilation compilation, AnalyzerDriver driver, bool started, CancellationToken cancellationToken)
        {
            lock (_gate)
            {
                var eventAlreadyGenerated = started ? _compilationStartGenerated : _compilationEndGenerated;
                if (eventAlreadyGenerated)
                {
                    return;
                }

                var compilationEvent = started ? (CompilationEvent)new CompilationStartedEvent(compilation) : new CompilationCompletedEvent(compilation);
                var events = ImmutableArray.Create(compilationEvent);
                OnCompilationEventsGenerated_NoLock(events, filterTreeOpt: null, driver: driver, cancellationToken: cancellationToken);

                if (started)
                {
                    _compilationStartGenerated = true;
                }
                else
                {
                    _compilationEndGenerated = true;
                }
            }
        }
예제 #47
0
        private void GenerateSimulatedCompilationSourceEvents(
            SyntaxTree tree,
            Compilation compilation,
            Func<SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            lock (_gate)
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }
            }

            var globalNs = compilation.Assembly.GlobalNamespace;
            var symbols = GetDeclaredSymbolsInTree(tree, compilation, getCachedSemanticModel, cancellationToken);
            var compilationEvents = CreateCompilationEventsForTree(symbols.Concat(globalNs), tree, compilation);

            lock (_gate)
            {
                if (_treesWithGeneratedSourceEvents.Contains(tree))
                {
                    return;
                }

                OnCompilationEventsGenerated_NoLock(compilationEvents, tree, driver, cancellationToken);

                var added = _treesWithGeneratedSourceEvents.Add(tree);
                Debug.Assert(added);
            }
        }
예제 #48
0
        public async Task GenerateSimulatedCompilationEventsAsync(
            AnalysisScope analysisScope,
            Compilation compilation,
            Func<SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel,
            AnalyzerDriver driver,
            CancellationToken cancellationToken)
        {
            await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);

            // Compilation started event.
            GenerateSimulatedCompilatioNonSourceEvent(compilation, driver, started: true, cancellationToken: cancellationToken);

            // Symbol declared and compilation unit completed events.
            foreach (var tree in analysisScope.SyntaxTrees)
            {
                GenerateSimulatedCompilationSourceEvents(tree, compilation, getCachedSemanticModel, driver, cancellationToken);
            }

            // Compilation ended event.
            if (analysisScope.FilterTreeOpt == null)
            {
                GenerateSimulatedCompilatioNonSourceEvent(compilation, driver, started: false, cancellationToken: cancellationToken);
            }
        }
예제 #49
0
        private void GenerateSimulatedCompilationNonSourceEvent(Compilation compilation, AnalyzerDriver driver, bool started, CancellationToken cancellationToken)
        {
            lock (_gate)
            {
                var eventAlreadyGenerated = started ? _compilationStartGenerated : _compilationEndGenerated;
                if (eventAlreadyGenerated)
                {
                    return;
                }

                var compilationEvent = started ? (CompilationEvent) new CompilationStartedEvent(compilation) : new CompilationCompletedEvent(compilation);
                var events           = ImmutableArray.Create(compilationEvent);
                OnCompilationEventsGenerated_NoLock(events, filterTreeOpt: null, driver: driver, cancellationToken: cancellationToken);

                if (started)
                {
                    _compilationStartGenerated = true;
                }
                else
                {
                    _compilationEndGenerated = true;
                }
            }
        }
 /// <summary>
 /// Creates a new compilation by attaching diagnostic analyzers to an existing compilation.
 /// </summary>
 /// <param name="compilation">The original compilation.</param>
 /// <param name="analyzers">The set of analyzers to include in future analyses.</param>
 /// <param name="options">Options that are passed to analyzers.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to abort analysis.</param>
 public CompilationWithAnalyzers(Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
 {
     _cancellationToken    = cancellationToken;
     _exceptionDiagnostics = new ConcurrentSet <Diagnostic>();
     _driver = AnalyzerDriver.Create(compilation, analyzers, options, AnalyzerManager.Instance, AddExceptionDiagnostic, out _compilation, _cancellationToken);
 }
예제 #51
0
        private void OnCompilationEventsGenerated_NoLock(ImmutableArray <CompilationEvent> compilationEvents, SyntaxTree filterTreeOpt, AnalyzerDriver driver, CancellationToken cancellationToken)
        {
            Debug.Assert(_lazyAnalyzerActionCountsMap != null);

            // Add the events to our global pending events map.
            AddToEventsMap_NoLock(compilationEvents, filterTreeOpt);

            // Mark the events for analysis for each analyzer.
            ArrayBuilder <ISymbol> newPartialSymbols = null;

            Debug.Assert(_pooledEventsWithAnyActionsSet.Count == 0);
            foreach (var kvp in _analyzerStateMap)
            {
                var analyzer      = kvp.Key;
                var analyzerState = _analyzerStates[kvp.Value];
                var actionCounts  = _lazyAnalyzerActionCountsMap[analyzer];

                foreach (var compilationEvent in compilationEvents)
                {
                    if (HasActionsForEvent(compilationEvent, actionCounts))
                    {
                        _pooledEventsWithAnyActionsSet.Add(compilationEvent);

                        var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;
                        if (symbolDeclaredEvent?.DeclaringSyntaxReferences.Length > 1)
                        {
                            if (_partialSymbolsWithGeneratedSourceEvents.Contains(symbolDeclaredEvent.Symbol))
                            {
                                // already processed.
                                continue;
                            }
                            else
                            {
                                newPartialSymbols = newPartialSymbols ?? ArrayBuilder <ISymbol> .GetInstance();

                                newPartialSymbols.Add(symbolDeclaredEvent.Symbol);
                            }
                        }

                        analyzerState.OnCompilationEventGenerated(compilationEvent, actionCounts);
                    }
                }
            }

            foreach (var compilationEvent in compilationEvents)
            {
                if (!_pooledEventsWithAnyActionsSet.Remove(compilationEvent))
                {
                    // Event has no relevant actions to execute, so mark it as complete.
                    UpdateEventsMap_NoLock(compilationEvent, add: false);
                }
            }

            if (newPartialSymbols != null)
            {
                _partialSymbolsWithGeneratedSourceEvents.AddAll(newPartialSymbols);
                newPartialSymbols.Free();
            }
        }
예제 #52
0
        private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope analysisScope, Action generateCompilationEventsOpt, Func <AsyncQueue <CompilationEvent> > getEventQueue, int newTaskToken, CancellationToken cancellationToken)
        {
            AnalyzerDriver          driver      = null;
            Task                    computeTask = null;
            CancellationTokenSource cts;

            // Generate compilation events, if required.
            if (generateCompilationEventsOpt != null)
            {
                generateCompilationEventsOpt();
            }

            // Populate the events cache from the generated compilation events.
            await PopulateEventsCacheAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                // Get the analyzer driver to execute analysis.
                driver = await GetAnalyzerDriverAsync(cancellationToken).ConfigureAwait(false);

                // Driver must have been initialized.
                Debug.Assert(driver.WhenInitializedTask != null);
                Debug.Assert(!driver.WhenInitializedTask.IsCanceled);

                cancellationToken.ThrowIfCancellationRequested();

                // Track if this task was suspended by another tree diagnostics request for the same tree.
                // If so, we wait for the high priority requests to complete before restarting analysis.
                bool suspendend;
                do
                {
                    suspendend = false;

                    // Create a new cancellation source to allow higher priority requests to suspend our analysis.
                    cts = new CancellationTokenSource();

                    // Link the cancellation source with client supplied cancellation source, so the public API callee can also cancel analysis.
                    using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken))
                    {
                        try
                        {
                            // Core task to compute analyzer diagnostics.
                            Func <Tuple <Task, CancellationTokenSource> > getComputeTask = () => Tuple.Create(
                                Task.Run(async() =>
                            {
                                AsyncQueue <CompilationEvent> eventQueue = null;
                                try
                                {
                                    // Get event queue with pending events to analyze.
                                    eventQueue = getEventQueue();

                                    // Execute analyzer driver on the given analysis scope with the given event queue.
                                    await ComputeAnalyzerDiagnosticsCoreAsync(driver, eventQueue, analysisScope, cancellationToken: linkedCts.Token).ConfigureAwait(false);
                                }
                                finally
                                {
                                    FreeEventQueue(eventQueue);
                                }
                            },
                                         linkedCts.Token),
                                cts);

                            // Wait for higher priority tree document tasks to complete.
                            computeTask = await SetActiveAnalysisTaskAsync(getComputeTask, analysisScope.FilterTreeOpt, newTaskToken, cancellationToken).ConfigureAwait(false);

                            cancellationToken.ThrowIfCancellationRequested();

                            await computeTask.ConfigureAwait(false);
                        }
                        catch (OperationCanceledException)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            suspendend = cts.IsCancellationRequested;
                        }
                        finally
                        {
                            cts.Dispose();
                            ClearExecutingTask(computeTask, analysisScope.FilterTreeOpt);
                            computeTask = null;
                        }
                    }
                } while (suspendend);
            }
            finally
            {
                FreeDriver(driver);
            }
        }