예제 #1
0
        /// <summary>
        /// Return true if the given <paramref name="analyzer"/> is suppressed for the given project.
        /// NOTE: This API is intended to be used only for performance optimization.
        /// </summary>
        public bool IsAnalyzerSuppressed(DiagnosticAnalyzer analyzer, Project project)
        {
            var options = project.CompilationOptions;

            if (
                options == null ||
                analyzer == FileContentLoadAnalyzer.Instance ||
                analyzer.IsCompilerAnalyzer()
                )
            {
                return(false);
            }

            // If user has disabled analyzer execution for this project, we only want to execute required analyzers
            // that report diagnostics with category "Compiler".
            if (
                !project.State.RunAnalyzers &&
                GetDiagnosticDescriptors(analyzer)
                .All(d => d.Category != DiagnosticCategory.Compiler)
                )
            {
                return(true);
            }

            // NOTE: Previously we used to return "CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(options)"
            //       on this code path, which returns true if analyzer is suppressed through compilation options.
            //       However, this check is no longer correct as analyzers can be enabled/disabled for individual
            //       documents through .editorconfig files. So we pessimistically assume analyzer is not suppressed
            //       and let the core analyzer driver in the compiler layer handle skipping redundant analysis callbacks.
            return(false);
        }
예제 #2
0
 private static bool IsTelemetryCollectionAllowed(
     DiagnosticAnalyzer analyzer,
     ImmutableArray <DiagnosticDescriptor> descriptors
     ) =>
 analyzer.IsCompilerAnalyzer() ||
 analyzer is IBuiltInAnalyzer ||
 descriptors.Length > 0 &&
 descriptors[0].CustomTags.Any(t => t == WellKnownDiagnosticTags.Telemetry);
예제 #3
0
        /// <summary>
        /// Return true if the given <paramref name="analyzer"/> is suppressed for the given project.
        /// </summary>
        public bool IsAnalyzerSuppressed(DiagnosticAnalyzer analyzer, Project project)
        {
            var options = project.CompilationOptions;

            if (options == null || analyzer.IsCompilerAnalyzer())
            {
                return(false);
            }

            // Skip telemetry logging for supported diagnostics, as that can cause an infinite loop.
            Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = (ex, a, diagnostic) =>
                                                                                     AnalyzerHelper.OnAnalyzerException_NoTelemetryLogging(ex, a, diagnostic, _hostDiagnosticUpdateSource, project.Id);

            return(CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options, onAnalyzerException));
        }
예제 #4
0
        private async Task <ImmutableArray <DiagnosticData> > GetCompilerAnalyzerDiagnosticsAsync(DiagnosticAnalyzer analyzer, TextSpan?span, CancellationToken cancellationToken)
        {
            RoslynDebug.Assert(analyzer.IsCompilerAnalyzer());
            RoslynDebug.Assert(_compilationWithAnalyzers != null);
            RoslynDebug.Assert(_compilationBasedAnalyzersInAnalysisScope.Contains(analyzer));
            RoslynDebug.Assert(AnalysisScope.TextDocument is Document);

            var analysisScope  = AnalysisScope.WithAnalyzers(ImmutableArray.Create(analyzer)).WithSpan(span);
            var analysisResult = await GetAnalysisResultAsync(analysisScope, cancellationToken).ConfigureAwait(false);

            if (!analysisResult.TryGetValue(analyzer, out var result))
            {
                return(ImmutableArray <DiagnosticData> .Empty);
            }

            return(result.GetDocumentDiagnostics(analysisScope.TextDocument.Id, analysisScope.Kind));
        }
예제 #5
0
 public static bool IsBuiltInAnalyzer(this DiagnosticAnalyzer analyzer)
 => analyzer is IBuiltInAnalyzer || analyzer.IsWorkspaceDiagnosticAnalyzer() || analyzer.IsCompilerAnalyzer();
