diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 7c6c492fa53..dda66a7fef4 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -368,6 +368,9 @@ implementation="org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsHandler" order="first,before kotlin.moveFilesOrDirectories"/> + diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt index f29ecccc97a..69422ea3b92 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveFilesWithDeclarationsProcessor.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.util.Ref import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.PsiJavaFile import com.intellij.refactoring.move.MoveCallback import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor import com.intellij.usageView.UsageInfo @@ -82,6 +83,17 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( sourceFile.name = temporaryName } + private fun markShouldFixFqName(value: Boolean) { + fun PsiElement.doMark(value: Boolean) { + when (this) { + is PsiJavaFile -> shouldFixFqName = value + is PsiDirectory -> children.forEach { it.doMark(value) } + } + } + + elementsToMove.forEach { it.doMark(value) } + } + override fun performRefactoring(usages: Array) { val needTemporaryRename = targetFileName != null && targetDirectory.findFile(targetFileName) != null if (needTemporaryRename) { @@ -89,9 +101,11 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor ( } 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/moveFilesOrDirectories/FqNameFixingMoveJavaFIleHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/FqNameFixingMoveJavaFIleHandler.kt new file mode 100644 index 00000000000..478c63e76dd --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/FqNameFixingMoveJavaFIleHandler.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2017 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.moveFilesOrDirectories + +import com.intellij.openapi.util.Key +import com.intellij.psi.* +import com.intellij.psi.util.FileTypeUtils +import com.intellij.psi.util.PsiUtil +import com.intellij.refactoring.move.moveClassesOrPackages.MoveJavaFileHandler +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler +import com.intellij.usageView.UsageInfo +import org.jetbrains.kotlin.psi.NotNullableUserDataProperty + +internal var PsiJavaFile.shouldFixFqName: Boolean by NotNullableUserDataProperty(Key.create("SHOULD_FIX_FQ_NAME"), false) + +class FqNameFixingMoveJavaFileHandler : MoveFileHandler() { + private val delegate = MoveJavaFileHandler() + + override fun canProcessElement(element: PsiFile) = + delegate.canProcessElement(element) + + override fun findUsages(psiFile: PsiFile, newParent: PsiDirectory?, searchInComments: Boolean, searchInNonJavaFiles: Boolean) = + delegate.findUsages(psiFile, newParent, searchInComments, searchInNonJavaFiles) + + override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap) { + delegate.prepareMovedFile(file, moveDestination, oldToNewMap) + if (file is PsiJavaFile && file.shouldFixFqName) { + val newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination) ?: return + if (!FileTypeUtils.isInServerPageFile(file) && !PsiUtil.isModuleFile(file)) { + file.packageName = newPackage.qualifiedName + } + } + } + + override fun updateMovedFile(file: PsiFile) = + delegate.updateMovedFile(file) + + override fun retargetUsages(usageInfos: MutableList, oldToNewMap: MutableMap) = + delegate.retargetUsages(usageInfos, oldToNewMap) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt index 597ec8e165a..938d67f4348 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt @@ -123,16 +123,16 @@ class MoveKotlinFileHandler : MoveFileHandler() { } override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap) { + if (file !is KtFile) return val moveProcessor = initMoveProcessor(file, moveDestination) ?: return val moveContext = MoveContext(file, moveProcessor) oldToNewMap[moveContext] = moveContext + val packageNameInfo = file.getPackageNameInfo(moveDestination, true) ?: return + file.packageDirective?.fqName = packageNameInfo.newContainer.fqName!!.quoteIfNeeded() } override fun updateMovedFile(file: PsiFile) { - if (file !is KtFile) return - val newDirectory = file.parent ?: return - val packageNameInfo = file.getPackageNameInfo(newDirectory, true) ?: return - file.packageDirective?.fqName = packageNameInfo.newContainer.fqName!!.quoteIfNeeded() + } override fun retargetUsages(usageInfos: List?, oldToNewMap: Map) { diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Bar.java b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Bar.java new file mode 100644 index 00000000000..9e4ce9d2ec7 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Bar.java @@ -0,0 +1,4 @@ +package test; + +public class Bar { +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Foo.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Foo.kt new file mode 100644 index 00000000000..f31405e81e0 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test/Foo.kt @@ -0,0 +1,9 @@ +package test.pack + +import test2.pack.A +import test2.pack.J + +class Foo { + val a = A() + val j = J() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/FooUsage.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/FooUsage.kt new file mode 100644 index 00000000000..53385992ea8 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/FooUsage.kt @@ -0,0 +1,5 @@ +package test2 + +import test.pack.Foo + +val foo = Foo() diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/dummy.txt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/dummy.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/J.java b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/J.java new file mode 100644 index 00000000000..09410d2143d --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/J.java @@ -0,0 +1,12 @@ +package test2.pack; + +import test.*; +import test.pack.Foo; + +public class J { + A a = new A(); + B b = new B(); + C c = new C(); + Foo foo = new Foo(); + Bar bar = new Bar(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/test.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/test.kt new file mode 100644 index 00000000000..b769a989ef0 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/after/test2/pack/test.kt @@ -0,0 +1,17 @@ +package test2.pack + +import test.Bar +import test.pack.Foo + +class A { + val b = B() +} + +class B { + val a = A() +} + +class C { + internal val foo = Foo() + internal val bar = Bar() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Bar.java b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Bar.java new file mode 100644 index 00000000000..9e4ce9d2ec7 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Bar.java @@ -0,0 +1,4 @@ +package test; + +public class Bar { +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Foo.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Foo.kt new file mode 100644 index 00000000000..77ad2aedb99 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/Foo.kt @@ -0,0 +1,6 @@ +package test.pack + +class Foo { + val a = A() + val j = J() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/FooUsage.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/FooUsage.kt new file mode 100644 index 00000000000..86071328878 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/FooUsage.kt @@ -0,0 +1,5 @@ +package test + +import test.pack.Foo + +val foo = Foo() diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/J.java b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/J.java new file mode 100644 index 00000000000..b70ad2d0bd8 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/J.java @@ -0,0 +1,11 @@ +package test.pack; + +import test.*; + +public class J { + A a = new A(); + B b = new B(); + C c = new C(); + Foo foo = new Foo(); + Bar bar = new Bar(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/test.kt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/test.kt new file mode 100644 index 00000000000..6c593dba120 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test/pack/test.kt @@ -0,0 +1,16 @@ +package test.pack + +import test.Bar + +class A { + val b = B() +} + +class B { + val a = A() +} + +class C { + internal val foo = Foo() + internal val bar = Bar() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test2/dummy.txt b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/before/test2/dummy.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test new file mode 100644 index 00000000000..5c9db35c64f --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test @@ -0,0 +1,5 @@ +{ + "filesToMove": ["test/FooUsage.kt", "test/pack"], + "type": "MOVE_FILES_WITH_DECLARATIONS", + "targetDirectory": "test2" +} \ No newline at end of file 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 9a1753fbf5d..44c503e918d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractMoveTest.kt @@ -271,16 +271,17 @@ enum class MoveAction { MOVE_FILES_WITH_DECLARATIONS { override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementsAtCaret: List, config: JsonObject) { val project = mainFile.project - val psiFilesToMove = config.getAsJsonArray("filesToMove").map { - rootDir.findFileByRelativePath(it.asString)!!.toPsiFile(project) as KtFile + val elementsToMove = config.getAsJsonArray("filesToMove").map { + val virtualFile = rootDir.findFileByRelativePath(it.asString)!! + if (virtualFile.isDirectory) virtualFile.toPsiDirectory(project)!! else virtualFile.toPsiFile(project)!! } val targetDirPath = config.getString("targetDirectory") val targetDir = rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!! MoveFilesWithDeclarationsProcessor( project, - psiFilesToMove, + elementsToMove, targetDir, - psiFilesToMove.singleOrNull()?.name, + (elementsToMove.singleOrNull() as? KtFile)?.name, searchInComments = true, searchInNonJavaFiles = true, moveCallback = null diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java index 771f3661225..0cc3a889fbb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java @@ -258,6 +258,12 @@ public class MoveTestGenerated extends AbstractMoveTest { doTest(fileName); } + @TestMetadata("kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test") + public void testKotlin_moveFile_moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir_MoveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test"); + doTest(fileName); + } + @TestMetadata("kotlin/moveFile/moveFileToFile/moveFileToFile.test") public void testKotlin_moveFile_moveFileToFile_MoveFileToFile() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileToFile/moveFileToFile.test");