private void performFileProcessing(@NotNull VirtualFile file) {
      // Using the same groupId for several file-processing actions allows undoing [format + optimize imports + rearrange code + cleanup code] in one shot.
      // Using the same groupId for *all* processed files makes this a single undoable action for all processed files.
      // See docs for #setProcessAllFilesAsSingleUndoRedoCommand(boolean)
      String groupId = myProcessAllFilesAsSingleUndoStep
                       ? AbstractLayoutCodeProcessor.this.toString()
                       : AbstractLayoutCodeProcessor.this.toString() + file.hashCode();
      for (AbstractLayoutCodeProcessor processor : myProcessors) {
        FutureTask<Boolean> writeTask;
        if (processor.needsReadActionToPrepareTask()) {
          writeTask = ReadAction.nonBlocking(() -> {
              PsiFile psiFile = PsiManager.getInstance(myProject).findFile(file);
              return psiFile != null ? processor.prepareTask(psiFile, myProcessChangedTextOnly) : null;
            })
            .executeSynchronously();
        }
        else {
          PsiFile psiFile = ReadAction.compute(() -> PsiManager.getInstance(myProject).findFile(file));
          writeTask = psiFile != null ? processor.prepareTask(psiFile, myProcessChangedTextOnly) : null;
        }
        if (writeTask == null) continue;

        ProgressIndicatorProvider.checkCanceled();

        WriteCommandAction.writeCommandAction(myProject)
          .withName(myCommandName)
          .withGroupId(groupId)
          .shouldRecordActionForActiveDocument(myProcessAllFilesAsSingleUndoStep)
          .run(() -> writeTask.run());

        checkStop(writeTask, file);
      }
    }
private void performFileProcessing(@NotNull VirtualFile file)