@Override
  public void performRefactoring(UsageInfo @NotNull [] usages) {
    //try to create all directories beforehand
    try {
      //top level directories should be created even if they are empty
      for (PsiDirectory directory : myDirectories) {
        getResultDirectory(directory).findOrCreateTargetDirectory();
      }

      for (PsiDirectory directory : myNestedDirsToMove.keySet()) {
        myNestedDirsToMove.get(directory).findOrCreateTargetDirectory();
      }

      for (VirtualFile virtualFile : myFilesToMove.keySet()) {
        myFilesToMove.get(virtualFile).findOrCreateTargetDirectory();
      }

      DumbService.getInstance(myProject).completeJustSubmittedTasks();

      final List<PsiFile> movedFiles = new ArrayList<>();
      final Map<PsiElement, PsiElement> oldToNewElementsMapping = new HashMap<>();
      for (VirtualFile virtualFile : myFilesToMove.keySet()) {
        PsiFile file = myManager.findFile(virtualFile);
        if (file == null) continue;
        for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) {
          helper.beforeMove(file);
        }
        final RefactoringElementListener listener = getTransaction().getElementListener(file);
        final PsiDirectory moveDestination = myFilesToMove.get(virtualFile).getTargetDirectory();

        for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) {
          boolean processed = helper.move(file, moveDestination, oldToNewElementsMapping, movedFiles, listener);
          if (processed) {
            break;
          }
        }
      }
      for (PsiElement newElement : oldToNewElementsMapping.values()) {
        for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) {
          helper.afterMove(newElement);
        }
      }

      // fix references in moved files to outer files
      for (PsiFile movedFile : movedFiles) {
        MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile);
        FileReferenceContextUtil.decodeFileReferences(movedFile);
      }

      myNonCodeUsages = ContainerUtil.filterIsInstance(usages, NonCodeUsageInfo.class).toArray(NonCodeUsageInfo[]::new);
      List<UsageInfo> usagesToRetarget = new SmartList<>(usages);
      for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) {
        helper.retargetUsages(usagesToRetarget, oldToNewElementsMapping);
      }
      List<UsageInfo> postProcessUsages = new SmartList<>(usages);
      myNestedDirsToMove.entrySet().stream().filter(entry -> entry.getValue().getTargetDirectory() != null)
        .map(entry -> new MoveDirectoryUsageInfo(entry.getKey(), entry.getValue().getTargetDirectory()))
        .forEach(postProcessUsages::add);
      for (MoveDirectoryWithClassesHelper helper : MoveDirectoryWithClassesHelper.findAll()) {
        helper.postProcessUsages(postProcessUsages.toArray(UsageInfo.EMPTY_ARRAY), dir -> getResultDirectory(dir).findOrCreateTargetDirectory());
      }
      for (PsiDirectory directory : myDirectories) {
        if (!isUsedInTarget(directory)) {
          directory.delete();
        }
      }

      for (PsiDirectory directory : myNestedDirsToMove.keySet()) {
        if (directory.isValid() && directory.getChildren().length == 0) {
          directory.delete();
        }
      }

    }
    catch (IncorrectOperationException e) {
      myNonCodeUsages = new NonCodeUsageInfo[0];
      RefactoringUIUtil.processIncorrectOperation(myProject, e);
    }
  }
@Override
  public void performRefactoring(UsageInfo @NotNull [] usages)