From 982d4d4ead38e13cd430e780da2a6b9960d45097 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 20 Sep 2016 15:12:13 +0300 Subject: [PATCH] Pull Up/Extract Super: Support properties declared in the primary constructor --- ChangeLog.md | 1 + .../org/jetbrains/kotlin/psi/KtPsiFactory.kt | 2 + .../AbstractPullPushMembersHandler.kt | 15 +++-- .../ui/KotlinExtractInterfaceDialog.kt | 7 +-- .../ui/KotlinExtractSuperclassDialog.kt | 3 +- .../idea/refactoring/kotlinRefactoringUtil.kt | 10 +++- .../memberInfo/KotlinMemberInfo.kt | 9 ++- .../memberInfo/KotlinMemberInfoStorage.kt | 5 ++ .../memberInfo/KotlinMemberSelectionTable.kt | 7 ++- .../refactoring/pullUp/KotlinPullUpData.kt | 15 ++++- .../refactoring/pullUp/KotlinPullUpDialog.kt | 5 +- .../refactoring/pullUp/KotlinPullUpHelper.kt | 46 +++++++++++--- .../pullUp/pullUpConflictsUtils.kt | 13 +++- .../idea/refactoring/pullUp/pullUpUtils.kt | 43 ++++++++----- .../pushDown/KotlinPushDownHandler.kt | 3 +- .../k2j/constructorParameterToClass.1.java | 3 + .../constructorParameterToClass.1.java.after | 8 +++ .../pullUp/k2j/constructorParameterToClass.kt | 8 +++ .../k2j/constructorParameterToClass.kt.after | 6 ++ .../k2k/constructorParametersToInterface.kt | 9 +++ .../constructorParametersToInterface.kt.after | 12 ++++ .../k2k/constructorParametersToSuperClass.kt | 11 ++++ ...constructorParametersToSuperClass.kt.after | 11 ++++ ...orParametersToSuperClassAndMakeAbstract.kt | 11 ++++ ...metersToSuperClassAndMakeAbstract.kt.after | 13 ++++ .../constructorParametersWithDefaultValue1.kt | 8 +++ ...ructorParametersWithDefaultValue1.kt.after | 8 +++ .../constructorParametersWithDefaultValue2.kt | 8 +++ ...ructorParametersWithDefaultValue2.kt.after | 8 +++ .../k2k/constructorParametersWithNamedArgs.kt | 8 +++ ...onstructorParametersWithNamedArgs.kt.after | 8 +++ ...ructorParametersWithNamedArgsAndDefault.kt | 8 +++ ...ParametersWithNamedArgsAndDefault.kt.after | 8 +++ .../k2k/constructorParametersWithVararg.kt | 8 +++ .../constructorParametersWithVararg.kt.after | 8 +++ .../pullUp/k2k/parameterNameConflict.kt | 8 +++ .../k2k/parameterNameConflict.kt.messages | 1 + .../pullUp/PullUpTestGenerated.java | 60 +++++++++++++++++++ 38 files changed, 378 insertions(+), 47 deletions(-) create mode 100644 idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java create mode 100644 idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java.after create mode 100644 idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt create mode 100644 idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt.after create mode 100644 idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt create mode 100644 idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt.messages diff --git a/ChangeLog.md b/ChangeLog.md index e17fa05b9ea..b1395f50c47 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index 72e823c38ef..e77bd10607d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -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 } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt index f601c9f6bfb..d1d8cd7cc32 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/AbstractPullPushMembersHandler.kt @@ -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() 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): Boolean { return elements.mapTo(HashSet()) { 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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt index 981484445dd..4e896430b4d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt index 71487a98ec8..62d391cf4c6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt @@ -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 } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt index f7960a9bdfc..bcccab1ed7e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt @@ -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) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt index f916031ade6..75fb3429d18 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt @@ -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(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() ?: it.firstIsInstanceOrNull() + } as PsiMember? is KtClassOrObject -> declaration.toLightClass() else -> null } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfoStorage.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfoStorage.kt index 1b519a39536..2f7c0711ccc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfoStorage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfoStorage.kt @@ -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<*> diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberSelectionTable.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberSelectionTable.kt index b5058273239..96ae9414eed 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberSelectionTable.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberSelectionTable.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpData.kt index b2e087221cb..f47186ced36 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpData.kt @@ -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) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt index e4fd07c0e1a..d05fd19c310 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt @@ -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 { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt index 34d26fcfe70..ad9f0195da2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt @@ -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) { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt index 0ad76a6603d..f3cdf31cfab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpConflictsUtils.kt @@ -90,13 +90,22 @@ internal fun KotlinPullUpData.getClashingMemberInTargetClass(memberDescriptor: C private fun KotlinPullUpData.checkClashWithSuperDeclaration( member: KtNamedDeclaration, memberDescriptor: DeclarationDescriptor, - conflicts: MultiMap) { + conflicts: MultiMap +) { + 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()) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt index 1d9e62758ac..791e514af57 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt @@ -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() - .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, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt index 5b031b24529..f2d476846fa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownHandler.kt @@ -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) diff --git a/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java new file mode 100644 index 00000000000..1b4568a8f26 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java @@ -0,0 +1,3 @@ +class A { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java.after b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java.after new file mode 100644 index 00000000000..85f72b50577 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.1.java.after @@ -0,0 +1,8 @@ +import org.jetbrains.annotations.NotNull; + +class A { + + public final int n; + @NotNull + public final String s; +} diff --git a/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt new file mode 100644 index 00000000000..8dca401fbb0 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +abstract class B( + // INFO: {"checked": "true"} + val n: Int, + // INFO: {"checked": "true"} + val s: String, + val b: Boolean +): A() \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt.after b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt.after new file mode 100644 index 00000000000..57fa567d9c5 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2j/constructorParameterToClass.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME +abstract class B( + // INFO: {"checked": "true"} + // INFO: {"checked": "true"} + val b: Boolean +): A() diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt new file mode 100644 index 00000000000..2d3e4c57952 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt @@ -0,0 +1,9 @@ +interface I + +class B( + // INFO: {"checked": "true", "toAbstract": "true"} + val s: String, + // INFO: {"checked": "true", "toAbstract": "true"} + val b: Boolean, + val i: Int +) : I \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt.after new file mode 100644 index 00000000000..a8148f05d62 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToInterface.kt.after @@ -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 \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt new file mode 100644 index 00000000000..464e595a66b --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt @@ -0,0 +1,11 @@ +open class A(n: Int) { + +} + +class B( + // INFO: {"checked": "true"} + val s: String, + // INFO: {"checked": "true"} + val b: Boolean, + val i: Int +) : A(1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt.after new file mode 100644 index 00000000000..293aebec35e --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClass.kt.after @@ -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) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt new file mode 100644 index 00000000000..cfd5d86c361 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt @@ -0,0 +1,11 @@ +open class A(n: Int) { + +} + +class B( + // INFO: {"checked": "true", "toAbstract": "true"} + val s: String, + // INFO: {"checked": "true", "toAbstract": "true"} + val b: Boolean, + val i: Int +) : A(1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt.after new file mode 100644 index 00000000000..644bd567248 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersToSuperClassAndMakeAbstract.kt.after @@ -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) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt new file mode 100644 index 00000000000..d86b80ec80b --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt @@ -0,0 +1,8 @@ +open class A(n: Int, s: String = "") { + +} + +class B( + // INFO: {"checked": "true"} + val i: Int +) : A(1, "2") \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt.after new file mode 100644 index 00000000000..9b309cf5466 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue1.kt.after @@ -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") \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt new file mode 100644 index 00000000000..f1bbd55073a --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt @@ -0,0 +1,8 @@ +open class A(n: Int, s: String = "") { + +} + +class B( + // INFO: {"checked": "true"} + val i: Int +) : A(1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt.after new file mode 100644 index 00000000000..5f3bbd2877e --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithDefaultValue2.kt.after @@ -0,0 +1,8 @@ +open class A(n: Int, val i: Int, s: String = "") { + +} + +class B( + // INFO: {"checked": "true"} + i: Int +) : A(1, i) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt new file mode 100644 index 00000000000..faf54561e03 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt @@ -0,0 +1,8 @@ +open class A(n: Int, s: String) { + +} + +class B( + // INFO: {"checked": "true"} + val i: Int +) : A(s = "2", n = 1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt.after new file mode 100644 index 00000000000..3fe8e06db3f --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgs.kt.after @@ -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) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt new file mode 100644 index 00000000000..012108fe9e3 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt @@ -0,0 +1,8 @@ +open class A(n: Int, s: String = "") { + +} + +class B( + // INFO: {"checked": "true"} + val i: Int +) : A(s = "2", n = 1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt.after new file mode 100644 index 00000000000..581e7fcfee5 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithNamedArgsAndDefault.kt.after @@ -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) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt new file mode 100644 index 00000000000..eccb46931c4 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt @@ -0,0 +1,8 @@ +open class A(n: Int, vararg s: String) { + +} + +class B( + // INFO: {"checked": "true"} + val i: Int +) : A(1, "2", "3") \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt.after b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt.after new file mode 100644 index 00000000000..e22aae5046d --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/constructorParametersWithVararg.kt.after @@ -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") \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt b/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt new file mode 100644 index 00000000000..47c0904c741 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt @@ -0,0 +1,8 @@ +open class A(x: Int) { + +} + +class B( + // INFO: {"checked": "true"} + val x: String +) : A(1) \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt.messages b/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt.messages new file mode 100644 index 00000000000..a2a167e0b84 --- /dev/null +++ b/idea/testData/refactoring/pullUp/k2k/parameterNameConflict.kt.messages @@ -0,0 +1 @@ +Class A already contains property 'val x: String' \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java index 732ce171b65..97c269fba98 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java @@ -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");