diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinAwareMoveFilesOrDirectoriesProcessor.kt similarity index 77% rename from idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt rename to idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinAwareMoveFilesOrDirectoriesProcessor.kt index cb1cf7f3287..dc9c8e18883 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinAwareMoveFilesOrDirectoriesProcessor.kt @@ -28,16 +28,14 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageViewDescriptor import com.intellij.util.containers.MultiMap -import com.intellij.util.text.UniqueNameGenerator import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.allElementsToMove import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.shouldFixFqName import org.jetbrains.kotlin.psi.KtFile -class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( +class KotlinAwareMoveFilesOrDirectoriesProcessor @JvmOverloads constructor ( project: Project, private val elementsToMove: List, private val targetDirectory: PsiDirectory, - private val targetFileName: String?, searchInComments: Boolean, searchInNonJavaFiles: Boolean, moveCallback: MoveCallback?, @@ -50,10 +48,6 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( searchInNonJavaFiles, moveCallback, prepareSuccessfulCallback) { - override fun getCommandName(): String { - return if (targetFileName != null) "Move " + (elementsToMove.single() as PsiFile).name else "Move" - } - override fun createUsageViewDescriptor(usages: Array): UsageViewDescriptor { return MoveFilesWithDeclarationsViewDescriptor(elementsToMove.toTypedArray(), targetDirectory) } @@ -83,17 +77,6 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( return showConflicts(conflicts, usages) } - // Assign a temporary name to file-under-move to avoid naming conflict during the refactoring - private fun renameFileTemporarily() { - if (targetFileName == null || targetDirectory.findFile(targetFileName) == null) return - - val sourceFile = elementsToMove.single() as PsiFile - val temporaryName = UniqueNameGenerator.generateUniqueName("temp", "", ".kt") { - sourceFile.containingDirectory!!.findFile(it) == null - } - sourceFile.name = temporaryName - } - private fun markPsiFiles(mark: PsiFile.() -> Unit) { fun PsiElement.doMark(mark: PsiFile.() -> Unit) { when (this) { @@ -114,20 +97,12 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( } override fun performRefactoring(usages: Array) { - val needTemporaryRename = targetFileName != null && targetDirectory.findFile(targetFileName) != null - if (needTemporaryRename) { - renameFileTemporarily() - } - try { markShouldFixFqName(true) super.performRefactoring(usages) } finally { markShouldFixFqName(false) - if (needTemporaryRename) { - (elementsToMove.single() as PsiFile).name = targetFileName!! - } } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveToKotlinFileProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveToKotlinFileProcessor.kt new file mode 100644 index 00000000000..a97dbbefbd5 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveToKotlinFileProcessor.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations + +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.EmptyRunnable +import com.intellij.openapi.util.Ref +import com.intellij.psi.PsiDirectory +import com.intellij.psi.PsiElement +import com.intellij.refactoring.move.MoveCallback +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor +import com.intellij.usageView.UsageInfo +import com.intellij.usageView.UsageViewDescriptor +import com.intellij.util.containers.MultiMap +import com.intellij.util.text.UniqueNameGenerator +import org.jetbrains.kotlin.psi.KtFile + +class MoveToKotlinFileProcessor @JvmOverloads constructor ( + project: Project, + private val sourceFile: KtFile, + private val targetDirectory: PsiDirectory, + private val targetFileName: String, + searchInComments: Boolean, + searchInNonJavaFiles: Boolean, + moveCallback: MoveCallback?, + prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE +) : MoveFilesOrDirectoriesProcessor(project, + arrayOf(sourceFile), + targetDirectory, + true, + searchInComments, + searchInNonJavaFiles, + moveCallback, + prepareSuccessfulCallback) { + override fun getCommandName() = "Move ${sourceFile.name}" + + override fun createUsageViewDescriptor(usages: Array): UsageViewDescriptor { + return MoveFilesWithDeclarationsViewDescriptor(arrayOf(sourceFile), targetDirectory) + } + + override fun preprocessUsages(refUsages: Ref>): Boolean { + val usages = refUsages.get() + + val (conflictUsages, usagesToProcess) = usages.partition { it is ConflictUsageInfo } + + val conflicts = MultiMap() + for (conflictUsage in conflictUsages) { + conflicts.putValues(conflictUsage.element, (conflictUsage as ConflictUsageInfo).messages) + } + + refUsages.set(usagesToProcess.toTypedArray()) + + return showConflicts(conflicts, usages) + } + + // Assign a temporary name to file-under-move to avoid naming conflict during the refactoring + private fun renameFileTemporarily() { + if (targetDirectory.findFile(targetFileName) == null) return + + val temporaryName = UniqueNameGenerator.generateUniqueName("temp", "", ".kt") { + sourceFile.containingDirectory!!.findFile(it) == null + } + sourceFile.name = temporaryName + } + + override fun performRefactoring(usages: Array) { + val needTemporaryRename = targetDirectory.findFile(targetFileName) != null + if (needTemporaryRename) { + renameFileTemporarily() + } + + try { + super.performRefactoring(usages) + } + finally { + if (needTemporaryRename) { + sourceFile.name = targetFileName + } + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java index f8350cb1446..031fd729273 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/ui/MoveKotlinTopLevelDeclarationsDialog.java @@ -31,10 +31,7 @@ import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.MoveDestination; -import com.intellij.refactoring.PackageWrapper; -import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.*; import com.intellij.refactoring.classMembers.AbstractMemberInfoModel; import com.intellij.refactoring.classMembers.MemberInfoChange; import com.intellij.refactoring.classMembers.MemberInfoChangeListener; @@ -738,15 +735,23 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog { MoveUtilsKt.setUpdatePackageDirective(sourceFile, cbUpdatePackageDirective.isSelected()); } - invokeRefactoring( - new MoveFilesWithDeclarationsProcessor(myProject, - sourceFiles, - targetDirectory, - targetFileName, - isSearchInComments(), - isSearchInNonJavaFiles(), - moveCallback) - ); + BaseRefactoringProcessor processor; + processor = sourceFiles.size() == 1 && targetFileName != null + ? new MoveToKotlinFileProcessor(myProject, + CollectionsKt.single(sourceFiles), + targetDirectory, + targetFileName, + isSearchInComments(), + isSearchInNonJavaFiles(), + moveCallback) + : new KotlinAwareMoveFilesOrDirectoriesProcessor(myProject, + sourceFiles, + targetDirectory, + isSearchInComments(), + isSearchInNonJavaFiles(), + moveCallback); + + invokeRefactoring(processor); return; } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesUtil.kt index e9f204a832d..242d6db7690 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesUtil.kt @@ -30,7 +30,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori import com.intellij.refactoring.util.CommonRefactoringUtil import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.idea.refactoring.isInJavaSourceRoot -import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveFilesWithDeclarationsProcessor +import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinAwareMoveFilesOrDirectoriesProcessor import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.runWriteAction @@ -78,11 +78,10 @@ fun invokeMoveFilesOrDirectoriesRefactoring( if (elementsToMove.isNotEmpty()) { @Suppress("UNCHECKED_CAST") - val processor = MoveFilesWithDeclarationsProcessor( + val processor = KotlinAwareMoveFilesOrDirectoriesProcessor( project, elementsToMove as List, selectedDir, - null, false, false, moveCallback, diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt index b223ebbdf7d..d5f46cb3666 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt @@ -296,11 +296,10 @@ enum class MoveAction { } val targetDirPath = config.getString("targetDirectory") val targetDir = rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!! - MoveFilesWithDeclarationsProcessor( + KotlinAwareMoveFilesOrDirectoriesProcessor( project, elementsToMove, targetDir, - (elementsToMove.singleOrNull() as? KtFile)?.name, searchInComments = true, searchInNonJavaFiles = true, moveCallback = null