Pull Up/Extract Super: Support properties declared in the primary constructor

This commit is contained in:
Alexey Sedunov
2016-09-20 15:12:13 +03:00
parent 3aedf0d79f
commit 982d4d4ead
38 changed files with 378 additions and 47 deletions
+1
View File
@@ -148,6 +148,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-13155`](https://youtrack.jetbrains.com/issue/KT-13155) Implement "Introduce Type Parameter" refactoring
- [`KT-11017`](https://youtrack.jetbrains.com/issue/KT-11017) Implement "Extract Superclass" refactoring
- [`KT-11017`](https://youtrack.jetbrains.com/issue/KT-11017) Implement "Extract Interface" refactoring
Pull Up: Support properties declared in the primary constructor
#### Android Lint
@@ -439,6 +439,8 @@ class KtPsiFactory(private val project: Project) {
return argumentList.arguments.single()
}
fun createArgument(text: String) = createCallArguments("($text)").arguments.first()!!
fun createSuperTypeCallEntry(text: String): KtSuperTypeCallEntry {
return createClass("class A: $text").getSuperTypeListEntries().first() as KtSuperTypeCallEntry
}
@@ -27,11 +27,11 @@ import com.intellij.refactoring.RefactoringActionHandler
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.lang.ElementsHandler
import com.intellij.refactoring.util.CommonRefactoringUtil
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import java.util.HashSet
import java.util.*
abstract class AbstractPullPushMembersHandler(
private val refactoringName: String,
@@ -43,6 +43,8 @@ abstract class AbstractPullPushMembersHandler(
CommonRefactoringUtil.showErrorHint(project, editor, message, refactoringName, helpId)
}
private fun KtParameter.getContainingClass() = if (hasValOrVar()) (ownerFunction as? KtPrimaryConstructor)?.containingClassOrObject else null
protected fun reportWrongContext(project: Project, editor: Editor?) {
val message = RefactoringBundle.getCannotRefactorMessage(
RefactoringBundle.message("is.not.supported.in.the.current.context", refactoringName)
@@ -61,7 +63,9 @@ abstract class AbstractPullPushMembersHandler(
editor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
val target = (file.findElementAt(offset) ?: return).parentsWithSelf.firstOrNull {
it is KtClassOrObject || ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody)
it is KtClassOrObject
|| ((it is KtNamedFunction || it is KtProperty) && it.parent is KtClassBody)
|| it is KtParameter && it.hasValOrVar() && it.ownerFunction is KtPrimaryConstructor
}
if (target == null) {
@@ -80,6 +84,7 @@ abstract class AbstractPullPushMembersHandler(
val (classOrObject, member) = when (element) {
is KtNamedFunction, is KtProperty -> element.getStrictParentOfType<KtClassOrObject>() to element as KtNamedDeclaration?
is KtParameter -> element.getContainingClass() to element
is KtClassOrObject -> element to null
else -> {
reportWrongPosition(project, editor)
@@ -93,8 +98,8 @@ abstract class AbstractPullPushMembersHandler(
override fun isEnabledOnElements(elements: Array<out PsiElement>): Boolean {
return elements.mapTo(HashSet<PsiElement>()) {
when (it) {
is KtNamedFunction, is KtProperty ->
(it.parent as? KtClassBody)?.parent as? KtClassOrObject
is KtNamedFunction, is KtProperty -> (it.parent as? KtClassBody)?.parent as? KtClassOrObject
is KtParameter -> it.getContainingClass()
is KtClassOrObject -> it
else -> null
} ?: return false
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
import org.jetbrains.kotlin.idea.refactoring.pullUp.mustBeAbstractInInterface
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.*
class KotlinExtractInterfaceDialog(
originalClass: KtClassOrObject,
@@ -54,7 +51,7 @@ class KotlinExtractInterfaceDialog(
return object : MemberInfoModelBase(extractableMemberInfos) {
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
val member = memberInfo.member
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface())
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface()) || member is KtParameter
}
override fun isAbstractWhenDisabled(member: KotlinMemberInfo) = member.member is KtProperty
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
class KotlinExtractSuperclassDialog(
@@ -46,7 +47,7 @@ class KotlinExtractSuperclassDialog(
return object : MemberInfoModelBase(extractClassMembers(originalClass)) {
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
val member = memberInfo.member
return member is KtNamedFunction || member is KtProperty
return member is KtNamedFunction || member is KtProperty || member is KtParameter
}
}
}
@@ -75,8 +75,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.highlighter.markers.getAccessorLightMethods
import org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateIntention
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.string.collapseSpaces
@@ -542,8 +545,9 @@ fun createJavaMethod(template: PsiMethod, targetClass: PsiClass): PsiMethod {
return method
}
fun createJavaField(property: KtProperty, targetClass: PsiClass): PsiField {
val template = LightClassUtil.getLightClassPropertyMethods(property).getter
fun createJavaField(property: KtNamedDeclaration, targetClass: PsiClass): PsiField {
val accessorLightMethods = property.getAccessorLightMethods()
val template = accessorLightMethods.getter
?: throw AssertionError("Can't generate light method: ${property.getElementTextWithContext()}")
val factory = PsiElementFactory.SERVICE.getInstance(template.project)
@@ -552,7 +556,7 @@ fun createJavaField(property: KtProperty, targetClass: PsiClass): PsiField {
with(field.modifierList!!) {
val templateModifiers = template.modifierList
setModifierProperty(VisibilityUtil.getVisibilityModifier(templateModifiers), true)
if (!property.isVar || targetClass.isInterface) {
if ((property as KtValVarKeywordOwner).valOrVarKeyword.toValVar() != KotlinValVar.Var || targetClass.isInterface) {
setModifierProperty(PsiModifier.FINAL, true)
}
copyModifierListItems(templateModifiers, this, false)
@@ -16,13 +16,15 @@
package org.jetbrains.kotlin.idea.refactoring.memberInfo
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.util.classMembers.MemberInfo
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor
@@ -31,6 +33,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptySet
class KotlinMemberInfo(member: KtNamedDeclaration, val isSuperClass: Boolean = false) : MemberInfoBase<KtNamedDeclaration>(member) {
@@ -72,7 +75,9 @@ fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
val declaration = member
val psiMember: PsiMember? = when (declaration) {
is KtNamedFunction -> declaration.getRepresentativeLightMethod()
is KtProperty -> declaration.getRepresentativeLightMethod() ?: LightClassUtil.getLightClassPropertyMethods(declaration).backingField
is KtProperty, is KtParameter -> declaration.toLightElements().let {
it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>()
} as PsiMember?
is KtClassOrObject -> declaration.toLightClass()
else -> null
}
@@ -102,6 +102,11 @@ fun extractClassMembers(
.mapTo(result) { KotlinMemberInfo(it, true) }
}
aClass.getPrimaryConstructor()
?.valueParameters
?.filter { it.hasValOrVar() }
?.mapTo(result) { KotlinMemberInfo(it) }
aClass.declarations
.filter { it is KtNamedDeclaration
&& it !is KtConstructor<*>
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.KotlinIconProvider
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
import javax.swing.Icon
@@ -36,7 +37,7 @@ class KotlinMemberSelectionTable(
if (memberInfo.isStatic()) return null
val member = memberInfo.member
if (member !is KtNamedFunction && member !is KtProperty) return null
if (member !is KtNamedFunction && member !is KtProperty && member !is KtParameter) return null
if (member.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
myMemberInfoModel.isFixedAbstract(memberInfo)?.let { return it }
@@ -51,7 +52,7 @@ class KotlinMemberSelectionTable(
if (memberInfo.isStatic()) return false
val member = memberInfo.member
if (member !is KtNamedFunction && member !is KtProperty) return false
if (member !is KtNamedFunction && member !is KtProperty && member !is KtParameter) return false
if (member.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
myMemberInfoModel.isFixedAbstract(memberInfo)?.let { return false }
@@ -68,7 +69,7 @@ class KotlinMemberSelectionTable(
val defaultIcon = AbstractMemberSelectionTable.EMPTY_OVERRIDE_ICON
val member = memberInfo.member
if (member !is KtNamedFunction && member !is KtProperty) return defaultIcon
if (member !is KtNamedFunction && member !is KtProperty && member !is KtParameter) return defaultIcon
return when (memberInfo.getOverrides()) {
true -> AllIcons.General.OverridingMethod
@@ -25,7 +25,9 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.types.*
@@ -42,10 +44,21 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
val sourceClassDescriptor = sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, sourceClass] as ClassDescriptor
val memberDescriptors = membersToMove.keysToMap { sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!! }
val memberDescriptors = membersToMove.keysToMap {
if (it is KtParameter) {
sourceClassContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!!
}
else {
sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!!
}
}
val targetClassDescriptor = targetClass.getClassDescriptorIfAny(resolutionFacade)!!
val superEntryForTargetClass = sourceClass.getSuperTypeEntryByDescriptor(targetClassDescriptor, sourceClassContext)
val targetClassSuperResolvedCall = superEntryForTargetClass.getResolvedCall(sourceClassContext)
val typeParametersInSourceClassContext by lazy {
sourceClassDescriptor.declaredTypeParameters +
sourceClass.getResolutionScope(sourceClassContext, resolutionFacade)
@@ -65,12 +65,13 @@ class KotlinPullUpDialog(
if (!superClass.isInterface()) return true
val member = memberInfo.member
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface())
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface()) || member is KtParameter
}
override fun isAbstractWhenDisabled(memberInfo: KotlinMemberInfo): Boolean {
val member = memberInfo.member
return (member is KtProperty && superClass !is PsiClass) || (member is KtNamedFunction && superClass is PsiClass)
return ((member is KtProperty || member is KtParameter) && superClass !is PsiClass)
|| (member is KtNamedFunction && superClass is PsiClass)
}
override fun isMemberEnabled(memberInfo: KotlinMemberInfo): Boolean {
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.dropDefaultValue
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.refactoring.createJavaField
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
@@ -42,11 +43,9 @@ import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.asAssignment
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -380,11 +379,16 @@ class KotlinPullUpHelper(
val lightMethod = member.getRepresentativeLightMethod()!!
val movedMember: PsiMember = when (member) {
is KtProperty -> {
is KtProperty, is KtParameter -> {
val newType = substitutor.substitute(lightMethod.returnType)
val newField = createJavaField(member, data.targetClass)
newField.typeElement?.replace(elementFactory.createTypeElement(newType))
member.delete()
if (member is KtParameter) {
(member.parent as? KtParameterList)?.removeParameter(member)
}
else {
member.delete()
}
newField
}
is KtNamedFunction -> {
@@ -448,6 +452,8 @@ class KotlinPullUpHelper(
val movedMember: KtCallableDeclaration
val clashingSuper = fixOverrideAndGetClashingSuper(member, memberCopy)
val psiFactory = KtPsiFactory(member)
val originalIsAbstract = member.hasModifier(KtTokens.ABSTRACT_KEYWORD)
val toAbstract = when {
info.isToAbstract -> true
@@ -469,7 +475,33 @@ class KotlinPullUpHelper(
}
else {
movedMember = doAddCallableMember(memberCopy, clashingSuper, data.targetClass)
member.delete()
if (member is KtParameter && movedMember is KtParameter) {
member.valOrVarKeyword?.delete()
val superEntry = data.superEntryForTargetClass
val superResolvedCall = data.targetClassSuperResolvedCall
if (superResolvedCall != null) {
val superCall = if (superEntry !is KtSuperTypeCallEntry || superEntry.valueArgumentList == null) {
superEntry!!.replaced(psiFactory.createSuperTypeCallEntry("${superEntry.text}()"))
} else superEntry
val argumentList = superCall.valueArgumentList!!
val parameterIndex = movedMember.parameterIndex()
val prevParameterDescriptor = superResolvedCall.resultingDescriptor.valueParameters.getOrNull(parameterIndex - 1)
val prevArgument = superResolvedCall.valueArguments[prevParameterDescriptor]?.arguments?.singleOrNull() as? KtValueArgument
val newArgumentName = if (prevArgument != null && prevArgument.isNamed()) Name.identifier(member.name!!) else null
val newArgument = psiFactory.createArgument(psiFactory.createExpression(member.name!!), newArgumentName)
if (prevArgument == null) {
argumentList.addArgument(newArgument)
}
else {
argumentList.addArgumentAfter(newArgument, prevArgument)
}
}
}
else {
member.delete()
}
}
if (originalIsAbstract && data.isInterfaceTarget) {
@@ -90,13 +90,22 @@ internal fun KotlinPullUpData.getClashingMemberInTargetClass(memberDescriptor: C
private fun KotlinPullUpData.checkClashWithSuperDeclaration(
member: KtNamedDeclaration,
memberDescriptor: DeclarationDescriptor,
conflicts: MultiMap<PsiElement, String>) {
conflicts: MultiMap<PsiElement, String>
) {
val message = "${targetClassDescriptor.renderForConflicts()} already contains ${memberDescriptor.renderForConflicts()}"
if (member is KtParameter) {
if (((targetClass as? KtClass)?.getPrimaryConstructorParameters() ?: emptyList()).any { it.name == member.name }) {
conflicts.putValue(member, message.capitalize())
}
return
}
if (memberDescriptor !is CallableMemberDescriptor) return
val clashingSuper = getClashingMemberInTargetClass(memberDescriptor) ?: return
if (clashingSuper.modality == Modality.ABSTRACT) return
if (clashingSuper.kind != CallableMemberDescriptor.Kind.DECLARATION) return
val message = "${targetClassDescriptor.renderForConflicts()} already contains ${memberDescriptor.renderForConflicts()}"
conflicts.putValue(member, message.capitalize())
}
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -39,10 +38,10 @@ fun KtProperty.mustBeAbstractInInterface() =
fun KtNamedDeclaration.canMoveMemberToJavaClass(targetClass: PsiClass): Boolean {
return when (this) {
is KtProperty -> {
is KtProperty, is KtParameter -> {
if (targetClass.isInterface) return false
if (hasModifier(KtTokens.OPEN_KEYWORD) || hasModifier(KtTokens.ABSTRACT_KEYWORD)) return false
if (accessors.isNotEmpty() || delegateExpression != null) return false
if (this is KtProperty && (accessors.isNotEmpty() || delegateExpression != null)) return false
true
}
is KtNamedFunction -> valueParameters.all { it.defaultValue == null }
@@ -51,22 +50,38 @@ fun KtNamedDeclaration.canMoveMemberToJavaClass(targetClass: PsiClass): Boolean
}
fun addMemberToTarget(targetMember: KtNamedDeclaration, targetClass: KtClassOrObject): KtNamedDeclaration {
if (targetMember is KtParameter) {
val parameterList = (targetClass as KtClass).createPrimaryConstructorIfAbsent().valueParameterList!!
val anchor = parameterList.parameters.firstOrNull { it.isVarArg || it.hasDefaultValue() }
return parameterList.addParameterBefore(targetMember, anchor)
}
val anchor = targetClass.declarations.filterIsInstance(targetMember.javaClass).lastOrNull()
val movedMember = when {
anchor == null && targetMember is KtProperty -> targetClass.addDeclarationBefore(targetMember, null)
else -> targetClass.addDeclarationAfter(targetMember, anchor)
}
return movedMember as KtNamedDeclaration
return movedMember
}
private fun KtParameter.toProperty(): KtProperty = KtPsiFactory(this).createProperty(text)
fun doAddCallableMember(
memberCopy: KtCallableDeclaration,
clashingSuper: KtCallableDeclaration?,
targetClass: KtClass): KtCallableDeclaration {
targetClass: KtClass
): KtCallableDeclaration {
val memberToAdd =
if (memberCopy is KtParameter && (memberCopy.hasModifier(KtTokens.ABSTRACT_KEYWORD) || targetClass.isInterface())) {
memberCopy.toProperty()
}
else memberCopy
if (clashingSuper != null && clashingSuper.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
return clashingSuper.replaced(memberCopy)
return clashingSuper.replaced(if (memberToAdd is KtParameter && clashingSuper is KtProperty) memberToAdd.toProperty() else memberToAdd)
}
return addMemberToTarget(memberCopy, targetClass) as KtCallableDeclaration
return addMemberToTarget(memberToAdd, targetClass) as KtCallableDeclaration
}
// TODO: Formatting rules don't apply here for some reason
@@ -85,13 +100,11 @@ fun KtClass.makeAbstract() {
fun KtClassOrObject.getSuperTypeEntryByDescriptor(
descriptor: ClassDescriptor,
context: BindingContext
): KtSuperTypeEntry? {
return getSuperTypeListEntries()
.filterIsInstance<KtSuperTypeEntry>()
.firstOrNull {
val referencedType = context[BindingContext.TYPE, it.typeReference]
referencedType?.constructor?.declarationDescriptor == descriptor
}
): KtSuperTypeListEntry? {
return getSuperTypeListEntries().firstOrNull {
val referencedType = context[BindingContext.TYPE, it.typeReference]
referencedType?.constructor?.declarationDescriptor == descriptor
}
}
fun makeAbstract(member: KtCallableDeclaration,
@@ -136,7 +149,7 @@ fun makeAbstract(member: KtCallableDeclaration,
}
fun addSuperTypeEntry(
delegator: KtSuperTypeEntry,
delegator: KtSuperTypeListEntry,
targetClass: KtClassOrObject,
targetClassDescriptor: ClassDescriptor,
context: BindingContext,
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.refactoring.pullUp.PULL_MEMBERS_UP
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.isInheritable
val PUSH_MEMBERS_DOWN = "Push Members Down"
@@ -71,7 +72,7 @@ class KotlinPushDownHandler : AbstractPullPushMembersHandler(
return
}
val members = KotlinMemberInfoStorage(classOrObject).getClassMemberInfos(classOrObject)
val members = KotlinMemberInfoStorage(classOrObject).getClassMemberInfos(classOrObject).filter { it.member !is KtParameter }
if (ApplicationManager.getApplication().isUnitTestMode) {
val helper = dataContext?.getData(PUSH_DOWN_TEST_HELPER_KEY) as TestHelper
val selectedMembers = helper.adjustMembers(members)
@@ -0,0 +1,3 @@
class A {
}
@@ -0,0 +1,8 @@
import org.jetbrains.annotations.NotNull;
class A {
public final int n;
@NotNull
public final String s;
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
abstract class <caret>B(
// INFO: {"checked": "true"}
val n: Int,
// INFO: {"checked": "true"}
val s: String,
val b: Boolean
): A()
@@ -0,0 +1,6 @@
// WITH_RUNTIME
abstract class B(
// INFO: {"checked": "true"}
// INFO: {"checked": "true"}
val b: Boolean
): A()
@@ -0,0 +1,9 @@
interface I
class <caret>B(
// INFO: {"checked": "true", "toAbstract": "true"}
val s: String,
// INFO: {"checked": "true", "toAbstract": "true"}
val b: Boolean,
val i: Int
) : I
@@ -0,0 +1,12 @@
interface I {
val s: String
val b: Boolean
}
class B(
// INFO: {"checked": "true", "toAbstract": "true"}
override val s: String,
// INFO: {"checked": "true", "toAbstract": "true"}
override val b: Boolean,
val i: Int
) : I
@@ -0,0 +1,11 @@
open class A(n: Int) {
}
class <caret>B(
// INFO: {"checked": "true"}
val s: String,
// INFO: {"checked": "true"}
val b: Boolean,
val i: Int
) : A(1)
@@ -0,0 +1,11 @@
open class A(n: Int, val s: String, val b: Boolean) {
}
class B(
// INFO: {"checked": "true"}
s: String,
// INFO: {"checked": "true"}
b: Boolean,
val i: Int
) : A(1, s, b)
@@ -0,0 +1,11 @@
open class A(n: Int) {
}
class <caret>B(
// INFO: {"checked": "true", "toAbstract": "true"}
val s: String,
// INFO: {"checked": "true", "toAbstract": "true"}
val b: Boolean,
val i: Int
) : A(1)
@@ -0,0 +1,13 @@
abstract class A(n: Int) {
abstract val s: String
abstract val b: Boolean
}
class B(
// INFO: {"checked": "true", "toAbstract": "true"}
override val s: String,
// INFO: {"checked": "true", "toAbstract": "true"}
override val b: Boolean,
val i: Int
) : A(1)
@@ -0,0 +1,8 @@
open class A(n: Int, s: String = "") {
}
class <caret>B(
// INFO: {"checked": "true"}
val i: Int
) : A(1, "2")
@@ -0,0 +1,8 @@
open class A(n: Int, val i: Int, s: String = "") {
}
class B(
// INFO: {"checked": "true"}
i: Int
) : A(1, i, "2")
@@ -0,0 +1,8 @@
open class A(n: Int, s: String = "") {
}
class <caret>B(
// INFO: {"checked": "true"}
val i: Int
) : A(1)
@@ -0,0 +1,8 @@
open class A(n: Int, val i: Int, s: String = "") {
}
class B(
// INFO: {"checked": "true"}
i: Int
) : A(1, i)
@@ -0,0 +1,8 @@
open class A(n: Int, s: String) {
}
class <caret>B(
// INFO: {"checked": "true"}
val i: Int
) : A(s = "2", n = 1)
@@ -0,0 +1,8 @@
open class A(n: Int, s: String, val i: Int) {
}
class B(
// INFO: {"checked": "true"}
i: Int
) : A(s = "2", i = i, n = 1)
@@ -0,0 +1,8 @@
open class A(n: Int, s: String = "") {
}
class <caret>B(
// INFO: {"checked": "true"}
val i: Int
) : A(s = "2", n = 1)
@@ -0,0 +1,8 @@
open class A(n: Int, val i: Int, s: String = "") {
}
class B(
// INFO: {"checked": "true"}
i: Int
) : A(s = "2", n = 1, i = i)
@@ -0,0 +1,8 @@
open class A(n: Int, vararg s: String) {
}
class <caret>B(
// INFO: {"checked": "true"}
val i: Int
) : A(1, "2", "3")
@@ -0,0 +1,8 @@
open class A(n: Int, val i: Int, vararg s: String) {
}
class B(
// INFO: {"checked": "true"}
i: Int
) : A(1, i, "2", "3")
@@ -0,0 +1,8 @@
open class A(x: Int) {
}
class <caret>B(
// INFO: {"checked": "true"}
val x: String
) : A(1)
@@ -0,0 +1 @@
Class A already contains property 'val x: String'
@@ -49,6 +49,54 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersToInterface.kt")
public void testConstructorParametersToInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersToSuperClass.kt")
public void testConstructorParametersToSuperClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersToSuperClassAndMakeAbstract.kt")
public void testConstructorParametersToSuperClassAndMakeAbstract() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersWithDefaultValue1.kt")
public void testConstructorParametersWithDefaultValue1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersWithDefaultValue2.kt")
public void testConstructorParametersWithDefaultValue2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersWithNamedArgs.kt")
public void testConstructorParametersWithNamedArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersWithNamedArgsAndDefault.kt")
public void testConstructorParametersWithNamedArgsAndDefault() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt");
doKotlinTest(fileName);
}
@TestMetadata("constructorParametersWithVararg.kt")
public void testConstructorParametersWithVararg() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt");
doKotlinTest(fileName);
}
@TestMetadata("defaultValuesInOverride.kt")
public void testDefaultValuesInOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/defaultValuesInOverride.kt");
@@ -217,6 +265,12 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doKotlinTest(fileName);
}
@TestMetadata("parameterNameConflict.kt")
public void testParameterNameConflict() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt");
doKotlinTest(fileName);
}
@TestMetadata("parametersInPrimaryInitializer.kt")
public void testParametersInPrimaryInitializer() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/parametersInPrimaryInitializer.kt");
@@ -292,6 +346,12 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp/k2j"), Pattern.compile("^(.+)\\.kt$"));
}
@TestMetadata("constructorParameterToClass.kt")
public void testConstructorParameterToClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt");
doKotlinTest(fileName);
}
@TestMetadata("defaultValuesInOverride.kt")
public void testDefaultValuesInOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/defaultValuesInOverride.kt");