Move: Add conflict checking for "Move directory with classes" case
This commit is contained in:
+1
-13
@@ -43,19 +43,7 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
|
|||||||
MoveDeclarationsDescriptor(
|
MoveDeclarationsDescriptor(
|
||||||
project = project,
|
project = project,
|
||||||
elementsToMove = file.declarations.filterIsInstance<KtNamedDeclaration>(),
|
elementsToMove = file.declarations.filterIsInstance<KtNamedDeclaration>(),
|
||||||
moveTarget = object: KotlinDirectoryBasedMoveTarget {
|
moveTarget = KotlinDirectoryMoveTarget(newFqName, file.containingDirectory!!),
|
||||||
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
|
|
||||||
},
|
|
||||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||||
scanEntireFile = true
|
scanEntireFile = true
|
||||||
),
|
),
|
||||||
|
|||||||
+13
@@ -98,3 +98,16 @@ class KotlinMoveTargetForDeferredFile(
|
|||||||
// No additional verification is needed
|
// No additional verification is needed
|
||||||
override fun verify(file: PsiFile): String? = null
|
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
|
||||||
|
}
|
||||||
+43
-7
@@ -25,18 +25,21 @@ import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClas
|
|||||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
|
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.util.Function
|
import com.intellij.util.Function
|
||||||
|
import com.intellij.util.containers.MultiMap
|
||||||
import org.jetbrains.kotlin.idea.core.getPackage
|
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.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.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import java.util.ArrayList
|
import java.util.*
|
||||||
import java.util.HashMap
|
|
||||||
|
|
||||||
class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
||||||
private class FileUsagesWrapper(
|
private data class FileUsagesWrapper(
|
||||||
val psiFile: PsiFile,
|
val psiFile: KtFile,
|
||||||
val usages: List<UsageInfo>,
|
val usages: List<UsageInfo>,
|
||||||
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
||||||
) : UsageInfo(psiFile)
|
) : UsageInfo(psiFile)
|
||||||
@@ -69,6 +72,39 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
.mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, searchInComments, searchInNonJavaFiles), null) }
|
.mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, searchInComments, searchInNonJavaFiles), null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun preprocessUsages(
|
||||||
|
project: Project,
|
||||||
|
files: MutableSet<PsiFile>,
|
||||||
|
infos: Array<UsageInfo>,
|
||||||
|
directory: PsiDirectory,
|
||||||
|
conflicts: MultiMap<PsiElement, String>
|
||||||
|
) {
|
||||||
|
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) {
|
override fun beforeMove(psiFile: PsiFile) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -113,7 +149,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
val moveDeclarationsProcessor = moveContext.moveDeclarationsProcessor ?: return@body
|
val moveDeclarationsProcessor = moveContext.moveDeclarationsProcessor ?: return@body
|
||||||
val movedFile = moveContext.newParent.findFile(file.name) ?: 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!!) }
|
usagesToProcess.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) }
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package test.pack
|
||||||
|
|
||||||
|
import test2.J
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
internal val foo = Foo()
|
||||||
|
val j = J()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test.pack
|
||||||
|
|
||||||
|
import test2.J
|
||||||
|
|
||||||
|
internal class Foo {
|
||||||
|
val j = J()
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test2;
|
||||||
|
|
||||||
|
import test2.pack.Foo;
|
||||||
|
|
||||||
|
public class J {
|
||||||
|
Foo foo = new Foo();
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test2;
|
||||||
|
|
||||||
|
import test2.pack.Foo;
|
||||||
|
|
||||||
|
public class J {
|
||||||
|
Foo foo = new Foo();
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package test2.pack
|
||||||
|
|
||||||
|
import test2.J
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
internal val foo = Foo()
|
||||||
|
val j = J()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test2.pack
|
||||||
|
|
||||||
|
import test2.J
|
||||||
|
|
||||||
|
internal class Foo {
|
||||||
|
val j = J()
|
||||||
|
}
|
||||||
Vendored
+4
@@ -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
|
||||||
+6
@@ -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"
|
||||||
|
}
|
||||||
+6
@@ -42,6 +42,12 @@ public class MultiModuleMoveTestGenerated extends AbstractMultiModuleMoveTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("moveFileWithDeclarationsToUnrelatedModuleConflict/moveFileWithDeclarationsToUnrelatedModuleConflict.test")
|
||||||
public void testMoveFileWithDeclarationsToUnrelatedModuleConflict_MoveFileWithDeclarationsToUnrelatedModuleConflict() throws Exception {
|
public void testMoveFileWithDeclarationsToUnrelatedModuleConflict_MoveFileWithDeclarationsToUnrelatedModuleConflict() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/moveMultiModule/moveFileWithDeclarationsToUnrelatedModuleConflict/moveFileWithDeclarationsToUnrelatedModuleConflict.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/moveMultiModule/moveFileWithDeclarationsToUnrelatedModuleConflict/moveFileWithDeclarationsToUnrelatedModuleConflict.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user