예제 #6
0
        public async Task <IEnumerable <DiagnosticData> > ComputeDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
        {
            Contract.ThrowIfFalse(AnalysisScope.Analyzers.Contains(analyzer));

            var textDocument = AnalysisScope.TextDocument;
            var span         = AnalysisScope.Span;
            var kind         = AnalysisScope.Kind;

            var document = textDocument as Document;

            RoslynDebug.Assert(document != null || kind == AnalysisKind.Syntax, "We only support syntactic analysis for non-source documents");

            var loadDiagnostic = await textDocument.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false);

            if (analyzer == FileContentLoadAnalyzer.Instance)
            {
                return(loadDiagnostic != null?
                       SpecializedCollections.SingletonEnumerable(DiagnosticData.Create(loadDiagnostic, textDocument)) :
                           SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            if (loadDiagnostic != null)
            {
                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            if (analyzer is DocumentDiagnosticAnalyzer documentAnalyzer)
            {
                if (document == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                }

                var documentDiagnostics = await AnalyzerHelper.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(
                    documentAnalyzer, document, kind, _compilationWithAnalyzers?.Compilation, cancellationToken).ConfigureAwait(false);

                return(documentDiagnostics.ConvertToLocalDiagnostics(document, span));
            }

            // quick optimization to reduce allocations.
            if (_compilationWithAnalyzers == null || !analyzer.SupportAnalysisKind(kind))
            {
                if (kind == AnalysisKind.Syntax)
                {
                    Logger.Log(FunctionId.Diagnostics_SyntaxDiagnostic,
                               (r, d, a, k) => $"Driver: {r != null}, {d.Id}, {d.Project.Id}, {a}, {k}", _compilationWithAnalyzers, textDocument, analyzer, kind);
                }

                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            // if project is not loaded successfully then, we disable semantic errors for compiler analyzers
            var isCompilerAnalyzer = analyzer.IsCompilerAnalyzer();

            if (kind != AnalysisKind.Syntax && isCompilerAnalyzer)
            {
                var isEnabled = await textDocument.Project.HasSuccessfullyLoadedAsync(cancellationToken).ConfigureAwait(false);

                Logger.Log(FunctionId.Diagnostics_SemanticDiagnostic, (a, d, e) => $"{a}, ({d.Id}, {d.Project.Id}), Enabled:{e}", analyzer, textDocument, isEnabled);

                if (!isEnabled)
                {
                    return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                }
            }

            if (document == null && textDocument is not AdditionalDocument)
            {
                // We currently support document analysis only for source documents and additional documents.
                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            var diagnostics = kind switch
            {
                AnalysisKind.Syntax => await GetSyntaxDiagnosticsAsync(analyzer, isCompilerAnalyzer, cancellationToken).ConfigureAwait(false),
                AnalysisKind.Semantic => await GetSemanticDiagnosticsAsync(analyzer, isCompilerAnalyzer, cancellationToken).ConfigureAwait(false),
                _ => throw ExceptionUtilities.UnexpectedValue(kind),
            };

#if DEBUG
            var diags = await diagnostics.ToDiagnosticsAsync(textDocument.Project, cancellationToken).ConfigureAwait(false);

            Debug.Assert(diags.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(diags, _compilationWithAnalyzers.Compilation).Count());
            Debug.Assert(diagnostics.Length == diags.ConvertToLocalDiagnostics(textDocument, span).Count());
#endif

            return(diagnostics);
        }
예제 #7
0
        /// <summary>
        /// Return true if the given <paramref name="analyzer"/> is suppressed for the given project.
        /// </summary>
        public bool IsAnalyzerSuppressed(DiagnosticAnalyzer analyzer, Project project)
        {
            var options = project.CompilationOptions;
            if (options == null || analyzer.IsCompilerAnalyzer())
            {
                return false;
            }

            // Skip telemetry logging for supported diagnostics, as that can cause an infinite loop.
            Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = (ex, a, diagnostic) =>
                    AnalyzerHelper.OnAnalyzerException_NoTelemetryLogging(ex, a, diagnostic, _hostDiagnosticUpdateSource, project.Id);

            return CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options, onAnalyzerException);
        }
예제 #8
0
 public static bool IsBuiltInAnalyzer(this DiagnosticAnalyzer analyzer)
 {
     return(analyzer is IBuiltInAnalyzer || analyzer is DocumentDiagnosticAnalyzer || analyzer is ProjectDiagnosticAnalyzer || analyzer.IsCompilerAnalyzer());
 }
예제 #9
0
        public async Task <IEnumerable <DiagnosticData> > ComputeDiagnosticsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
        {
            Contract.ThrowIfFalse(AnalysisScope.Analyzers.Contains(analyzer));

            var document = AnalysisScope.Document;
            var span     = AnalysisScope.Span;
            var kind     = AnalysisScope.Kind;

            var loadDiagnostic = await document.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false);

            if (analyzer == FileContentLoadAnalyzer.Instance)
            {
                return(loadDiagnostic != null?
                       SpecializedCollections.SingletonEnumerable(DiagnosticData.Create(loadDiagnostic, document)) :
                           SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            if (loadDiagnostic != null)
            {
                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            if (analyzer is DocumentDiagnosticAnalyzer documentAnalyzer)
            {
                var diagnostics = await AnalyzerHelper.ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(
                    documentAnalyzer, document, kind, _compilationWithAnalyzers?.Compilation, cancellationToken).ConfigureAwait(false);

                return(diagnostics.ConvertToLocalDiagnostics(document, span));
            }

            // quick optimization to reduce allocations.
            if (_compilationWithAnalyzers == null || !analyzer.SupportAnalysisKind(kind))
            {
                if (kind == AnalysisKind.Syntax)
                {
                    Logger.Log(FunctionId.Diagnostics_SyntaxDiagnostic,
                               (r, d, a, k) => $"Driver: {r != null}, {d.Id}, {d.Project.Id}, {a}, {k}", _compilationWithAnalyzers, document, analyzer, kind);
                }

                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            // if project is not loaded successfully then, we disable semantic errors for compiler analyzers
            var isCompilerAnalyzer = analyzer.IsCompilerAnalyzer();

            if (kind != AnalysisKind.Syntax && isCompilerAnalyzer)
            {
                var isEnabled = await document.Project.HasSuccessfullyLoadedAsync(cancellationToken).ConfigureAwait(false);

                Logger.Log(FunctionId.Diagnostics_SemanticDiagnostic, (a, d, e) => $"{a}, ({d.Id}, {d.Project.Id}), Enabled:{e}", analyzer, document, isEnabled);

                if (!isEnabled)
                {
                    return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                }
            }

            var skippedAnalyzerInfo = document.Project.GetSkippedAnalyzersInfo(_analyzerInfoCache);
            ImmutableArray <string> filteredIds;

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

                if (tree == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                }

                var diagnostics = await GetSyntaxDiagnosticsAsync(tree, analyzer, isCompilerAnalyzer, cancellationToken).ConfigureAwait(false);

                if (diagnostics.IsDefaultOrEmpty)
                {
                    Logger.Log(FunctionId.Diagnostics_SyntaxDiagnostic, (d, a, t) => $"{d.Id}, {d.Project.Id}, {a}, {t.Length}", document, analyzer, tree);
                }
                else if (skippedAnalyzerInfo.FilteredDiagnosticIdsForAnalyzers.TryGetValue(analyzer, out filteredIds))
                {
                    diagnostics = diagnostics.Filter(filteredIds);
                }

                Debug.Assert(diagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, _compilationWithAnalyzers.Compilation).Count());
                return(diagnostics.ConvertToLocalDiagnostics(document, span));

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

                if (model == null)
                {
                    return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                }

                diagnostics = await GetSemanticDiagnosticsAsync(model, analyzer, isCompilerAnalyzer, cancellationToken).ConfigureAwait(false);

                if (skippedAnalyzerInfo.FilteredDiagnosticIdsForAnalyzers.TryGetValue(analyzer, out filteredIds))
                {
                    diagnostics = diagnostics.Filter(filteredIds);
                }

                Debug.Assert(diagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, _compilationWithAnalyzers.Compilation).Count());
                return(diagnostics.ConvertToLocalDiagnostics(document, span));

            default:
                throw ExceptionUtilities.UnexpectedValue(kind);
            }
        }