/// <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>
        /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
        internal static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, params Document[] documents)
        {
            var diagnostics = new List<Diagnostic>();
            foreach (var project in documents.Select(x => x.Project))
            {
                var compilation = project.GetCompilationAsync().Result;
                var diags = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)).GetAnalyzerDiagnosticsAsync().Result;
                foreach (var diagnostic in diags)
                {
                    if (diagnostic.Location == Location.None || diagnostic.Location.IsInMetadata)
                    {
                        diagnostics.Add(diagnostic);
                    }
                    else
                    {
                        for (var i = 0; i < documents.Length; i++)
                        {
                            var document = documents[i];
                            var tree = document.GetSyntaxTreeAsync().Result;
                            if (tree == diagnostic.Location.SourceTree)
                            {
                                diagnostics.Add(diagnostic);
                            }
                        }
                    }
                }
            }

            return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
        }
Example #2
0
 public static Diagnostic[] GetDiagnostics(DiagnosticAnalyzer analyzer, string source)
 {
     var project = CreateProject(source);
     var compilation = project.GetCompilationAsync().Result;
     var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));
     return compilationWithAnalyzers.GetAllDiagnosticsAsync().Result.ToArray();
 }
        private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected)
        {
            var actualSpan = actual.GetLineSpan();

            Assert.True(actualSpan.Path == expected.Path || (actualSpan.Path != null && actualSpan.Path.Contains("Test0.") && expected.Path.Contains("Test.")),
                string.Format("Expected diagnostic to be in file \"{0}\" was actually in file \"{1}\"\r\n\r\nDiagnostic:\r\n    {2}\r\n",
                    expected.Path, actualSpan.Path, FormatDiagnostics(analyzer, diagnostic)));

            var actualLinePosition = actualSpan.StartLinePosition;

            // Only check line position if there is an actual line in the real diagnostic
            if (actualLinePosition.Line > 0)
            {
                if (actualLinePosition.Line + 1 != expected.Line)
                {
                    Assert.True(false,
                        string.Format("Expected diagnostic to be on line \"{0}\" was actually on line \"{1}\"\r\n\r\nDiagnostic:\r\n    {2}\r\n",
                            expected.Line, actualLinePosition.Line + 1, FormatDiagnostics(analyzer, diagnostic)));
                }
            }

            // Only check column position if there is an actual column position in the real diagnostic
            if (actualLinePosition.Character > 0)
            {
                if (actualLinePosition.Character + 1 != expected.Column)
                {
                    Assert.True(false,
                        string.Format("Expected diagnostic to start at column \"{0}\" was actually at column \"{1}\"\r\n\r\nDiagnostic:\r\n    {2}\r\n",
                            expected.Column, actualLinePosition.Character + 1, FormatDiagnostics(analyzer, diagnostic)));
                }
            }
        }
                public async Task<AnalysisData> GetDocumentBodyAnalysisDataAsync(
                    DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver,
                    SyntaxNode root, SyntaxNode member, int memberId, bool supportsSemanticInSpan, MemberRangeMap.MemberRanges ranges)
                {
                    try
                    {
                        var document = analyzerDriver.Document;
                        var cancellationToken = analyzerDriver.CancellationToken;

                        var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language);
                        var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false);

                        ImmutableArray<DiagnosticData> diagnosticData;
                        if (supportsSemanticInSpan && CanUseDocumentState(existingData, ranges.TextVersion, versions.DataVersion))
                        {
                            var memberDxData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false);

                            diagnosticData = _owner.UpdateDocumentDiagnostics(existingData, ranges.Ranges, memberDxData.AsImmutableOrEmpty(), root.SyntaxTree, member, memberId);
                            ValidateMemberDiagnostics(providerId, provider, document, root, diagnosticData);
                        }
                        else
                        {
                            // if we can't re-use existing document state, only option we have is updating whole document state here.
                            var dx = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false);
                            diagnosticData = dx.AsImmutableOrEmpty();
                        }

                        return new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData);
                    }
                    catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
                    }
        internal void ReportAnalyzerDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Workspace workspace, ProjectId projectId)
        {
            if (workspace != this.Workspace)
            {
                return;
            }

            var project = workspace.CurrentSolution.GetProject(projectId);

            bool raiseDiagnosticsUpdated = true;
            var diagnosticData = project != null ?
                DiagnosticData.Create(project, diagnostic) :
                DiagnosticData.Create(this.Workspace, diagnostic);

            var dxs = ImmutableInterlocked.AddOrUpdate(ref s_analyzerHostDiagnosticsMap,
                analyzer,
                ImmutableHashSet.Create(diagnosticData),
                (a, existing) =>
                {
                    var newDiags = existing.Add(diagnosticData);
                    raiseDiagnosticsUpdated = newDiags.Count > existing.Count;
                    return newDiags;
                });

            if (raiseDiagnosticsUpdated)
            {
                RaiseDiagnosticsUpdated(MakeArgs(analyzer, dxs, project));
            }
        }
        private static Compilation CreateCompilation(string source, string language, DiagnosticAnalyzer[] analyzers, string rootNamespace)
        {
            string fileName = language == LanguageNames.CSharp ? "Test.cs" : "Test.vb";
            string projectName = "TestProject";

            var syntaxTree = language == LanguageNames.CSharp ?
                CSharpSyntaxTree.ParseText(source, path: fileName) :
                VisualBasicSyntaxTree.ParseText(source, path: fileName);

            if (language == LanguageNames.CSharp)
            {
                return CSharpCompilation.Create(
                    projectName,
                    syntaxTrees: new[] { syntaxTree },
                    references: new[] { TestBase.MscorlibRef });
            }
            else
            {
                return VisualBasicCompilation.Create(
                    projectName,
                    syntaxTrees: new[] { syntaxTree },
                    references: new[] { TestBase.MscorlibRef },
                    options: new VisualBasicCompilationOptions(
                        OutputKind.DynamicallyLinkedLibrary,
                        rootNamespace: rootNamespace));
            }
        }
 public static async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(DiagnosticAnalyzer workspaceAnalyzerOpt, Project project, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = false, bool includeSuppressedDiagnostics = false)
 {
     using (var testDriver = new TestDiagnosticAnalyzerDriver(project, workspaceAnalyzerOpt, onAnalyzerException, logAnalyzerExceptionAsDiagnostics, includeSuppressedDiagnostics))
     {
         return await testDriver.GetProjectDiagnosticsAsync(workspaceAnalyzerOpt, project);
     }
 }
 public static IEnumerable<Diagnostic> GetDocumentDiagnostics(DiagnosticAnalyzer workspaceAnalyzerOpt, Document document, TextSpan span, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = false)
 {
     using (var testDriver = new TestDiagnosticAnalyzerDriver(document.Project, workspaceAnalyzerOpt, onAnalyzerException, logAnalyzerExceptionAsDiagnostics))
     {
         return testDriver.GetDocumentDiagnostics(workspaceAnalyzerOpt, document, span);
     }
 }
        /// <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>
        /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns>
        protected async static Task<Diagnostic[]> GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer 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 = await project.GetCompilationAsync().ConfigureAwait(true);
                var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));
                var diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(true);
                CheckIfAnalyzerThrew(await compilationWithAnalyzers.GetAllDiagnosticsAsync().ConfigureAwait(true));
                foreach (var diag in diags)
                {
                    if (diag.Location == Location.None || diag.Location.IsInMetadata)
                    {
                        diagnostics.Add(diag);
                    }
                    else
                    {
                        foreach (var document in project.Documents)
                        {
                            var tree = await document.GetSyntaxTreeAsync().ConfigureAwait(true);
                            if (tree == diag.Location.SourceTree) diagnostics.Add(diag);
                        }
                    }
                }
            }
            var results = SortDiagnostics(diagnostics);
            return results;
        }
        protected void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            Document document = CreateDocument(oldSource, language);

            VerifyFix(document, analyzer, codeFixProvider, newSource, codeFixIndex, useCompilerAnalyzerDriver: true, allowNewCompilerDiagnostics: allowNewCompilerDiagnostics);
            VerifyFix(document, analyzer, codeFixProvider, newSource, codeFixIndex, useCompilerAnalyzerDriver: false, allowNewCompilerDiagnostics: allowNewCompilerDiagnostics);
        }
 public static IEnumerable<Diagnostic> GetProjectDiagnostics(DiagnosticAnalyzer workspaceAnalyzerOpt, Project project, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = false)
 {
     using (var testDriver = new TestDiagnosticAnalyzerDriver(project, workspaceAnalyzerOpt, onAnalyzerException, logAnalyzerExceptionAsDiagnostics))
     {
         return testDriver.GetProjectDiagnostics(workspaceAnalyzerOpt, project);
     }
 }
        protected Info ProcessCode(DiagnosticAnalyzer analyzer, string sampleProgram,
                                   ImmutableArray<SyntaxKind> expected, bool allowBuildErrors = false)
        {
            var options = new CSharpParseOptions(kind: SourceCodeKind.Script); //, languageVersion: LanguageVersion.CSharp5);
            var tree = CSharpSyntaxTree.ParseText(sampleProgram, options);
            var compilation = CSharpCompilation.Create("Test", new[] { tree }, references);

            var diagnostics = compilation.GetDiagnostics();
            if (diagnostics.Count(d => d.Severity == DiagnosticSeverity.Error) > 0)
            {
                var msg = "There were Errors in the sample code\n";
                if (allowBuildErrors == false)
                    Assert.Fail(msg + string.Join("\n", diagnostics));
                else
                    Console.WriteLine(msg + string.Join("\n", diagnostics));
            }

            var semanticModel = compilation.GetSemanticModel(tree);
            var matches = GetExpectedDescendants(tree.GetRoot().ChildNodes(), expected);

            // Run the code tree through the analyzer and record the allocations it reports
            var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));
               var allocations = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().GetAwaiter().GetResult().Distinct(DiagnosticEqualityComparer.Instance).ToList();

            return new Info
            {
                Options = options,
                Tree = tree,
                Compilation = compilation,
                Diagnostics = diagnostics,
                SemanticModel = semanticModel,
                Matches = matches,
                Allocations = allocations,
            };
        }
        /// <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>
        /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
        protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer 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 compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer));
                var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().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;
        }
