internal static async Task<ImmutableList<CodeFixEquivalenceGroup>> CreateAsync(CodeFixProvider codeFixProvider, IEnumerable<Diagnostic> allDiagnostics, Solution solution)
        {
            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            var relevantDiagnostics = allDiagnostics.Where(diagnostic => codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id)).ToImmutableArray();

            if (fixAllProvider == null)
            {
                return ImmutableList.Create<CodeFixEquivalenceGroup>();
            }

            List<CodeAction> actions = new List<CodeAction>();

            foreach (var diagnostic in relevantDiagnostics)
            {
                actions.AddRange(await GetFixesAsync(solution, codeFixProvider, diagnostic).ConfigureAwait(false));
            }

            List<CodeFixEquivalenceGroup> groups = new List<CodeFixEquivalenceGroup>();

            foreach (var item in actions.GroupBy(x => x.EquivalenceKey))
            {
                groups.Add(new CodeFixEquivalenceGroup(item.Key, solution, fixAllProvider, codeFixProvider, relevantDiagnostics));
            }

            return groups.ToImmutableList();
        }
Пример #2
0
        /// <summary>
        /// Gets an optional <see cref="FixAllProviderInfo"/> for the given code fix provider.
        /// </summary>
        private static FixAllProviderInfo CreateWithCodeFixer(CodeFixProvider provider)
        {
            var fixAllProvider = provider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return(null);
            }

            var diagnosticIds = fixAllProvider.GetSupportedFixAllDiagnosticIds(provider);

            if (diagnosticIds == null || diagnosticIds.IsEmpty())
            {
                return(null);
            }

            var scopes = fixAllProvider.GetSupportedFixAllScopes();

            if (scopes == null || scopes.IsEmpty())
            {
                return(null);
            }

            return(new CodeFixerFixAllProviderInfo(fixAllProvider, diagnosticIds, scopes));
        }
Пример #3
0
        /// <summary>
        /// Gets an optional <see cref="FixAllProviderInfo"/> for the given code fix provider.
        /// </summary>
        private static FixAllProviderInfo CreateWithCodeFixer(CodeFixProvider provider)
        {
            var fixAllProvider = provider.GetFixAllProvider();
            if (fixAllProvider == null)
            {
                return null;
            }

            var diagnosticIds = fixAllProvider.GetSupportedFixAllDiagnosticIds(provider);
            if (diagnosticIds == null || diagnosticIds.IsEmpty())
            {
                return null;
            }

            var scopes = fixAllProvider.GetSupportedFixAllScopes();
            if (scopes == null || scopes.IsEmpty())
            {
                return null;
            }

            return new CodeFixerFixAllProviderInfo(fixAllProvider, diagnosticIds, scopes);
        }
        private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int maxNumberOfIterations, CancellationToken cancellationToken)
        {
            var previousDiagnostics = ImmutableArray.Create<Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return null;
            }

            bool done;
            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);
                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--maxNumberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List<CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, codeFixProvider.FixableDiagnosticIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
                if (action == null)
                {
                    return document;
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);
                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }
            while (!done);

            return document;
        }
