Push Down: Support moving members from Java to Kotlin class
#KT-9485 Fixed
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -814,7 +814,9 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
testClass<AbstractPushDownTest>() {
|
||||
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<AbstractSelectExpressionForDebuggerTest>() {
|
||||
|
||||
@@ -711,6 +711,10 @@
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinClassMembersRefactoringSupport"/>
|
||||
|
||||
<refactoring.pushDown
|
||||
language="kotlin"
|
||||
implementationClass="org.jetbrains.kotlin.idea.refactoring.pushDown.JavaToKotlinPushDownDelegate"/>
|
||||
|
||||
<problemFileHighlightFilter implementation="org.jetbrains.kotlin.idea.projectView.KotlinProblemFileHighlightFilter"/>
|
||||
|
||||
<codeInsight.typeInfo language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinExpressionTypeProvider"/>
|
||||
|
||||
+116
@@ -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<MemberInfo, PsiMember>,
|
||||
conflicts: MultiMap<PsiElement, String>,
|
||||
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<MemberInfo, PsiMember>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-31
@@ -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 -> {
|
||||
|
||||
@@ -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<PsiElement, String>,
|
||||
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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
class K : A()
|
||||
@@ -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 + "_"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
abstract class <caret>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 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
abstract class A {
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
class K : A()
|
||||
@@ -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 + "_"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
abstract class <caret>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 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
abstract class A {
|
||||
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
abstract boolean foo(int n);
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
abstract class <caret>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 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
@@ -0,0 +1,3 @@
|
||||
class K : I
|
||||
|
||||
interface IK: I
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
interface <caret>I {
|
||||
// INFO: {"checked": "true"}
|
||||
int x = 2 * 3;
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
int bar(String s);
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class X {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
interface I {
|
||||
|
||||
}
|
||||
Vendored
@@ -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<KotlinMemberInfo>) = 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<PsiComment>(DocCommentPolicy.ASIS)).run()
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
}
|
||||
}
|
||||
}
|
||||
+167
-122
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user