Example #14
0
        internal void VerifyFix(CodeFixProvider codeFixProvider,
                                DiagnosticAnalyzer diagnosticAnalyzer,
                                string language,
                                string oldSource,
                                string newSource,
                                int? codeFixIndex = null,
                                string[] allowedNewCompilerDiagnosticsId = null)
        {
            CodeFixProvider = codeFixProvider;
            DiagnosticAnalyzer = diagnosticAnalyzer;

            if (allowedNewCompilerDiagnosticsId == null || !allowedNewCompilerDiagnosticsId.Any())
            {
                VerifyFix(language, DiagnosticAnalyzer, CodeFixProvider, oldSource, newSource, codeFixIndex, false);
            }
            else
            {
                var document = DiagnosticVerifier.CreateDocument(oldSource, language);
                var compilerDiagnostics = GetCompilerDiagnostics(document).ToArray();

                VerifyFix(language, DiagnosticAnalyzer, CodeFixProvider, oldSource, newSource, codeFixIndex, true);

                var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)).ToList();

                if (newCompilerDiagnostics.Any(diagnostic => allowedNewCompilerDiagnosticsId.Any(s => s == diagnostic.Id)))
                {
                    Assert.AreEqual(document.GetSyntaxRootAsync().Result.ToFullString(),
                        string.Join(Environment.NewLine, newCompilerDiagnostics.Select(d => d.ToString())),
                        "Fix introduced new compiler diagnostics");
                }
            }
        }
Example #15
0
 private async Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeAsync(
     DiagnosticAnalyzer analyzer,
     AnalyzerExecutor analyzerExecutor)
 {
     var analyzerExecutionContext = _analyzerExecutionContextMap.GetOrCreateValue(analyzer);
     return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor, analyzerExecutionContext).ConfigureAwait(false);
 }
Example #16
0
        private void UpdateLocalDiagnostics_NoLock(DiagnosticAnalyzer analyzer, ImmutableArray<Diagnostic> diagnostics, ref Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>> lazyLocalDiagnostics)
        {
            if (diagnostics.IsEmpty)
            {
                return;
            }

            lazyLocalDiagnostics = lazyLocalDiagnostics ?? new Dictionary<SyntaxTree, Dictionary<DiagnosticAnalyzer, List<Diagnostic>>>();

            foreach (var diagsByTree in diagnostics.GroupBy(d => d.Location.SourceTree))
            {
                var tree = diagsByTree.Key;

                Dictionary<DiagnosticAnalyzer, List<Diagnostic>> allDiagnostics;
                if (!lazyLocalDiagnostics.TryGetValue(tree, out allDiagnostics))
                {
                    allDiagnostics = new Dictionary<DiagnosticAnalyzer, List<Diagnostic>>();
                    lazyLocalDiagnostics[tree] = allDiagnostics;
                }

                List<Diagnostic> analyzerDiagnostics;
                if (!allDiagnostics.TryGetValue(analyzer, out analyzerDiagnostics))
                {
                    analyzerDiagnostics = new List<Diagnostic>();
                    allDiagnostics[analyzer] = analyzerDiagnostics;
                }

                analyzerDiagnostics.AddRange(diagsByTree);
            }
        }
