docs/analyzers/FixAllProvider.md
This document covers the following:
DiagnosticAnalyzer that reports diagnostics.CodeFixProvider that provides code fixes for compiler and/or analyzer diagnostics.CodeRefactoringProvider that provides source code refactorings.CodeFixProvider.RegisterCodeFixesAsync that performs a code fix OR an action registered by CodeRefactoringProvider.ComputeRefactoringsAsync that performs a code refactoring.EquivalenceKey values and were generated by the same code fixer or refactoring.FixAllProvider that provides a FixAll occurrences code fix. A FixAll provider is associated with a corresponding code fixer by CodeFixProvider.GetFixAllProvider method.FixAllProvider.GetFixAsync, that fixes all or multiple occurrences of diagnostics fixed by the corresponding code fixer, within a given FixAllScope.In layman terms, a FixAll occurrences code fix means: I have a code fix 'C', that fixes a specific instance of diagnostic 'D' in my source and I want to apply this fix to all instances of 'D' across a broader scope, such as a document or a project or the entire solution.
In more technical terms: Given a particular code action registered by a code fixer to fix one or more diagnostics, a corresponding code action registered by its FixAll provider, that applies the original trigger code action across a broader scope (such as a document/project/solution) to fix multiple instances of such diagnostics.
Following steps are used to compute a FixAll occurrences code fix:
FixAllScope from this set. In the Visual Studio IDE, this is done by clicking on the scope hyperlink in the preview dialog.FixAllProvider.GetFixAsync to compute the FixAll occurrences code fix.Follow the below steps to add FixAll support to your code fixer:
CodeFixProvider.GetFixAllProvider method and return a non-null instance of a FixAllProvider. You may either use our built-in FixAllProvider or implement a custom FixAllProvider. See the following sections in this document for determining the correct approach for your fixer.Each unique equivalence key for a code fixer defines a unique equivalence class of code actions. Equivalence key of the trigger code action is part of the FixAllContext and is used to determine the FixAll occurrences code fix.
Normally, you can use the 'title' of the code action as the equivalence key. However, there are cases where you may desire to have different values. Let us take an example to get a better understanding.
Let us consider the C# SimplifyTypeNamesCodeFixProvider that registers multiple code actions and also has FixAll support. This code fixer offers fixes to simplify the following expressions:
this expressions of the form 'this.x' to 'x'.This fixer needs the following semantics for the corresponding FixAll occurrences code fixes:
this expression simplification: Fix all should simplify all this expressions, regardless of the member being accessed (this.x, this.y, this.z, etc.).It uses the below equivalence keys for its registered code actions to get the desired FixAll behavior:
this expression simplification: Generic resource string "Simplify this expression", which explicitly excludes the contents of the node being simplified.Note that 'this expression simplification' fix requires a different kind of an equivalence class from the other two simplifications. See method GetCodeActionId for the actual implementation.
To summarize, use the equivalence key that best suits the category of fixes to be applied as part of a FixAll operation.
When multiple fixes need to be applied to documents, there are various ways to do it:
WellKnownFixAllProviders.BatchFixerFixAllProvider that simply generates the file once if there were any diagnostics at all.Since there are various ways of fixing all issues, we've implemented a framework and provided the one general implementation that we think is useful in many cases.
We provide a default BatchFixAllProvider implementation of a FixAll provider that uses the underlying code fixer to compute the FixAll occurrences code fixes.
To use the batch fixer, you should return the static WellKnownFixAllProviders.BatchFixer instance in the CodeFixProvider.GetFixAllProvider override.
NOTE: See the following section on 'Limitations of the BatchFixer' to determine if the batch fixer can be used by your code fixer.
Given a trigger diagnostic, a trigger code action, the underlying code fixer and the FixAll scope, the BatchFixer computes FixAll occurrences code fix with the following steps:
ApplyChangesOperation present within the individual code actions, other types of operations are ignored.The BatchFixer is designed for a common category of fixers where fix spans for diagnostics don't overlap with each other. For example, assume there is a diagnostic that spans a particular expression, and a fixer that fixes that expression. If all the instances of this diagnostic are guaranteed to have non-overlapping spans, then their fixes can be computed independently and this batch of fixes can be subsequently merged together.
However, there are cases where the BatchFixer might not work for your fixer. Following are some such examples:
ApplyChangesOperation. BatchFixer ignores such operations and hence may produce unexpected results.For cases where you cannot use the BatchFixer, you must implement your own FixAllProvider. It is recommended that you create a singleton instance of the FixAll provider, instead of creating a new instance for every CodeFixProvider.GetFixAllProvider invocation.
Following guidelines should help in the implementation:
FixAllContext. You may use the set of 'GetXXXDiagnosticsAsync' methods on the FixAllContext to compute the diagnostics to be fixed. You must return a single code action that fixes all the diagnostics in the given FixAll scope.FixableDiagnosticIds. Generally, you need not override this method. However, you may do so if you wish to support FixAll only for a subset of these ids.See DeclarePublicAPIFix for an example implementation of a custom FixAllProvider.