Move: Retain imports when moving top-level declaration
#KT-5049 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+5
-1
@@ -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()
|
||||
|
||||
@@ -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<PackageFragmentDescriptor>(), 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -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()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package fourth
|
||||
|
||||
class X {
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package third
|
||||
|
||||
public class B {
|
||||
class C {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class D {
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package fourth
|
||||
|
||||
class X {
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
+18
@@ -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 <caret>Test {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val d_ = D_()
|
||||
val c = C()
|
||||
val x = X()
|
||||
val y = Y()
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package third
|
||||
|
||||
public class B {
|
||||
class C {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class D {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "second/A.kt",
|
||||
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
|
||||
"targetPackage": "first"
|
||||
}
|
||||
+15
@@ -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()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package fourth
|
||||
|
||||
class X {
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package third
|
||||
|
||||
public class B {
|
||||
class C {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class D {
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package fourth
|
||||
|
||||
class X {
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
+18
@@ -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 <caret>test() {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val d_ = D_()
|
||||
val c = C()
|
||||
val x = X()
|
||||
val y = Y()
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package third
|
||||
|
||||
public class B {
|
||||
class C {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class D {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "second/A.kt",
|
||||
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
|
||||
"targetPackage": "first"
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user