Example #17
0
        public static void VerifyAnalyzer(string path, DiagnosticAnalyzer diagnosticAnalyzer, ParseOptions options = null,
            params MetadataReference[] additionalReferences)
        {
            var file = new FileInfo(path);
            var parseOptions = GetParseOptionsAlternatives(options, file);

            using (var workspace = new AdhocWorkspace())
            {
                var document = GetDocument(file, GeneratedAssemblyName, workspace, additionalReferences);
                var project = document.Project;

                foreach (var parseOption in parseOptions)
                {
                    if (parseOption != null)
                    {
                        project = project.WithParseOptions(parseOption);
                    }

                    var compilation = project.GetCompilationAsync().Result;
                    var diagnostics = GetDiagnostics(compilation, diagnosticAnalyzer);
                    var expected = ExpectedIssues(compilation.SyntaxTrees.First()).ToList();

                    foreach (var diagnostic in diagnostics)
                    {
                        var line = diagnostic.GetLineNumberToReport();
                        expected.Should().Contain(line);
                        expected.Remove(line);
                    }

                    expected.Should().BeEquivalentTo(Enumerable.Empty<int>());
                }
            }
        }
        private async Task<HostCompilationStartAnalysisScope> GetCompilationAnalysisScopeAsync(
            DiagnosticAnalyzer analyzer,
            HostSessionStartAnalysisScope sessionScope,
            AnalyzerExecutor analyzerExecutor)
        {
            var analyzerAndOptions = new AnalyzerAndOptions(analyzer, analyzerExecutor.AnalyzerOptions);

            try
            {
                return await GetCompilationAnalysisScopeCoreAsync(analyzerAndOptions, sessionScope, analyzerExecutor).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                // Task to compute the scope was cancelled.
                // Clear the entry in scope map for analyzer, so we can attempt a retry.
                ConditionalWeakTable<Compilation, Task<HostCompilationStartAnalysisScope>> compilationActionsMap;
                if (_compilationScopeMap.TryGetValue(analyzerAndOptions, out compilationActionsMap))
                {
                    compilationActionsMap.Remove(analyzerExecutor.Compilation);
                }

                analyzerExecutor.CancellationToken.ThrowIfCancellationRequested();
                return await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor).ConfigureAwait(false);
            }
        }
 protected override Task VerifyAsync(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] diagnostics, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = false, string rootNamespace = null)
 {
     Assert.True(analyzers != null && analyzers.Length > 0, "Must specify at least one diagnostic analyzer to test suppression");
     var compilation = CreateCompilation(source, language, analyzers, rootNamespace);
     compilation.VerifyAnalyzerDiagnostics(analyzers, onAnalyzerException: onAnalyzerException, logAnalyzerExceptionAsDiagnostics: logAnalyzerExceptionAsDiagnostics, expected: diagnostics);
     return Task.FromResult(false);
 }
        private async Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(DiagnosticAnalyzer workspaceAnalyzerOpt, Document document, TextSpan span, Project project, bool getDocumentDiagnostics, bool getProjectDiagnostics)
        {
            var documentDiagnostics = SpecializedCollections.EmptyEnumerable<Diagnostic>();
            var projectDiagnostics = SpecializedCollections.EmptyEnumerable<Diagnostic>();

            if (getDocumentDiagnostics)
            {
                var dxs = await _diagnosticAnalyzerService.GetDiagnosticsAsync(project.Solution, project.Id, document.Id, _includeSuppressedDiagnostics);
                documentDiagnostics = await CodeAnalysis.Diagnostics.Extensions.ToDiagnosticsAsync(dxs.Where(d => d.HasTextSpan && d.TextSpan.IntersectsWith(span)), project, CancellationToken.None);
            }

            if (getProjectDiagnostics)
            {
                var dxs = await _diagnosticAnalyzerService.GetDiagnosticsAsync(project.Solution, project.Id, includeSuppressedDiagnostics: _includeSuppressedDiagnostics);
                projectDiagnostics = await CodeAnalysis.Diagnostics.Extensions.ToDiagnosticsAsync(dxs.Where(d => !d.HasTextSpan), project, CancellationToken.None);
            }

            var exceptionDiagnostics = await CodeAnalysis.Diagnostics.Extensions.ToDiagnosticsAsync(_exceptionDiagnosticsSource.TestOnly_GetReportedDiagnostics(), project, CancellationToken.None);
            var allDiagnostics = documentDiagnostics.Concat(projectDiagnostics).Concat(exceptionDiagnostics);

            if (!_includeSuppressedDiagnostics)
            {
                Assert.True(!allDiagnostics.Any(d => d.IsSuppressed));
            }

            return allDiagnostics;
        }
 public static async Task<IEnumerable<Diagnostic>> GetAllDiagnosticsAsync(DiagnosticAnalyzer workspaceAnalyzerOpt, Document document, TextSpan span, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = false, bool includeSuppressedDiagnostics = false)
 {
     using (var testDriver = new TestDiagnosticAnalyzerDriver(document.Project, workspaceAnalyzerOpt, onAnalyzerException, logAnalyzerExceptionAsDiagnostics, includeSuppressedDiagnostics))
     {
         return await testDriver.GetAllDiagnosticsAsync(workspaceAnalyzerOpt, document, span);
     }
 }
        private void ProcessAnalyzer(DiagnosticAnalyzer analyzer, SqaleModel root)
        {
            foreach(DiagnosticDescriptor diagnostic in analyzer.SupportedDiagnostics)
            {
                SqaleDescriptor sqaleDescriptor = new SqaleDescriptor
                {
                    Remediation = new SqaleRemediation
                    {
                        RuleKey = diagnostic.Id
                    },
                    SubCharacteristic = "MAINTAINABILITY_COMPLIANCE"
                };

                sqaleDescriptor.Remediation.Properties.AddRange(new[]
                {
                    new SqaleRemediationProperty
                    {
                        Key = "remediationFunction",
                        Text = "CONSTANT_ISSUE"
                    },
                    new SqaleRemediationProperty
                    {
                        Key = "offset",
                        Value = this.remediationConstantValue,
                        Text = string.Empty
                    }
                });

                root.Sqale.Add(sqaleDescriptor);
            }
        }
