示例#1
0
    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++]);
            }
        }
    }
示例#3
0
    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));
    }
示例#4
0
    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);
    }
示例#5
0
 protected Task VerifyCSharpDiagnosticAsync(AnalyzerVerificationContext context, string source, params DiagnosticResult[] expected)
 {
     return(VerifyDiagnosticsAsync(context, new[] { source }, GetCSharpDiagnosticAnalyzer(), expected));
 }
示例#6
0
 protected static Document CreateDocument(AnalyzerVerificationContext context, string source)
 {
     return(CreateProject(context, new[] { source }).Documents.First());
 }
示例#7
0
    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, (e, _, _) => throw e, 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);
    }
示例#8
0
 private Task <Diagnostic[]> GetSortedDiagnosticsAsync(AnalyzerVerificationContext context, string[] sources, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected)
 {
     return(GetSortedDiagnosticsFromDocumentsAsync(context, analyzer, GetDocuments(context, sources), expected));
 }
    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, _) => 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));
 }