/// <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(); }
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; }
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"); } } }
private async Task<HostSessionStartAnalysisScope> GetSessionAnalysisScopeAsync( DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor) { var analyzerExecutionContext = _analyzerExecutionContextMap.GetOrCreateValue(analyzer); return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor, analyzerExecutionContext).ConfigureAwait(false); }
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); } }
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); } }
/// <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) { }
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)); } }
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(); }
/// <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); }
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;
public AnalyzerManager(DiagnosticAnalyzer analyzer) { _analyzerExecutionContextMap = CreateAnalyzerExecutionContextMap(SpecializedCollections.SingletonEnumerable(analyzer)); }
public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope scope, bool isIOperationFeatureEnabled = false) { _analyzer = analyzer; _scope = scope; _isIOperationFeatureEnabled = isIOperationFeatureEnabled; }
public void EnableConcurrentExecution(DiagnosticAnalyzer analyzer) { _concurrentAnalyzers = _concurrentAnalyzers.Add(analyzer); }
public AnalyzerActions GetCompilationOnlyAnalyzerActions(DiagnosticAnalyzer analyzer) { return(base.GetAnalyzerActions(analyzer)); }
public void RegisterOperationBlockEndAction(DiagnosticAnalyzer analyzer, Action <OperationBlockAnalysisContext> action) { _operationBlockEndActions = _operationBlockEndActions.Add(new OperationBlockAnalyzerAction(action, analyzer)); }
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)); }
internal AnalyzerAction(DiagnosticAnalyzer analyzer) { Analyzer = analyzer; }
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);
/// <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)); }
public void RegisterSyntaxNodeAction(DiagnosticAnalyzer analyzer, Action <SyntaxNodeAnalysisContext> action, ImmutableArray <TLanguageKindEnum> syntaxKinds) { _syntaxNodeActions = _syntaxNodeActions.Add(new SyntaxNodeAnalyzerAction <TLanguageKindEnum>(action, syntaxKinds, analyzer)); }
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); }
public void RegisterCodeBlockEndAction(DiagnosticAnalyzer analyzer, Action <CodeBlockAnalysisContext> action) { _codeBlockEndActions = _codeBlockEndActions.Add(new CodeBlockAnalyzerAction(action, analyzer)); }
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); }
public void ConfigureGeneratedCodeAnalysis(DiagnosticAnalyzer analyzer, GeneratedCodeAnalysisFlags mode) { _generatedCodeConfigurationMap.AddOrUpdate(analyzer, addValue: mode, updateValueFactory: (a, c) => mode); }
public static bool IsOpenFileOnly(this DiagnosticAnalyzer analyzer, OptionSet options) => analyzer is IBuiltInAnalyzer builtInAnalyzer && builtInAnalyzer.OpenFileOnly(options);
public GeneratedCodeAnalysisFlags GetGeneratedCodeAnalysisFlags(DiagnosticAnalyzer analyzer) { GeneratedCodeAnalysisFlags mode; return(_generatedCodeConfigurationMap.TryGetValue(analyzer, out mode) ? mode : AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags); }
public static bool IsBuiltInAnalyzer(this DiagnosticAnalyzer analyzer) => analyzer is IBuiltInAnalyzer || analyzer.IsWorkspaceDiagnosticAnalyzer() || analyzer.IsCompilerAnalyzer();
public bool IsConcurrentAnalyzer(DiagnosticAnalyzer analyzer) { return(_concurrentAnalyzers.Contains(analyzer)); }
public static bool IsWorkspaceDiagnosticAnalyzer(this DiagnosticAnalyzer analyzer) => analyzer is DocumentDiagnosticAnalyzer || analyzer is ProjectDiagnosticAnalyzer || analyzer == FileContentLoadAnalyzer.Instance;
private AnalyzerExecutionContext GetAnalyzerExecutionContext(DiagnosticAnalyzer analyzer) => _analyzerExecutionContextMap[analyzer];
public void RegisterOperationAction(DiagnosticAnalyzer analyzer, Action <OperationAnalysisContext> action, ImmutableArray <OperationKind> operationKinds) { _operationActions = _operationActions.Add(new OperationAnalyzerAction(action, operationKinds, analyzer)); }
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); } }
/// <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)); }