Example #23
0
        /// <summary>
        /// General verifier for codefixes.
        /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes.
        /// Then gets the string after the codefix is applied and compares it with the expected result.
        /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
        /// </summary>
        /// <param name="language">The language the source code is in</param>
        /// <param name="analyzer">The analyzer to be applied to the source code</param>
        /// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param>
        /// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
        /// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
        /// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
        /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
        private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            Document document = DiagnosticVerifier.CreateDocument(oldSource, language);
              Diagnostic[] analyzerDiagnostics = DiagnosticVerifier.GetSortedDiagnosticsFromDocuments(analyzer, new[]
                                                                                                          {
                                                                                                            document
                                                                                                          });
              IEnumerable<Diagnostic> compilerDiagnostics = CodeFixVerifier.GetCompilerDiagnostics(document);
              int attempts = analyzerDiagnostics.Length;

              for (int i = 0; i < attempts; ++i)
              {
            List<CodeAction> actions = new List<CodeAction>();
            CodeFixContext context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
            codeFixProvider.RegisterCodeFixesAsync(context).Wait();

            if (!actions.Any())
            {
              break;
            }

            if (codeFixIndex != null)
            {
              document = CodeFixVerifier.ApplyFix(document, actions.ElementAt((int)codeFixIndex));
              break;
            }

            document = CodeFixVerifier.ApplyFix(document, actions.ElementAt(0));
            analyzerDiagnostics = DiagnosticVerifier.GetSortedDiagnosticsFromDocuments(analyzer, new[]
                                                                                               {
                                                                                                 document
                                                                                               });

            IEnumerable<Diagnostic> newCompilerDiagnostics = CodeFixVerifier.GetNewDiagnostics(compilerDiagnostics, CodeFixVerifier.GetCompilerDiagnostics(document));

            // check if applying the code fix introduced any new compiler diagnostics
            if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
            {
              // Format and get the compiler diagnostics again so that the locations make sense in the output
              document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace));
              newCompilerDiagnostics = CodeFixVerifier.GetNewDiagnostics(compilerDiagnostics, CodeFixVerifier.GetCompilerDiagnostics(document));

              Assert.IsTrue(false,
            string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
              string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())),
              document.GetSyntaxRootAsync().Result.ToFullString()));
            }

            // check if there are analyzer diagnostics left after the code fix
            if (!analyzerDiagnostics.Any())
            {
              break;
            }
              }

              // after applying all of the code fixes, compare the resulting string to the inputted one
              string actual = CodeFixVerifier.GetStringFromDocument(document);
              Assert.AreEqual(newSource, actual);
        }
        /// <summary>
        /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results.
        /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic.
        /// </summary>
        /// <param name="actualResults">The Diagnostics found by the compiler after running the analyzer on the source code</param>
        /// <param name="analyzer">The analyzer that was being run on the sources</param>
        /// <param name="expectedResults">Diagnostic Results that should have appeared in the code</param>
        private static void VerifyDiagnosticResults(IEnumerable<Diagnostic> actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults)
        {
            int expectedCount = expectedResults.Count();
            var diagnostics = actualResults as IList<Diagnostic> ?? actualResults.ToList();
            int actualCount = diagnostics.Count();

            if (expectedCount != actualCount)
            {
                string diagnosticsOutput = diagnostics.Any() ? FormatDiagnostics(analyzer, diagnostics.ToArray()) : "    NONE.";
                throw new InvalidDataException($"Mismatch between number of diagnostics returned, expected \"{expectedCount}\" actual \"{actualCount}\"\r\n\r\nDiagnostics:\r\n{diagnosticsOutput}\r\n");
            }

            for (int i = 0; i < expectedResults.Length; i++)
            {
                var actual = diagnostics.ElementAt(i);
                var expected = expectedResults[i];

                if (expected.Line == -1 && expected.Column == -1)
                {
                    if (actual.Location != Location.None)
                    {
                        throw new InvalidDataException($"Expected:\nA project diagnostic with No location\nActual:\n{FormatDiagnostics(analyzer, actual)}");
                    }
                }
                else
                {
                    VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First());
                    var additionalLocations = actual.AdditionalLocations.ToArray();

                    if (additionalLocations.Length != expected.Locations.Length - 1)
                    {
                        throw new InvalidDataException($"Expected {expected.Locations.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:\r\n    {FormatDiagnostics(analyzer, actual)}\r\n");
                    }

                    for (int j = 0; j < additionalLocations.Length; ++j)
                    {
                        VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]);
                    }
                }

                if (actual.Id != expected.Id)
                {
                    throw new InvalidDataException(
                        $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.Id}\"\r\n\r\nDiagnostic:\r\n    {FormatDiagnostics(analyzer, actual)}\r\n");
                }

                if (actual.Severity != expected.Severity)
                {
                    throw new InvalidDataException(
                        $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.Severity}\"\r\n\r\nDiagnostic:\r\n    {FormatDiagnostics(analyzer, actual)}\r\n");
                }

                if (actual.GetMessage() != expected.Message)
                {
                    throw new InvalidDataException(
                        $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.GetMessage()}\"\r\n\r\nDiagnostic:\r\n    {FormatDiagnostics(analyzer, actual)}\r\n");
                }
            }
        }
            public AnalyzerAndOptions(DiagnosticAnalyzer analyzer, AnalyzerOptions analyzerOptions)
            {
                Debug.Assert(analyzer != null);
                Debug.Assert(analyzerOptions != null);

                Analyzer = analyzer;
                _analyzerOptions = analyzerOptions;
            }
 internal TestDiagnosticAnalyzerService(
     string language,
     DiagnosticAnalyzer analyzer,
     AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource = null,
     Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
     : this(CreateHostAnalyzerManager(language, analyzer, hostDiagnosticUpdateSource), hostDiagnosticUpdateSource, onAnalyzerException)
 {
 }
Example #27
0
 private void OnAnalyzerException(Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diagnostic)
 {
     lock (_exceptions)
     {
         var list = _exceptions.GetOrAdd(analyzer, _ => new HashSet<DiagnosticData>());
         list.Add(DiagnosticData.Create(_project, diagnostic));
     }
 }
Example #28
0
 internal static async Task<List<Diagnostic>> GetDiagnosticsAsync(string code, DiagnosticAnalyzer analyzer)
 {
   var document = TestHelpers.Create(code);
   var root = await document.GetSyntaxRootAsync();
   var compilation = (await document.Project.GetCompilationAsync())
     .WithAnalyzers(ImmutableArray.Create(analyzer));
   return (await compilation.GetAnalyzerDiagnosticsAsync()).ToList();
 }
Example #29
0
        /// <summary>
        /// General verifier for code fixes.
        /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant code fixes.
        /// Then gets the string after the code fix is applied and compares it with the expected result.
        /// Note: If any code fix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
        /// </summary>
        /// <param name="language">The language the source code is in.</param>
        /// <param name="analyzer">The analyzer to be applied to the source code.</param>
        /// <param name="codeFixProvider">The code fix to be applied to the code wherever the relevant Diagnostic is found.</param>
        /// <param name="oldSource">A class in the form of a string before the code fix was applied to it.</param>
        /// <param name="newSource">A class in the form of a string after the code fix was applied to it.</param>
        /// <param name="codeFixIndex">Index determining which code fix to apply if there are multiple.</param>
        /// <param name="allowNewCompilerDiagnostics">A boolean controlling whether or not the test will fail if the code fix introduces other warnings after being applied.</param>
        private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            var document = CreateDocument(oldSource, language);
            var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document });
            var compilerDiagnostics = GetCompilerDiagnostics(document);
            var attempts = analyzerDiagnostics.Length;

            for (int i = 0; i < attempts; ++i)
            {
                var actions = new List<CodeAction>();
                var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
                codeFixProvider.RegisterCodeFixesAsync(context).Wait();

                if (!actions.Any())
                {
                    break;
                }

                if (codeFixIndex != null)
                {
                    document = ApplyFix(document, actions.ElementAt((int)codeFixIndex));
                    break;
                }

                document = ApplyFix(document, actions.ElementAt(0));
                analyzerDiagnostics = CodeFixVerifier.GetSortedDiagnosticsFromDocuments(analyzer, new[] { document });

                var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));

                // Check if applying the code fix introduced any new compiler diagnostics
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));

                    string message =
                        FormattableString.Invariant(
                            $@"Fix introduced new compiler diagnostics:
{string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString()))}

