package com.intellij.refactoring.move.moveClassesOrPackages; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ProperTextRange; import com.intellij.psi.*; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil; import com.intellij.usageView.UsageInfo; import com.intellij.util.Function; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; /** * @author ksafonov */ public abstract class MoveDirectoryWithClassesHelper { private static final ExtensionPointName<MoveDirectoryWithClassesHelper> EP_NAME = ExtensionPointName.create("com.intellij.refactoring.moveDirectoryWithClassesHelper"); public abstract void findUsages(Collection<PsiFile> filesToMove, PsiDirectory[] directoriesToMove, Collection<UsageInfo> result, boolean searchInComments, boolean searchInNonJavaFiles, Project project); public abstract boolean move(PsiFile file, PsiDirectory moveDestination, Map<PsiElement, PsiElement> oldToNewElementsMapping, List<PsiFile> movedFiles, RefactoringElementListener listener); public abstract void postProcessUsages(UsageInfo[] usages, Function<PsiDirectory, PsiDirectory> newDirMapper); public abstract void beforeMove(PsiFile psiFile); public abstract void afterMove(PsiElement newElement); public void preprocessUsages(Project project, Set<PsiFile> files, UsageInfo[] infos, PsiDirectory directory, MultiMap<PsiElement, String> conflicts) {} public static MoveDirectoryWithClassesHelper[] findAll() { return Extensions.getExtensions(EP_NAME); } public static class Default extends MoveDirectoryWithClassesHelper { @Override public void findUsages(Collection<PsiFile> filesToMove, PsiDirectory[] directoriesToMove, Collection<UsageInfo> result, boolean searchInComments, boolean searchInNonJavaFiles, Project project) { for (PsiFile file : filesToMove) { for (PsiReference reference : ReferencesSearch.search(file)) { result.add(new MyUsageInfo(reference, file)); } } for (PsiDirectory psiDirectory : directoriesToMove) { for (PsiReference reference : ReferencesSearch.search(psiDirectory)) { result.add(new MyUsageInfo(reference, psiDirectory)); } } } @Override public void postProcessUsages(UsageInfo[] usages, Function<PsiDirectory, PsiDirectory> newDirMapper) { for (UsageInfo usage : usages) { if (usage instanceof MyUsageInfo) { PsiReference reference = usage.getReference(); if (reference != null) { PsiFileSystemItem file = ((MyUsageInfo)usage).myFile; if (file instanceof PsiDirectory) { file = newDirMapper.fun((PsiDirectory)file); } reference.bindToElement(file); } } } } @Override public boolean move(PsiFile psiFile, PsiDirectory moveDestination, Map<PsiElement, PsiElement> oldToNewElementsMapping, List<PsiFile> movedFiles, RefactoringElementListener listener) { if (moveDestination.equals(psiFile.getContainingDirectory())) { return false; } MoveFileHandler.forElement(psiFile).prepareMovedFile(psiFile, moveDestination, oldToNewElementsMapping); PsiFile moving = moveDestination.findFile(psiFile.getName()); if (moving == null) { MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, moveDestination); } moving = moveDestination.findFile(psiFile.getName()); movedFiles.add(moving); listener.elementMoved(psiFile); return true; } @Override public void beforeMove(PsiFile psiFile) { } @Override public void afterMove(PsiElement newElement) { } private static class MyUsageInfo extends UsageInfo { private final @NotNull PsiFileSystemItem myFile; public MyUsageInfo(@NotNull PsiReference reference, @NotNull PsiFileSystemItem file) { super(reference); myFile = file; } @Override @Nullable public PsiReference getReference() { PsiElement element = getElement(); if (element == null) return null; final ProperTextRange rangeInElement = getRangeInElement(); PsiReference reference = rangeInElement != null ? element.findReferenceAt(rangeInElement.getStartOffset()) : element.getReference(); return reference != null && reference.getRangeInElement().equals(rangeInElement) ? reference : null; } } } }