private static async Task <DocumentAnalyzerPerformance> TestDocumentPerformanceAsync(ImmutableDictionary <string, ImmutableArray <DiagnosticAnalyzer> > analyzers, Project project, DocumentId documentId, Options analyzerOptionsInternal, CancellationToken cancellationToken)
        {
            if (!analyzers.TryGetValue(project.Language, out var languageAnalyzers))
            {
                languageAnalyzers = ImmutableArray <DiagnosticAnalyzer> .Empty;
            }

            Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            var stopwatch = PerformanceTracker.StartNew();

            for (int i = 0; i < analyzerOptionsInternal.TestDocumentIterations; i++)
            {
                var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution);
                CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(languageAnalyzers, new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, null, analyzerOptionsInternal.RunConcurrent, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: analyzerOptionsInternal.ReportSuppressedDiagnostics));

                SyntaxTree tree = await project.GetDocument(documentId).GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(tree, cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(compilation.GetSemanticModel(tree), null, cancellationToken).ConfigureAwait(false);
            }

            return(new DocumentAnalyzerPerformance(analyzerOptionsInternal.TestDocumentIterations / stopwatch.Elapsed.TotalSeconds, stopwatch.AllocatedBytes / Math.Max(1, analyzerOptionsInternal.TestDocumentIterations)));
        }
示例#2
0
            private async Task <IEnumerable <Diagnostic> > ComputeDiagnosticAnalyzerDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan?spanOpt, CancellationToken cancellationToken)
            {
                // quick optimization to reduce allocations.
                if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind))
                {
                    return(ImmutableArray <Diagnostic> .Empty);
                }

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                switch (kind)
                {
                case AnalysisKind.Syntax:
                    var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                case AnalysisKind.Semantic:
                    var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                default:
                    return(Contract.FailWithReturn <ImmutableArray <Diagnostic> >("shouldn't reach here"));
                }
            }
示例#3
0
        private static async Task <DocumentAnalyzerPerformance> TestDocumentPerformanceAsync(ImmutableDictionary <string, ImmutableArray <DiagnosticAnalyzer> > analyzers, Project project, DocumentId documentId, Options analyzerOptionsInternal, CancellationToken cancellationToken)
        {
            // update the project compilation options
            var modifiedSpecificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions
                                                    .Add("AD0001", ReportDiagnostic.Error)
                                                    .Add("AD0002", ReportDiagnostic.Error);
            // Report exceptions during the analysis process as errors
            var modifiedCompilationOptions = project.CompilationOptions.WithSpecificDiagnosticOptions(modifiedSpecificDiagnosticOptions);
            var processedProject           = project.WithCompilationOptions(modifiedCompilationOptions);

            if (!analyzers.TryGetValue(project.Language, out var languageAnalyzers))
            {
                languageAnalyzers = ImmutableArray <DiagnosticAnalyzer> .Empty;
            }

            var stopwatch = Stopwatch.StartNew();

            for (int i = 0; i < analyzerOptionsInternal.TestDocumentIterations; i++)
            {
                Compilation compilation = await processedProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var workspaceAnalyzerOptions = new WorkspaceAnalyzerOptions(project.AnalyzerOptions, project.Solution.Options, project.Solution);
                CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(languageAnalyzers, new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, null, analyzerOptionsInternal.RunConcurrent, logAnalyzerExecutionTime: true, reportSuppressedDiagnostics: analyzerOptionsInternal.ReportSuppressedDiagnostics));

                SyntaxTree tree = await project.GetDocument(documentId).GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(tree, cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(compilation.GetSemanticModel(tree), null, cancellationToken).ConfigureAwait(false);
            }

            return(new DocumentAnalyzerPerformance(analyzerOptionsInternal.TestDocumentIterations / stopwatch.Elapsed.TotalSeconds));
        }