New document:
{document.GetSyntaxRootAsync().Result.ToFullString()}
");
                    Execute.Assertion.FailWith(message);
                }

                // Check if there are analyzer diagnostics left after the code fix
                if (!analyzerDiagnostics.Any())
                {
                    break;
                }
            }

            // After applying all of the code fixes, compare the resulting string to the inputted one
            var actual = GetStringFromDocument(document);
            actual.Should().Be(newSource);
        }
        private void VerifyFix(Document document, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string newSource, int? codeFixIndex, bool useCompilerAnalyzerDriver, bool allowNewCompilerDiagnostics)
        {
            Diagnostic[] analyzerDiagnostics = GetSortedDiagnostics(analyzer, document, useCompilerAnalyzerDriver: useCompilerAnalyzerDriver);
            System.Collections.Immutable.ImmutableArray<Diagnostic> compilerDiagnostics = document.GetSemanticModelAsync().Result.GetDiagnostics();

            // TODO(mavasani): Delete the below if statement once FxCop Analyzers have been ported to new IDiagnosticAnalyzer API.
            if (!useCompilerAnalyzerDriver)
            {
                Assert.True(analyzerDiagnostics.IsEmpty());
                return;
            }

            int attempts = analyzerDiagnostics.Length;

            for (int i = 0; i < attempts; ++i)
            {
                var actions = new List<CodeAction>();
                var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
                codeFixProvider.RegisterCodeFixesAsync(context).Wait();
                if (!actions.Any())
                {
                    break;
                }

                if (codeFixIndex != null)
                {
                    document = document.Apply(actions.ElementAt((int)codeFixIndex));
                    break;
                }

                document = document.Apply(actions.ElementAt(0));

                analyzerDiagnostics = GetSortedDiagnostics(analyzer, document, useCompilerAnalyzerDriver: useCompilerAnalyzerDriver);
                IEnumerable<Diagnostic> newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, document.GetSemanticModelAsync().Result.GetDiagnostics());
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, document.GetSemanticModelAsync().Result.GetDiagnostics());

                    Assert.True(false,
                        string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
                            newCompilerDiagnostics.Select(d => d.ToString()).Join("\r\n"),
                            document.GetSyntaxRootAsync().Result.ToFullString()));
                }

                if (analyzerDiagnostics.IsEmpty())
                {
                    break;
                }
            }

            Document newDocument = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result;
            SyntaxNode root = newDocument.GetSyntaxRootAsync().Result;
            root = Formatter.Format(root, Formatter.Annotation, newDocument.Project.Solution.Workspace);
            string actual = root.GetText().ToString();
            Assert.Equal(newSource, actual);
        }
Example #31
0
        private async Task <ImmutableArray <Diagnostic> > GetSemanticDiagnosticsAsync(SemanticModel model, DiagnosticAnalyzer analyzer, bool isCompilerAnalyzer, CancellationToken cancellationToken)
        {
            // PERF:
            //  1. Compute diagnostics for all analyzers with a single invocation into CompilationWithAnalyzers.
            //     This is critical for better analyzer execution performance through re-use of bound node cache.
            //  2. Ensure that the compiler analyzer is treated specially and does not block on diagnostic computation
            //     for rest of the analyzers. This is needed to ensure faster refresh for compiler diagnostics while typing.

            RoslynDebug.Assert(_compilationWithAnalyzers != null);

            var span = AnalysisScope.Span;

            if (isCompilerAnalyzer)
            {
#if DEBUG
                VerifySpanBasedCompilerDiagnostics(model);
#endif

                var adjustedSpan = await GetAdjustedSpanForCompilerAnalyzerAsync().ConfigureAwait(false);

                // TODO: Move this invocation to OOP
                return(await _compilationWithAnalyzers.GetAnalyzerSemanticDiagnosticsAsync(model, adjustedSpan, ImmutableArray.Create(analyzer), cancellationToken).ConfigureAwait(false));
            }

            // We specially handle IInlineSourceSuppressionsAnalyzer by passing in the 'CompilationWithAnalyzers'
            // context to compute unnecessary inline source suppression diagnostics.
            // This is required because this analyzer relies on reported compiler + analyzer diagnostics
            // for unnecessary inline source suppression analysis.
            if (analyzer is IPragmaSuppressionsAnalyzer suppressionsAnalyzer &&
                !AnalysisScope.Span.HasValue)
            {
                using var _ = ArrayBuilder <Diagnostic> .GetInstance(out var builder);

                await suppressionsAnalyzer.AnalyzeAsync(model, span, _compilationWithAnalyzers,
                                                        _analyzerInfoCache.GetDiagnosticDescriptors, IsCompilationEndAnalyzer, builder.Add, cancellationToken).ConfigureAwait(false);

                return(builder.ToImmutable());
            }

            if (_lazySemanticDiagnostics == null)
            {
                // TODO: Move this invocation to OOP
                var analysisResult = await _compilationWithAnalyzers.GetAnalysisResultAsync(model, span, _compilationBasedAnalyzersInAnalysisScope, cancellationToken).ConfigureAwait(false);

                var treeDiagnostics = analysisResult.SemanticDiagnostics.TryGetValue(model.SyntaxTree, out var value) ? value : ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > .Empty;
                Interlocked.CompareExchange(ref _lazySemanticDiagnostics, treeDiagnostics, null);
            }

            return(_lazySemanticDiagnostics.TryGetValue(analyzer, out var diagnostics) ?
                   diagnostics :
                   ImmutableArray <Diagnostic> .Empty);

            bool IsCompilationEndAnalyzer(DiagnosticAnalyzer analyzer)
            {
                RoslynDebug.AssertNotNull(_compilationWithAnalyzers);
                return(_analyzerInfoCache.IsCompilationEndAnalyzer(analyzer, AnalysisScope.TextDocument.Project, _compilationWithAnalyzers.Compilation) ?? true);
            }

            async Task <TextSpan?> GetAdjustedSpanForCompilerAnalyzerAsync()
            {
                // This method is to workaround a bug (https://github.com/dotnet/roslyn/issues/1557)
                // once that bug is fixed, we should be able to use given span as it is.

                Debug.Assert(isCompilerAnalyzer);

                if (!span.HasValue)
                {
                    return(null);
                }

                var document = (Document)AnalysisScope.TextDocument;
                var service  = document.GetRequiredLanguageService <ISyntaxFactsService>();
                var root     = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

                var startNode = service.GetContainingMemberDeclaration(root, span.Value.Start);
                var endNode   = service.GetContainingMemberDeclaration(root, span.Value.End);

                if (startNode == endNode)
                {
                    // use full member span
                    if (service.IsMethodLevelMember(startNode))
                    {
                        return(startNode.FullSpan);
                    }

                    // use span as it is
                    return(span);
                }

                var startSpan = service.IsMethodLevelMember(startNode) ? startNode.FullSpan : span.Value;
                var endSpan   = service.IsMethodLevelMember(endNode) ? endNode.FullSpan : span.Value;

                return(TextSpan.FromBounds(Math.Min(startSpan.Start, endSpan.Start), Math.Max(startSpan.End, endSpan.End)));
            }

#if DEBUG
            void VerifySpanBasedCompilerDiagnostics(SemanticModel model)
            {
                if (!span.HasValue)
                {
                    return;
                }

                // make sure what we got from range is same as what we got from whole diagnostics
                var rangeDeclaractionDiagnostics = model.GetDeclarationDiagnostics(span.Value).ToArray();
                var rangeMethodBodyDiagnostics   = model.GetMethodBodyDiagnostics(span.Value).ToArray();
                var rangeDiagnostics             = rangeDeclaractionDiagnostics.Concat(rangeMethodBodyDiagnostics).Where(shouldInclude).ToArray();

                var wholeDeclarationDiagnostics = model.GetDeclarationDiagnostics().ToArray();
                var wholeMethodBodyDiagnostics  = model.GetMethodBodyDiagnostics().ToArray();
                var wholeDiagnostics            = wholeDeclarationDiagnostics.Concat(wholeMethodBodyDiagnostics).Where(shouldInclude).ToArray();

                if (!AnalyzerHelper.AreEquivalent(rangeDiagnostics, wholeDiagnostics))
                {
                    // otherwise, report non-fatal watson so that we can fix those cases
                    FatalError.ReportWithoutCrash(new Exception("Bug in GetDiagnostics"));

                    // make sure we hold onto these for debugging.
                    GC.KeepAlive(rangeDeclaractionDiagnostics);
                    GC.KeepAlive(rangeMethodBodyDiagnostics);
                    GC.KeepAlive(rangeDiagnostics);
                    GC.KeepAlive(wholeDeclarationDiagnostics);
                    GC.KeepAlive(wholeMethodBodyDiagnostics);
                    GC.KeepAlive(wholeDiagnostics);
                }

                return;
Example #32
0
 public AnalyzerManager(DiagnosticAnalyzer analyzer)
 {
     _analyzerExecutionContextMap = CreateAnalyzerExecutionContextMap(SpecializedCollections.SingletonEnumerable(analyzer));
 }
Example #33
0
 public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope scope, bool isIOperationFeatureEnabled = false)
 {
     _analyzer = analyzer;
     _scope    = scope;
     _isIOperationFeatureEnabled = isIOperationFeatureEnabled;
 }
Example #34
0
 public void EnableConcurrentExecution(DiagnosticAnalyzer analyzer)
 {
     _concurrentAnalyzers = _concurrentAnalyzers.Add(analyzer);
 }
Example #35
0
 public AnalyzerActions GetCompilationOnlyAnalyzerActions(DiagnosticAnalyzer analyzer)
 {
     return(base.GetAnalyzerActions(analyzer));
 }
Example #36
0
 public void RegisterOperationBlockEndAction(DiagnosticAnalyzer analyzer, Action <OperationBlockAnalysisContext> action)
 {
     _operationBlockEndActions = _operationBlockEndActions.Add(new OperationBlockAnalyzerAction(action, analyzer));
 }
Example #37
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>());
            }

            ImmutableArray <Diagnostic> diagnostics;

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

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

                return(diagnostics.ConvertToLocalDiagnostics(textDocument, 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>());
                }
            }

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

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

                    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);
                        return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                    }
                }
                else
                {
                    // Currently, we only support analysis for additional documents. In future, we may support analyzer config documents.
                    if (textDocument.Kind != TextDocumentKind.AdditionalDocument)
                    {
                        return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
                    }

                    diagnostics = await GetAdditionalDocumentDiagnosticsAsync((AdditionalDocument)textDocument, analyzer, isCompilerAnalyzer, cancellationToken).ConfigureAwait(false);
                }

                break;

            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);

                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(kind);
            }

            if (diagnostics.IsEmpty)
            {
                return(SpecializedCollections.EmptyEnumerable <DiagnosticData>());
            }

            var skippedAnalyzerInfo = textDocument.Project.GetSkippedAnalyzersInfo(_analyzerInfoCache);

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

            Debug.Assert(diagnostics.Length == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, _compilationWithAnalyzers.Compilation).Count());
            return(diagnostics.ConvertToLocalDiagnostics(textDocument, span));
        }
