@Override
  protected void performRefactoring(UsageInfo @NotNull [] _usages) {
    try {
      ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
      progressIndicator.setIndeterminate(myElementsToMove.length <= 1); // only show progress when moving multiple elements
      progressIndicator.setFraction(0.0);
      List<PsiElement> toChange = new ArrayList<>();
      Collections.addAll(toChange, myElementsToMove);

      PsiDirectory newParent = myNewParent;

      List<UsageInfo> codeUsages = new ArrayList<>();
      List<NonCodeUsageInfo> nonCodeUsages = new ArrayList<>();
      for (UsageInfo usage : _usages) {
        if (usage instanceof NonCodeUsageInfo) {
          nonCodeUsages.add((NonCodeUsageInfo)usage);
        }
        else {
          codeUsages.add(usage);
        }
      }

      //keep hard references to PSI and AST to prevent collecting the object between saving references and restoring
      Map<PsiFile, FileASTNode> movingFiles = new HashMap<>();

      final Map<PsiElement, PsiElement> oldToNewMap = new HashMap<>();
      if (mySearchForReferences) {
        for (PsiElement element : toChange) {
          if (element instanceof PsiDirectory) {
            encodeDirectoryFiles(element, movingFiles);
          }
          else if (element instanceof PsiFile) {
            movingFiles.put((PsiFile)element, ((PsiFile)element).getNode());
            FileReferenceContextUtil.encodeFileReferences(element);
          }
        }
      }

      List<RefactoringElementListener> listeners = ContainerUtil.map(myElementsToMove, item -> getTransaction().getElementListener(item));

      List<Runnable> notifyListeners = new ArrayList<>();
      List<SmartPsiElementPointer<PsiFile>> movedFiles = new ArrayList<>();
      for (int i = 0; i < myElementsToMove.length; i++) {
        PsiElement element = toChange.get(i);
        progressIndicator.setFraction((double)i / myElementsToMove.length);
        if (element instanceof PsiDirectory directory) {
          progressIndicator.setText2(directory.getVirtualFile().getPresentableUrl());
          MoveFilesOrDirectoriesUtil.doMoveDirectory(directory, newParent);
          for (PsiElement psiElement : directory.getChildren()) {
            processDirectoryFiles(movedFiles, oldToNewMap, psiElement);
          }
        }
        else if (element instanceof PsiFile movedFile) {
          progressIndicator.setText2(movedFile.getVirtualFile().getPresentableUrl());
          MoveFileHandler.forElement(movedFile).prepareMovedFile(movedFile, newParent, oldToNewMap);

          PsiFile moving = newParent.findFile(movedFile.getName());
          if (moving == null) {
            MoveFilesOrDirectoriesUtil.doMoveFile(movedFile, newParent);
          }
          moving = newParent.findFile(movedFile.getName());
          if (moving != null) {
            movedFiles.add(SmartPointerManager.createPointer(moving));
          }
        }

        if (element.isValid()) {
          RefactoringElementListener listener = listeners.get(i);
          SmartPsiElementPointer<PsiElement> pointer = SmartPointerManager.createPointer(element);
          notifyListeners.add(() -> {
            PsiElement restored = pointer.getElement();
            if (restored != null) {
              listener.elementMoved(restored);
            }
          });
        }
      }
      progressIndicator.setText2("");
      progressIndicator.setFraction(1.0);
      // sort by offset descending to process correctly several usages in one PsiElement [IDEADEV-33013]
      UsageInfo[] usages = codeUsages.toArray(UsageInfo.EMPTY_ARRAY);
      CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages);

      DumbService.getInstance(myProject).completeJustSubmittedTasks();

      // fix references in moved files to outer files
      for (SmartPsiElementPointer<PsiFile> pointer : movedFiles) {
        PsiFile movedFile = pointer.getElement();
        if (movedFile != null) {
          MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile);
          if (mySearchForReferences) FileReferenceContextUtil.decodeFileReferences(movedFile);
        }
      }

      retargetUsages(usages, oldToNewMap);

      for (Map.Entry<PsiFile, List<UsageInfo>> entry : myFoundUsages.entrySet()) {
        // Before retargeting sort usages by start offset to get consistent results
        ContainerUtil.sort(entry.getValue(), Comparator.comparingInt(o -> {
          PsiElement element = o.getElement();
          if (element == null) return -1;
          return element.getTextRange().getStartOffset();
        }));
        MoveFileHandler.forElement(entry.getKey()).retargetUsages(entry.getValue(), oldToNewMap);
      }

      myNonCodeUsages = nonCodeUsages.toArray(new NonCodeUsageInfo[0]);

      afterMove(movedFiles, notifyListeners);

      Reference.reachabilityFence(movingFiles);
    }
    catch (IncorrectOperationException e) {
      Throwable cause = e.getCause();
      if (cause instanceof IOException) {
        LOG.info(e);
        ApplicationManager.getApplication().invokeLater(
          () -> Messages.showMessageDialog(myProject, cause.getMessage(), RefactoringBundle.message("error.title"), Messages.getErrorIcon()));
      }
      else {
        LOG.error(e);
      }
    }
  }
@Override
  protected void performRefactoring(UsageInfo @NotNull [] _usages)