Page Comparison - 4.14 Fix in Scope (R8) (v.1 vs v.2)

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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:

Code Block
csharp
csharp
var cleanupProfile = BulkCodeCleanupActionBuilderBase.CreateProfile(profile => profile.SetSetting(ReplaceByVar.USE_VAR_DESCRIPTOR, new ReplaceByVar.Options()
      {
        BehavourStyle = ReplaceByVar.BehavourStyle.CAN_CHANGE_TO_EXPLICIT,
        ForeachVariableStyle = ReplaceByVar.ForeachVariableStyle.ALWAYS_EXPLICIT,
        LocalVariableStyle = ReplaceByVar.LocalVariableStyle.ALWAYS_EXPLICIT
      }));
      var projectFile = myProvider.SourceFile.ToProjectFile();
      Assertion.AssertNotNull(projectFile, "projectFile must not be null");
      return BulkCodeCleanupContextActionBuilder.CreateByPsiLanguage<CSharpLanguage>(cleanupProfile, "Use explicit type everywhere", projectFile.GetSolution(), this)
        .CreateBulkActions(projectFile, IntentionsAnchors.ContextActionsAnchor, IntentionsAnchors.ContextActionsAnchorPosition);

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.

When it comes to quick-fixes such as the OptimizeImportsFix, the infrastructure is a bit more complicated. If you examine the JetBrains.ReSharper.Intentions.QuickFixes.Bulk, you will find a hierarchy stemming from BulkQuickFixBase that is useful in implementing, e.g., a global Quick-Fix change under a single Psi transaction.

Thus, in order to support the Fix in Scope mechanic for a quick-fix you typically need to do the following:

  • Implement the quick-fix, ensuring that its ExecutePsiTransaction() method is sufficiently global to be applicable to, e.g., a single file. Please note that ExecutePsiTransaction() will only be called in the singular case, whereas the Fix in Scope mechanic cases will be called elsewhere.
  • Prepare an action that processes a single file with your chosen logic. It makes sense to move the implementation to a static member. Here’s an example:
    Code Block
    csharp
    csharp
    var solution = projectFile.GetSolution();
    var psiFiles = solution.GetComponent<IPsiFiles>();
    Action<IDocument, IPsiSourceFile, IProgressIndicator> processFileAction = 
      (document, psiSourceFile, indicator) =>
    {
      var csharpFiles = psiFiles.GetPsiFiles<CSharpLanguage>(psiSourceFile).OfType<ICSharpFile>();
      foreach (var csharpFile in csharpFiles)
      {
        UsingUtil.RemoveUnusedImports(document, csharpFile);
      }
    };
    
  • Create a BulkQuickFixWithCommonTransactionBuilder, which also happens to accept a predicate that you can use to filter out files you do not want to process:
    Code Block
    csharp
    csharp
    var acceptProjectFilePredicate = BulkItentionsBuilderEx.CreateAcceptFilePredicateByPsiLanaguage<CSharpLanguage>(solution);
      var builder = new BulkQuickFixWithCommonTransactionBuilder(
        this, solution, RemoveUnusedDirectivesString, processFileAction, acceptProjectFilePredicate);
    
  • Finally, use the builder to create all the actions in bulk:
    Code Block
    csharp
    csharp
    return builder.CreateBulkActions(projectFile, 
      IntentionsAnchors.QuickFixesAnchor, IntentionsAnchors.QuickFixesAnchorPosition);