예제 #1
0
 private FixAllContext.DiagnosticProvider GetDiagnosticProvider(FixAllContext context)
 {
     // This is a hack to get the DiagnosticProvider. But it's not working in newer versions of Roslyn.
     try
     {
         object fixAllState = GetNonpublicProperty(context, "State"); // returns an internal type FixAllState
         FixAllContext.DiagnosticProvider diagnosticProvider = (FixAllContext.DiagnosticProvider)GetNonpublicProperty(fixAllState, "DiagnosticProvider");
         return(diagnosticProvider);
     }
     catch
     {
         return(null);
     }
 }
예제 #2
0
        private FixAllContext GetNextStageFixAllContext(FixAllContext originalContext, Solution revisedSolution)
        {
            FixAllContext.DiagnosticProvider diagnosticProvider = GetDiagnosticProvider(originalContext);
            if (diagnosticProvider == null)
            {
                return(null); // Roslyn changed -- won't be able to do multi-stage work, but analyzer should still be able to perform single stage
            }
            FixAllContext revisedContext;

            if (originalContext.Document != null)
            {
                var id = originalContext.Document.Id;
                var documentInRevised = revisedSolution.GetDocument(id);
                revisedContext = new FixAllContext(documentInRevised, originalContext.CodeFixProvider, originalContext.Scope, originalContext.CodeActionEquivalenceKey, originalContext.DiagnosticIds, diagnosticProvider, originalContext.CancellationToken);
            }
            else
            {
                var id = originalContext.Project.Id;
                var projectInRevised = revisedSolution.GetProject(id);
                revisedContext = new FixAllContext(projectInRevised, originalContext.CodeFixProvider, originalContext.Scope, originalContext.CodeActionEquivalenceKey, originalContext.DiagnosticIds, diagnosticProvider, originalContext.CancellationToken);
            }
            return(revisedContext);
        }
예제 #3
0
        private static async Task <Project> FixAllAnalyerDiagnosticsInScopeAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int?codeFixIndex, Project project, 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, project.Documents.ToArray(), 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");
                }

                Diagnostic firstDiagnostic = null;
                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(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        firstDiagnostic = diagnostic;
                        equivalenceKey  = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                if (firstDiagnostic == null)
                {
                    return(project);
                }

                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 = 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(project.GetDocument(firstDiagnostic.Location.SourceTree), codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(project);
                }

                var fixedProject = await ApplyFixAsync(project, action, cancellationToken).ConfigureAwait(false);

                if (fixedProject != project)
                {
                    done = false;

                    project = await RecreateProjectDocumentsAsync(fixedProject, cancellationToken).ConfigureAwait(false);
                }
            }while (!done);

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

            return(project);
        }
예제 #4
0
        private async Task <Project> FixAllAnalyerDiagnosticsInScopeAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, ImmutableArray <CodeFixProvider> codeFixProviders, int?codeFixIndex, string codeFixEquivalenceKey, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken)
        {
            var expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

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

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, CompilerDiagnostics, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

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

                verifier.False(--numberOfIterations < -1, "The upper limit for the number of fix all iterations was exceeded");

                Diagnostic      firstDiagnostic          = null;
                CodeFixProvider effectiveCodeFixProvider = null;
                string          equivalenceKey           = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List <(CodeAction, CodeFixProvider)>();

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

                        var context = new CodeFixContext(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add((a, codeFixProvider)), cancellationToken);
                        await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    }

                    var actionToApply = TryGetCodeActionToApply(actions.Select(a => a.Item1).ToList(), codeFixIndex, codeFixEquivalenceKey, verifier);
                    if (actionToApply != null)
                    {
                        firstDiagnostic          = diagnostic;
                        effectiveCodeFixProvider = actions.SingleOrDefault(a => a.Item1 == actionToApply).Item2;
                        equivalenceKey           = actionToApply.EquivalenceKey;
                        break;
                    }
                }

                var fixAllProvider = effectiveCodeFixProvider?.GetFixAllProvider();
                if (firstDiagnostic == null || fixAllProvider == null)
                {
                    numberOfIterations++;
                    break;
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

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

                var analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                var compilerDiagnosticIds = codeFixProviders.SelectMany(codeFixProvider => codeFixProvider.FixableDiagnosticIds).Where(x => x.StartsWith("CS", StringComparison.Ordinal) || x.StartsWith("BC", StringComparison.Ordinal));
                var disabledDiagnosticIds = project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                var relevantIds           = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                var fixAllContext         = new FixAllContext(project.GetDocument(firstDiagnostic.Location.SourceTree), effectiveCodeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(project);
                }

                var fixedProject = await ApplyFixAsync(project, action, cancellationToken).ConfigureAwait(false);

                if (fixedProject != project)
                {
                    done = false;

                    project = await RecreateProjectDocumentsAsync(fixedProject, verifier, cancellationToken).ConfigureAwait(false);
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                verifier.Equal(expectedNumberOfIterations, expectedNumberOfIterations - numberOfIterations, $"Expected '{expectedNumberOfIterations}' iterations but found '{expectedNumberOfIterations - numberOfIterations}' iterations.");
            }
            else
            {
                verifier.True(numberOfIterations >= 0, "The upper limit for the number of code fix iterations was exceeded");
            }

            return(project);
        }
        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);
        }