Example #38
0
 internal AnalyzerAction(DiagnosticAnalyzer analyzer)
 {
     Analyzer = analyzer;
 }
Example #39
0
        internal bool IsDiagnosticAnalyzerSuppressed(
            DiagnosticAnalyzer analyzer,
            CompilationOptions options,
            Func <DiagnosticAnalyzer, bool> isCompilerAnalyzer,
            AnalyzerExecutor analyzerExecutor,
            SeverityFilter severityFilter)
        {
            if (isCompilerAnalyzer(analyzer))
            {
                // Compiler analyzer must always be executed for compiler errors, which cannot be suppressed or filtered.
                return(false);
            }

            var supportedDiagnostics = GetSupportedDiagnosticDescriptors(analyzer, analyzerExecutor);
            var diagnosticOptions    = options.SpecificDiagnosticOptions;

            foreach (var diag in supportedDiagnostics)
            {
                if (HasNotConfigurableTag(diag.CustomTags))
                {
                    if (diag.IsEnabledByDefault)
                    {
                        // Diagnostic descriptor is not configurable, so the diagnostics created through it cannot be suppressed.
                        return(false);
                    }
                    else
                    {
                        // NotConfigurable disabled diagnostic can be ignored as it is never reported.
                        continue;
                    }
                }

                // Is this diagnostic suppressed by default (as written by the rule author)
                var isSuppressed = !diag.IsEnabledByDefault;

                // Compilation wide user settings from ruleset/nowarn/warnaserror overrides the analyzer author.
                if (diagnosticOptions.TryGetValue(diag.Id, out var severity))
                {
                    isSuppressed = severity == ReportDiagnostic.Suppress;
                }
                else
                {
                    severity = isSuppressed ? ReportDiagnostic.Suppress : DiagnosticDescriptor.MapSeverityToReport(diag.DefaultSeverity);
                }

                // Is this diagnostic suppressed due to its severity
                if (severityFilter.Contains(severity))
                {
                    isSuppressed = true;
                }

                // Editorconfig user settings override compilation wide settings.
                if (isSuppressed &&
                    isEnabledWithAnalyzerConfigOptions(diag, severityFilter, analyzerExecutor.Compilation, analyzerExecutor.AnalyzerOptions))
                {
                    isSuppressed = false;
                }

                if (!isSuppressed)
                {
                    return(false);
                }
            }

            if (analyzer is DiagnosticSuppressor suppressor)
            {
                foreach (var suppressionDescriptor in GetSupportedSuppressionDescriptors(suppressor, analyzerExecutor))
                {
                    if (!suppressionDescriptor.IsDisabled(options))
                    {
                        return(false);
                    }
                }
            }

            return(true);
Example #40
0
        /// <summary>
        /// Returns true if the given analyzer has enabled concurrent execution by invoking <see cref="AnalysisContext.EnableConcurrentExecution"/>.
        /// </summary>
        public async Task <bool> IsConcurrentAnalyzerAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor)
        {
            var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false);

            return(sessionScope.IsConcurrentAnalyzer(analyzer));
        }
Example #41
0
 public void RegisterSyntaxNodeAction(DiagnosticAnalyzer analyzer, Action <SyntaxNodeAnalysisContext> action, ImmutableArray <TLanguageKindEnum> syntaxKinds)
 {
     _syntaxNodeActions = _syntaxNodeActions.Add(new SyntaxNodeAnalyzerAction <TLanguageKindEnum>(action, syntaxKinds, analyzer));
 }
Example #42
0
        private async Task <ImmutableArray <Diagnostic> > GetAdditionalDocumentDiagnosticsAsync(AdditionalDocument document, DiagnosticAnalyzer analyzer, bool isCompilerAnalyzer, CancellationToken cancellationToken)
        {
            // PERF: Compute diagnostics for all analyzers with a single invocation into CompilationWithAnalyzers.
            // This is critical for better analyzer execution performance.

            RoslynDebug.Assert(_compilationWithAnalyzers != null);
            RoslynDebug.Assert(_compilationBasedAnalyzersInAnalysisScope.Contains(analyzer));

            if (isCompilerAnalyzer)
            {
                return(ImmutableArray <Diagnostic> .Empty);
            }

            if (_lazyAdditionalDocumentDiagnostics == null)
            {
                var filePath       = document.FilePath ?? document.Name;
                var additionalFile = _compilationWithAnalyzers.AnalysisOptions.Options?.AdditionalFiles.FirstOrDefault(a => PathUtilities.Comparer.Equals(a.Path, filePath));
                ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > diagnosticsMap;
                if (additionalFile == null)
                {
                    diagnosticsMap = ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > .Empty;
                }
                else
                {
                    // TODO: Move this invocation to OOP
                    var analysisResult = await _compilationWithAnalyzers.GetAnalysisResultAsync(additionalFile, _compilationBasedAnalyzersInAnalysisScope, cancellationToken).ConfigureAwait(false);

                    diagnosticsMap = analysisResult.AdditionalFileDiagnostics.TryGetValue(additionalFile, out var value) ? value : ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > .Empty;
                }

                Interlocked.CompareExchange(ref _lazyAdditionalDocumentDiagnostics, diagnosticsMap, null);
            }

            return(_lazyAdditionalDocumentDiagnostics.TryGetValue(analyzer, out var diagnostics) ?
                   diagnostics :
                   ImmutableArray <Diagnostic> .Empty);
        }
Example #43
0
 public void RegisterCodeBlockEndAction(DiagnosticAnalyzer analyzer, Action <CodeBlockAnalysisContext> action)
 {
     _codeBlockEndActions = _codeBlockEndActions.Add(new CodeBlockAnalyzerAction(action, analyzer));
 }