Пример #5
0
        private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int numberOfIterations, CancellationToken cancellationToken)
        {
            int expectedNumberOfIterations = numberOfIterations;
            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create<Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return null;
            }

            bool done;
            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);
                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--numberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                    {
                        // do not pass unsupported diagnostics to a code fix provider
                        continue;
                    }

                    var actions = new List<CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                IEnumerable<string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                IEnumerable<string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal));
                IEnumerable<string> disabledDiagnosticIds = document.Project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                IEnumerable<string> relevantIds = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
                if (action == null)
                {
                    return document;
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);
                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }
            while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations");
            }

            return document;
        }
        private bool? IsBatchFixer(CodeFixProvider provider)
        {
            var fixAllProvider = provider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return null;
            }
            else
            {
                return fixAllProvider.GetType() == this.batchFixerType;
            }
        }
        internal static async Task<ImmutableArray<CodeFixEquivalenceGroup>> CreateAsync(CodeFixProvider codeFixProvider, ImmutableDictionary<ProjectId, ImmutableArray<Diagnostic>> allDiagnostics, Solution solution, CancellationToken cancellationToken)
        {
            var fixAllProvider = codeFixProvider.GetFixAllProvider();
            if (fixAllProvider == null)
            {
                return ImmutableArray.Create<CodeFixEquivalenceGroup>();
            }

            Dictionary<ProjectId, Dictionary<string, List<Diagnostic>>> relevantDocumentDiagnostics =
                new Dictionary<ProjectId, Dictionary<string, List<Diagnostic>>>();
            Dictionary<ProjectId, List<Diagnostic>> relevantProjectDiagnostics =
                new Dictionary<ProjectId, List<Diagnostic>>();

            foreach (var projectDiagnostics in allDiagnostics)
            {
                foreach (var diagnostic in projectDiagnostics.Value)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                    {
                        continue;
                    }

                    if (diagnostic.Location.IsInSource)
                    {
                        string sourcePath = diagnostic.Location.GetLineSpan().Path;

                        Dictionary<string, List<Diagnostic>> projectDocumentDiagnostics;
                        if (!relevantDocumentDiagnostics.TryGetValue(projectDiagnostics.Key, out projectDocumentDiagnostics))
                        {
                            projectDocumentDiagnostics = new Dictionary<string, List<Diagnostic>>();
                            relevantDocumentDiagnostics.Add(projectDiagnostics.Key, projectDocumentDiagnostics);
                        }

                        List<Diagnostic> diagnosticsInFile;
                        if (!projectDocumentDiagnostics.TryGetValue(sourcePath, out diagnosticsInFile))
                        {
                            diagnosticsInFile = new List<Diagnostic>();
                            projectDocumentDiagnostics.Add(sourcePath, diagnosticsInFile);
                        }

                        diagnosticsInFile.Add(diagnostic);
                    }
                    else
                    {
                        List<Diagnostic> diagnosticsInProject;
                        if (!relevantProjectDiagnostics.TryGetValue(projectDiagnostics.Key, out diagnosticsInProject))
                        {
                            diagnosticsInProject = new List<Diagnostic>();
                            relevantProjectDiagnostics.Add(projectDiagnostics.Key, diagnosticsInProject);
                        }

                        diagnosticsInProject.Add(diagnostic);
                    }
                }
            }

            ImmutableDictionary<ProjectId, ImmutableDictionary<string, ImmutableArray<Diagnostic>>> documentDiagnosticsToFix =
                relevantDocumentDiagnostics.ToImmutableDictionary(i => i.Key, i => i.Value.ToImmutableDictionary(j => j.Key, j => j.Value.ToImmutableArray(), StringComparer.OrdinalIgnoreCase));
            ImmutableDictionary<ProjectId, ImmutableArray<Diagnostic>> projectDiagnosticsToFix =
                relevantProjectDiagnostics.ToImmutableDictionary(i => i.Key, i => i.Value.ToImmutableArray());

            HashSet<string> equivalenceKeys = new HashSet<string>();
            foreach (var diagnostic in relevantDocumentDiagnostics.Values.SelectMany(i => i.Values).SelectMany(i => i).Concat(relevantProjectDiagnostics.Values.SelectMany(i => i)))
            {
                foreach (var codeAction in await GetFixesAsync(solution, codeFixProvider, diagnostic, cancellationToken).ConfigureAwait(false))
                {
                    equivalenceKeys.Add(codeAction.EquivalenceKey);
                }
            }

            List<CodeFixEquivalenceGroup> groups = new List<CodeFixEquivalenceGroup>();
            foreach (var equivalenceKey in equivalenceKeys)
            {
                groups.Add(new CodeFixEquivalenceGroup(equivalenceKey, solution, fixAllProvider, codeFixProvider, documentDiagnosticsToFix, projectDiagnosticsToFix));
            }

            return groups.ToImmutableArray();
        }
