4.14 Fix in Scope (R8)

Skip to end of metadata
Go to start of metadata

The Fix in Scope mechanic allows the user of a Quick Fix or a Context Action to affect either a single file or all the files present in a folder, project, or solution as illustrated below:

This mechanic is available for both Quick-Fix actions as well as context actions that are part of Code Cleanup.

In the case of a context action (such as ReSharper’s VarToTypeAction), the implementation of additional items happens in the CreateBulbItems() method. A context action can, of course, create all the required bulb items directly, but it can also use elements from the JetBrains.ReSharper.Intentions.Bulk namespace to simplify the process.

In the case of VarToTypeAction, ReSharper uses the BulkCodeCleanupContextActionBuilder to construct all the requisite items as follows:

The exact mechanic of creating bulk context actions can be found in BulkIntentionsBuilderEx.CreateBulkActions(). It is a rather simple process that creates actions for the current caret position, then (if applicable) the current file, project folder, project or the whole solution.

Quick fixes have a similar workflow - create a builder and in your call CreateBulbItems method, return builder.CreateBulkActions(). The builder to use for quick-fixes is called BulkQuickFixWithCommonTransactionBuilder, and can be used in a couple of ways. As of ReSharper 8.2, it is internally used for quick-fixes such as OptimizeImportsFix, which removes all redundant C# "using" statements in a file, and optionally, folder, project and solution. In other words, the default implementation of the quick fix operates on the whole file, rather than the current text caret position.

As such, it has a slightly awkward API, and requires a little extra work to support caret position as well as file, folder, project and solution scope. The constructor has two overloads. The first takes in a QuickFixBase that represents the "in file" scope, as well as a delegate to operate on files in folder, project and solution scope, and a predicate to see which file in scope it should apply to (e.g. just C# files). The second overload takes two QuickFixBase instances. One is for the caret position, and the second is for the "in file" scope. It also requires the delegate and predicate.

The awkward part of this is that to support both "at caret" and "in file" scope, you need to implement two classes that derive from QuickFixBase. Fortunately, this is mostly boiler plate and can be implemented using the same delegate passed in for folder, project and solution scope. You need just one class that looks something like this:

So, if your quick-fix operates on just the caret position, you should do something like this:

  • Implement the quick-fix. The ExecutePsiTransaction() method just fixes the issue at the text caret position
  • Prepare an action that processes a single file with your chosen logic. Here’s an example:
  • Create an instance of the BulkQuickFixInFileWithCommonPsiTransaction class defined above (make sure to add this class to your project), passing in an instance of the processFileAction delegate
  • Create a BulkQuickFixWithCommonTransactionBuilder, which also happens to accept a predicate that you can use to filter out files you do not want to process:
  • Finally, use the builder to create all the actions in bulk:

And if your quick-fix operates on the whole file by default (e.g. remove all redundant using statements):

  • Implement the quick-fix. The ExecutePsiTransaction() method fixes the issue across the whole file
  • Prepare an action that processes a single file with your chosen logic. The example here is the same as above:
  • Create a BulkQuickFixWithCommonTransactionBuilder, together with a predicate to indicate which files you want to process. Note that we call a different constructor here, and pass in this as the quick fix to operate by default. This overload treats this quick-fix as the "in file" scope quick fix, and assumes the "at caret position" quick-fix isn't required:
  • Finally, use the builder to create all the actions in bulk: