diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt index 332bc88185d..8c6b8e2679f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt @@ -142,7 +142,7 @@ class MoveKotlinDeclarationsProcessor( .search(lightElement, projectScope, false) .mapNotNullTo(ArrayList()) { ref -> if (foundReferences.add(ref) && elementsToMove.all { !it.isAncestor(ref.element)}) { - createMoveUsageInfoIfPossible(ref, lightElement, true) + createMoveUsageInfoIfPossible(ref, lightElement, true, null) } else null } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt index e0730e9bab2..4ebba2dbc1d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt @@ -121,8 +121,13 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange( fun processReference(refExpr: KtSimpleNameExpression, bindingContext: BindingContext): ((KtSimpleNameExpression) -> UsageInfo?)? { val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null + val containingDescriptor = descriptor.containingDeclaration ?: return null val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null + val callableKind = (descriptor as? CallableMemberDescriptor)?.kind + val containingDeclarationForNonRealMember = if (callableKind != CallableMemberDescriptor.Kind.DECLARATION) { + DescriptorToSourceUtilsIde.getAnyDeclaration(project, containingDescriptor) as? KtClassOrObject + } else null // Special case for enum entry superclass references (they have empty text and don't need to be processed by the refactoring) if (refExpr.textRange.isEmpty) return null @@ -134,7 +139,6 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange( val isCallableReference = isCallableReference(refExpr.mainReference) if (isCallable && !isCallableReference) { - val containingDescriptor = descriptor.containingDeclaration if (isExtension && containingDescriptor is ClassDescriptor) { val implicitClass = (refExpr.getResolvedCall(bindingContext)?.dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor if (DescriptorUtils.isCompanionObject(implicitClass)) { @@ -174,7 +178,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange( .firstOrNull() fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? { - if (isAncestor(declaration, false)) { + // Check container instead of declaration itself as the latter may be not real (e.g. fake override) + if (isAncestor(containingDeclarationForNonRealMember ?: declaration, false)) { if (descriptor.importableFqName == null) return null if (isUnqualifiedExtensionReference(refExpr.mainReference, declaration)) return null if (isCallableReference(refExpr.mainReference)) return null @@ -192,7 +197,7 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange( } } - return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false) + return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false, fqName.toSafe()) } if (isExtension || isCallableReference || containerFqName != null || isImported(descriptor)) return ::doCreateUsageInfo @@ -226,10 +231,20 @@ class MoveRenameSelfUsageInfo(ref: KtSimpleNameReference, refTarget: PsiElement, override fun getReference() = super.getReference() as? KtSimpleNameReference } +class QualifiableMoveRenameUsageInfo( + element: PsiElement, + reference: PsiReference, + startOffset: Int, + endOffset: Int, + referencedElement: PsiElement, + val newFqName: FqName? +): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false) + fun createMoveUsageInfoIfPossible( reference: PsiReference, referencedElement: PsiElement, - addImportToOriginalFile: Boolean + addImportToOriginalFile: Boolean, + newFqName: FqName? ): UsageInfo? { val element = reference.element if (element.getStrictParentOfType() != null) return null @@ -243,7 +258,7 @@ fun createMoveUsageInfoIfPossible( element, reference, startOffset, endOffset, referencedElement, element.containingFile!!, addImportToOriginalFile ) } - return MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false) + return QualifiableMoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, newFqName) } private fun isUnqualifiedExtensionReference(reference: PsiReference, referencedElement: PsiElement): Boolean { @@ -351,7 +366,15 @@ fun postProcessMoveUsages(usages: Collection, val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference try { when { - reference is KtSimpleNameReference -> reference.bindToElement(newElement, shorteningMode) + reference is KtSimpleNameReference -> { + val newFqName = (usage as? QualifiableMoveRenameUsageInfo)?.newFqName + if (newFqName != null) { + reference.bindToFqName(newFqName, shorteningMode) + } + else { + reference.bindToElement(newElement, shorteningMode) + } + } reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> continue@usageLoop else -> reference?.bindToElement(newElement) } diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/source/Foo.kt new file mode 100644 index 00000000000..d37da99c453 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/source/Foo.kt @@ -0,0 +1,13 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +open class Klogging + +val Klogging.loggerExt: Logger get() = Logger +fun Klogging.logExt(s: String) {} + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/target/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/target/Foo.kt new file mode 100644 index 00000000000..10a084ac96e --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/after/target/Foo.kt @@ -0,0 +1,14 @@ +package target + +import source.Klogging +import source.logExt +import source.loggerExt + +class Foo { + companion object : Klogging() + + fun baz() { + loggerExt.debug { "something" } + logExt("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/before/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/before/source/Foo.kt new file mode 100644 index 00000000000..589b7c5956a --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/before/source/Foo.kt @@ -0,0 +1,21 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +open class Klogging + +val Klogging.loggerExt: Logger get() = Logger +fun Klogging.logExt(s: String) {} + +class Foo { + companion object : Klogging() + + fun baz() { + loggerExt.debug { "something" } + logExt("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test new file mode 100644 index 00000000000..1a649bb5efc --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test @@ -0,0 +1,5 @@ +{ + "mainFile": "source/Foo.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "target" +} diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/source/Foo.kt new file mode 100644 index 00000000000..cba3e354d21 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/source/Foo.kt @@ -0,0 +1,18 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +interface ILogging { + val logger: Logger + fun log(s: String) +} + +class Klogging : ILogging { + override val logger = Logger() + override fun log(s: String) {} +} + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/target/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/target/Foo.kt new file mode 100644 index 00000000000..a4d9d19e340 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/after/target/Foo.kt @@ -0,0 +1,13 @@ +package target + +import source.ILogging +import source.Klogging + +class Foo { + companion object : ILogging by Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/before/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/before/source/Foo.kt new file mode 100644 index 00000000000..7f919a3b35e --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/before/source/Foo.kt @@ -0,0 +1,26 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +interface ILogging { + val logger: Logger + fun log(s: String) +} + +class Klogging : ILogging { + override val logger = Logger() + override fun log(s: String) {} +} + +class Foo { + companion object : ILogging by Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test new file mode 100644 index 00000000000..1a649bb5efc --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test @@ -0,0 +1,5 @@ +{ + "mainFile": "source/Foo.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "target" +} diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/source/Foo.kt new file mode 100644 index 00000000000..b8bb568c1ef --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/source/Foo.kt @@ -0,0 +1,13 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +open class Klogging { + val logger = Logger() + fun log(s: String) {} +} + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/target/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/target/Foo.kt new file mode 100644 index 00000000000..73553965055 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/after/target/Foo.kt @@ -0,0 +1,12 @@ +package target + +import source.Klogging + +class Foo { + companion object : Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/before/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/before/source/Foo.kt new file mode 100644 index 00000000000..192a8c63eff --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/before/source/Foo.kt @@ -0,0 +1,21 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +open class Klogging { + val logger = Logger() + fun log(s: String) {} +} + +class Foo { + companion object : Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test new file mode 100644 index 00000000000..1a649bb5efc --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test @@ -0,0 +1,5 @@ +{ + "mainFile": "source/Foo.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "target" +} diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Foo.kt new file mode 100644 index 00000000000..3d3914fe063 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Foo.kt @@ -0,0 +1,8 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Klogging.java b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Klogging.java new file mode 100644 index 00000000000..51b586b893a --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/source/Klogging.java @@ -0,0 +1,6 @@ +package source; + +public class Klogging { + public Logger logger = Logger(); + public void log(String s) {} +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/target/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/target/Foo.kt new file mode 100644 index 00000000000..73553965055 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/after/target/Foo.kt @@ -0,0 +1,12 @@ +package target + +import source.Klogging + +class Foo { + companion object : Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Foo.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Foo.kt new file mode 100644 index 00000000000..d224abd7336 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Foo.kt @@ -0,0 +1,16 @@ +package source + +class Logger { + fun debug(s: () -> String) { + + } +} + +class Foo { + companion object : Klogging() + + fun baz() { + logger.debug { "something" } + log("something") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Klogging.java b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Klogging.java new file mode 100644 index 00000000000..51b586b893a --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/before/source/Klogging.java @@ -0,0 +1,6 @@ +package source; + +public class Klogging { + public Logger logger = Logger(); + public void log(String s) {} +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test new file mode 100644 index 00000000000..1a649bb5efc --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test @@ -0,0 +1,5 @@ +{ + "mainFile": "source/Foo.kt", + "type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS", + "targetPackage": "target" +} 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 64e2938e195..4abe10cee41 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveTestGenerated.java @@ -414,6 +414,30 @@ public class MoveTestGenerated extends AbstractMoveTest { doTest(fileName); } + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test") + public void testKotlin_moveTopLevelDeclarations_misc_companionExtensionMemberRef_CompanionExtensionMemberRef() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test"); + doTest(fileName); + } + + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test") + public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefDelegation_CompanionMemberRefDelegation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test"); + doTest(fileName); + } + + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test") + public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefFakeOverride_CompanionMemberRefFakeOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test"); + doTest(fileName); + } + + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test") + public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefWithJavaParent_CompanionMemberRefWithJavaParent() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test"); + doTest(fileName); + } + @TestMetadata("kotlin/moveTopLevelDeclarations/misc/delegateInObject/delegateInObject.test") public void testKotlin_moveTopLevelDeclarations_misc_delegateInObject_DelegateInObject() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/delegateInObject/delegateInObject.test");