private static Document[] GetDocuments(AnalyzerVerificationContext context, string[] sources) { var project = CreateProject(context, sources); var documents = project.Documents.ToArray(); if (sources.Length != documents.Length) { throw new Exception("Amount of sources did not match amount of Documents created"); } return(documents); }
private static IEnumerable <Diagnostic> GetNewDiagnostics(AnalyzerVerificationContext context, IEnumerable <Diagnostic> diagnostics, IEnumerable <Diagnostic> newDiagnostics) { var oldArray = FilterDiagnostics(diagnostics, context.Filters).OrderBy(d => d.Location.SourceSpan.Start).ToArray(); var newArray = FilterDiagnostics(newDiagnostics, context.Filters).OrderBy(d => d.Location.SourceSpan.Start).ToArray(); var oldIndex = 0; var newIndex = 0; while (newIndex < newArray.Length) { if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id) { ++oldIndex; ++newIndex; } else { yield return(newArray[newIndex++]); } } }
private static Project CreateProject(AnalyzerVerificationContext context, string[] sources) { var projectId = ProjectId.CreateNewId(TestProjectName); var solution = new AdhocWorkspace() .CurrentSolution .AddProject(projectId, TestProjectName, TestProjectName, LanguageNames.CSharp); solution = UnityAssemblies().Aggregate(solution, (current, dll) => current.AddMetadataReference(projectId, MetadataReference.CreateFromFile(dll))); solution = solution.WithProjectParseOptions(projectId, new CSharpParseOptions(context.LanguageVersion)); var count = 0; foreach (var source in sources) { var newFileName = DefaultFilePathPrefix + count + "." + CSharpDefaultFileExt; var documentId = DocumentId.CreateNewId(projectId, newFileName); solution = solution.AddDocument(documentId, newFileName, SourceText.From(source), filePath: @"/" + newFileName); count++; } return(solution.GetProject(projectId)); }
private async Task VerifyFixAsync(AnalyzerVerificationContext context, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int?codeFixIndex, bool allowNewCompilerDiagnostics) { var document = CreateDocument(context, oldSource); var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(context, analyzer, new[] { document }); var compilerDiagnostics = (await GetCompilerDiagnosticsAsync(document)).ToList(); var attempts = analyzerDiagnostics.Length; for (var i = 0; i < attempts; ++i) { var actions = new List <CodeAction>(); var codeFixContext = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); await codeFixProvider.RegisterCodeFixesAsync(codeFixContext); if (!actions.Any()) { break; } if (codeFixIndex != null) { document = await ApplyFixAsync(document, actions.ElementAt((int)codeFixIndex)); break; } document = await ApplyFixAsync(document, actions.ElementAt(0)); analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(context, analyzer, new[] { document }); var newCompilerDiagnostics = GetNewDiagnostics(context, compilerDiagnostics, await GetCompilerDiagnosticsAsync(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 var root = await document.GetSyntaxRootAsync(); Assert.NotNull(root); document = document.WithSyntaxRoot(Formatter.Format(root, Formatter.Annotation, document.Project.Solution.Workspace)); newCompilerDiagnostics = GetNewDiagnostics(context, compilerDiagnostics, await GetCompilerDiagnosticsAsync(document)); var diagnostics = string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())); var newDoc = root.ToFullString(); Assert.True(false, $"Fix introduced new compiler diagnostics:\r\n{diagnostics}\r\n\r\nNew document:\r\n{newDoc}\r\n"); } //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 = await GetStringFromDocumentAsync(document); Assert.Equal(newSource, actual); }
protected Task VerifyCSharpFixAsync(AnalyzerVerificationContext context, string oldSource, string newSource, int?codeFixIndex = null, bool allowNewCompilerDiagnostics = false) { return(VerifyFixAsync(context, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics)); }
private async Task VerifyDiagnosticsAsync(AnalyzerVerificationContext context, string[] sources, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = await GetSortedDiagnosticsAsync(context, sources, analyzer, expected); VerifyDiagnosticResults(diagnostics, analyzer, expected); }
protected Task VerifyCSharpDiagnosticAsync(AnalyzerVerificationContext context, string source, params DiagnosticResult[] expected) { return(VerifyDiagnosticsAsync(context, new[] { source }, GetCSharpDiagnosticAnalyzer(), expected)); }
protected static Document CreateDocument(AnalyzerVerificationContext context, string source) { return(CreateProject(context, new[] { source }).Documents.First()); }
protected async Task <Diagnostic[]> GetSortedDiagnosticsFromDocumentsAsync(AnalyzerVerificationContext context, DiagnosticAnalyzer analyzer, Document[] documents, params DiagnosticResult[] expected) { 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 analyzers = ImmutableArray.Create(analyzer) .AddRange(GetRelatedAnalyzers(analyzer)); var compilation = await project.GetCompilationAsync(); Assert.NotNull(compilation); var optionsProvider = new AnalyzerOptionsProvider(context.Options); var options = new AnalyzerOptions(ImmutableArray <AdditionalText> .Empty, optionsProvider); var analyzerOptions = new CompilationWithAnalyzersOptions(options, null, true, true, true); var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, reportSuppressedDiagnostics: true); var specificDiagnosticOptions = compilationOptions.SpecificDiagnosticOptions; // Force all tested diagnostics to be enabled foreach (var descriptor in analyzer.SupportedDiagnostics) { specificDiagnosticOptions = specificDiagnosticOptions.SetItem(descriptor.Id, ReportDiagnostic.Info); } var compilationWithAnalyzers = compilation .WithOptions(compilationOptions.WithSpecificDiagnosticOptions(specificDiagnosticOptions)) .WithAnalyzers(analyzers, analyzerOptions); var allDiagnostics = await compilationWithAnalyzers.GetAllDiagnosticsAsync(); var errors = allDiagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); foreach (var error in errors) { Assert.True(false, $"Line {error.Location.GetLineSpan().StartLinePosition.Line}: {error.GetMessage()}"); } var diags = allDiagnostics .Except(errors) .Where(d => d.Location.IsInSource); //only keep diagnostics related to a source location foreach (var diag in diags) { // We should not hit this anymore, but keep in case we change the previous filter if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { foreach (var document in documents) { var tree = await document.GetSyntaxTreeAsync(); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(FilterDiagnostics(diagnostics, context.Filters)); diagnostics.Clear(); return(results); }
private Task <Diagnostic[]> GetSortedDiagnosticsAsync(AnalyzerVerificationContext context, string[] sources, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { return(GetSortedDiagnosticsFromDocumentsAsync(context, analyzer, GetDocuments(context, sources), expected)); }