private void addDoRefactoringAction(
     @NotNull UsageView usageView,
     @NotNull Runnable refactoringRunnable,
     @NotNull String canNotMakeString) {
   usageView.addPerformOperationAction(
       refactoringRunnable,
       getCommandName(),
       canNotMakeString,
       RefactoringBundle.message("usageView.doAction"),
       false);
 }
  protected void customizeUsagesView(
      @NotNull final UsageViewDescriptor viewDescriptor, @NotNull final UsageView usageView) {
    final Runnable refactoringRunnable =
        new Runnable() {
          @Override
          public void run() {
            Set<UsageInfo> usagesToRefactor = UsageViewUtil.getNotExcludedUsageInfos(usageView);
            final UsageInfo[] infos =
                usagesToRefactor.toArray(new UsageInfo[usagesToRefactor.size()]);
            if (ensureElementsWritable(infos, viewDescriptor)) {
              execute(infos);
            }
          }
        };

    String canNotMakeString = RefactoringBundle.message("usageView.need.reRun");

    addDoRefactoringAction(usageView, refactoringRunnable, canNotMakeString);
  }
  private void doRefactoring(@NotNull final Collection<UsageInfo> usageInfoSet) {
    for (Iterator<UsageInfo> iterator = usageInfoSet.iterator(); iterator.hasNext(); ) {
      UsageInfo usageInfo = iterator.next();
      final PsiElement element = usageInfo.getElement();
      if (element == null || !isToBeChanged(usageInfo)) {
        iterator.remove();
      }
    }

    LocalHistoryAction action = LocalHistory.getInstance().startAction(getCommandName());

    final UsageInfo[] writableUsageInfos = usageInfoSet.toArray(new UsageInfo[usageInfoSet.size()]);
    try {
      PsiDocumentManager.getInstance(myProject).commitAllDocuments();
      RefactoringListenerManagerImpl listenerManager =
          (RefactoringListenerManagerImpl) RefactoringListenerManager.getInstance(myProject);
      myTransaction = listenerManager.startTransaction();
      final Map<RefactoringHelper, Object> preparedData = new LinkedHashMap<>();
      final Runnable prepareHelpersRunnable =
          new Runnable() {
            @Override
            public void run() {
              for (final RefactoringHelper helper :
                  Extensions.getExtensions(RefactoringHelper.EP_NAME)) {
                Object operation =
                    ApplicationManager.getApplication()
                        .runReadAction(
                            new Computable<Object>() {
                              @Override
                              public Object compute() {
                                return helper.prepareOperation(writableUsageInfos);
                              }
                            });
                preparedData.put(helper, operation);
              }
            }
          };

      ProgressManager.getInstance()
          .runProcessWithProgressSynchronously(
              prepareHelpersRunnable, "Prepare ...", false, myProject);

      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  final String refactoringId = getRefactoringId();
                  if (refactoringId != null) {
                    RefactoringEventData data = getBeforeData();
                    if (data != null) {
                      data.addUsages(usageInfoSet);
                    }
                    myProject
                        .getMessageBus()
                        .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
                        .refactoringStarted(refactoringId, data);
                  }

                  try {
                    if (refactoringId != null) {
                      UndoableAction action = new UndoRefactoringAction(myProject, refactoringId);
                      UndoManager.getInstance(myProject).undoableActionPerformed(action);
                    }

                    performRefactoring(writableUsageInfos);
                  } finally {
                    if (refactoringId != null) {
                      myProject
                          .getMessageBus()
                          .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
                          .refactoringDone(refactoringId, getAfterData(writableUsageInfos));
                    }
                  }
                }
              });

      DumbService.getInstance(myProject).completeJustSubmittedTasks();

      for (Map.Entry<RefactoringHelper, Object> e : preparedData.entrySet()) {
        //noinspection unchecked
        e.getKey().performOperation(myProject, e.getValue());
      }
      myTransaction.commit();
      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  performPsiSpoilingRefactoring();
                }
              });
    } finally {
      action.finish();
    }

    int count = writableUsageInfos.length;
    if (count > 0) {
      StatusBarUtil.setStatusBarInfo(
          myProject, RefactoringBundle.message("statusBar.refactoring.result", count));
    } else {
      if (!isPreviewUsages(writableUsageInfos)) {
        StatusBarUtil.setStatusBarInfo(myProject, RefactoringBundle.message("statusBar.noUsages"));
      }
    }
  }
  @NotNull
  private static UsageViewPresentation createPresentation(
      @NotNull UsageViewDescriptor descriptor, @NotNull Usage[] usages) {
    UsageViewPresentation presentation = new UsageViewPresentation();
    presentation.setTabText(RefactoringBundle.message("usageView.tabText"));
    presentation.setTargetsNodeText(descriptor.getProcessedElementsHeader());
    presentation.setShowReadOnlyStatusAsRed(true);
    presentation.setShowCancelButton(true);
    presentation.setUsagesString(RefactoringBundle.message("usageView.usagesText"));
    int codeUsageCount = 0;
    int nonCodeUsageCount = 0;
    int dynamicUsagesCount = 0;
    Set<PsiFile> codeFiles = new HashSet<>();
    Set<PsiFile> nonCodeFiles = new HashSet<>();
    Set<PsiFile> dynamicUsagesCodeFiles = new HashSet<>();

    for (Usage usage : usages) {
      if (usage instanceof PsiElementUsage) {
        final PsiElementUsage elementUsage = (PsiElementUsage) usage;
        final PsiElement element = elementUsage.getElement();
        if (element == null) continue;
        final PsiFile containingFile = element.getContainingFile();
        if (elementUsage.isNonCodeUsage()) {
          nonCodeUsageCount++;
          nonCodeFiles.add(containingFile);
        } else {
          codeUsageCount++;
          codeFiles.add(containingFile);
        }
        if (usage instanceof UsageInfo2UsageAdapter) {
          final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo();
          if (usageInfo instanceof MoveRenameUsageInfo && usageInfo.isDynamicUsage()) {
            dynamicUsagesCount++;
            dynamicUsagesCodeFiles.add(containingFile);
          }
        }
      }
    }
    codeFiles.remove(null);
    nonCodeFiles.remove(null);
    dynamicUsagesCodeFiles.remove(null);

    String codeReferencesText = descriptor.getCodeReferencesText(codeUsageCount, codeFiles.size());
    presentation.setCodeUsagesString(codeReferencesText);
    final String commentReferencesText =
        descriptor.getCommentReferencesText(nonCodeUsageCount, nonCodeFiles.size());
    if (commentReferencesText != null) {
      presentation.setNonCodeUsagesString(commentReferencesText);
    }
    presentation.setDynamicUsagesString(
        "Dynamic "
            + StringUtil.decapitalize(
                descriptor.getCodeReferencesText(
                    dynamicUsagesCount, dynamicUsagesCodeFiles.size())));
    String generatedCodeString;
    if (codeReferencesText.contains("in code")) {
      generatedCodeString = StringUtil.replace(codeReferencesText, "in code", "in generated code");
    } else {
      generatedCodeString = codeReferencesText + " in generated code";
    }
    presentation.setUsagesInGeneratedCodeString(generatedCodeString);
    return presentation;
  }
  protected void doRun() {
    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
    final Ref<UsageInfo[]> refUsages = new Ref<>();
    final Ref<Language> refErrorLanguage = new Ref<>();
    final Ref<Boolean> refProcessCanceled = new Ref<>();
    final Ref<Boolean> anyException = new Ref<>();

    final Runnable findUsagesRunnable =
        new Runnable() {
          @Override
          public void run() {
            try {
              refUsages.set(
                  DumbService.getInstance(myProject)
                      .runReadActionInSmartMode(
                          new Computable<UsageInfo[]>() {
                            @Override
                            public UsageInfo[] compute() {
                              return findUsages();
                            }
                          }));
            } catch (UnknownReferenceTypeException e) {
              refErrorLanguage.set(e.getElementLanguage());
            } catch (ProcessCanceledException e) {
              refProcessCanceled.set(Boolean.TRUE);
            } catch (Throwable e) {
              anyException.set(Boolean.TRUE);
              LOG.error(e);
            }
          }
        };

    if (!ProgressManager.getInstance()
        .runProcessWithProgressSynchronously(
            findUsagesRunnable, RefactoringBundle.message("progress.text"), true, myProject)) {
      return;
    }

    if (!refErrorLanguage.isNull()) {
      Messages.showErrorDialog(
          myProject,
          RefactoringBundle.message(
              "unsupported.refs.found", refErrorLanguage.get().getDisplayName()),
          RefactoringBundle.message("error.title"));
      return;
    }
    if (DumbService.isDumb(myProject)) {
      DumbService.getInstance(myProject)
          .showDumbModeNotification("Refactoring is not available until indices are ready");
      return;
    }
    if (!refProcessCanceled.isNull()) {
      Messages.showErrorDialog(
          myProject,
          "Index corruption detected. Please retry the refactoring - indexes will be rebuilt automatically",
          RefactoringBundle.message("error.title"));
      return;
    }

    if (!anyException.isNull()) {
      // do not proceed if find usages fails
      return;
    }
    assert !refUsages.isNull() : "Null usages from processor " + this;
    if (!preprocessUsages(refUsages)) return;
    final UsageInfo[] usages = refUsages.get();
    assert usages != null;
    UsageViewDescriptor descriptor = createUsageViewDescriptor(usages);

    boolean isPreview = isPreviewUsages(usages);
    if (!isPreview) {
      isPreview =
          !ensureElementsWritable(usages, descriptor) || UsageViewUtil.hasReadOnlyUsages(usages);
      if (isPreview) {
        StatusBarUtil.setStatusBarInfo(
            myProject, RefactoringBundle.message("readonly.occurences.found"));
      }
    }
    if (isPreview) {
      for (UsageInfo usage : usages) {
        LOG.assertTrue(usage != null, getClass());
      }
      previewRefactoring(usages);
    } else {
      execute(usages);
    }
  }