protected void VerifyFix(string language, IDiagnosticAnalyzer analyzer, ICodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) { var document = CreateDocument(oldSource, language); VerifyFix(document, analyzer, codeFixProvider, newSource, codeFixIndex, useCompilerAnalyzerDriver: true, allowNewCompilerDiagnostics: allowNewCompilerDiagnostics); VerifyFix(document, analyzer, codeFixProvider, newSource, codeFixIndex, useCompilerAnalyzerDriver: false, allowNewCompilerDiagnostics: allowNewCompilerDiagnostics); }
private static void VerifyDiagnosticLocation(IDiagnosticAnalyzer 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))); } } }
private void VerifyFix(Document document, IDiagnosticAnalyzer analyzer, ICodeFixProvider codeFixProvider, string newSource, int? codeFixIndex, bool useCompilerAnalyzerDriver, bool allowNewCompilerDiagnostics) { var analyzerDiagnostics = GetSortedDiagnostics(analyzer, document, useCompilerAnalyzerDriver: useCompilerAnalyzerDriver); var 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; } var attempts = analyzerDiagnostics.Length; for (int i = 0; i < attempts; ++i) { var actions = codeFixProvider.GetFixesAsync(document, analyzerDiagnostics[0].Location.SourceSpan, analyzerDiagnostics, CancellationToken.None).Result; 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); var 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; } } var newDocument = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; var root = newDocument.GetSyntaxRootAsync().Result; root = Formatter.Format(root, Formatter.Annotation, newDocument.Project.Solution.Workspace); var actual = root.GetText().ToString(); Assert.Equal(newSource, actual); }
/// <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, IDiagnosticAnalyzer analyzer, ICodeFixProvider 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 = codeFixProvider.GetFixesAsync(document, analyzerDiagnostics[0].Location.SourceSpan, analyzerDiagnostics, CancellationToken.None).Result; if (!actions.Any()) { break; } if (codeFixIndex != null) { document = ApplyFix(document, actions.ElementAt((int)codeFixIndex)); break; } document = ApplyFix(document, actions.ElementAt(0)); analyzerDiagnostics = 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)); 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 var actual = GetStringFromDocument(document); Assert.AreEqual(newSource, actual); }
/// <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(IDiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet<Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List<Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().GetAwaiter().GetResult(); var driver = GetAnalyzerDriver(analyzer, compilation.Language); compilation = compilation.WithEventQueue(driver.CompilationEventQueue); var discarded = compilation.GetDiagnostics(); var diags = driver.GetDiagnosticsAsync().GetAwaiter().GetResult(); 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().GetAwaiter().GetResult(); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return results; }
private static void ExecuteAndCatchIfThrows(IDiagnosticAnalyzer a, Action <Diagnostic> addDiagnostic, bool continueOnError, CancellationToken cancellationToken, Action analyze) { try { analyze(); } catch (OperationCanceledException oce) if (continueOnError) { if (oce.CancellationToken != cancellationToken) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(a, oce)); } } catch (Exception e) if (continueOnError) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(a, e)); } }
public static void Verify(string path, IDiagnosticAnalyzer diagnosticAnalyzer) { var runner = new DiagnosticsRunner(ImmutableArray.Create(diagnosticAnalyzer)); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(path, Encoding.UTF8)); List <int> expected = new List <int>(ExpectedIssues(syntaxTree)); foreach (var diagnostic in runner.GetDiagnostics(syntaxTree)) { if (diagnostic.Id == diagnosticAnalyzer.SupportedDiagnostics.Single().Id) { int line = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1; expected.Should().Contain(line); expected.Remove(line); } } expected.Should().BeEquivalentTo(Enumerable.Empty <int>()); }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet<Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List<Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var driver = new AnalyzerDriver<SyntaxKind>((new[] { analyzer }).ToImmutableArray(), n => n.CSharpKind(), null, CancellationToken.None); compilation = compilation.WithEventQueue(driver.CompilationEventQueue); var discarded = compilation.GetDiagnostics(); var diags = driver.GetDiagnosticsAsync().Result; foreach (var diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var tree = document.GetSyntaxTreeAsync().Result; if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return results; }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List <Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var diags = AnalyzerDriver.GetDiagnostics(compilation, new[] { analyzer }, null, CancellationToken.None); 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); }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet<Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List<Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var diags = AnalyzerDriver.GetDiagnostics(compilation, new[] { analyzer }, null, CancellationToken.None); 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; }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// </summary> private static bool IsDiagnosticAnalyzerSuppressed(IDiagnosticAnalyzer analyzer, CompilationOptions options, Action <Diagnostic> addDiagnostic, bool continueOnError, CancellationToken cancellationToken) { var supportedDiagnostics = ImmutableArray <DiagnosticDescriptor> .Empty; // Catch Exception from analyzer.SupportedDiagnostics ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { supportedDiagnostics = analyzer.SupportedDiagnostics; }); var diagnosticOptions = options.SpecificDiagnosticOptions; foreach (var diag in supportedDiagnostics) { if (diagnosticOptions.ContainsKey(diag.Id) && diagnosticOptions[diag.Id] == ReportDiagnostic.Suppress) { continue; } else { return(false); } } return(true); }
protected static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, IDiagnosticAnalyzer analyzer) { var documentsAndUseSpan = GetDocumentsAndSpans(sources, language); var documents = documentsAndUseSpan.Item1; var useSpans = documentsAndUseSpan.Item2; var spans = documentsAndUseSpan.Item3; return GetSortedDiagnostics(analyzer, documents, useSpans ? spans : null); }
private static IEnumerable<Diagnostic> GetDiagnosticsUsingIDEAnalyzerDriver(IDiagnosticAnalyzer analyzer, Document document, TextSpan? span) { // TODO(mavasani): Uncomment the below code once FxCop Analyzers have been ported to new IDiagnosticAnalyzer API. ////return includeProjectDiagnostics ? //// DiagnosticProviderTestUtilities.GetAllDiagnostics(analyzerFactory, document, span) : //// DiagnosticProviderTestUtilities.GetDocumentDiagnostics(analyzerFactory, document, span); return SpecializedCollections.EmptyEnumerable<Diagnostic>(); }
protected void Verify(string[] sources, string language, IDiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { GetSortedDiagnostics(sources, language, analyzer).Verify(analyzer, expected); }
protected static Diagnostic[] GetSortedDiagnostics(IDiagnosticAnalyzer analyzer, Document document, TextSpan?[] spans = null) { return(GetSortedDiagnostics(analyzer, new[] { document }, spans)); }
private static void AnalyzeDocument(IDiagnosticAnalyzer analyzer, Document document, Action<Diagnostic> addDiagnostic, TextSpan? span = null) { Assert.True(analyzer.GetType().IsDefined(typeof(ExportDiagnosticAnalyzerAttribute)), "Top-level analyzers should have the ExportDiagnosticAnalyzerAttribute"); Assert.True(analyzer.GetType().IsDefined(typeof(DiagnosticAnalyzerAttribute)), "Top-level analyzers should have the DiagnosticAnalyzerAttribute"); AnalyzeDocumentCore(analyzer, document, addDiagnostic, span); }
/// <summary> /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the diagnostics found in the string after converting it to a document. /// </summary> /// <param name="sources">Classes in the form of strings</param> /// <param name="language">The language the soruce classes are in</param> /// <param name="analyzer">The analyzer to be run on the sources</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, IDiagnosticAnalyzer analyzer) { return(GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language))); }
private static Diagnostic GetAnalyzerDiagnostic(IDiagnosticAnalyzer analyzer, Exception e) { return(Diagnostic.Create(GetDiagnosticDescriptor(analyzer.GetType().ToString(), e.Message), Location.None)); }
protected void VerifyBasic(string source, string rootNamespace, IDiagnosticAnalyzer[] analyzers, params DiagnosticDescription[] diagnostics) { Assert.False(string.IsNullOrWhiteSpace(rootNamespace), string.Format("Invalid root namespace '{0}'", rootNamespace)); Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics, rootNamespace); }
private static Diagnostic[] GetSortedDiagnostics(IDiagnosticAnalyzer analyzerFactory, Document document, bool useCompilerAnalyzerDriver, TextSpan? span = null) { TextSpan spanToTest = span.HasValue ? span.Value : document.GetSyntaxRootAsync().Result.FullSpan; var diagnostics = useCompilerAnalyzerDriver ? GetDiagnosticsUsingCompilerAnalyzerDriver(analyzerFactory, document, span) : GetDiagnosticsUsingIDEAnalyzerDriver(analyzerFactory, document, span); return GetSortedDiagnostics(diagnostics); }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// <paramref name="continueOnAnalyzerException"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled. /// </summary> public static bool IsDiagnosticAnalyzerSuppressed(IDiagnosticAnalyzer analyzer, CompilationOptions options, Func<Exception, IDiagnosticAnalyzer, bool> continueOnAnalyzerException) { if (analyzer == null) { throw new ArgumentNullException("analyzer"); } if (options == null) { throw new ArgumentNullException("options"); } Action<Diagnostic> dummy = _ => { }; return IsDiagnosticAnalyzerSuppressed(analyzer, options, dummy, continueOnAnalyzerException, CancellationToken.None); }
/// <summary> /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the diagnostics found in the string after converting it to a document. /// </summary> /// <param name="sources">Classes in the form of strings</param> /// <param name="language">The language the soruce classes are in</param> /// <param name="analyzer">The analyzer to be run on the sources</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, IDiagnosticAnalyzer analyzer) { return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language)); }
private static string FormatDiagnostics(IDiagnosticAnalyzer analyzer, IEnumerable <Diagnostic> diagnostics) { return(FormatDiagnostics(analyzer, diagnostics.ToArray())); }
public static void Verify(this IEnumerable <Diagnostic> actualResults, IDiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) { int expectedCount = expectedResults.Count(); int actualCount = actualResults.Count(); if (expectedCount != actualCount) { string diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzer, actualResults) : " NONE."; Assert.True(false, string.Format("Mismatch between number of diagnostics returned, expected \"{0}\" acutal \"{1}\"\r\n\r\nDiagnostics:\r\n{2}\r\n", expectedCount, actualCount, diagnosticsOutput)); } for (int i = 0; i < expectedResults.Length; i++) { var actual = actualResults.ElementAt(i); var expected = expectedResults[i]; if (expected.Line == -1 && expected.Column == -1) { if (actual.Location != Location.None) { Assert.True(false, string.Format("Expected:\nA project diagnostic with No location\nActual:\n{0}", FormatDiagnostics(analyzer, actual))); } } else { VerifyDiagnosticLocation(analyzer, actual, actual.Location, expected.Locations.First()); var additionalLocations = actual.AdditionalLocations.ToArray(); if (additionalLocations.Length != expected.Locations.Length - 1) { Assert.True(false, string.Format("Expected {0} additional locations but got {1} for Diagnostic:\r\n {2}\r\n", expected.Locations.Length - 1, additionalLocations.Length, FormatDiagnostics(analyzer, actual))); } for (int j = 0; j < additionalLocations.Length; ++j) { VerifyDiagnosticLocation(analyzer, actual, additionalLocations[j], expected.Locations[j + 1]); } } if (actual.Id != expected.Id) { Assert.True(false, string.Format("Expected diagnostic id to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Id, actual.Id, FormatDiagnostics(analyzer, actual))); } if (actual.Severity != expected.Severity) { Assert.True(false, string.Format("Expected diagnostic severity to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Severity, actual.Severity, FormatDiagnostics(analyzer, actual))); } if (actual.GetMessage() != expected.Message) { Assert.True(false, string.Format("Expected diagnostic message to be \"{0}\" was \"{1}\"\r\n\r\nDiagnostic:\r\n {2}\r\n", expected.Message, actual.GetMessage(), FormatDiagnostics(analyzer, actual))); } } }
protected static Diagnostic[] GetSortedDiagnostics(IDiagnosticAnalyzer analyzer, Document document, TextSpan?[] spans = null) { return GetSortedDiagnostics(analyzer, new[] { document }, spans); }
protected virtual void Verify(string source, string language, IDiagnosticAnalyzer[] analyzers, DiagnosticDescription[] diagnostics, 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, diagnostics); }
protected static Diagnostic[] GetSortedDiagnostics(IDiagnosticAnalyzer analyzer, Document[] documents, TextSpan?[] spans = null) { var projects = new HashSet<Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = DiagnosticBag.GetInstance(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var compilationStartedAnalyzer = analyzer as ICompilationStartedAnalyzer; ICompilationEndedAnalyzer compilationEndedAnalyzer = null; if (compilationStartedAnalyzer != null) { compilationEndedAnalyzer = compilationStartedAnalyzer.OnCompilationStarted(compilation, diagnostics.Add, default(CancellationToken)); } for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var span = spans != null ? spans[i] : null; AnalyzeDocument(analyzer, document, diagnostics.Add, span); if (compilationEndedAnalyzer != null) { AnalyzeDocumentCore(compilationEndedAnalyzer, document, diagnostics.Add, span); } } if (compilationEndedAnalyzer != null) { compilationEndedAnalyzer.OnCompilationEnded(compilation, diagnostics.Add, default(CancellationToken)); } } var results = GetSortedDiagnostics(diagnostics.AsEnumerable()); diagnostics.Free(); return results; }
/// <summary> /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// </summary> /// <param name="sources">An array of strings to create source documents from to run teh analyzers on</param> /// <param name="language">The language of the classes represented by the source strings</param> /// <param name="analyzer">The analyzer to be run on the source code</param> /// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param> private void VerifyDiagnostics(string[] sources, string language, IDiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = GetSortedDiagnostics(sources, language, analyzer); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
protected static void AnalyzeDocumentCore(IDiagnosticAnalyzer analyzer, Document document, Action<Diagnostic> addDiagnostic, TextSpan? span = null, bool continueOnError = false) { TextSpan spanToTest = span.HasValue ? span.Value : document.GetSyntaxRootAsync().Result.FullSpan; var semanticModel = document.GetSemanticModelAsync().Result; AnalyzerDriver.RunAnalyzers(semanticModel, spanToTest, ImmutableArray.Create(analyzer), addDiagnostic, continueOnError: continueOnError); }
protected static void AnalyzeDocumentCore(IDiagnosticAnalyzer analyzer, Document document, Action<Diagnostic> addDiagnostic, TextSpan? span = null, Func<Exception, IDiagnosticAnalyzer, bool> continueOnAnalyzerException = null) { var semanticModel = document.GetSemanticModelAsync().Result; var diagnostics = semanticModel.Compilation.GetAnalyzerDiagnostics(new[] { analyzer }, continueOnAnalyzerException: continueOnAnalyzerException); foreach (var diagnostic in diagnostics) { if (!span.HasValue || diagnostic.Location == Location.None || diagnostic.Location.IsInMetadata || (diagnostic.Location.SourceTree == semanticModel.SyntaxTree && span.Value.Contains(diagnostic.Location.SourceSpan))) { addDiagnostic(diagnostic); } } }
protected void Verify(string source, string language, IDiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { Verify(new[] { source }, language, analyzer, expected); }
protected static void ExecuteAndCatchIfThrows(IDiagnosticAnalyzer a, Action<Diagnostic> addDiagnostic, bool continueOnError, CancellationToken cancellationToken, Action analyze) { try { analyze(); } catch (OperationCanceledException oce) { if (continueOnError) { if (oce.CancellationToken != cancellationToken) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(a, oce)); } } } catch (Exception e) { if (continueOnError) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(a, e)); } } }
protected static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, IDiagnosticAnalyzer analyzer) { var documentsAndUseSpan = GetDocumentsAndSpans(sources, language); var documents = documentsAndUseSpan.Item1; var useSpans = documentsAndUseSpan.Item2; var spans = documentsAndUseSpan.Item3; return(GetSortedDiagnostics(analyzer, documents, useSpans ? spans : null)); }
/// <summary> /// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options. /// </summary> private static bool IsDiagnosticAnalyzerSuppressed( IDiagnosticAnalyzer analyzer, CompilationOptions options, Action<Diagnostic> addDiagnostic, Func<Exception, IDiagnosticAnalyzer, bool> continueOnAnalyzerException, CancellationToken cancellationToken) { var supportedDiagnostics = ImmutableArray<DiagnosticDescriptor>.Empty; // Catch Exception from analyzer.SupportedDiagnostics ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnAnalyzerException, cancellationToken, () => { supportedDiagnostics = analyzer.SupportedDiagnostics; }); var diagnosticOptions = options.SpecificDiagnosticOptions; foreach (var diag in supportedDiagnostics) { // Is this diagnostic suppressed by default (as written by the rule author) var isSuppressed = !diag.IsEnabledByDefault; // If the user said something about it, that overrides the author. if (diagnosticOptions.ContainsKey(diag.Id)) { isSuppressed = diagnosticOptions[diag.Id] == ReportDiagnostic.Suppress; } if (isSuppressed) { continue; } else { return false; } } return true; }
private static IEnumerable<Diagnostic> GetDiagnosticsUsingCompilerAnalyzerDriver(IDiagnosticAnalyzer analyzer, Document document, TextSpan? span) { var semanticModel = document.GetSemanticModelAsync().Result; var compilation = semanticModel.Compilation; var diagnostics = new List<Diagnostic>(); AnalyzeDocumentCore(analyzer, document, diagnostics.Add, span); return diagnostics; }
protected void VerifyCSharp(string source, IDiagnosticAnalyzer[] analyzers, params DiagnosticDescription[] diagnostics) { Verify(source, LanguageNames.CSharp, analyzers, diagnostics); }
protected static void ExecuteAndCatchIfThrows(IDiagnosticAnalyzer analyzer, Action<Diagnostic> addDiagnostic, Func<Exception, IDiagnosticAnalyzer, bool> continueOnAnalyzerException, CancellationToken cancellationToken, Action analyze) { try { analyze(); } catch (OperationCanceledException oce) if (continueOnAnalyzerException(oce, analyzer)) { if (oce.CancellationToken != cancellationToken) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(analyzer, oce)); } } catch (Exception e) if (continueOnAnalyzerException(e, analyzer)) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(analyzer, e)); } }
protected void VerifyBasic(string source, IDiagnosticAnalyzer[] analyzers, params DiagnosticDescription[] diagnostics) { Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics); }
internal static Diagnostic GetAnalyzerDiagnostic(IDiagnosticAnalyzer analyzer, Exception e) { return Diagnostic.Create(GetDiagnosticDescriptor(analyzer.GetType().ToString(), e.Message), Location.None); }
private static Compilation CreateCompilation(string source, string language, IDiagnosticAnalyzer[] analyzers, string rootNamespace) { string fileName = language == LanguageNames.CSharp ? "Test.cs" : "Test.vb"; string projectName = "TestProject"; var syntaxTree = language == LanguageNames.CSharp ? CSharpSyntaxTree.ParseText(source, fileName) : VisualBasicSyntaxTree.ParseText(source, 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)); } }
protected static Diagnostic[] GetSortedDiagnostics(IDiagnosticAnalyzer analyzer, Document[] documents, TextSpan?[] spans = null) { var projects = new HashSet<Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = DiagnosticBag.GetInstance(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var diags = compilation.GetAnalyzerDiagnostics(new[] { analyzer }); 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) { var span = spans != null ? spans[i] : null; if (span == null || span.Value.Contains(diag.Location.SourceSpan)) { diagnostics.Add(diag); } } } } } } var results = GetSortedDiagnostics(diagnostics.AsEnumerable()); diagnostics.Free(); return results; }