Пример #8
0
        private async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(
            IEnumerable<Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            TextSpan span,
            FixAllScope? scope,
            string fixAllActionId)
        {
            Assert.NotEmpty(diagnostics);
            var result = new List<Tuple<Diagnostic, CodeFixCollection>>();
            if (scope == null)
            {
                // Simple code fix.
                foreach (var diagnostic in diagnostics)
                {
                    var fixes = new List<CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), CancellationToken.None);

                    await fixer.RegisterCodeFixesAsync(context);
                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(
                            fixer, diagnostic.Location.SourceSpan, fixes,
                            fixAllState: null, supportedScopes: null, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }
            else
            {
                // Fix all fix.
                var fixAllProvider = fixer.GetFixAllProvider();
                Assert.NotNull(fixAllProvider);

                var fixAllState = GetFixAllState(fixAllProvider, diagnostics, provider, fixer, testDriver, document, scope.Value, fixAllActionId);
                var fixAllContext = fixAllState.CreateFixAllContext(new ProgressTracker(), CancellationToken.None);
                var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext);
                if (fixAllFix != null)
                {
                    // Same fix applies to each diagnostic in scope.
                    foreach (var diagnostic in diagnostics)
                    {
                        var diagnosticSpan = diagnostic.Location.IsInSource ? diagnostic.Location.SourceSpan : default(TextSpan);
                        var codeFix = new CodeFixCollection(
                            fixAllProvider, diagnosticSpan, ImmutableArray.Create(new CodeFix(document.Project, fixAllFix, diagnostic)),
                            fixAllState: null, supportedScopes: null, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }

            return result;
        }
Пример #9
0
 private async static Task VerifyFixAllAsync(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string[] oldSources, string[] newSources, bool allowNewCompilerDiagnostics, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB, string equivalenceKey = null)
 {
     var project = CreateProject(oldSources, language, languageVersionCSharp, languageVersionVB);
     var compilerDiagnostics = (await Task.WhenAll(project.Documents.Select(d => GetCompilerDiagnosticsAsync(d))).ConfigureAwait(true)).SelectMany(d => d);
     var fixAllProvider = codeFixProvider.GetFixAllProvider();
     if (equivalenceKey == null) equivalenceKey = codeFixProvider.GetType().Name;
     FixAllContext fixAllContext;
     if (analyzer != null)
     {
         var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzer, project.Documents.ToArray()).ConfigureAwait(true);
         Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync = (doc, ids, ct) =>
             Task.FromResult(analyzerDiagnostics.Where(d => d.Location.SourceTree.FilePath == doc.Name));
         Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync = (proj, b, ids, ct) =>
             Task.FromResult((IEnumerable<Diagnostic>)analyzerDiagnostics); //todo: verify, probably wrong
         var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(codeFixProvider.FixableDiagnosticIds.ToImmutableHashSet(), getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
         fixAllContext = new FixAllContext(project.Documents.First(), codeFixProvider, FixAllScope.Solution,
             equivalenceKey,
             codeFixProvider.FixableDiagnosticIds,
             fixAllDiagnosticProvider,
             CancellationToken.None);
     }
     else
     {
         Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync = async (doc, ids, ct) =>
         {
             var compilerDiags = await GetCompilerDiagnosticsAsync(doc).ConfigureAwait(true);
             return compilerDiags.Where(d => codeFixProvider.FixableDiagnosticIds.Contains(d.Id));
         };
         Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync = async (proj, b, ids, ct) =>
             {
                 var theDocs = proj.Documents;
                 var diags = await Task.WhenAll(theDocs.Select(d => getDocumentDiagnosticsAsync(d, ids, ct))).ConfigureAwait(true);
                 return diags.SelectMany(d => d);
             };
         var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(codeFixProvider.FixableDiagnosticIds.ToImmutableHashSet(), getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
         fixAllContext = new FixAllContext(project.Documents.First(), codeFixProvider, FixAllScope.Solution,
             equivalenceKey,
             codeFixProvider.FixableDiagnosticIds,
             fixAllDiagnosticProvider,
             CancellationToken.None);
     }
     var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(true);
     if (action == null) throw new Exception("No action supplied for the code fix.");
     project = await ApplyFixAsync(project, action).ConfigureAwait(true);
     //check if applying the code fix introduced any new compiler diagnostics
     var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, (await Task.WhenAll(project.Documents.Select(d => GetCompilerDiagnosticsAsync(d))).ConfigureAwait(true)).SelectMany(d => d));
     if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
         Assert.True(false, $"Fix introduced new compiler diagnostics:\r\n{string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString()))}\r\n");
     var docs = project.Documents.ToArray();
     for (int i = 0; i < docs.Length; i++)
     {
         var document = docs[i];
         var actual = await GetStringFromDocumentAsync(document).ConfigureAwait(true);
         newSources[i].Should().Be(actual);
     }
 }
Пример #10
0
 private async static Task VerifyFixAllAsync(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, bool allowNewCompilerDiagnostics, LanguageVersion languageVersionCSharp, Microsoft.CodeAnalysis.VisualBasic.LanguageVersion languageVersionVB, string equivalenceKey = null)
 {
     var document = CreateDocument(oldSource, language, languageVersionCSharp, languageVersionVB);
     var compilerDiagnostics = await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true);
     var getDocumentDiagnosticsAsync = analyzer != null
         ? (Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>>)(async (doc, ids, ct) =>
              await GetSortedDiagnosticsFromDocumentsAsync(analyzer, new[] { doc }).ConfigureAwait(true))
         : (async (doc, ids, ct) =>
         {
             var compilerDiags = await GetCompilerDiagnosticsAsync(doc).ConfigureAwait(true);
             return compilerDiags.Where(d => codeFixProvider.FixableDiagnosticIds.Contains(d.Id));
         });
     Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync = async (proj, b, ids, ct) =>
     {
         var theDocs = proj.Documents;
         var diags = await Task.WhenAll(theDocs.Select(d => getDocumentDiagnosticsAsync?.Invoke(d, ids, ct))).ConfigureAwait(true);
         return diags.SelectMany(d => d);
     };
     var fixAllProvider = codeFixProvider.GetFixAllProvider();
     var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(codeFixProvider.FixableDiagnosticIds.ToImmutableHashSet(), getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
     if (equivalenceKey == null) equivalenceKey = codeFixProvider.GetType().Name;
     var fixAllContext = new FixAllContext(document, codeFixProvider, FixAllScope.Document,
         equivalenceKey,
         codeFixProvider.FixableDiagnosticIds,
         fixAllDiagnosticProvider,
         CancellationToken.None);
     var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(true);
     if (action == null) throw new Exception("No action supplied for the code fix.");
     document = await ApplyFixAsync(document, action).ConfigureAwait(true);
     //check if applying the code fix introduced any new compiler diagnostics
     var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true));
     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(await document.GetSyntaxRootAsync().ConfigureAwait(true), Formatter.Annotation, document.Project.Solution.Workspace));
         newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnosticsAsync(document).ConfigureAwait(true));
         Assert.True(false, $"Fix introduced new compiler diagnostics:\r\n{string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString()))}\r\n\r\nNew document:\r\n{(await document.GetSyntaxRootAsync().ConfigureAwait(true)).ToFullString()}\r\n");
     }
     var actual = await GetStringFromDocumentAsync(document).ConfigureAwait(true);
     Assert.Equal(newSource, actual);
 }
