protected void previewRefactoring(@NotNull UsageInfo[] usages) {
    if (ApplicationManager.getApplication().isUnitTestMode()) {
      if (!PREVIEW_IN_TESTS)
        throw new RuntimeException(
            "Unexpected preview in tests: "
                + StringUtil.join(usages, info -> info.toString(), ", "));
      ensureElementsWritable(usages, createUsageViewDescriptor(usages));
      execute(usages);
      return;
    }
    final UsageViewDescriptor viewDescriptor = createUsageViewDescriptor(usages);
    final PsiElement[] elements = viewDescriptor.getElements();
    final PsiElement2UsageTargetAdapter[] targets = PsiElement2UsageTargetAdapter.convert(elements);
    Factory<UsageSearcher> factory =
        new Factory<UsageSearcher>() {
          @Override
          public UsageSearcher create() {
            return new UsageInfoSearcherAdapter() {
              @Override
              public void generate(@NotNull final Processor<Usage> processor) {
                ApplicationManager.getApplication()
                    .runReadAction(
                        new Runnable() {
                          @Override
                          public void run() {
                            for (int i = 0; i < elements.length; i++) {
                              elements[i] = targets[i].getElement();
                            }
                            refreshElements(elements);
                          }
                        });
                processUsages(processor, myProject);
              }

              @Override
              protected UsageInfo[] findUsages() {
                return BaseRefactoringProcessor.this.findUsages();
              }
            };
          }
        };

    showUsageView(viewDescriptor, factory, usages);
  }
  private void showUsageView(
      @NotNull final UsageViewDescriptor viewDescriptor,
      final Factory<UsageSearcher> factory,
      @NotNull final UsageInfo[] usageInfos) {
    UsageViewManager viewManager = UsageViewManager.getInstance(myProject);

    final PsiElement[] initialElements = viewDescriptor.getElements();
    final UsageTarget[] targets = PsiElement2UsageTargetAdapter.convert(initialElements);
    final Ref<Usage[]> convertUsagesRef = new Ref<>();
    if (!ProgressManager.getInstance()
        .runProcessWithProgressSynchronously(
            new Runnable() {
              @Override
              public void run() {
                ApplicationManager.getApplication()
                    .runReadAction(
                        new Runnable() {
                          @Override
                          public void run() {
                            convertUsagesRef.set(UsageInfo2UsageAdapter.convert(usageInfos));
                          }
                        });
              }
            },
            "Preprocess usages",
            true,
            myProject)) return;

    if (convertUsagesRef.isNull()) return;

    final Usage[] usages = convertUsagesRef.get();

    final UsageViewPresentation presentation = createPresentation(viewDescriptor, usages);

    final UsageView usageView = viewManager.showUsages(targets, usages, presentation, factory);
    customizeUsagesView(viewDescriptor, usageView);
  }
 @NotNull
 protected Collection<? extends PsiElement> getElementsToWrite(
     @NotNull UsageViewDescriptor descriptor) {
   return Arrays.asList(descriptor.getElements());
 }
  @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;
  }