示例#4
0
        public static async Task <ImmutableDictionary <DiagnosticAnalyzer, AnalysisResult> > AnalyzeAsync(this CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
        {
            var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

            // Run all analyzers at once.
            // REVIEW: why there are 2 different cancellation token? one that I can give to constructor and one I can give in to each method?
            // REVIEW: we drop all those allocations for the diagnostics returned. can we avoid this?
            await analyzerDriver.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false);

            // this is wierd, but now we iterate through each analyzer for each tree to get cached result.
            // REVIEW: no better way to do this?
            var noSpanFilter = default(TextSpan?);
            var analyzers    = analyzerDriver.Analyzers;
            var compilation  = analyzerDriver.Compilation;

            var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalysisResult>();

            foreach (var analyzer in analyzers)
            {
                var result = new Builder(project, version);

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                foreach (var tree in compilation.SyntaxTrees)
                {
                    var model = compilation.GetSemanticModel(tree);

                    var syntax = await analyzerDriver.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(syntax.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(syntax, analyzerDriver.Compilation).Count());
                    result.AddSyntaxDiagnostics(tree, syntax);

                    var semantic = await analyzerDriver.GetAnalyzerSemanticDiagnosticsAsync(model, noSpanFilter, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(semantic.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(semantic, analyzerDriver.Compilation).Count());
                    result.AddSemanticDiagnostics(tree, semantic);
                }

                var rest = await analyzerDriver.GetAnalyzerCompilationDiagnosticsAsync(oneAnalyzers, cancellationToken).ConfigureAwait(false);

                Contract.Requires(rest.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(rest, analyzerDriver.Compilation).Count());
                result.AddCompilationDiagnostics(rest);

                builder.Add(analyzer, result.ToResult());
            }

            return(builder.ToImmutable());
        }
示例#5
0
        private static async Task <DocumentAnalyzerPerformance> TestDocumentPerformanceAsync(ImmutableArray <DiagnosticAnalyzer> analyzers, Project project, DocumentId documentId, int iterations, bool force, CancellationToken cancellationToken)
        {
            var supportedDiagnosticsSpecificOptions = new Dictionary <string, ReportDiagnostic>();

            if (force)
            {
                foreach (var analyzer in analyzers)
                {
                    foreach (var diagnostic in analyzer.SupportedDiagnostics)
                    {
                        // make sure the analyzers we are testing are enabled
                        supportedDiagnosticsSpecificOptions[diagnostic.Id] = ReportDiagnostic.Default;
                    }
                }
            }

            // Report exceptions during the analysis process as errors
            supportedDiagnosticsSpecificOptions.Add("AD0001", ReportDiagnostic.Error);

            // update the project compilation options
            var modifiedSpecificDiagnosticOptions = supportedDiagnosticsSpecificOptions.ToImmutableDictionary().SetItems(project.CompilationOptions.SpecificDiagnosticOptions);
            var modifiedCompilationOptions        = project.CompilationOptions.WithSpecificDiagnosticOptions(modifiedSpecificDiagnosticOptions);

            var stopwatch = Stopwatch.StartNew();

            for (int i = 0; i < iterations; i++)
            {
                var processedProject = project.WithCompilationOptions(modifiedCompilationOptions);

                Compilation compilation = await processedProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, new CompilationWithAnalyzersOptions(processedProject.AnalyzerOptions, null, true, false));

                SyntaxTree tree = await project.GetDocument(documentId).GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(tree, cancellationToken).ConfigureAwait(false);

                await compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(compilation.GetSemanticModel(tree), null, cancellationToken).ConfigureAwait(false);
            }

            return(new DocumentAnalyzerPerformance(iterations / stopwatch.Elapsed.TotalSeconds));
        }
示例#6
0
            private async Task<IEnumerable<Diagnostic>> ComputeDiagnosticAnalyzerDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? spanOpt, CancellationToken cancellationToken)
            {
                // quick optimization to reduce allocations.
                if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind))
                {
                    return ImmutableArray<Diagnostic>.Empty;
                }

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                switch (kind)
                {
                    case AnalysisKind.Syntax:
                        var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                        var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                        Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                        return diagnostics.ToImmutableArrayOrEmpty();
                    case AnalysisKind.Semantic:
                        var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
                        diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                        Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                        return diagnostics.ToImmutableArrayOrEmpty();
                    default:
                        return Contract.FailWithReturn<ImmutableArray<Diagnostic>>("shouldn't reach here");
                }
            }
