From ab5e0c8c9ca92fc7a6c10298d763a4b3006415f8 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 27 May 2014 14:51:08 +0400 Subject: [PATCH] Move: Retain imports when moving top-level declaration #KT-5049 Fixed --- .../jet/lang/resolve/name/FqNamesUtil.kt | 4 +-- .../MoveKotlinFileHandler.kt | 2 +- ...MoveKotlinTopLevelDeclarationsProcessor.kt | 6 +++- .../jet/plugin/refactoring/move/moveUtils.kt | 36 ++++++++++++------- .../after/first/Test.kt | 15 ++++++++ .../after/fourth/X.kt | 7 ++++ .../after/second/A.kt | 10 ++++++ .../after/third/B.kt | 11 ++++++ .../before/fourth/X.kt | 7 ++++ .../before/second/A.kt | 18 ++++++++++ .../before/third/B.kt | 11 ++++++ .../moveClassWithImportsRetained.test | 5 +++ .../after/first/test.kt | 15 ++++++++ .../after/fourth/X.kt | 7 ++++ .../after/second/A.kt | 10 ++++++ .../after/third/B.kt | 11 ++++++ .../before/fourth/X.kt | 7 ++++ .../before/second/A.kt | 18 ++++++++++ .../before/third/B.kt | 11 ++++++ .../moveFunctionWithImportsRetained.test | 5 +++ .../move/JetMoveTestGenerated.java | 10 ++++++ 21 files changed, 210 insertions(+), 16 deletions(-) create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/first/Test.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/fourth/X.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/second/A.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/third/B.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/fourth/X.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/second/A.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/third/B.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/first/test.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/fourth/X.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/second/A.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/third/B.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/fourth/X.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/second/A.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/third/B.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt index abdabdbe3ae..c1cbb026f10 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt @@ -68,9 +68,9 @@ public fun FqName.plusOneSegment(fullFQN: FqName): FqName? { return child(fullFQN.tail(this).pathSegments().first!!) } -public fun FqName.isImported(importPath: ImportPath): Boolean { +public fun FqName.isImported(importPath: ImportPath, skipAliasedImports: Boolean = true): Boolean { return when { - importPath.hasAlias() -> false + skipAliasedImports && importPath.hasAlias() -> false importPath.isAllUnder() && !isRoot() -> importPath.fqnPart() == this.parent() else -> importPath.fqnPart() == this } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt index 4b8e23c767e..3f0da644222 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt @@ -181,7 +181,7 @@ public class MoveKotlinFileHandler : MoveFileHandler() { val packageNameInfo = file.getAndRemoveCopyableUserData(PACKAGE_NAME_INFO_KEY) if (packageNameInfo == null) return - file.updateInternalReferencesOnPackageNameChange(packageNameInfo) + file.updateInternalReferencesOnPackageNameChange(packageNameInfo, updateImportedReferences = false) val packageRef = file.getPackageDirective()?.getLastReferenceExpression()?.getReference() as? JetSimpleNameReference packageRef?.bindToFqName(packageNameInfo.newPackageName) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt index 0bdccda2597..494066d1346 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt @@ -243,7 +243,11 @@ public class MoveKotlinTopLevelDeclarationsProcessor(project: Project, val optio val newPackageFqName = (targetFile as JetFile).getPackageFqName() val packageNameInfo = PackageNameInfo(file!!.getPackageFqName(), newPackageFqName) - declaration.updateInternalReferencesOnPackageNameChange(packageNameInfo, ShorteningMode.NO_SHORTENING) + declaration.updateInternalReferencesOnPackageNameChange( + packageNameInfo, + updateImportedReferences = true, + shorteningMode = ShorteningMode.NO_SHORTENING + ) val newElement = targetFile.add(declaration) as JetNamedDeclaration declaration.delete() diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveUtils.kt index 8d3645f86f6..7d2963cb7a9 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/move/moveUtils.kt @@ -27,24 +27,33 @@ import org.jetbrains.jet.lang.resolve.name.FqName import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.plugin.references.JetSimpleNameReference.ShorteningMode -import com.intellij.psi.PsiClass -import org.jetbrains.jet.asJava.KotlinLightClass import org.jetbrains.jet.plugin.JetFileType -import org.jetbrains.jet.lang.psi.JetClassOrObject import org.jetbrains.jet.lang.psi.JetNamedDeclaration import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil -import org.jetbrains.jet.lang.psi.psiUtil.isInsideOf import org.jetbrains.jet.lang.psi.psiUtil.isAncestor +import java.util.Collections +import org.jetbrains.jet.lang.resolve.name.isImported public class PackageNameInfo(val oldPackageName: FqName, val newPackageName: FqName) public fun JetElement.updateInternalReferencesOnPackageNameChange( - packageNameInfo: PackageNameInfo, shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING + packageNameInfo: PackageNameInfo, + updateImportedReferences: Boolean, + shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING ) { val file = getContainingFile() as? JetFile if (file == null) return + val importPaths = + if (updateImportedReferences) { + file.getImportDirectives().map { it.getImportPath() }.filterNotNull() + } + else Collections.emptyList() + + fun isImportedName(fqName: FqName): Boolean = + updateImportedReferences && importPaths.any { fqName.isImported(it, false) } + val referenceToContext = JetFileReferencesResolver.resolve(file = file, elements = listOf(this), visitReceivers = false) for ((refExpr, bindingContext) in referenceToContext) { @@ -58,16 +67,19 @@ public fun JetElement.updateInternalReferencesOnPackageNameChange( val declaration = DescriptorToDeclarationUtil.getDeclaration(file, descriptor, bindingContext) if (declaration == null || isAncestor(declaration, true)) continue + val fqName = DescriptorUtils.getFqName(descriptor) + if (!fqName.isSafe()) continue + + val fqNameSafe = fqName.toSafe() val packageName = DescriptorUtils.getParentOfType( descriptor, javaClass(), false )?.let { DescriptorUtils.getFqName(it).toSafe() } - when (packageName) { - packageNameInfo.oldPackageName, - packageNameInfo.newPackageName -> { - val fqName = DescriptorUtils.getFqName(descriptor) - if (fqName.isSafe()) { - (refExpr.getReference() as? JetSimpleNameReference)?.bindToFqName(fqName.toSafe(), shorteningMode) - } + + when { + packageName == packageNameInfo.oldPackageName, + packageName == packageNameInfo.newPackageName, + isImportedName(fqNameSafe) -> { + (refExpr.getReference() as? JetSimpleNameReference)?.bindToFqName(fqNameSafe, shorteningMode) } } } diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/first/Test.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/first/Test.kt new file mode 100644 index 00000000000..87ac8708819 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/first/Test.kt @@ -0,0 +1,15 @@ +package first + +import second.A +import third.B +import third.D +import fourth.X + +class Test { + val a = A() + val b = B() + val d_ = D() + val c = B.C() + val x = X() + val y = X.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/fourth/X.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/fourth/X.kt new file mode 100644 index 00000000000..47d9e798cc3 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/fourth/X.kt @@ -0,0 +1,7 @@ +package fourth + +class X { + class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/second/A.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/second/A.kt new file mode 100644 index 00000000000..d6a1d8cd80a --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/second/A.kt @@ -0,0 +1,10 @@ +package second + +import third.B +import fourth.X.Y +import third.D as D_ +import fourth.* +import third.B.* + +class A + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/third/B.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/third/B.kt new file mode 100644 index 00000000000..1ee610d09de --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/after/third/B.kt @@ -0,0 +1,11 @@ +package third + +public class B { + class C { + + } +} + +public class D { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/fourth/X.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/fourth/X.kt new file mode 100644 index 00000000000..47d9e798cc3 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/fourth/X.kt @@ -0,0 +1,7 @@ +package fourth + +class X { + class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/second/A.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/second/A.kt new file mode 100644 index 00000000000..0be0b80806f --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/second/A.kt @@ -0,0 +1,18 @@ +package second + +import third.B +import fourth.X.Y +import third.D as D_ +import fourth.* +import third.B.* + +class A + +class Test { + val a = A() + val b = B() + val d_ = D_() + val c = C() + val x = X() + val y = Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/third/B.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/third/B.kt new file mode 100644 index 00000000000..1ee610d09de --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/before/third/B.kt @@ -0,0 +1,11 @@ +package third + +public class B { + class C { + + } +} + +public class D { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test new file mode 100644 index 00000000000..8c55701baf4 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test @@ -0,0 +1,5 @@ +{ + "mainFile": "second/A.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "first" +} diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/first/test.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/first/test.kt new file mode 100644 index 00000000000..d9eb999e23d --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/first/test.kt @@ -0,0 +1,15 @@ +package first + +import second.A +import third.B +import third.D +import fourth.X + +fun test() { + val a = A() + val b = B() + val d_ = D() + val c = B.C() + val x = X() + val y = X.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/fourth/X.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/fourth/X.kt new file mode 100644 index 00000000000..47d9e798cc3 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/fourth/X.kt @@ -0,0 +1,7 @@ +package fourth + +class X { + class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/second/A.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/second/A.kt new file mode 100644 index 00000000000..d6a1d8cd80a --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/second/A.kt @@ -0,0 +1,10 @@ +package second + +import third.B +import fourth.X.Y +import third.D as D_ +import fourth.* +import third.B.* + +class A + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/third/B.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/third/B.kt new file mode 100644 index 00000000000..1ee610d09de --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/after/third/B.kt @@ -0,0 +1,11 @@ +package third + +public class B { + class C { + + } +} + +public class D { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/fourth/X.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/fourth/X.kt new file mode 100644 index 00000000000..47d9e798cc3 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/fourth/X.kt @@ -0,0 +1,7 @@ +package fourth + +class X { + class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/second/A.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/second/A.kt new file mode 100644 index 00000000000..f59f011fd20 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/second/A.kt @@ -0,0 +1,18 @@ +package second + +import third.B +import fourth.X.Y +import third.D as D_ +import fourth.* +import third.B.* + +class A + +fun test() { + val a = A() + val b = B() + val d_ = D_() + val c = C() + val x = X() + val y = Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/third/B.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/third/B.kt new file mode 100644 index 00000000000..1ee610d09de --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/before/third/B.kt @@ -0,0 +1,11 @@ +package third + +public class B { + class C { + + } +} + +public class D { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test new file mode 100644 index 00000000000..8c55701baf4 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test @@ -0,0 +1,5 @@ +{ + "mainFile": "second/A.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "first" +} diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java index a690efac091..67408fc6570 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/move/JetMoveTestGenerated.java @@ -191,6 +191,16 @@ public class JetMoveTestGenerated extends AbstractJetMoveTest { doTest("idea/testData/refactoring/move/kotlin/movePackage/movePackage/movePackage.test"); } + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test") + public void testKotlin_moveTopLevelDeclarations_misc_moveClassWithImportsRetained_MoveClassWithImportsRetained() throws Exception { + doTest("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveClassWithImportsRetained/moveClassWithImportsRetained.test"); + } + + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test") + public void testKotlin_moveTopLevelDeclarations_misc_moveFunctionWithImportsRetained_MoveFunctionWithImportsRetained() throws Exception { + doTest("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveFunctionWithImportsRetained/moveFunctionWithImportsRetained.test"); + } + @TestMetadata("kotlin/moveTopLevelDeclarations/moveClassToFile/moveClassToFile.test") public void testKotlin_moveTopLevelDeclarations_moveClassToFile_MoveClassToFile() throws Exception { doTest("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveClassToFile/moveClassToFile.test");