From 956c6eeec7d139aaa30d45da234966616cf83a23 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 22 Sep 2016 20:19:36 +0300 Subject: [PATCH] Push Down: Support moving members from Java to Kotlin class #KT-9485 Fixed --- ChangeLog.md | 1 + .../kotlin/generators/tests/GenerateTests.kt | 4 +- idea/src/META-INF/plugin.xml | 4 + .../pushDown/JavaToKotlinPushDownDelegate.kt | 116 +++++++ .../pushDown/KotlinPushDownProcessor.kt | 41 +-- .../pushDown/pushDownConflictsUtils.kt | 13 +- .../idea/refactoring/pushDown/pushDownImpl.kt | 66 ++++ .../refactoring/pushDown/j2k/fromClass.1.kt | 1 + .../pushDown/j2k/fromClass.1.kt.after | 28 ++ .../refactoring/pushDown/j2k/fromClass.java | 29 ++ .../pushDown/j2k/fromClass.java.after | 3 + .../j2k/fromClassAndMakeAbstract.1.kt | 1 + .../j2k/fromClassAndMakeAbstract.1.kt.after | 28 ++ .../j2k/fromClassAndMakeAbstract.java | 29 ++ .../j2k/fromClassAndMakeAbstract.java.after | 6 + .../pushDown/j2k/fromClassUsageConflicts.1.kt | 10 + .../pushDown/j2k/fromClassUsageConflicts.java | 29 ++ .../j2k/fromClassUsageConflicts.java.messages | 3 + .../pushDown/j2k/fromInterface.1.kt | 3 + .../pushDown/j2k/fromInterface.1.kt.after | 25 ++ .../pushDown/j2k/fromInterface.java | 12 + .../pushDown/j2k/fromInterface.java.after | 3 + .../pushDown/{ => k2j}/kotlinToJava.java | 0 .../pushDown/{ => k2j}/kotlinToJava.kt | 0 .../{ => k2j}/kotlinToJava.kt.messages | 0 .../pushDown/{ => k2k}/accidentalOverrides.kt | 0 .../{ => k2k}/accidentalOverrides.kt.messages | 0 .../pushDown/{ => k2k}/clashingMembers.kt | 0 .../{ => k2k}/clashingMembers.kt.messages | 0 .../pushDown/{ => k2k}/classToInterface.kt | 0 .../{ => k2k}/classToInterface.kt.messages | 0 .../{ => k2k}/conflictingSuperCall.kt | 0 .../conflictingSuperCall.kt.messages | 0 .../dropVisibilityOnGeneratedOverride.kt | 0 ...dropVisibilityOnGeneratedOverride.kt.after | 0 .../pushDown/{ => k2k}/finalClass.kt | 0 .../pushDown/{ => k2k}/finalClass.kt.messages | 0 .../{ => k2k}/implicitCompanionUsages.kt | 0 .../implicitCompanionUsages.kt.after | 0 .../pushDown/{ => k2k}/liftPrivate.kt | 0 .../pushDown/{ => k2k}/liftPrivate.kt.after | 0 .../refactoring/pushDown/{ => k2k}/noCaret.kt | 0 .../pushDown/{ => k2k}/noCaret.kt.messages | 0 .../pushDown/{ => k2k}/objectDeclaration.kt | 0 .../{ => k2k}/objectDeclaration.kt.messages | 0 .../pushDown/{ => k2k}/outsideOfClass.kt | 0 .../{ => k2k}/outsideOfClass.kt.messages | 0 .../pushDown/{ => k2k}/pushClassMembers.kt | 0 .../{ => k2k}/pushClassMembers.kt.after | 0 .../pushClassMembersAndMakeAbstract.kt | 0 .../pushClassMembersAndMakeAbstract.kt.after | 0 .../{ => k2k}/pushClassMembersWithGenerics.kt | 0 .../pushClassMembersWithGenerics.kt.after | 0 .../{ => k2k}/pushInterfaceMembers.kt | 0 .../{ => k2k}/pushInterfaceMembers.kt.after | 0 .../pushInterfaceMembersAndMakeAbstract.kt | 0 ...shInterfaceMembersAndMakeAbstract.kt.after | 0 .../{ => k2k}/pushMembersUsingPrivates.kt | 0 .../pushMembersUsingPrivates.kt.messages | 0 .../pushMembersWithExternalUsages.kt | 0 .../pushMembersWithExternalUsages.kt.messages | 0 .../pushDown/{ => k2k}/pushSuperInterfaces.kt | 0 .../{ => k2k}/pushSuperInterfaces.kt.after | 0 .../pushSuperInterfacesWithGenerics.kt | 0 .../pushSuperInterfacesWithGenerics.kt.after | 0 .../pushDown/AbstractPushDownTest.kt | 21 +- .../pushDown/PushDownTestGenerated.java | 289 ++++++++++-------- 67 files changed, 604 insertions(+), 161 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/JavaToKotlinPushDownDelegate.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownImpl.kt create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClass.1.kt create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClass.1.kt.after create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClass.java create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClass.java.after create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt.after create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java.after create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.1.kt create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java create mode 100644 idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java.messages create mode 100644 idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt create mode 100644 idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt.after create mode 100644 idea/testData/refactoring/pushDown/j2k/fromInterface.java create mode 100644 idea/testData/refactoring/pushDown/j2k/fromInterface.java.after rename idea/testData/refactoring/pushDown/{ => k2j}/kotlinToJava.java (100%) rename idea/testData/refactoring/pushDown/{ => k2j}/kotlinToJava.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2j}/kotlinToJava.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/accidentalOverrides.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/accidentalOverrides.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/clashingMembers.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/clashingMembers.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/classToInterface.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/classToInterface.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/conflictingSuperCall.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/conflictingSuperCall.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/dropVisibilityOnGeneratedOverride.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/dropVisibilityOnGeneratedOverride.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/finalClass.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/finalClass.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/implicitCompanionUsages.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/implicitCompanionUsages.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/liftPrivate.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/liftPrivate.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/noCaret.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/noCaret.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/objectDeclaration.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/objectDeclaration.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/outsideOfClass.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/outsideOfClass.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembers.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembers.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembersAndMakeAbstract.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembersAndMakeAbstract.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembersWithGenerics.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushClassMembersWithGenerics.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushInterfaceMembers.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushInterfaceMembers.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushInterfaceMembersAndMakeAbstract.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushInterfaceMembersAndMakeAbstract.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushMembersUsingPrivates.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushMembersUsingPrivates.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushMembersWithExternalUsages.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushMembersWithExternalUsages.kt.messages (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushSuperInterfaces.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushSuperInterfaces.kt.after (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushSuperInterfacesWithGenerics.kt (100%) rename idea/testData/refactoring/pushDown/{ => k2k}/pushSuperInterfacesWithGenerics.kt.after (100%) diff --git a/ChangeLog.md b/ChangeLog.md index edbaa776be7..e9def6f870a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -151,6 +151,7 @@ These artifacts include extensions for the types available in the latter JDKs, s Pull Up: Support properties declared in the primary constructor Pull Up: Support members declared in the companion object of the original class Pull Up: Show member dependencies in the refactoring dialog +- [`KT-9485`](https://youtrack.jetbrains.com/issue/KT-9485) Push Down: Support moving members from Java to Kotlin class #### Android Lint diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index ace85b15958..50e9d7cbd7c 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -814,7 +814,9 @@ fun main(args: Array) { } testClass() { - model("refactoring/pushDown", extension = "kt", singleClass = true) + model("refactoring/pushDown/k2k", extension = "kt", singleClass = true, testClassName = "K2K", testMethod = "doKotlinTest") + model("refactoring/pushDown/k2j", extension = "kt", singleClass = true, testClassName = "K2J", testMethod = "doKotlinTest") + model("refactoring/pushDown/j2k", extension = "java", singleClass = true, testClassName = "J2K", testMethod = "doJavaTest") } testClass() { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 4e38c170230..bfb516279c9 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -711,6 +711,10 @@ language="kotlin" implementationClass="org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinClassMembersRefactoringSupport"/> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/JavaToKotlinPushDownDelegate.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/JavaToKotlinPushDownDelegate.kt new file mode 100644 index 00000000000..f8bc3196ef7 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/JavaToKotlinPushDownDelegate.kt @@ -0,0 +1,116 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.pushDown + +import com.intellij.psi.* +import com.intellij.refactoring.memberPushDown.JavaPushDownDelegate +import com.intellij.refactoring.memberPushDown.NewSubClassData +import com.intellij.refactoring.memberPushDown.PushDownData +import com.intellij.refactoring.util.RefactoringUtil +import com.intellij.refactoring.util.classMembers.MemberInfo +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getJavaMemberDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject +import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass +import org.jetbrains.kotlin.idea.refactoring.j2k +import org.jetbrains.kotlin.idea.refactoring.j2kText +import org.jetbrains.kotlin.idea.refactoring.pullUp.addMemberToTarget +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor + +class JavaToKotlinPushDownDelegate : JavaPushDownDelegate() { + override fun checkTargetClassConflicts( + targetClass: PsiElement?, + pushDownData: PushDownData, + conflicts: MultiMap, + subClassData: NewSubClassData? + ) { + super.checkTargetClassConflicts(targetClass, pushDownData, conflicts, subClassData) + + val ktClass = targetClass?.unwrapped as? KtClassOrObject ?: return + val resolutionFacade = ktClass.getResolutionFacade() + val targetClassDescriptor = resolutionFacade.resolveToDescriptor(ktClass) as ClassDescriptor + for (memberInfo in pushDownData.membersToMove) { + val member = memberInfo.member ?: continue + checkExternalUsages(conflicts, member, targetClassDescriptor, resolutionFacade) + } + } + + override fun pushDownToClass(targetClass: PsiElement, pushDownData: PushDownData) { + val superClass = pushDownData.sourceClass as? PsiClass ?: return + val subClass = targetClass.unwrapped as? KtClassOrObject ?: return + val resolutionFacade = subClass.getResolutionFacade() + val superClassDescriptor = superClass.getJavaClassDescriptor(resolutionFacade) ?: return + val subClassDescriptor = resolutionFacade.resolveToDescriptor(subClass) as ClassDescriptor + val substitutor = getTypeSubstitutor(superClassDescriptor.defaultType, subClassDescriptor.defaultType) ?: TypeSubstitutor.EMPTY + val psiFactory = KtPsiFactory(subClass) + var hasAbstractMembers = false + members@ for (memberInfo in pushDownData.membersToMove) { + val member = memberInfo.member + val memberDescriptor = member.getJavaMemberDescriptor(resolutionFacade) ?: continue + when (member) { + is PsiMethod, is PsiField -> { + val ktMember = member.j2k() as? KtCallableDeclaration ?: continue@members + ktMember.removeModifier(KtTokens.DEFAULT_VISIBILITY_KEYWORD) + val isStatic = member.hasModifierProperty(PsiModifier.STATIC) + val targetMemberClass = if (isStatic && subClass is KtClass) subClass.getOrCreateCompanionObject() else subClass + val targetMemberClassDescriptor = resolutionFacade.resolveToDescriptor(targetMemberClass) as ClassDescriptor + if (member.hasModifierProperty(PsiModifier.ABSTRACT)) { + hasAbstractMembers = true + } + moveCallableMemberToClass( + ktMember, + memberDescriptor as CallableMemberDescriptor, + targetMemberClass, + targetMemberClassDescriptor, + substitutor, + memberInfo.isToAbstract + ).apply { + if (subClass.isInterfaceClass()) { + removeModifier(KtTokens.ABSTRACT_KEYWORD) + } + } + } + + is PsiClass -> { + if (memberInfo.overrides != null) { + val typeText = RefactoringUtil.findReferenceToClass(superClass.implementsList, member)?.j2kText() ?: continue@members + subClass.addSuperTypeListEntry(psiFactory.createSuperTypeEntry(typeText)) + } + else { + val ktClass = member.j2k() as? KtClassOrObject ?: continue@members + addMemberToTarget(ktClass, subClass) + } + } + } + } + + if (hasAbstractMembers && !subClass.isInterfaceClass()) { + subClass.addModifier(KtTokens.ABSTRACT_KEYWORD) + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownProcessor.kt index a9bb5f15459..a9c32b99a05 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownProcessor.kt @@ -29,28 +29,24 @@ import com.intellij.usageView.UsageViewDescriptor import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet -import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper import org.jetbrains.kotlin.idea.refactoring.pullUp.* +import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors import org.jetbrains.kotlin.idea.util.application.runReadAction -import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor -import org.jetbrains.kotlin.util.findCallableMemberBySignature import org.jetbrains.kotlin.utils.keysToMap -import java.util.ArrayList +import java.util.* class KotlinPushDownContext( val sourceClass: KtClass, @@ -141,31 +137,14 @@ class KotlinPushDownProcessor( is KtProperty, is KtNamedFunction -> { memberDescriptor as CallableMemberDescriptor - val targetMemberDescriptor = memberDescriptor.substitute(substitutor)?.let { - targetClassDescriptor.findCallableMemberBySignature(it as CallableMemberDescriptor) - } - val targetMember = targetMemberDescriptor?.source?.getPsi() as? KtCallableDeclaration - targetMember?.apply { - if (memberDescriptor.modality != Modality.ABSTRACT && memberInfo.isToAbstract) { - addModifier(KtTokens.OVERRIDE_KEYWORD) - } - else if (memberDescriptor.overriddenDescriptors.isEmpty()) { - removeModifier(KtTokens.OVERRIDE_KEYWORD) - } - else { - addModifier(KtTokens.OVERRIDE_KEYWORD) - } - } ?: addMemberToTarget(member, targetClass).apply { - if (this@KotlinPushDownProcessor.context.sourceClassDescriptor.kind == ClassKind.INTERFACE) { - if (targetClassDescriptor.kind != ClassKind.INTERFACE && memberDescriptor.modality == Modality.ABSTRACT) { - addModifier(KtTokens.ABSTRACT_KEYWORD) - } - } - if (memberDescriptor.modality != Modality.ABSTRACT && memberInfo.isToAbstract) { - KtTokens.VISIBILITY_MODIFIERS.types.forEach { removeModifier(it as KtModifierKeywordToken) } - addModifier(KtTokens.OVERRIDE_KEYWORD) - } - } + moveCallableMemberToClass( + member as KtCallableDeclaration, + memberDescriptor, + targetClass, + targetClassDescriptor, + substitutor, + memberInfo.isToAbstract + ) } is KtClassOrObject, is KtPsiClassWrapper -> { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownConflictsUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownConflictsUtils.kt index 87932d9705b..fe30218ce5d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownConflictsUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownConflictsUtils.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper import org.jetbrains.kotlin.idea.refactoring.pullUp.renderForConflicts import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver @@ -97,7 +98,7 @@ private fun checkConflicts( for (member in membersToPush) { checkMemberClashing(conflicts, context, member, membersToKeepAbstract, substitutor, targetClass, targetClassDescriptor) checkSuperCalls(conflicts, context, member, membersToPush) - checkExternalUsages(conflicts, context, member, targetClassDescriptor) + checkExternalUsages(conflicts, member, targetClassDescriptor, context.resolutionFacade) checkVisibility(conflicts, context, member, targetClassDescriptor) } } @@ -169,15 +170,15 @@ private fun checkSuperCalls( ) } -private fun checkExternalUsages( +internal fun checkExternalUsages( conflicts: MultiMap, - context: KotlinPushDownContext, - member: KtNamedDeclaration, - targetClassDescriptor: ClassDescriptor + member: PsiElement, + targetClassDescriptor: ClassDescriptor, + resolutionFacade: ResolutionFacade ): Unit { for (ref in ReferencesSearch.search(member, member.resolveScope, false)) { val calleeExpr = ref.element as? KtSimpleNameExpression ?: continue - val resolvedCall = calleeExpr.getResolvedCall(context.resolutionFacade.analyze(calleeExpr)) ?: continue + val resolvedCall = calleeExpr.getResolvedCall(resolutionFacade.analyze(calleeExpr)) ?: continue val callElement = resolvedCall.call.callElement val dispatchReceiver = resolvedCall.dispatchReceiver if (dispatchReceiver == null || dispatchReceiver is Qualifier) continue diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownImpl.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownImpl.kt new file mode 100644 index 00000000000..63add42ac81 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/pushDownImpl.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.pushDown + +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.idea.refactoring.pullUp.addMemberToTarget +import org.jetbrains.kotlin.lexer.KtModifierKeywordToken +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.util.findCallableMemberBySignature + +internal fun moveCallableMemberToClass( + member: KtCallableDeclaration, + memberDescriptor: CallableMemberDescriptor, + targetClass: KtClassOrObject, + targetClassDescriptor: ClassDescriptor, + substitutor: TypeSubstitutor, + makeAbstract: Boolean +): KtCallableDeclaration { + val targetMemberDescriptor = memberDescriptor.substitute(substitutor)?.let { + targetClassDescriptor.findCallableMemberBySignature(it as CallableMemberDescriptor) + } + val targetMember = targetMemberDescriptor?.source?.getPsi() as? KtCallableDeclaration + return targetMember?.apply { + if (memberDescriptor.modality != Modality.ABSTRACT && makeAbstract) { + addModifier(KtTokens.OVERRIDE_KEYWORD) + } + else if (memberDescriptor.overriddenDescriptors.isEmpty()) { + removeModifier(KtTokens.OVERRIDE_KEYWORD) + } + else { + addModifier(KtTokens.OVERRIDE_KEYWORD) + } + } ?: addMemberToTarget(member, targetClass).apply { + val sourceClassDescriptor = memberDescriptor.containingDeclaration as? ClassDescriptor + if (sourceClassDescriptor?.kind == ClassKind.INTERFACE) { + if (targetClassDescriptor.kind != ClassKind.INTERFACE && memberDescriptor.modality == Modality.ABSTRACT) { + addModifier(KtTokens.ABSTRACT_KEYWORD) + } + } + if (memberDescriptor.modality != Modality.ABSTRACT && makeAbstract) { + KtTokens.VISIBILITY_MODIFIERS.types.forEach { removeModifier(it as KtModifierKeywordToken) } + addModifier(KtTokens.OVERRIDE_KEYWORD) + } + } as KtCallableDeclaration +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt b/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt new file mode 100644 index 00000000000..e1d05ad0338 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt @@ -0,0 +1 @@ +class K : A() \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt.after b/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt.after new file mode 100644 index 00000000000..a6d9c70d438 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClass.1.kt.after @@ -0,0 +1,28 @@ +abstract class K : A() { + // INFO: {"checked": "true"} + var x = 2 * 3 + + // INFO: {"checked": "true"} + internal inner class X + + // INFO: {"checked": "true"} + internal class Y + + // INFO: {"checked": "true"} + fun foo(n: Int): Boolean { + return n > 0 + } + + // INFO: {"checked": "true"} + internal abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true"} + fun foo2(n: Int): String { + return "_" + n + "_" + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClass.java b/idea/testData/refactoring/pushDown/j2k/fromClass.java new file mode 100644 index 00000000000..1fdda7e981f --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClass.java @@ -0,0 +1,29 @@ +abstract class A { + // INFO: {"checked": "true"} + int x = 2 * 3; + // INFO: {"checked": "true"} + static String X = "1" + "2"; + + // INFO: {"checked": "true"} + boolean foo(int n) { + return n > 0; + } + + // INFO: {"checked": "true"} + static String foo2(int n) { + return "_" + n + "_"; + } + + // INFO: {"checked": "true"} + abstract int bar(String s); + + // INFO: {"checked": "true"} + class X { + + } + + // INFO: {"checked": "true"} + static class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClass.java.after b/idea/testData/refactoring/pushDown/j2k/fromClass.java.after new file mode 100644 index 00000000000..e7a48f71d96 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClass.java.after @@ -0,0 +1,3 @@ +abstract class A { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt new file mode 100644 index 00000000000..e1d05ad0338 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt @@ -0,0 +1 @@ +class K : A() \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt.after b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt.after new file mode 100644 index 00000000000..ddea66090c2 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.1.kt.after @@ -0,0 +1,28 @@ +abstract class K : A() { + // INFO: {"checked": "true"} + var x = 2 * 3 + + // INFO: {"checked": "true"} + internal inner class X + + // INFO: {"checked": "true"} + internal class Y + + // INFO: {"checked": "true", "toAbstract": "true"} + override fun foo(n: Int): Boolean { + return n > 0 + } + + // INFO: {"checked": "true"} + internal abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true"} + fun foo2(n: Int): String { + return "_" + n + "_" + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java new file mode 100644 index 00000000000..e816ec4cd32 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java @@ -0,0 +1,29 @@ +abstract class A { + // INFO: {"checked": "true"} + int x = 2 * 3; + // INFO: {"checked": "true"} + static String X = "1" + "2"; + + // INFO: {"checked": "true", "toAbstract": "true"} + boolean foo(int n) { + return n > 0; + } + + // INFO: {"checked": "true"} + static String foo2(int n) { + return "_" + n + "_"; + } + + // INFO: {"checked": "true"} + abstract int bar(String s); + + // INFO: {"checked": "true"} + class X { + + } + + // INFO: {"checked": "true"} + static class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java.after b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java.after new file mode 100644 index 00000000000..98408b3bc4d --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java.after @@ -0,0 +1,6 @@ +abstract class A { + + // INFO: {"checked": "true", "toAbstract": "true"} + abstract boolean foo(int n); + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.1.kt b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.1.kt new file mode 100644 index 00000000000..a27c62b708c --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.1.kt @@ -0,0 +1,10 @@ +class K : A() + +fun test(a: A) { + val t1 = a.x + a.x = t1 + 1 + val t2 = A.X + a.foo(1) + A.foo2(2) + A.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java new file mode 100644 index 00000000000..1fdda7e981f --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java @@ -0,0 +1,29 @@ +abstract class A { + // INFO: {"checked": "true"} + int x = 2 * 3; + // INFO: {"checked": "true"} + static String X = "1" + "2"; + + // INFO: {"checked": "true"} + boolean foo(int n) { + return n > 0; + } + + // INFO: {"checked": "true"} + static String foo2(int n) { + return "_" + n + "_"; + } + + // INFO: {"checked": "true"} + abstract int bar(String s); + + // INFO: {"checked": "true"} + class X { + + } + + // INFO: {"checked": "true"} + static class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java.messages b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java.messages new file mode 100644 index 00000000000..a84f6aeccf8 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java.messages @@ -0,0 +1,3 @@ +Pushed member won't be available in 'foo(1)' +Pushed member won't be available in 'x' +Pushed member won't be available in 'x' diff --git a/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt b/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt new file mode 100644 index 00000000000..9f65fac797f --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt @@ -0,0 +1,3 @@ +class K : I + +interface IK: I \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt.after b/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt.after new file mode 100644 index 00000000000..77629061dd2 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromInterface.1.kt.after @@ -0,0 +1,25 @@ +abstract class K : I { + // INFO: {"checked": "true"} + class X + + // INFO: {"checked": "true"} + abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + val x = 2 * 3 + } +} + +interface IK: I { + // INFO: {"checked": "true"} + class X + + // INFO: {"checked": "true"} + fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + val x = 2 * 3 + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromInterface.java b/idea/testData/refactoring/pushDown/j2k/fromInterface.java new file mode 100644 index 00000000000..ad597eb07b2 --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromInterface.java @@ -0,0 +1,12 @@ +interface I { + // INFO: {"checked": "true"} + int x = 2 * 3; + + // INFO: {"checked": "true"} + int bar(String s); + + // INFO: {"checked": "true"} + class X { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/j2k/fromInterface.java.after b/idea/testData/refactoring/pushDown/j2k/fromInterface.java.after new file mode 100644 index 00000000000..59b90a4c96a --- /dev/null +++ b/idea/testData/refactoring/pushDown/j2k/fromInterface.java.after @@ -0,0 +1,3 @@ +interface I { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pushDown/kotlinToJava.java b/idea/testData/refactoring/pushDown/k2j/kotlinToJava.java similarity index 100% rename from idea/testData/refactoring/pushDown/kotlinToJava.java rename to idea/testData/refactoring/pushDown/k2j/kotlinToJava.java diff --git a/idea/testData/refactoring/pushDown/kotlinToJava.kt b/idea/testData/refactoring/pushDown/k2j/kotlinToJava.kt similarity index 100% rename from idea/testData/refactoring/pushDown/kotlinToJava.kt rename to idea/testData/refactoring/pushDown/k2j/kotlinToJava.kt diff --git a/idea/testData/refactoring/pushDown/kotlinToJava.kt.messages b/idea/testData/refactoring/pushDown/k2j/kotlinToJava.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/kotlinToJava.kt.messages rename to idea/testData/refactoring/pushDown/k2j/kotlinToJava.kt.messages diff --git a/idea/testData/refactoring/pushDown/accidentalOverrides.kt b/idea/testData/refactoring/pushDown/k2k/accidentalOverrides.kt similarity index 100% rename from idea/testData/refactoring/pushDown/accidentalOverrides.kt rename to idea/testData/refactoring/pushDown/k2k/accidentalOverrides.kt diff --git a/idea/testData/refactoring/pushDown/accidentalOverrides.kt.messages b/idea/testData/refactoring/pushDown/k2k/accidentalOverrides.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/accidentalOverrides.kt.messages rename to idea/testData/refactoring/pushDown/k2k/accidentalOverrides.kt.messages diff --git a/idea/testData/refactoring/pushDown/clashingMembers.kt b/idea/testData/refactoring/pushDown/k2k/clashingMembers.kt similarity index 100% rename from idea/testData/refactoring/pushDown/clashingMembers.kt rename to idea/testData/refactoring/pushDown/k2k/clashingMembers.kt diff --git a/idea/testData/refactoring/pushDown/clashingMembers.kt.messages b/idea/testData/refactoring/pushDown/k2k/clashingMembers.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/clashingMembers.kt.messages rename to idea/testData/refactoring/pushDown/k2k/clashingMembers.kt.messages diff --git a/idea/testData/refactoring/pushDown/classToInterface.kt b/idea/testData/refactoring/pushDown/k2k/classToInterface.kt similarity index 100% rename from idea/testData/refactoring/pushDown/classToInterface.kt rename to idea/testData/refactoring/pushDown/k2k/classToInterface.kt diff --git a/idea/testData/refactoring/pushDown/classToInterface.kt.messages b/idea/testData/refactoring/pushDown/k2k/classToInterface.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/classToInterface.kt.messages rename to idea/testData/refactoring/pushDown/k2k/classToInterface.kt.messages diff --git a/idea/testData/refactoring/pushDown/conflictingSuperCall.kt b/idea/testData/refactoring/pushDown/k2k/conflictingSuperCall.kt similarity index 100% rename from idea/testData/refactoring/pushDown/conflictingSuperCall.kt rename to idea/testData/refactoring/pushDown/k2k/conflictingSuperCall.kt diff --git a/idea/testData/refactoring/pushDown/conflictingSuperCall.kt.messages b/idea/testData/refactoring/pushDown/k2k/conflictingSuperCall.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/conflictingSuperCall.kt.messages rename to idea/testData/refactoring/pushDown/k2k/conflictingSuperCall.kt.messages diff --git a/idea/testData/refactoring/pushDown/dropVisibilityOnGeneratedOverride.kt b/idea/testData/refactoring/pushDown/k2k/dropVisibilityOnGeneratedOverride.kt similarity index 100% rename from idea/testData/refactoring/pushDown/dropVisibilityOnGeneratedOverride.kt rename to idea/testData/refactoring/pushDown/k2k/dropVisibilityOnGeneratedOverride.kt diff --git a/idea/testData/refactoring/pushDown/dropVisibilityOnGeneratedOverride.kt.after b/idea/testData/refactoring/pushDown/k2k/dropVisibilityOnGeneratedOverride.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/dropVisibilityOnGeneratedOverride.kt.after rename to idea/testData/refactoring/pushDown/k2k/dropVisibilityOnGeneratedOverride.kt.after diff --git a/idea/testData/refactoring/pushDown/finalClass.kt b/idea/testData/refactoring/pushDown/k2k/finalClass.kt similarity index 100% rename from idea/testData/refactoring/pushDown/finalClass.kt rename to idea/testData/refactoring/pushDown/k2k/finalClass.kt diff --git a/idea/testData/refactoring/pushDown/finalClass.kt.messages b/idea/testData/refactoring/pushDown/k2k/finalClass.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/finalClass.kt.messages rename to idea/testData/refactoring/pushDown/k2k/finalClass.kt.messages diff --git a/idea/testData/refactoring/pushDown/implicitCompanionUsages.kt b/idea/testData/refactoring/pushDown/k2k/implicitCompanionUsages.kt similarity index 100% rename from idea/testData/refactoring/pushDown/implicitCompanionUsages.kt rename to idea/testData/refactoring/pushDown/k2k/implicitCompanionUsages.kt diff --git a/idea/testData/refactoring/pushDown/implicitCompanionUsages.kt.after b/idea/testData/refactoring/pushDown/k2k/implicitCompanionUsages.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/implicitCompanionUsages.kt.after rename to idea/testData/refactoring/pushDown/k2k/implicitCompanionUsages.kt.after diff --git a/idea/testData/refactoring/pushDown/liftPrivate.kt b/idea/testData/refactoring/pushDown/k2k/liftPrivate.kt similarity index 100% rename from idea/testData/refactoring/pushDown/liftPrivate.kt rename to idea/testData/refactoring/pushDown/k2k/liftPrivate.kt diff --git a/idea/testData/refactoring/pushDown/liftPrivate.kt.after b/idea/testData/refactoring/pushDown/k2k/liftPrivate.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/liftPrivate.kt.after rename to idea/testData/refactoring/pushDown/k2k/liftPrivate.kt.after diff --git a/idea/testData/refactoring/pushDown/noCaret.kt b/idea/testData/refactoring/pushDown/k2k/noCaret.kt similarity index 100% rename from idea/testData/refactoring/pushDown/noCaret.kt rename to idea/testData/refactoring/pushDown/k2k/noCaret.kt diff --git a/idea/testData/refactoring/pushDown/noCaret.kt.messages b/idea/testData/refactoring/pushDown/k2k/noCaret.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/noCaret.kt.messages rename to idea/testData/refactoring/pushDown/k2k/noCaret.kt.messages diff --git a/idea/testData/refactoring/pushDown/objectDeclaration.kt b/idea/testData/refactoring/pushDown/k2k/objectDeclaration.kt similarity index 100% rename from idea/testData/refactoring/pushDown/objectDeclaration.kt rename to idea/testData/refactoring/pushDown/k2k/objectDeclaration.kt diff --git a/idea/testData/refactoring/pushDown/objectDeclaration.kt.messages b/idea/testData/refactoring/pushDown/k2k/objectDeclaration.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/objectDeclaration.kt.messages rename to idea/testData/refactoring/pushDown/k2k/objectDeclaration.kt.messages diff --git a/idea/testData/refactoring/pushDown/outsideOfClass.kt b/idea/testData/refactoring/pushDown/k2k/outsideOfClass.kt similarity index 100% rename from idea/testData/refactoring/pushDown/outsideOfClass.kt rename to idea/testData/refactoring/pushDown/k2k/outsideOfClass.kt diff --git a/idea/testData/refactoring/pushDown/outsideOfClass.kt.messages b/idea/testData/refactoring/pushDown/k2k/outsideOfClass.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/outsideOfClass.kt.messages rename to idea/testData/refactoring/pushDown/k2k/outsideOfClass.kt.messages diff --git a/idea/testData/refactoring/pushDown/pushClassMembers.kt b/idea/testData/refactoring/pushDown/k2k/pushClassMembers.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembers.kt rename to idea/testData/refactoring/pushDown/k2k/pushClassMembers.kt diff --git a/idea/testData/refactoring/pushDown/pushClassMembers.kt.after b/idea/testData/refactoring/pushDown/k2k/pushClassMembers.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembers.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushClassMembers.kt.after diff --git a/idea/testData/refactoring/pushDown/pushClassMembersAndMakeAbstract.kt b/idea/testData/refactoring/pushDown/k2k/pushClassMembersAndMakeAbstract.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembersAndMakeAbstract.kt rename to idea/testData/refactoring/pushDown/k2k/pushClassMembersAndMakeAbstract.kt diff --git a/idea/testData/refactoring/pushDown/pushClassMembersAndMakeAbstract.kt.after b/idea/testData/refactoring/pushDown/k2k/pushClassMembersAndMakeAbstract.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembersAndMakeAbstract.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushClassMembersAndMakeAbstract.kt.after diff --git a/idea/testData/refactoring/pushDown/pushClassMembersWithGenerics.kt b/idea/testData/refactoring/pushDown/k2k/pushClassMembersWithGenerics.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembersWithGenerics.kt rename to idea/testData/refactoring/pushDown/k2k/pushClassMembersWithGenerics.kt diff --git a/idea/testData/refactoring/pushDown/pushClassMembersWithGenerics.kt.after b/idea/testData/refactoring/pushDown/k2k/pushClassMembersWithGenerics.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushClassMembersWithGenerics.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushClassMembersWithGenerics.kt.after diff --git a/idea/testData/refactoring/pushDown/pushInterfaceMembers.kt b/idea/testData/refactoring/pushDown/k2k/pushInterfaceMembers.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushInterfaceMembers.kt rename to idea/testData/refactoring/pushDown/k2k/pushInterfaceMembers.kt diff --git a/idea/testData/refactoring/pushDown/pushInterfaceMembers.kt.after b/idea/testData/refactoring/pushDown/k2k/pushInterfaceMembers.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushInterfaceMembers.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushInterfaceMembers.kt.after diff --git a/idea/testData/refactoring/pushDown/pushInterfaceMembersAndMakeAbstract.kt b/idea/testData/refactoring/pushDown/k2k/pushInterfaceMembersAndMakeAbstract.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushInterfaceMembersAndMakeAbstract.kt rename to idea/testData/refactoring/pushDown/k2k/pushInterfaceMembersAndMakeAbstract.kt diff --git a/idea/testData/refactoring/pushDown/pushInterfaceMembersAndMakeAbstract.kt.after b/idea/testData/refactoring/pushDown/k2k/pushInterfaceMembersAndMakeAbstract.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushInterfaceMembersAndMakeAbstract.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushInterfaceMembersAndMakeAbstract.kt.after diff --git a/idea/testData/refactoring/pushDown/pushMembersUsingPrivates.kt b/idea/testData/refactoring/pushDown/k2k/pushMembersUsingPrivates.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushMembersUsingPrivates.kt rename to idea/testData/refactoring/pushDown/k2k/pushMembersUsingPrivates.kt diff --git a/idea/testData/refactoring/pushDown/pushMembersUsingPrivates.kt.messages b/idea/testData/refactoring/pushDown/k2k/pushMembersUsingPrivates.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/pushMembersUsingPrivates.kt.messages rename to idea/testData/refactoring/pushDown/k2k/pushMembersUsingPrivates.kt.messages diff --git a/idea/testData/refactoring/pushDown/pushMembersWithExternalUsages.kt b/idea/testData/refactoring/pushDown/k2k/pushMembersWithExternalUsages.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushMembersWithExternalUsages.kt rename to idea/testData/refactoring/pushDown/k2k/pushMembersWithExternalUsages.kt diff --git a/idea/testData/refactoring/pushDown/pushMembersWithExternalUsages.kt.messages b/idea/testData/refactoring/pushDown/k2k/pushMembersWithExternalUsages.kt.messages similarity index 100% rename from idea/testData/refactoring/pushDown/pushMembersWithExternalUsages.kt.messages rename to idea/testData/refactoring/pushDown/k2k/pushMembersWithExternalUsages.kt.messages diff --git a/idea/testData/refactoring/pushDown/pushSuperInterfaces.kt b/idea/testData/refactoring/pushDown/k2k/pushSuperInterfaces.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushSuperInterfaces.kt rename to idea/testData/refactoring/pushDown/k2k/pushSuperInterfaces.kt diff --git a/idea/testData/refactoring/pushDown/pushSuperInterfaces.kt.after b/idea/testData/refactoring/pushDown/k2k/pushSuperInterfaces.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushSuperInterfaces.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushSuperInterfaces.kt.after diff --git a/idea/testData/refactoring/pushDown/pushSuperInterfacesWithGenerics.kt b/idea/testData/refactoring/pushDown/k2k/pushSuperInterfacesWithGenerics.kt similarity index 100% rename from idea/testData/refactoring/pushDown/pushSuperInterfacesWithGenerics.kt rename to idea/testData/refactoring/pushDown/k2k/pushSuperInterfacesWithGenerics.kt diff --git a/idea/testData/refactoring/pushDown/pushSuperInterfacesWithGenerics.kt.after b/idea/testData/refactoring/pushDown/k2k/pushSuperInterfacesWithGenerics.kt.after similarity index 100% rename from idea/testData/refactoring/pushDown/pushSuperInterfacesWithGenerics.kt.after rename to idea/testData/refactoring/pushDown/k2k/pushSuperInterfacesWithGenerics.kt.after diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/AbstractPushDownTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/AbstractPushDownTest.kt index 90be328a12a..c2dbe8be05d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/AbstractPushDownTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/AbstractPushDownTest.kt @@ -16,12 +16,19 @@ package org.jetbrains.kotlin.idea.refactoring.pushDown +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiComment +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.refactoring.memberPushDown.PushDownProcessor +import com.intellij.refactoring.util.DocCommentPolicy +import com.intellij.refactoring.util.classMembers.MemberInfoStorage +import com.intellij.util.ui.UIUtil import org.jetbrains.kotlin.idea.refactoring.AbstractMemberPullPushTest import org.jetbrains.kotlin.idea.refactoring.chooseMembers import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo abstract class AbstractPushDownTest : AbstractMemberPullPushTest() { - protected fun doTest(path: String) { + protected fun doKotlinTest(path: String) { doTest(path) { file -> val helper = object: KotlinPushDownHandler.TestHelper { override fun adjustMembers(members: List) = chooseMembers(members) @@ -31,4 +38,16 @@ abstract class AbstractPushDownTest : AbstractMemberPullPushTest() { } } } + + protected fun doJavaTest(path: String) { + doTest(path) { file -> + val elementAt = getFile().findElementAt(editor.caretModel.offset) + val sourceClass = PsiTreeUtil.getParentOfType(elementAt, PsiClass::class.java)!! + val storage = MemberInfoStorage(sourceClass) { true } + val memberInfos = chooseMembers(storage.getClassMemberInfos(sourceClass)) + + PushDownProcessor(sourceClass, memberInfos, DocCommentPolicy(DocCommentPolicy.ASIS)).run() + UIUtil.dispatchAllInvocationEvents() + } + } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/PushDownTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/PushDownTestGenerated.java index 8267d05ad82..5ce3a5e59fc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/PushDownTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pushDown/PushDownTestGenerated.java @@ -27,137 +27,182 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@TestMetadata("idea/testData/refactoring/pushDown") -@TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public class PushDownTestGenerated extends AbstractPushDownTest { - @TestMetadata("accidentalOverrides.kt") - public void testAccidentalOverrides() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/accidentalOverrides.kt"); - doTest(fileName); + @TestMetadata("idea/testData/refactoring/pushDown/k2k") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class K2K extends AbstractPushDownTest { + @TestMetadata("accidentalOverrides.kt") + public void testAccidentalOverrides() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/accidentalOverrides.kt"); + doKotlinTest(fileName); + } + + public void testAllFilesPresentInK2K() throws Exception { + KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pushDown/k2k"), Pattern.compile("^(.+)\\.kt$")); + } + + @TestMetadata("clashingMembers.kt") + public void testClashingMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/clashingMembers.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("classToInterface.kt") + public void testClassToInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/classToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("conflictingSuperCall.kt") + public void testConflictingSuperCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/conflictingSuperCall.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("dropVisibilityOnGeneratedOverride.kt") + public void testDropVisibilityOnGeneratedOverride() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/dropVisibilityOnGeneratedOverride.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("finalClass.kt") + public void testFinalClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/finalClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("implicitCompanionUsages.kt") + public void testImplicitCompanionUsages() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/implicitCompanionUsages.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("liftPrivate.kt") + public void testLiftPrivate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/liftPrivate.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("noCaret.kt") + public void testNoCaret() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/noCaret.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("objectDeclaration.kt") + public void testObjectDeclaration() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/objectDeclaration.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("outsideOfClass.kt") + public void testOutsideOfClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/outsideOfClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushClassMembers.kt") + public void testPushClassMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushClassMembers.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushClassMembersAndMakeAbstract.kt") + public void testPushClassMembersAndMakeAbstract() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushClassMembersAndMakeAbstract.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushClassMembersWithGenerics.kt") + public void testPushClassMembersWithGenerics() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushClassMembersWithGenerics.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushInterfaceMembers.kt") + public void testPushInterfaceMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushInterfaceMembers.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushInterfaceMembersAndMakeAbstract.kt") + public void testPushInterfaceMembersAndMakeAbstract() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushInterfaceMembersAndMakeAbstract.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushMembersUsingPrivates.kt") + public void testPushMembersUsingPrivates() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushMembersUsingPrivates.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushMembersWithExternalUsages.kt") + public void testPushMembersWithExternalUsages() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushMembersWithExternalUsages.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushSuperInterfaces.kt") + public void testPushSuperInterfaces() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushSuperInterfaces.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("pushSuperInterfacesWithGenerics.kt") + public void testPushSuperInterfacesWithGenerics() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2k/pushSuperInterfacesWithGenerics.kt"); + doKotlinTest(fileName); + } } - public void testAllFilesPresentInPushDown() throws Exception { - KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pushDown"), Pattern.compile("^(.+)\\.kt$")); + @TestMetadata("idea/testData/refactoring/pushDown/k2j") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class K2J extends AbstractPushDownTest { + public void testAllFilesPresentInK2J() throws Exception { + KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pushDown/k2j"), Pattern.compile("^(.+)\\.kt$")); + } + + @TestMetadata("kotlinToJava.kt") + public void testKotlinToJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/k2j/kotlinToJava.kt"); + doKotlinTest(fileName); + } } - @TestMetadata("clashingMembers.kt") - public void testClashingMembers() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/clashingMembers.kt"); - doTest(fileName); - } + @TestMetadata("idea/testData/refactoring/pushDown/j2k") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class J2K extends AbstractPushDownTest { + public void testAllFilesPresentInJ2K() throws Exception { + KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pushDown/j2k"), Pattern.compile("^(.+)\\.java$")); + } - @TestMetadata("classToInterface.kt") - public void testClassToInterface() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/classToInterface.kt"); - doTest(fileName); - } + @TestMetadata("fromClass.java") + public void testFromClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/j2k/fromClass.java"); + doJavaTest(fileName); + } - @TestMetadata("conflictingSuperCall.kt") - public void testConflictingSuperCall() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/conflictingSuperCall.kt"); - doTest(fileName); - } + @TestMetadata("fromClassAndMakeAbstract.java") + public void testFromClassAndMakeAbstract() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/j2k/fromClassAndMakeAbstract.java"); + doJavaTest(fileName); + } - @TestMetadata("dropVisibilityOnGeneratedOverride.kt") - public void testDropVisibilityOnGeneratedOverride() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/dropVisibilityOnGeneratedOverride.kt"); - doTest(fileName); - } + @TestMetadata("fromClassUsageConflicts.java") + public void testFromClassUsageConflicts() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/j2k/fromClassUsageConflicts.java"); + doJavaTest(fileName); + } - @TestMetadata("finalClass.kt") - public void testFinalClass() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/finalClass.kt"); - doTest(fileName); - } - - @TestMetadata("implicitCompanionUsages.kt") - public void testImplicitCompanionUsages() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/implicitCompanionUsages.kt"); - doTest(fileName); - } - - @TestMetadata("kotlinToJava.kt") - public void testKotlinToJava() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/kotlinToJava.kt"); - doTest(fileName); - } - - @TestMetadata("liftPrivate.kt") - public void testLiftPrivate() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/liftPrivate.kt"); - doTest(fileName); - } - - @TestMetadata("noCaret.kt") - public void testNoCaret() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/noCaret.kt"); - doTest(fileName); - } - - @TestMetadata("objectDeclaration.kt") - public void testObjectDeclaration() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/objectDeclaration.kt"); - doTest(fileName); - } - - @TestMetadata("outsideOfClass.kt") - public void testOutsideOfClass() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/outsideOfClass.kt"); - doTest(fileName); - } - - @TestMetadata("pushClassMembers.kt") - public void testPushClassMembers() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushClassMembers.kt"); - doTest(fileName); - } - - @TestMetadata("pushClassMembersAndMakeAbstract.kt") - public void testPushClassMembersAndMakeAbstract() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushClassMembersAndMakeAbstract.kt"); - doTest(fileName); - } - - @TestMetadata("pushClassMembersWithGenerics.kt") - public void testPushClassMembersWithGenerics() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushClassMembersWithGenerics.kt"); - doTest(fileName); - } - - @TestMetadata("pushInterfaceMembers.kt") - public void testPushInterfaceMembers() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushInterfaceMembers.kt"); - doTest(fileName); - } - - @TestMetadata("pushInterfaceMembersAndMakeAbstract.kt") - public void testPushInterfaceMembersAndMakeAbstract() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushInterfaceMembersAndMakeAbstract.kt"); - doTest(fileName); - } - - @TestMetadata("pushMembersUsingPrivates.kt") - public void testPushMembersUsingPrivates() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushMembersUsingPrivates.kt"); - doTest(fileName); - } - - @TestMetadata("pushMembersWithExternalUsages.kt") - public void testPushMembersWithExternalUsages() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushMembersWithExternalUsages.kt"); - doTest(fileName); - } - - @TestMetadata("pushSuperInterfaces.kt") - public void testPushSuperInterfaces() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushSuperInterfaces.kt"); - doTest(fileName); - } - - @TestMetadata("pushSuperInterfacesWithGenerics.kt") - public void testPushSuperInterfacesWithGenerics() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/pushSuperInterfacesWithGenerics.kt"); - doTest(fileName); + @TestMetadata("fromInterface.java") + public void testFromInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pushDown/j2k/fromInterface.java"); + doJavaTest(fileName); + } } }