示例#7
0
        private static async Task <(ImmutableArray <Diagnostic> reportedDiagnostics, ImmutableArray <string> unhandledIds)> GetReportedDiagnosticsForIdsAsync(
            ImmutableHashSet <string> idsToAnalyze,
            SyntaxNode root,
            SemanticModel semanticModel,
            CompilationWithAnalyzers compilationWithAnalyzers,
            Func <DiagnosticAnalyzer, ImmutableArray <DiagnosticDescriptor> > getSupportedDiagnostics,
            Func <DiagnosticAnalyzer, bool> getIsCompilationEndAnalyzer,
            PooledHashSet <string> compilerDiagnosticIds,
            CancellationToken cancellationToken)
        {
            using var _1 = ArrayBuilder <DiagnosticAnalyzer> .GetInstance(out var analyzersBuilder);

            using var _2 = ArrayBuilder <string> .GetInstance(out var unhandledIds);

            // First, we compute the relevant analyzers whose reported diagnostics need to be computed.
            var addedCompilerAnalyzer   = false;
            var hasNonCompilerAnalyzers = idsToAnalyze.Count > compilerDiagnosticIds.Count;

            foreach (var analyzer in compilationWithAnalyzers.Analyzers)
            {
                if (!addedCompilerAnalyzer &&
                    analyzer.IsCompilerAnalyzer())
                {
                    addedCompilerAnalyzer = true;
                    analyzersBuilder.Add(analyzer);

                    if (!hasNonCompilerAnalyzers)
                    {
                        break;
                    }

                    continue;
                }

                if (hasNonCompilerAnalyzers)
                {
                    Debug.Assert(!analyzer.IsCompilerAnalyzer());

                    bool?lazyIsUnhandledAnalyzer = null;
                    foreach (var descriptor in getSupportedDiagnostics(analyzer))
                    {
                        if (!idsToAnalyze.Contains(descriptor.Id))
                        {
                            continue;
                        }

                        lazyIsUnhandledAnalyzer ??= getIsCompilationEndAnalyzer(analyzer) || analyzer is IPragmaSuppressionsAnalyzer;
                        if (lazyIsUnhandledAnalyzer.Value)
                        {
                            unhandledIds.Add(descriptor.Id);
                        }
                    }

                    if (lazyIsUnhandledAnalyzer.HasValue && !lazyIsUnhandledAnalyzer.Value)
                    {
                        analyzersBuilder.Add(analyzer);
                    }
                }
            }

            // Then, we execute these analyzers on the current file to fetch these diagnostics.
            // Note that if an analyzer has already executed, then this will be just a cache access
            // as computed analyzer diagnostics are cached on CompilationWithAnalyzers instance.

            using var _3 = ArrayBuilder <Diagnostic> .GetInstance(out var reportedDiagnostics);

            if (!addedCompilerAnalyzer && compilerDiagnosticIds.Count > 0)
            {
                // Special case when compiler analyzer could not be found.
                Debug.Assert(semanticModel.Compilation.Options.ReportSuppressedDiagnostics);
                reportedDiagnostics.AddRange(root.GetDiagnostics());
                reportedDiagnostics.AddRange(semanticModel.GetDiagnostics(cancellationToken: cancellationToken));
                cancellationToken.ThrowIfCancellationRequested();
            }

            if (analyzersBuilder.Count > 0)
            {
                var analyzers = analyzersBuilder.ToImmutable();

                var syntaxDiagnostics = await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(semanticModel.SyntaxTree, analyzers, cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();
                reportedDiagnostics.AddRange(syntaxDiagnostics);

                var semanticDiagnostics = await compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(semanticModel, filterSpan : null, analyzers, cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();
                reportedDiagnostics.AddRange(semanticDiagnostics);
            }

            return(reportedDiagnostics.ToImmutable(), unhandledIds.ToImmutable());
        }