Пример #11
0
        private static void VerifyFixAllCodeFix(string path, string pathToExpected, DiagnosticAnalyzer diagnosticAnalyzer,
            CodeFixProvider codeFixProvider, string codeFixTitle)
        {
            var fixAllProvider = codeFixProvider.GetFixAllProvider();
            if (fixAllProvider == null)
            {
                return;
            }

            using (var workspace = new AdhocWorkspace())
            {
                var file = new FileInfo(path);
                var parseOptions = GetParseOptionsWithDifferentLanguageVersions(null, file.Extension);

                foreach (var parseOption in parseOptions)
                {
                    var document = GetDocument(file, GeneratedAssemblyName, workspace, removeAnalysisComments: true);
                    RunFixAllProvider(diagnosticAnalyzer, codeFixProvider, codeFixTitle, fixAllProvider, document, parseOption, pathToExpected);
                }
            }
        }
Пример #12
0
        private static void VerifyFixAllCodeFix(string path, string pathToExpected, DiagnosticAnalyzer diagnosticAnalyzer,
            CodeFixProvider codeFixProvider, string codeFixTitle)
        {
            var fixAllProvider = codeFixProvider.GetFixAllProvider();
            if (fixAllProvider == null)
            {
                return;
            }

            using (var workspace = new AdhocWorkspace())
            {
                var document = GetDocument(path, GeneratedAssemblyName, workspace);

                List<Diagnostic> diagnostics;
                string actualCode;
                CalculateDiagnosticsAndCode(diagnosticAnalyzer, document, out diagnostics, out actualCode);

                Assert.AreNotEqual(0, diagnostics.Count);

                var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(
                    codeFixProvider.FixableDiagnosticIds.ToImmutableHashSet(),
                    (doc, ids, ct) => Task.FromResult(
                        GetDiagnostics(document.Project.GetCompilationAsync().Result, diagnosticAnalyzer)),
                    null);
                var fixAllContext = new FixAllContext(document, codeFixProvider, FixAllScope.Document,
                    codeFixTitle,
                    codeFixProvider.FixableDiagnosticIds,
                    fixAllDiagnosticProvider,
                    CancellationToken.None);
                var codeActionToExecute = fixAllProvider.GetFixAsync(fixAllContext).Result;

                Assert.IsNotNull(codeActionToExecute);

                document = ApplyCodeFix(document, codeActionToExecute);

                CalculateDiagnosticsAndCode(diagnosticAnalyzer, document, out diagnostics, out actualCode);
                Assert.AreEqual(File.ReadAllText(pathToExpected), actualCode);
            }
        }
        internal IEnumerable<Tuple<Diagnostic, CodeFixCollection>> GetDiagnosticAndFixes(
            IEnumerable<Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            TextSpan span,
            string annotation,
            string fixAllActionId)
        {
            foreach (var diagnostic in diagnostics)
            {
                if (annotation == null)
                {
                    var fixes = new List<CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), CancellationToken.None);

                    fixer.RegisterCodeFixesAsync(context).Wait();
                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(fixer, diagnostic.Location.SourceSpan, fixes);
                        yield return Tuple.Create(diagnostic, codeFix);
                    }
                }
                else
                {
                    var fixAllProvider = fixer.GetFixAllProvider();
                    Assert.NotNull(fixAllProvider);
                    FixAllScope scope = GetFixAllScope(annotation);

                    Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync =
                        (d, diagIds, c) =>
                        {
                            var root = d.GetSyntaxRootAsync().Result;
                            var diags = testDriver.GetDocumentDiagnostics(provider, d, root.FullSpan);
                            diags = diags.Where(diag => diagIds.Contains(diag.Id));
                            return Task.FromResult(diags);
                        };

                    Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync =
                        (p, includeAllDocumentDiagnostics, diagIds, c) =>
                        {
                            var diags = includeAllDocumentDiagnostics ?
                                testDriver.GetAllDiagnostics(provider, p) :
                                testDriver.GetProjectDiagnostics(provider, p);
                            diags = diags.Where(diag => diagIds.Contains(diag.Id));
                            return Task.FromResult(diags);
                        };

                    var diagnosticIds = ImmutableHashSet.Create(diagnostic.Id);
                    var fixAllDiagnosticProvider = new FixAllCodeActionContext.FixAllDiagnosticProvider(diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
                    var fixAllContext = diagnostic.Location.IsInSource ?
                        new FixAllContext(document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None) :
                        new FixAllContext(document.Project, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None);
                    var fixAllFix = fixAllProvider.GetFixAsync(fixAllContext).WaitAndGetResult(CancellationToken.None);
                    if (fixAllFix != null)
                    {
                        var diagnosticSpan = diagnostic.Location.IsInSource ? diagnostic.Location.SourceSpan : default(TextSpan);
                        var codeFix = new CodeFixCollection(fixAllProvider, diagnosticSpan, ImmutableArray.Create(new CodeFix(document.Project, fixAllFix, diagnostic)));
                        yield return Tuple.Create(diagnostic, codeFix);
                    }
                }
            }
        }