Example #44
0
        private async Task <ImmutableArray <Diagnostic> > GetSyntaxDiagnosticsAsync(SyntaxTree tree, DiagnosticAnalyzer analyzer, bool isCompilerAnalyzer, CancellationToken cancellationToken)
        {
            // PERF:
            //  1. Compute diagnostics for all analyzers with a single invocation into CompilationWithAnalyzers.
            //     This is critical for better analyzer execution performance.
            //  2. Ensure that the compiler analyzer is treated specially and does not block on diagnostic computation
            //     for rest of the analyzers. This is needed to ensure faster refresh for compiler diagnostics while typing.

            RoslynDebug.Assert(_compilationWithAnalyzers != null);
            RoslynDebug.Assert(_compilationBasedAnalyzersInAnalysisScope.Contains(analyzer));

            if (isCompilerAnalyzer)
            {
                // TODO: Move this invocation to OOP
                return(await _compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(tree, ImmutableArray.Create(analyzer), cancellationToken).ConfigureAwait(false));
            }

            if (_lazySyntaxDiagnostics == null)
            {
                // TODO: Move this invocation to OOP
                var analysisResult = await _compilationWithAnalyzers.GetAnalysisResultAsync(tree, _compilationBasedAnalyzersInAnalysisScope, cancellationToken).ConfigureAwait(false);

                var treeDiagnostics = analysisResult.SyntaxDiagnostics.TryGetValue(tree, out var value) ? value : ImmutableDictionary <DiagnosticAnalyzer, ImmutableArray <Diagnostic> > .Empty;
                Interlocked.CompareExchange(ref _lazySyntaxDiagnostics, treeDiagnostics, null);
            }

            return(_lazySyntaxDiagnostics.TryGetValue(analyzer, out var diagnostics) ?
                   diagnostics :
                   ImmutableArray <Diagnostic> .Empty);
        }
Example #45
0
 public void ConfigureGeneratedCodeAnalysis(DiagnosticAnalyzer analyzer, GeneratedCodeAnalysisFlags mode)
 {
     _generatedCodeConfigurationMap.AddOrUpdate(analyzer, addValue: mode, updateValueFactory: (a, c) => mode);
 }
Example #46
0
 public static bool IsOpenFileOnly(this DiagnosticAnalyzer analyzer, OptionSet options)
 => analyzer is IBuiltInAnalyzer builtInAnalyzer && builtInAnalyzer.OpenFileOnly(options);
Example #47
0
        public GeneratedCodeAnalysisFlags GetGeneratedCodeAnalysisFlags(DiagnosticAnalyzer analyzer)
        {
            GeneratedCodeAnalysisFlags mode;

            return(_generatedCodeConfigurationMap.TryGetValue(analyzer, out mode) ? mode : AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags);
        }
Example #48
0
 public static bool IsBuiltInAnalyzer(this DiagnosticAnalyzer analyzer)
 => analyzer is IBuiltInAnalyzer || analyzer.IsWorkspaceDiagnosticAnalyzer() || analyzer.IsCompilerAnalyzer();
Example #49
0
 public bool IsConcurrentAnalyzer(DiagnosticAnalyzer analyzer)
 {
     return(_concurrentAnalyzers.Contains(analyzer));
 }
Example #50
0
 public static bool IsWorkspaceDiagnosticAnalyzer(this DiagnosticAnalyzer analyzer)
 => analyzer is DocumentDiagnosticAnalyzer || analyzer is ProjectDiagnosticAnalyzer || analyzer == FileContentLoadAnalyzer.Instance;
Example #51
0
 private AnalyzerExecutionContext GetAnalyzerExecutionContext(DiagnosticAnalyzer analyzer) => _analyzerExecutionContextMap[analyzer];
Example #52
0
 public void RegisterOperationAction(DiagnosticAnalyzer analyzer, Action <OperationAnalysisContext> action, ImmutableArray <OperationKind> operationKinds)
 {
     _operationActions = _operationActions.Add(new OperationAnalyzerAction(action, operationKinds, analyzer));
 }
Example #53
0
        public async ValueTask <AnalyzerActions> GetPerSymbolAnalyzerActionsAsync(ISymbol symbol, DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor)
        {
            var analyzerActions = await GetAnalyzerActionsAsync(analyzer, analyzerExecutor).ConfigureAwait(false);

            if (analyzerActions.SymbolStartActionsCount > 0)
            {
                var filteredSymbolStartActions = getFilteredActionsByKind(analyzerActions.SymbolStartActions);
                if (filteredSymbolStartActions.Length > 0)
                {
                    var symbolScope = await GetSymbolAnalysisScopeAsync(symbol, analyzer, filteredSymbolStartActions, analyzerExecutor).ConfigureAwait(false);

                    return(symbolScope.GetAnalyzerActions(analyzer));
                }
            }

            return(AnalyzerActions.Empty);

            ImmutableArray <SymbolStartAnalyzerAction> getFilteredActionsByKind(ImmutableArray <SymbolStartAnalyzerAction> symbolStartActions)
            {
                ArrayBuilder <SymbolStartAnalyzerAction>?filteredActionsBuilderOpt = null;

                for (int i = 0; i < symbolStartActions.Length; i++)
                {
                    var symbolStartAction = symbolStartActions[i];
                    if (symbolStartAction.Kind != symbol.Kind)
                    {
                        if (filteredActionsBuilderOpt == null)
                        {
                            filteredActionsBuilderOpt = ArrayBuilder <SymbolStartAnalyzerAction> .GetInstance();

                            filteredActionsBuilderOpt.AddRange(symbolStartActions, i);
                        }
                    }
                    else if (filteredActionsBuilderOpt != null)
                    {
                        filteredActionsBuilderOpt.Add(symbolStartAction);
                    }
                }

                return(filteredActionsBuilderOpt != null?filteredActionsBuilderOpt.ToImmutableAndFree() : symbolStartActions);
            }
        }
Example #54
0
        /// <summary>
        /// Returns <see cref="GeneratedCodeAnalysisFlags"/> for the given analyzer.
        /// If an analyzer hasn't configured generated code analysis, returns <see cref="AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags"/>.
        /// </summary>
        public async Task <GeneratedCodeAnalysisFlags> GetGeneratedCodeAnalysisFlagsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor)
        {
            var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor).ConfigureAwait(false);

            return(sessionScope.GetGeneratedCodeAnalysisFlags(analyzer));
        }