diff --git a/plugin/src/main/java/com/intellij/java/impl/refactoring/copy/CopyClassesHandler.java b/plugin/src/main/java/com/intellij/java/impl/refactoring/copy/CopyClassesHandler.java index e5fe65a5cf..4226c53541 100644 --- a/plugin/src/main/java/com/intellij/java/impl/refactoring/copy/CopyClassesHandler.java +++ b/plugin/src/main/java/com/intellij/java/impl/refactoring/copy/CopyClassesHandler.java @@ -30,11 +30,13 @@ import consulo.language.editor.refactoring.copy.CopyHandler; import consulo.language.editor.refactoring.copy.CopyHandlerDelegateBase; import consulo.language.editor.refactoring.localize.RefactoringLocalize; +import consulo.language.editor.refactoring.util.CommonRefactoringUtil; import consulo.language.editor.util.EditorHelper; import consulo.language.psi.*; import consulo.language.psi.scope.LocalSearchScope; import consulo.language.psi.search.ReferencesSearch; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.module.content.ProjectRootManager; import consulo.project.Project; @@ -54,531 +56,566 @@ @ExtensionImpl(order = "before copyFilesOrDirectories") public class CopyClassesHandler extends CopyHandlerDelegateBase { - private static final Logger LOG = Logger.getInstance(CopyClassesHandler.class); - - @Override - @RequiredReadAction - public boolean forbidToClone(PsiElement[] elements, boolean fromUpdate) { - final Map fileMap = convertToTopLevelClasses(elements, fromUpdate, null, null); - if (fileMap != null && fileMap.size() == 1) { - final PsiClass[] psiClasses = fileMap.values().iterator().next(); - return psiClasses != null && psiClasses.length > 1; - } - return true; - } - - @Override - @RequiredReadAction - public boolean canCopy(PsiElement[] elements, boolean fromUpdate) { - return canCopyClass(fromUpdate, elements); - } - - @RequiredReadAction - public static boolean canCopyClass(PsiElement... elements) { - return canCopyClass(false, elements); - } - - @RequiredReadAction - public static boolean canCopyClass(boolean fromUpdate, PsiElement... elements) { - if (fromUpdate && elements.length > 0 && elements[0] instanceof PsiDirectory) return true; - return convertToTopLevelClasses(elements, fromUpdate, null, null) != null; - } - - @Nullable - @RequiredReadAction - private static Map convertToTopLevelClasses( - final PsiElement[] elements, - final boolean fromUpdate, - String relativePath, - Map relativeMap - ) { - final Map result = new HashMap<>(); - for (PsiElement element : elements) { - final PsiElement navigationElement = element.getNavigationElement(); - LOG.assertTrue(navigationElement != null, element); - final PsiFile containingFile = navigationElement.getContainingFile(); - if (!(containingFile instanceof PsiClassOwner && JavaProjectRootsUtil.isOutsideSourceRoot(containingFile))) { - PsiClass[] topLevelClasses = getTopLevelClasses(element); - if (topLevelClasses == null) { - if (element instanceof PsiDirectory directory) { - if (!fromUpdate) { - final String name = directory.getName(); - final String path = relativePath != null ? (relativePath.length() > 0 ? (relativePath + "/") : "") + name : null; - final Map map = convertToTopLevelClasses(element.getChildren(), fromUpdate, path, relativeMap); - if (map == null) return null; - for (Map.Entry entry : map.entrySet()) { - fillResultsMap(result, entry.getKey(), entry.getValue()); - } - } - continue; - } - if (!(element instanceof PsiFileSystemItem)) return null; + private static final Logger LOG = Logger.getInstance(CopyClassesHandler.class); + + @Override + @RequiredReadAction + public boolean forbidToClone(PsiElement[] elements, boolean fromUpdate) { + Map fileMap = convertToTopLevelClasses(elements, fromUpdate, null, null); + if (fileMap != null && fileMap.size() == 1) { + PsiClass[] psiClasses = fileMap.values().iterator().next(); + return psiClasses != null && psiClasses.length > 1; } - fillResultsMap(result, containingFile, topLevelClasses); - if (relativeMap != null) { - relativeMap.put(containingFile, relativePath); - } - } - } - if (result.isEmpty()) { - return null; - } else { - boolean hasClasses = false; - for (PsiClass[] classes : result.values()) { - if (classes != null) { - hasClasses = true; - break; - } - } - return hasClasses ? result : null; + return true; } - } - - @Nullable - private static String normalizeRelativeMap(Map relativeMap) { - String vector = null; - for (String relativePath : relativeMap.values()) { - if (vector == null) { - vector = relativePath; - } else if (vector.startsWith(relativePath + "/")) { - vector = relativePath; - } else if (!relativePath.startsWith(vector + "/") && !relativePath.equals(vector)) { - return null; - } + + @Override + @RequiredReadAction + public boolean canCopy(PsiElement[] elements, boolean fromUpdate) { + return canCopyClass(fromUpdate, elements); } - if (vector != null) { - for (PsiFile psiFile : relativeMap.keySet()) { - final String path = relativeMap.get(psiFile); - relativeMap.put(psiFile, path.equals(vector) ? "" : path.substring(vector.length() + 1)); - } + + @RequiredReadAction + public static boolean canCopyClass(PsiElement... elements) { + return canCopyClass(false, elements); } - return vector; - } - - private static void fillResultsMap(Map result, PsiFile containingFile, PsiClass[] topLevelClasses) { - PsiClass[] classes = result.get(containingFile); - if (topLevelClasses != null) { - if (classes != null) { - topLevelClasses = ArrayUtil.mergeArrays(classes, topLevelClasses, PsiClass.ARRAY_FACTORY); - } - result.put(containingFile, topLevelClasses); - } else { - result.put(containingFile, classes); + + @RequiredReadAction + public static boolean canCopyClass(boolean fromUpdate, PsiElement... elements) { + if (fromUpdate && elements.length > 0 && elements[0] instanceof PsiDirectory) { + return true; + } + return convertToTopLevelClasses(elements, fromUpdate, null, null) != null; } - } - - @RequiredReadAction - public void doCopy(PsiElement[] elements, PsiDirectory defaultTargetDirectory) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass"); - final HashMap relativePathsMap = new HashMap<>(); - final Map classes = convertToTopLevelClasses(elements, false, "", relativePathsMap); - assert classes != null; - if (defaultTargetDirectory == null) { - final PsiFile psiFile = classes.keySet().iterator().next(); - defaultTargetDirectory = psiFile.getContainingDirectory(); - LOG.assertTrue(defaultTargetDirectory != null, psiFile); - } else { - Project project = defaultTargetDirectory.getProject(); - VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex() - .getSourceRootForFile(defaultTargetDirectory.getVirtualFile()); - if (sourceRootForFile == null) { - final List files = new ArrayList<>(); + + @Nullable + @RequiredReadAction + private static Map convertToTopLevelClasses( + PsiElement[] elements, + boolean fromUpdate, + String relativePath, + Map relativeMap + ) { + Map result = new HashMap<>(); for (PsiElement element : elements) { - PsiFile containingFile = element.getContainingFile(); - if (containingFile != null) { - files.add(containingFile); - } - else if (element instanceof PsiDirectory) { - files.add(element); - } - } - CopyFilesOrDirectoriesHandler.copyAsFiles(files.toArray(new PsiElement[files.size()]), defaultTargetDirectory, project); - return; - } + PsiElement navigationElement = element.getNavigationElement(); + LOG.assertTrue(navigationElement != null, element); + PsiFile containingFile = navigationElement.getContainingFile(); + if (!(containingFile instanceof PsiClassOwner && JavaProjectRootsUtil.isOutsideSourceRoot(containingFile))) { + PsiClass[] topLevelClasses = getTopLevelClasses(element); + if (topLevelClasses == null) { + if (element instanceof PsiDirectory directory) { + if (!fromUpdate) { + String name = directory.getName(); + String path = relativePath != null ? (relativePath.length() > 0 ? (relativePath + "/") : "") + name : null; + Map map = convertToTopLevelClasses(element.getChildren(), fromUpdate, path, relativeMap); + if (map == null) { + return null; + } + for (Map.Entry entry : map.entrySet()) { + fillResultsMap(result, entry.getKey(), entry.getValue()); + } + } + continue; + } + if (!(element instanceof PsiFileSystemItem)) { + return null; + } + } + fillResultsMap(result, containingFile, topLevelClasses); + if (relativeMap != null) { + relativeMap.put(containingFile, relativePath); + } + } + } + if (result.isEmpty()) { + return null; + } + else { + boolean hasClasses = false; + for (PsiClass[] classes : result.values()) { + if (classes != null) { + hasClasses = true; + break; + } + } + return hasClasses ? result : null; + } } - Project project = defaultTargetDirectory.getProject(); - Object targetDirectory = null; - String className = null; - if (copyOneClass(classes)) { - final String commonPath = ArrayUtil.find(elements, classes.values().iterator().next()) == -1 ? normalizeRelativeMap(relativePathsMap) : null; - CopyClassDialog dialog = new CopyClassDialog(classes.values().iterator().next()[0], defaultTargetDirectory, project, false) { - @Override - protected String getQualifiedName() { - if (commonPath != null && !commonPath.isEmpty()) { - return StringUtil.getQualifiedName(super.getQualifiedName(), commonPath.replaceAll("/", ".")); - } - return super.getQualifiedName(); - } - }; - dialog.setTitle(RefactoringLocalize.copyHandlerCopyClass().get()); - dialog.show(); - if (dialog.isOK()) { - targetDirectory = dialog.getTargetDirectory(); - className = dialog.getClassName(); - if (className == null || className.length() == 0) return; - } - } else { - if (project.getApplication().isUnitTestMode()) { - targetDirectory = defaultTargetDirectory; - } else { - defaultTargetDirectory = CopyFilesOrDirectoriesHandler.resolveDirectory(defaultTargetDirectory); - if (defaultTargetDirectory == null) return; - PsiElement[] files = PsiUtilCore.toPsiFileArray(classes.keySet()); - if (classes.keySet().size() == 1) { - //do not choose a new name for a file when multiple classes exist in one file - final PsiClass[] psiClasses = classes.values().iterator().next(); - if (psiClasses != null) { - files = psiClasses; - } - } - final CopyFilesOrDirectoriesDialog dialog = new CopyFilesOrDirectoriesDialog(files, defaultTargetDirectory, project, false); - dialog.show(); - if (dialog.isOK()) { - targetDirectory = dialog.getTargetDirectory(); - className = dialog.getNewName(); + + @Nullable + private static String normalizeRelativeMap(Map relativeMap) { + String vector = null; + for (String relativePath : relativeMap.values()) { + if (vector == null) { + vector = relativePath; + } + else if (vector.startsWith(relativePath + "/")) { + vector = relativePath; + } + else if (!relativePath.startsWith(vector + "/") && !relativePath.equals(vector)) { + return null; + } } - } + if (vector != null) { + for (PsiFile psiFile : relativeMap.keySet()) { + String path = relativeMap.get(psiFile); + relativeMap.put(psiFile, path.equals(vector) ? "" : path.substring(vector.length() + 1)); + } + } + return vector; } - if (targetDirectory != null) { - copyClassesImpl( - className, - project, - classes, - relativePathsMap, - targetDirectory, - defaultTargetDirectory, - RefactoringLocalize.copyHandlerCopyClass().get(), - false - ); + + private static void fillResultsMap(Map result, PsiFile containingFile, PsiClass[] topLevelClasses) { + PsiClass[] classes = result.get(containingFile); + if (topLevelClasses != null) { + if (classes != null) { + topLevelClasses = ArrayUtil.mergeArrays(classes, topLevelClasses, PsiClass.ARRAY_FACTORY); + } + result.put(containingFile, topLevelClasses); + } + else { + result.put(containingFile, classes); + } } - } - private static boolean copyOneClass(Map classes) { - if (classes.size() == 1) { - final PsiClass[] psiClasses = classes.values().iterator().next(); - return psiClasses != null && psiClasses.length == 1; + @Override + @RequiredUIAccess + public void doCopy(PsiElement[] elements, PsiDirectory defaultTargetDirectory) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass"); + Map relativePathsMap = new HashMap<>(); + final Map classes = convertToTopLevelClasses(elements, false, "", relativePathsMap); + assert classes != null; + if (defaultTargetDirectory == null) { + PsiFile psiFile = classes.keySet().iterator().next(); + defaultTargetDirectory = psiFile.getContainingDirectory(); + LOG.assertTrue(defaultTargetDirectory != null, psiFile); + } + else { + Project project = defaultTargetDirectory.getProject(); + VirtualFile sourceRootForFile = ProjectRootManager.getInstance(project).getFileIndex() + .getSourceRootForFile(defaultTargetDirectory.getVirtualFile()); + if (sourceRootForFile == null) { + List files = new ArrayList<>(); + for (PsiElement element : elements) { + PsiFile containingFile = element.getContainingFile(); + if (containingFile != null) { + files.add(containingFile); + } + else if (element instanceof PsiDirectory) { + files.add(element); + } + } + CopyFilesOrDirectoriesHandler.copyAsFiles(files.toArray(new PsiElement[files.size()]), defaultTargetDirectory, project); + return; + } + } + Project project = defaultTargetDirectory.getProject(); + Object targetDirectory = null; + String className = null; + if (copyOneClass(classes)) { + final String commonPath = + ArrayUtil.find(elements, classes.values().iterator().next()) == -1 ? normalizeRelativeMap(relativePathsMap) : null; + CopyClassDialog dialog = new CopyClassDialog(classes.values().iterator().next()[0], defaultTargetDirectory, project, false) { + @Override + protected String getQualifiedName() { + if (commonPath != null && !commonPath.isEmpty()) { + return StringUtil.getQualifiedName(super.getQualifiedName(), commonPath.replaceAll("/", ".")); + } + return super.getQualifiedName(); + } + }; + dialog.setTitle(RefactoringLocalize.copyHandlerCopyClass()); + dialog.show(); + if (dialog.isOK()) { + targetDirectory = dialog.getTargetDirectory(); + className = dialog.getClassName(); + if (className == null || className.length() == 0) { + return; + } + } + } + else { + if (project.getApplication().isUnitTestMode()) { + targetDirectory = defaultTargetDirectory; + } + else { + defaultTargetDirectory = CopyFilesOrDirectoriesHandler.resolveDirectory(defaultTargetDirectory); + if (defaultTargetDirectory == null) { + return; + } + PsiElement[] files = PsiUtilCore.toPsiFileArray(classes.keySet()); + if (classes.keySet().size() == 1) { + //do not choose a new name for a file when multiple classes exist in one file + PsiClass[] psiClasses = classes.values().iterator().next(); + if (psiClasses != null) { + files = psiClasses; + } + } + CopyFilesOrDirectoriesDialog dialog = new CopyFilesOrDirectoriesDialog(files, defaultTargetDirectory, project, false); + dialog.show(); + if (dialog.isOK()) { + targetDirectory = dialog.getTargetDirectory(); + className = dialog.getNewName(); + } + } + } + if (targetDirectory != null) { + copyClassesImpl( + className, + project, + classes, + relativePathsMap, + targetDirectory, + defaultTargetDirectory, + RefactoringLocalize.copyHandlerCopyClass(), + false + ); + } } - return false; - } - - @RequiredUIAccess - public void doClone(PsiElement element) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass"); - PsiClass[] classes = getTopLevelClasses(element); - if (classes == null) { - CopyFilesOrDirectoriesHandler.doCloneFile(element); - return; + + private static boolean copyOneClass(Map classes) { + if (classes.size() == 1) { + PsiClass[] psiClasses = classes.values().iterator().next(); + return psiClasses != null && psiClasses.length == 1; + } + return false; } - Project project = element.getProject(); - - CopyClassDialog dialog = new CopyClassDialog(classes[0], null, project, true); - dialog.setTitle(RefactoringLocalize.copyHandlerCloneClass()); - dialog.show(); - if (dialog.isOK()) { - String className = dialog.getClassName(); - PsiDirectory targetDirectory = element.getContainingFile().getContainingDirectory(); - copyClassesImpl( - className, - project, - Collections.singletonMap(classes[0].getContainingFile(), classes), - null, - targetDirectory, - targetDirectory, - RefactoringLocalize.copyHandlerCloneClass().get(), - true - ); + + @Override + @RequiredUIAccess + public void doClone(PsiElement element) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.copyClass"); + PsiClass[] classes = getTopLevelClasses(element); + if (classes == null) { + CopyFilesOrDirectoriesHandler.doCloneFile(element); + return; + } + Project project = element.getProject(); + + CopyClassDialog dialog = new CopyClassDialog(classes[0], null, project, true); + dialog.setTitle(RefactoringLocalize.copyHandlerCloneClass()); + dialog.show(); + if (dialog.isOK()) { + String className = dialog.getClassName(); + PsiDirectory targetDirectory = element.getContainingFile().getContainingDirectory(); + copyClassesImpl( + className, + project, + Collections.singletonMap(classes[0].getContainingFile(), classes), + null, + targetDirectory, + targetDirectory, + RefactoringLocalize.copyHandlerCloneClass(), + true + ); + } } - } - - private static void copyClassesImpl( - final String copyClassName, - final Project project, - final Map classes, - final HashMap map, - final Object targetDirectory, - final PsiDirectory defaultTargetDirectory, - final String commandName, - final boolean selectInActivePanel - ) { - final boolean[] result = new boolean[]{false}; - Runnable command = () -> { - final Runnable action = () -> { - try { - PsiDirectory target = targetDirectory instanceof PsiDirectory directory ? directory - : ((MoveDestination)targetDirectory).getTargetDirectory(defaultTargetDirectory); - PsiElement newElement = doCopyClasses(classes, map, copyClassName, target, project); - if (newElement != null) { - CopyHandler.updateSelectionInActiveProjectView(newElement, project, selectInActivePanel); - EditorHelper.openInEditor(newElement); - - result[0] = true; - } - } catch (final IncorrectOperationException ex) { - project.getApplication().invokeLater(() -> Messages.showMessageDialog( - project, - ex.getMessage(), - RefactoringLocalize.errorTitle().get(), - UIUtil.getErrorIcon() - )); - } - }; - project.getApplication().runWriteAction(action); - }; - CommandProcessor processor = CommandProcessor.getInstance(); - processor.executeCommand(project, command, commandName, null); - - if (result[0]) { - ToolWindowManager.getInstance(project).invokeLater(() -> ToolWindowManager.getInstance(project).activateEditorComponent()); + + private static void copyClassesImpl( + String copyClassName, + Project project, + Map classes, + Map map, + Object targetDirectory, + PsiDirectory defaultTargetDirectory, + @Nonnull LocalizeValue commandName, + boolean selectInActivePanel + ) { + boolean[] result = new boolean[]{false}; + CommandProcessor processor = CommandProcessor.getInstance(); + processor.newCommand() + .project(project) + .name(commandName) + .inWriteAction() + .run(() -> { + try { + PsiDirectory target = targetDirectory instanceof PsiDirectory directory ? directory + : ((MoveDestination) targetDirectory).getTargetDirectory(defaultTargetDirectory); + PsiElement newElement = doCopyClasses(classes, map, copyClassName, target, project); + if (newElement != null) { + CopyHandler.updateSelectionInActiveProjectView(newElement, project, selectInActivePanel); + EditorHelper.openInEditor(newElement); + + result[0] = true; + } + } + catch (IncorrectOperationException ex) { + project.getApplication().invokeLater(() -> Messages.showMessageDialog( + project, + ex.getMessage(), + RefactoringLocalize.errorTitle().get(), + UIUtil.getErrorIcon() + )); + } + }); + + if (result[0]) { + ToolWindowManager.getInstance(project).invokeLater(() -> ToolWindowManager.getInstance(project).activateEditorComponent()); + } } - } - - @Nullable - @RequiredReadAction - public static PsiElement doCopyClasses( - final Map fileToClasses, - final String copyClassName, - final PsiDirectory targetDirectory, - final Project project - ) throws IncorrectOperationException { - return doCopyClasses(fileToClasses, null, copyClassName, targetDirectory, project); - } - - @Nullable - @RequiredWriteAction - public static PsiElement doCopyClasses( - final Map fileToClasses, - @Nullable HashMap map, - final String copyClassName, - final PsiDirectory targetDirectory, - final Project project - ) throws IncorrectOperationException { - PsiElement newElement = null; - final Map oldToNewMap = new HashMap<>(); - for (final PsiClass[] psiClasses : fileToClasses.values()) { - if (psiClasses != null) { - for (PsiClass aClass : psiClasses) { - if (aClass instanceof SyntheticElement) { - continue; - } - oldToNewMap.put(aClass, null); - } - } + + @Nullable + @RequiredWriteAction + public static PsiElement doCopyClasses( + Map fileToClasses, + String copyClassName, + PsiDirectory targetDirectory, + Project project + ) throws IncorrectOperationException { + return doCopyClasses(fileToClasses, null, copyClassName, targetDirectory, project); } - final List createdFiles = new ArrayList<>(fileToClasses.size()); - int[] choice = fileToClasses.size() > 1 ? new int[]{-1} : null; - List files = new ArrayList<>(); - for (final Map.Entry entry : fileToClasses.entrySet()) { - final PsiFile psiFile = entry.getKey(); - final PsiClass[] sources = entry.getValue(); - if (psiFile instanceof PsiClassOwner && sources != null) { - final PsiFile createdFile = copy(psiFile, targetDirectory, copyClassName, map == null ? null : map.get(psiFile), choice); - if (createdFile == null) return null; - for (final PsiClass destination : ((PsiClassOwner) createdFile).getClasses()) { - if (destination instanceof SyntheticElement) { - continue; - } - PsiClass source = findByName(sources, destination.getName()); - if (source != null) { - final PsiClass copy = copy(source, copyClassName); - newElement = destination.replace(copy); - oldToNewMap.put(source, newElement); - } else { - destination.delete(); - } - } - createdFiles.add(createdFile); - } else { - files.add(psiFile); - } + + @Nullable + @RequiredWriteAction + public static PsiElement doCopyClasses( + Map fileToClasses, + @Nullable Map map, + String copyClassName, + PsiDirectory targetDirectory, + Project project + ) throws IncorrectOperationException { + PsiElement newElement = null; + Map oldToNewMap = new HashMap<>(); + for (PsiClass[] psiClasses : fileToClasses.values()) { + if (psiClasses != null) { + for (PsiClass aClass : psiClasses) { + if (aClass instanceof SyntheticElement) { + continue; + } + oldToNewMap.put(aClass, null); + } + } + } + List createdFiles = new ArrayList<>(fileToClasses.size()); + int[] choice = fileToClasses.size() > 1 ? new int[]{-1} : null; + List files = new ArrayList<>(); + for (Map.Entry entry : fileToClasses.entrySet()) { + PsiFile psiFile = entry.getKey(); + PsiClass[] sources = entry.getValue(); + if (psiFile instanceof PsiClassOwner && sources != null) { + PsiFile createdFile = copy(psiFile, targetDirectory, copyClassName, map == null ? null : map.get(psiFile), choice); + if (createdFile == null) { + return null; + } + for (PsiClass destination : ((PsiClassOwner) createdFile).getClasses()) { + if (destination instanceof SyntheticElement) { + continue; + } + PsiClass source = findByName(sources, destination.getName()); + if (source != null) { + PsiClass copy = copy(source, copyClassName); + newElement = destination.replace(copy); + oldToNewMap.put(source, newElement); + } + else { + destination.delete(); + } + } + createdFiles.add(createdFile); + } + else { + files.add(psiFile); + } + } + + for (PsiFile file : files) { + try { + PsiDirectory finalTarget = targetDirectory; + String relativePath = map != null ? map.get(file) : null; + if (relativePath != null && !relativePath.isEmpty()) { + finalTarget = buildRelativeDir(targetDirectory, relativePath).findOrCreateTargetDirectory(); + } + PsiFile fileCopy = + CopyFilesOrDirectoriesHandler.copyToDirectory(file, getNewFileName(file, copyClassName), finalTarget, choice, null); + if (fileCopy != null) { + createdFiles.add(fileCopy); + } + } + catch (IOException e) { + throw new IncorrectOperationException(e.getMessage()); + } + } + + Set rebindExpressions = new HashSet<>(); + for (PsiElement element : oldToNewMap.values()) { + if (element == null) { + LOG.error(oldToNewMap.keySet()); + continue; + } + decodeRefs(element, oldToNewMap, rebindExpressions); + } + + JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); + for (PsiFile psiFile : createdFiles) { + if (psiFile instanceof PsiJavaFile javaFile) { + codeStyleManager.removeRedundantImports(javaFile); + } + } + for (PsiElement expression : rebindExpressions) { + codeStyleManager.shortenClassReferences(expression); + } + new OptimizeImportsProcessor(project, createdFiles.toArray(new PsiFile[createdFiles.size()]), null).run(); + return newElement != null ? newElement : createdFiles.size() > 0 ? createdFiles.get(0) : null; } - for (PsiFile file : files) { - try { - PsiDirectory finalTarget = targetDirectory; - final String relativePath = map != null ? map.get(file) : null; + @RequiredUIAccess + private static PsiFile copy(@Nonnull PsiFile file, PsiDirectory directory, String name, String relativePath, int[] choice) { + String fileName = getNewFileName(file, name); if (relativePath != null && !relativePath.isEmpty()) { - finalTarget = buildRelativeDir(targetDirectory, relativePath).findOrCreateTargetDirectory(); + return buildRelativeDir(directory, relativePath).findOrCreateTargetDirectory().copyFileFrom(fileName, file); } - final PsiFile fileCopy = CopyFilesOrDirectoriesHandler.copyToDirectory(file, getNewFileName(file, copyClassName), finalTarget, choice, null); - if (fileCopy != null) { - createdFiles.add(fileCopy); + if (CommonRefactoringUtil.checkFileExist(directory, choice, file, fileName, RefactoringLocalize.commandNameCopy())) { + return null; } - } catch (IOException e) { - throw new IncorrectOperationException(e.getMessage()); - } + return directory.copyFileFrom(fileName, file); } - final Set rebindExpressions = new HashSet<>(); - for (PsiElement element : oldToNewMap.values()) { - if (element == null) { - LOG.error(oldToNewMap.keySet()); - continue; - } - decodeRefs(element, oldToNewMap, rebindExpressions); + @RequiredReadAction + private static String getNewFileName(PsiFile file, String name) { + if (name != null) { + if (file instanceof PsiClassOwner classOwner) { + PsiClass[] classes = classOwner.getClasses(); + if (classes.length > 0 && !(classes[0] instanceof SyntheticElement)) { + return name + "." + file.getViewProvider().getVirtualFile().getExtension(); + } + } + return name; + } + return file.getName(); } - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - for (PsiFile psiFile : createdFiles) { - if (psiFile instanceof PsiJavaFile javaFile) { - codeStyleManager.removeRedundantImports(javaFile); - } - } - for (PsiElement expression : rebindExpressions) { - codeStyleManager.shortenClassReferences(expression); - } - new OptimizeImportsProcessor(project, createdFiles.toArray(new PsiFile[createdFiles.size()]), null).run(); - return newElement != null ? newElement : createdFiles.size() > 0 ? createdFiles.get(0) : null; - } - - @RequiredReadAction - private static PsiFile copy(@Nonnull PsiFile file, PsiDirectory directory, String name, String relativePath, int[] choice) { - final String fileName = getNewFileName(file, name); - if (relativePath != null && !relativePath.isEmpty()) { - return buildRelativeDir(directory, relativePath).findOrCreateTargetDirectory().copyFileFrom(fileName, file); - } - if (CopyFilesOrDirectoriesHandler.checkFileExist(directory, choice, file, fileName, "Copy")) return null; - return directory.copyFileFrom(fileName, file); - } - - @RequiredReadAction - private static String getNewFileName(PsiFile file, String name) { - if (name != null) { - if (file instanceof PsiClassOwner classOwner) { - final PsiClass[] classes = classOwner.getClasses(); - if (classes.length > 0 && !(classes[0] instanceof SyntheticElement)) { - return name + "." + file.getViewProvider().getVirtualFile().getExtension(); - } - } - return name; - } - return file.getName(); - } - - @Nonnull - private static MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper buildRelativeDir( - final @Nonnull PsiDirectory directory, - final @Nonnull String relativePath - ) { - MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper current = null; - for (String pathElement : relativePath.split("/")) { - if (current == null) { - current = new MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper(directory, pathElement); - } else { - current = new MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper(current, pathElement); - } + @Nonnull + private static MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper buildRelativeDir( + @Nonnull PsiDirectory directory, + @Nonnull String relativePath + ) { + MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper current = null; + for (String pathElement : relativePath.split("/")) { + if (current == null) { + current = new MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper(directory, pathElement); + } + else { + current = new MoveDirectoryWithClassesProcessor.TargetDirectoryWrapper(current, pathElement); + } + } + LOG.assertTrue(current != null); + return current; } - LOG.assertTrue(current != null); - return current; - } - - private static PsiClass copy(PsiClass aClass, String name) { - final PsiClass classNavigationElement = (PsiClass) aClass.getNavigationElement(); - final PsiClass classCopy = (PsiClass) classNavigationElement.copy(); - if (name != null) { - classCopy.setName(name); + + private static PsiClass copy(PsiClass aClass, String name) { + PsiClass classNavigationElement = (PsiClass) aClass.getNavigationElement(); + PsiClass classCopy = (PsiClass) classNavigationElement.copy(); + if (name != null) { + classCopy.setName(name); + } + return classCopy; } - return classCopy; - } - - @Nullable - @RequiredReadAction - private static PsiClass findByName(PsiClass[] classes, String name) { - if (name != null) { - for (PsiClass aClass : classes) { - if (name.equals(aClass.getName())) { - return aClass; - } - } + + @Nullable + @RequiredReadAction + private static PsiClass findByName(PsiClass[] classes, String name) { + if (name != null) { + for (PsiClass aClass : classes) { + if (name.equals(aClass.getName())) { + return aClass; + } + } + } + return null; } - return null; - } - - @RequiredWriteAction - private static void rebindExternalReferences( - PsiElement element, - Map oldToNewMap, - Set rebindExpressions - ) { - final LocalSearchScope searchScope = new LocalSearchScope(element); - for (PsiClass aClass : oldToNewMap.keySet()) { - final PsiElement newClass = oldToNewMap.get(aClass); - for (PsiReference reference : ReferencesSearch.search(aClass, searchScope)) { - rebindExpressions.add(reference.bindToElement(newClass)); - } + + @RequiredWriteAction + private static void rebindExternalReferences( + PsiElement element, + Map oldToNewMap, + Set rebindExpressions + ) { + LocalSearchScope searchScope = new LocalSearchScope(element); + for (PsiClass aClass : oldToNewMap.keySet()) { + PsiElement newClass = oldToNewMap.get(aClass); + for (PsiReference reference : ReferencesSearch.search(aClass, searchScope)) { + rebindExpressions.add(reference.bindToElement(newClass)); + } + } } - } - - - @RequiredWriteAction - private static void decodeRefs(@Nonnull PsiElement element, final Map oldToNewMap, final Set rebindExpressions) { - element.accept(new JavaRecursiveElementVisitor() { - @Override - @RequiredWriteAction - public void visitReferenceExpression(PsiReferenceExpression expression) { - decodeRef(expression, oldToNewMap, rebindExpressions); - super.visitReferenceExpression(expression); - } - - @Override - @RequiredWriteAction - public void visitNewExpression(PsiNewExpression expression) { - final PsiJavaCodeReferenceElement referenceElement = expression.getClassReference(); - if (referenceElement != null) { - decodeRef(referenceElement, oldToNewMap, rebindExpressions); - } - super.visitNewExpression(expression); - } - - @Override - @RequiredWriteAction - public void visitTypeElement(@Nonnull PsiTypeElement type) { - final PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); - if (referenceElement != null) { - decodeRef(referenceElement, oldToNewMap, rebindExpressions); - } - super.visitTypeElement(type); - } - }); - rebindExternalReferences(element, oldToNewMap, rebindExpressions); - } - - @RequiredWriteAction - private static void decodeRef( - final PsiJavaCodeReferenceElement expression, - final Map oldToNewMap, - Set rebindExpressions - ) { - final PsiElement resolved = expression.resolve(); - if (resolved instanceof PsiClass psiClass) { - if (oldToNewMap.containsKey(psiClass)) { - rebindExpressions.add(expression.bindToElement(oldToNewMap.get(psiClass))); - } + + + @RequiredWriteAction + private static void decodeRefs( + @Nonnull PsiElement element, + final Map oldToNewMap, + final Set rebindExpressions + ) { + element.accept(new JavaRecursiveElementVisitor() { + @Override + @RequiredWriteAction + public void visitReferenceExpression(PsiReferenceExpression expression) { + decodeRef(expression, oldToNewMap, rebindExpressions); + super.visitReferenceExpression(expression); + } + + @Override + @RequiredWriteAction + public void visitNewExpression(@Nonnull PsiNewExpression expression) { + PsiJavaCodeReferenceElement referenceElement = expression.getClassReference(); + if (referenceElement != null) { + decodeRef(referenceElement, oldToNewMap, rebindExpressions); + } + super.visitNewExpression(expression); + } + + @Override + @RequiredWriteAction + public void visitTypeElement(@Nonnull PsiTypeElement type) { + PsiJavaCodeReferenceElement referenceElement = type.getInnermostComponentReferenceElement(); + if (referenceElement != null) { + decodeRef(referenceElement, oldToNewMap, rebindExpressions); + } + super.visitTypeElement(type); + } + }); + rebindExternalReferences(element, oldToNewMap, rebindExpressions); } - } - - @Nullable - private static PsiClass[] getTopLevelClasses(PsiElement element) { - while (true) { - if (element == null || element instanceof PsiFile) break; - if (element instanceof PsiClass psiClass && element.getParent() != null - && psiClass.getContainingClass() == null && !(element instanceof PsiAnonymousClass)) { - break; - } - element = element.getParent(); + + @RequiredWriteAction + private static void decodeRef( + PsiJavaCodeReferenceElement expression, + Map oldToNewMap, + Set rebindExpressions + ) { + if (expression.resolve() instanceof PsiClass psiClass && oldToNewMap.containsKey(psiClass)) { + rebindExpressions.add(expression.bindToElement(oldToNewMap.get(psiClass))); + } } - if (element instanceof PsiCompiledElement) return null; - if (element instanceof PsiClassOwner classOwner) { - PsiClass[] classes = classOwner.getClasses(); - if (classes.length > 0) { - for (final PsiClass aClass : classes) { - if (aClass instanceof SyntheticElement) { + + @Nullable + private static PsiClass[] getTopLevelClasses(PsiElement element) { + while (true) { + if (element == null || element instanceof PsiFile) { + break; + } + if (element instanceof PsiClass psiClass && element.getParent() != null + && psiClass.getContainingClass() == null && !(element instanceof PsiAnonymousClass)) { + break; + } + element = element.getParent(); + } + if (element instanceof PsiCompiledElement) { return null; - } } - - return classes; - } + if (element instanceof PsiClassOwner classOwner) { + PsiClass[] classes = classOwner.getClasses(); + if (classes.length > 0) { + for (PsiClass aClass : classes) { + if (aClass instanceof SyntheticElement) { + return null; + } + } + + return classes; + } + } + return element instanceof PsiClass psiClass ? new PsiClass[]{psiClass} : null; } - return element instanceof PsiClass psiClass ? new PsiClass[]{psiClass} : null; - } }