From e21ff23e263f7d6c76608bae7ea264afee8c1101 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 7 Apr 2017 21:14:39 +0300 Subject: [PATCH] Move: Add conflict checking for "Move directory with classes" case --- .../KotlinChangePackageRefactoring.kt | 14 +----- .../move/moveDeclarations/KotlinMoveTarget.kt | 13 +++++ .../KotlinMoveDirectoryWithClassesHelper.kt | 50 ++++++++++++++++--- .../after/A/A.iml | 11 ++++ .../after/A/src/test/dummy.txt | 0 .../after/A/src/test/pack/Bar.kt | 8 +++ .../after/A/src/test/pack/Foo.kt | 7 +++ .../after/B/B.iml | 11 ++++ .../after/B/src/test2/J.java | 7 +++ .../before/A/A.iml | 11 ++++ .../before/A/src/test/dummy.txt | 0 .../before/B/B.iml | 11 ++++ .../before/B/src/test2/J.java | 7 +++ .../before/B/src/test2/pack/Bar.kt | 8 +++ .../before/B/src/test2/pack/Foo.kt | 7 +++ .../conflicts.txt | 4 ++ ...oveDirectoryToUnrelatedModuleConflict.test | 6 +++ .../move/MultiModuleMoveTestGenerated.java | 6 +++ 18 files changed, 161 insertions(+), 20 deletions(-) create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/A.iml create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/dummy.txt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Bar.kt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Foo.kt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/B.iml create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/src/test2/J.java create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/A.iml create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/src/test/dummy.txt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/B.iml create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/J.java create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Bar.kt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Foo.kt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/conflicts.txt create mode 100644 idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt index f2c7c175436..c3bbad637ae 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt @@ -43,19 +43,7 @@ class KotlinChangePackageRefactoring(val file: KtFile) { MoveDeclarationsDescriptor( project = project, elementsToMove = file.declarations.filterIsInstance(), - moveTarget = object: KotlinDirectoryBasedMoveTarget { - override val targetContainerFqName = newFqName - - override val directory: PsiDirectory = file.containingDirectory!! - - override val targetFile: VirtualFile? = directory.virtualFile - - override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile - - override fun getTargetPsiIfExists(originalPsi: PsiElement) = null - - override fun verify(file: PsiFile) = null - }, + moveTarget = KotlinDirectoryMoveTarget(newFqName, file.containingDirectory!!), delegate = MoveDeclarationsDelegate.TopLevel, scanEntireFile = true ), diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinMoveTarget.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinMoveTarget.kt index 990dec490ca..11fa56dbe20 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinMoveTarget.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/KotlinMoveTarget.kt @@ -98,3 +98,16 @@ class KotlinMoveTargetForDeferredFile( // No additional verification is needed override fun verify(file: PsiFile): String? = null } + +class KotlinDirectoryMoveTarget( + override val targetContainerFqName: FqName, + override val directory: PsiDirectory +) : KotlinDirectoryBasedMoveTarget { + override val targetFile: VirtualFile? = directory.virtualFile + + override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile + + override fun getTargetPsiIfExists(originalPsi: PsiElement) = null + + override fun verify(file: PsiFile) = null +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt index d13468f073c..6084aa22c95 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt @@ -25,18 +25,21 @@ import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClas 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.kotlin.idea.core.getPackage -import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish -import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor import org.jetbrains.kotlin.idea.core.quoteIfNeeded +import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish +import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveUsage +import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget +import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveConflictChecker +import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile -import java.util.ArrayList -import java.util.HashMap +import java.util.* class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() { - private class FileUsagesWrapper( - val psiFile: PsiFile, + private data class FileUsagesWrapper( + val psiFile: KtFile, val usages: List, val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor? ) : UsageInfo(psiFile) @@ -69,6 +72,39 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() { .mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, searchInComments, searchInNonJavaFiles), null) } } + override fun preprocessUsages( + project: Project, + files: MutableSet, + infos: Array, + directory: PsiDirectory, + conflicts: MultiMap + ) { + val psiPackage = directory.getPackage() ?: return + val moveTarget = KotlinDirectoryMoveTarget(FqName(psiPackage.qualifiedName), directory) + for ((index, usageInfo) in infos.withIndex()) { + if (usageInfo !is FileUsagesWrapper) continue + + val elementsToMove = usageInfo.psiFile.declarations + if (elementsToMove.isEmpty()) continue + + val (internalUsages, externalUsages) = usageInfo.usages.partition { it is KotlinMoveUsage && it.isInternal } + val internalUsageSet = internalUsages.toMutableSet() + val externalUsageSet = externalUsages.toMutableSet() + + val conflictChecker = MoveConflictChecker( + project, + elementsToMove, + moveTarget, + elementsToMove.first(), + allElementsToMove = files + ) + conflictChecker.checkAllConflicts(externalUsageSet, internalUsageSet, conflicts) + if (externalUsageSet.size != externalUsages.size || internalUsageSet.size != internalUsages.size) { + infos[index] = usageInfo.copy(usages = (externalUsageSet + internalUsageSet).toList()) + } + } + } + override fun beforeMove(psiFile: PsiFile) { } @@ -113,7 +149,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() { val moveDeclarationsProcessor = moveContext.moveDeclarationsProcessor ?: return@body val movedFile = moveContext.newParent.findFile(file.name) ?: return@body - usagesToProcess += FileUsagesWrapper(movedFile, it.usages, moveDeclarationsProcessor) + usagesToProcess += FileUsagesWrapper(movedFile as KtFile, it.usages, moveDeclarationsProcessor) } usagesToProcess.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) } } diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/A.iml b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/A.iml new file mode 100644 index 00000000000..c90834f2d60 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/A.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/dummy.txt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/dummy.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Bar.kt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Bar.kt new file mode 100644 index 00000000000..f04f0e11eb7 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Bar.kt @@ -0,0 +1,8 @@ +package test.pack + +import test2.J + +class Bar { + internal val foo = Foo() + val j = J() +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Foo.kt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Foo.kt new file mode 100644 index 00000000000..8a6d20a89fe --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/A/src/test/pack/Foo.kt @@ -0,0 +1,7 @@ +package test.pack + +import test2.J + +internal class Foo { + val j = J() +} diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/B.iml b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/B.iml new file mode 100644 index 00000000000..c90834f2d60 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/B.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/src/test2/J.java b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/src/test2/J.java new file mode 100644 index 00000000000..7c0a0b3cb19 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/after/B/src/test2/J.java @@ -0,0 +1,7 @@ +package test2; + +import test2.pack.Foo; + +public class J { + Foo foo = new Foo(); +} diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/A.iml b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/A.iml new file mode 100644 index 00000000000..c90834f2d60 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/A.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/src/test/dummy.txt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/A/src/test/dummy.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/B.iml b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/B.iml new file mode 100644 index 00000000000..c90834f2d60 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/B.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/J.java b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/J.java new file mode 100644 index 00000000000..7c0a0b3cb19 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/J.java @@ -0,0 +1,7 @@ +package test2; + +import test2.pack.Foo; + +public class J { + Foo foo = new Foo(); +} diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Bar.kt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Bar.kt new file mode 100644 index 00000000000..d2ff5df67b6 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Bar.kt @@ -0,0 +1,8 @@ +package test2.pack + +import test2.J + +class Bar { + internal val foo = Foo() + val j = J() +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Foo.kt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Foo.kt new file mode 100644 index 00000000000..be238234078 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/before/B/src/test2/pack/Foo.kt @@ -0,0 +1,7 @@ +package test2.pack + +import test2.J + +internal class Foo { + val j = J() +} diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/conflicts.txt b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/conflicts.txt new file mode 100644 index 00000000000..ede2d1a3611 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/conflicts.txt @@ -0,0 +1,4 @@ +Class test2.J, referenced in property test2.pack.Bar.j, will not be accessible in module A +Class test2.J, referenced in property test2.pack.Foo.j, will not be accessible in module A +Class test2.pack.Foo, referenced in field J.foo, will not be accessible from module B +Class test2.pack.Foo, referenced in field J.foo, will not be accessible from module B \ No newline at end of file diff --git a/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test new file mode 100644 index 00000000000..a52b3a12957 --- /dev/null +++ b/idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test @@ -0,0 +1,6 @@ +{ + "mainFile": "B/src/test2/pack/Bar.kt", + "type": "MOVE_DIRECTORY_WITH_CLASSES", + "sourceDir": "B/src/test2/pack", + "targetDir": "A/src/test" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MultiModuleMoveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MultiModuleMoveTestGenerated.java index d45102199c1..fbcf4ae9e2e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MultiModuleMoveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MultiModuleMoveTestGenerated.java @@ -42,6 +42,12 @@ public class MultiModuleMoveTestGenerated extends AbstractMultiModuleMoveTest { doTest(fileName); } + @TestMetadata("moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test") + public void testMoveDirectoryToUnrelatedModuleConflict_MoveDirectoryToUnrelatedModuleConflict() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/moveMultiModule/moveDirectoryToUnrelatedModuleConflict/moveDirectoryToUnrelatedModuleConflict.test"); + doTest(fileName); + } + @TestMetadata("moveFileWithDeclarationsToUnrelatedModuleConflict/moveFileWithDeclarationsToUnrelatedModuleConflict.test") public void testMoveFileWithDeclarationsToUnrelatedModuleConflict_MoveFileWithDeclarationsToUnrelatedModuleConflict() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/moveMultiModule/moveFileWithDeclarationsToUnrelatedModuleConflict/moveFileWithDeclarationsToUnrelatedModuleConflict.test");