예제 #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);
        }
예제 #2
0
        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 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);
        }
예제 #5
0
 protected Task VerifyCSharpFixAsync(AnalyzerVerificationContext context, string oldSource, string newSource, int?codeFixIndex = null, bool allowNewCompilerDiagnostics = false)
 {
     return(VerifyFixAsync(context, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics));
 }
예제 #6
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);
        }
예제 #7
0
 protected Task VerifyCSharpDiagnosticAsync(AnalyzerVerificationContext context, string source, params DiagnosticResult[] expected)
 {
     return(VerifyDiagnosticsAsync(context, new[] { source }, GetCSharpDiagnosticAnalyzer(), expected));
 }
예제 #8
0
 protected static Document CreateDocument(AnalyzerVerificationContext context, string source)
 {
     return(CreateProject(context, new[] { source }).Documents.First());
 }
예제 #9
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, 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);
        }
예제 #10
0
 private Task <Diagnostic[]> GetSortedDiagnosticsAsync(AnalyzerVerificationContext context, string[] sources, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected)
 {
     return(GetSortedDiagnosticsFromDocumentsAsync(context, analyzer, GetDocuments(context, sources), expected));
 }