diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index 923094ed58d..89c95d1b951 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -136,6 +136,10 @@ public class JetPsiFactory(private val project: Project) { return createDeclaration(text) } + public fun createCompanionObject(): JetObjectDeclaration { + return createClass("class A {\n companion object{\n}\n}").getCompanionObjects().first() + } + public fun createFile(text: String): JetFile { return createFile("dummy.kt", text) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetTypeParameterListOwnerStub.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetTypeParameterListOwnerStub.java index a21d5604ec2..c3f8be8992e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetTypeParameterListOwnerStub.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetTypeParameterListOwnerStub.java @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; import java.util.Collections; import java.util.List; -abstract class JetTypeParameterListOwnerStub> extends JetNamedDeclarationStub implements JetTypeParameterListOwner { +public abstract class JetTypeParameterListOwnerStub> extends JetNamedDeclarationStub implements JetTypeParameterListOwner { public JetTypeParameterListOwnerStub(@NotNull T stub, @NotNull IStubElementType nodeType) { super(stub, nodeType); } diff --git a/compiler/tests/org/jetbrains/kotlin/test/util/jetTestUtils.kt b/compiler/tests/org/jetbrains/kotlin/test/util/jetTestUtils.kt index 470f023980e..46d01b2e552 100644 --- a/compiler/tests/org/jetbrains/kotlin/test/util/jetTestUtils.kt +++ b/compiler/tests/org/jetbrains/kotlin/test/util/jetTestUtils.kt @@ -19,9 +19,7 @@ package org.jetbrains.kotlin.test.util import com.intellij.codeInspection.SmartHashMap import com.intellij.testFramework.fixtures.CodeInsightTestFixture import com.intellij.openapi.util.io.FileUtil -import com.intellij.psi.PsiComment -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.* import com.intellij.psi.util.PsiTreeUtil import com.intellij.util.SmartFMap import org.jetbrains.kotlin.psi.* @@ -77,11 +75,11 @@ public fun String.trimIndent(): String { }.joinToString(separator = "\n") } -public fun JetFile.findElementByCommentPrefix(commentText: String): JetElement? = +public fun PsiFile.findElementByCommentPrefix(commentText: String): PsiElement? = findElementsByCommentPrefix(commentText).keySet().singleOrNull() -public fun JetFile.findElementsByCommentPrefix(prefix: String): Map { - var result = SmartFMap.emptyMap() +public fun PsiFile.findElementsByCommentPrefix(prefix: String): Map { + var result = SmartFMap.emptyMap() accept( object : JetTreeVisitorVoid() { override fun visitComment(comment: PsiComment) { @@ -90,11 +88,12 @@ public fun JetFile.findElementsByCommentPrefix(prefix: String): Map parent + is PsiMember -> parent else -> PsiTreeUtil.skipSiblingsForward( comment, javaClass(), javaClass(), javaClass() ) - } as? JetElement ?: return + } as? PsiElement ?: return result = result.plus(elementToAdd, commentText.substring(prefix.length()).trim()) } diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 7a6bee2b3f9..becec3b06f7 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -658,7 +658,9 @@ fun main(args: Array) { } testClass(javaClass()) { - model("refactoring/pullUp", extension = "kt", singleClass = true) + model("refactoring/pullUp/k2k", extension = "kt", singleClass = true, testClassName = "K2K", testMethod = "doKotlinTest") + model("refactoring/pullUp/k2j", extension = "kt", singleClass = true, testClassName = "K2J", testMethod = "doKotlinTest") + model("refactoring/pullUp/j2k", extension = "java", singleClass = true, testClassName = "J2K", testMethod = "doJavaTest") } testClass(javaClass()) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt index 8c3661ccd15..964f38763d4 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/searchUtil.kt @@ -30,4 +30,4 @@ public fun Project.allScope(): GlobalSearchScope = GlobalSearchScope.allScope(th public fun Project.projectScope(): GlobalSearchScope = GlobalSearchScope.projectScope(this) -public fun PsiFile.fileScope(): GlobalSearchScope = GlobalSearchScope.fileScope(this) +public fun PsiFile.fileScope(): GlobalSearchScope = GlobalSearchScope.fileScope(this) \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt index 33996e0ddcd..2f5ecbe1624 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt @@ -148,4 +148,9 @@ private fun deleteElementWithDelimiters(element: PsiElement) { public fun PsiElement.deleteSingle() { CodeEditUtil.removeChild(getParent()?.getNode() ?: return, getNode() ?: return) +} + +public fun JetClass.getOrCreateCompanionObject() : JetObjectDeclaration { + getCompanionObjects().firstOrNull()?.let { return it } + return addDeclaration(JetPsiFactory(this).createCompanionObject()) as JetObjectDeclaration } \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index a505f744267..909c3d6aa63 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -534,7 +534,13 @@ language="jet" implementationClass="org.jetbrains.kotlin.idea.search.ideaExtensions.JetTargetElementEvaluator" /> - + + diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt index 81ae4ea3f66..62dfc51be05 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt @@ -512,8 +512,8 @@ fun createJavaField(property: JetProperty, targetClass: PsiClass): PsiField { return field } -fun createJavaClass(klass: JetClass, targetClass: PsiClass): PsiMember { - val kind = (klass.resolveToDescriptor() as ClassDescriptor).getKind() +fun createJavaClass(klass: JetClass, targetClass: PsiClass?, forcePlainClass: Boolean = false): PsiClass { + val kind = if (forcePlainClass) ClassKind.CLASS else (klass.resolveToDescriptor() as ClassDescriptor).getKind() val factory = PsiElementFactory.SERVICE.getInstance(klass.getProject()) val className = klass.getName()!! @@ -524,7 +524,7 @@ fun createJavaClass(klass: JetClass, targetClass: PsiClass): PsiMember { ClassKind.ENUM_CLASS -> factory.createEnum(className) else -> throw AssertionError("Unexpected class kind: ${klass.getElementTextWithContext()}") } - val javaClass = targetClass.add(javaClassToAdd) as PsiClass + val javaClass = (targetClass?.add(javaClassToAdd) ?: javaClassToAdd) as PsiClass val template = LightClassUtil.getPsiClass(klass) ?: throw AssertionError("Can't generate light class: ${klass.getElementTextWithContext()}") @@ -538,17 +538,27 @@ fun createJavaClass(klass: JetClass, targetClass: PsiClass): PsiMember { klass.addAfter(typeParameterList, klass.getNameIdentifier()) } - val extendsList = factory.createReferenceListWithRole( - template.getExtendsList()?.getReferenceElements() ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY, - PsiReferenceList.Role.EXTENDS_LIST - ) - extendsList?.let { javaClass.getExtendsList()?.replace(it) } + // Turning interface to class + if (!javaClass.isInterface && template.isInterface) { + val implementsList = factory.createReferenceListWithRole( + template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY, + PsiReferenceList.Role.IMPLEMENTS_LIST + ) + implementsList?.let { javaClass.implementsList?.replace(it) } + } + else { + val extendsList = factory.createReferenceListWithRole( + template.extendsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY, + PsiReferenceList.Role.EXTENDS_LIST + ) + extendsList?.let { javaClass.extendsList?.replace(it) } - val implementsList = factory.createReferenceListWithRole( - template.getImplementsList()?.getReferenceElements() ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY, - PsiReferenceList.Role.IMPLEMENTS_LIST - ) - implementsList?.let { javaClass.getImplementsList()?.replace(it) } + val implementsList = factory.createReferenceListWithRole( + template.implementsList?.referenceElements ?: PsiJavaCodeReferenceElement.EMPTY_ARRAY, + PsiReferenceList.Role.IMPLEMENTS_LIST + ) + implementsList?.let { javaClass.implementsList?.replace(it) } + } for (method in template.getMethods()) { val hasParams = method.getParameterList().getParametersCount() > 0 @@ -567,15 +577,23 @@ fun createJavaClass(klass: JetClass, targetClass: PsiClass): PsiMember { return javaClass } -fun PsiExpression.j2k(): JetExpression? { - if (getLanguage() != JavaLanguage.INSTANCE) return null +fun PsiElement.j2kText(): String? { + if (language != JavaLanguage.INSTANCE) return null - val project = getProject() val j2kConverter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices) - val text = j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports - return JetPsiFactory(getProject()).createExpression(text) + return j2kConverter.elementsToKotlin(listOf(this)).results.single()?.text ?: return null //TODO: insert imports +} + +fun PsiExpression.j2k(): JetExpression? { + val text = j2kText() ?: return null + return JetPsiFactory(project).createExpression(text) +} + +fun PsiMember.j2k(): JetNamedDeclaration? { + val text = j2kText() ?: return null + return JetPsiFactory(project).createDeclaration(text) } public fun (() -> Any).runRefactoringWithPostprocessing( diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPostconversionPullUpHelper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPostconversionPullUpHelper.kt new file mode 100644 index 00000000000..76c553dab0a --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPostconversionPullUpHelper.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2015 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.pullUp + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMember +import com.intellij.psi.PsiSubstitutor +import com.intellij.refactoring.memberPullUp.PullUpData +import com.intellij.refactoring.memberPullUp.PullUpHelper +import com.intellij.refactoring.util.classMembers.MemberInfo +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector +import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression +import java.util.LinkedHashSet + +public class JavaToKotlinPostconversionPullUpHelper(private val data: PullUpData) : PullUpHelper { + override fun setCorrectVisibility(info: MemberInfo?) { } + + override fun encodeContextInfo(info: MemberInfo?) { } + + override fun move(info: MemberInfo?, substitutor: PsiSubstitutor?) { } + + override fun postProcessMember(member: PsiMember?) { } + + // TODO: To be implemented + override fun moveFieldInitializations(movedFields: LinkedHashSet?) { } + + override fun updateUsage(element: PsiElement?) { + if (element !is JetSimpleNameExpression) return + val qualifier = element.getReceiverExpression()?.getQualifiedElementSelector() as? JetSimpleNameExpression ?: return + qualifier.mainReference.bindToElement(data.targetClass.unwrapped!!) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPreconversionPullUpHelper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPreconversionPullUpHelper.kt new file mode 100644 index 00000000000..3e6ef8c6c0d --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/JavaToKotlinPreconversionPullUpHelper.kt @@ -0,0 +1,168 @@ +/* + * Copyright 2010-2015 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.pullUp + +import com.intellij.openapi.util.Key +import com.intellij.psi.* +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.refactoring.encapsulateFields.* +import com.intellij.refactoring.memberPullUp.JavaPullUpHelper +import com.intellij.refactoring.memberPullUp.PullUpData +import com.intellij.refactoring.memberPullUp.PullUpHelper +import com.intellij.refactoring.util.DocCommentPolicy +import com.intellij.refactoring.util.RefactoringUtil +import com.intellij.refactoring.util.classMembers.MemberInfo +import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet +import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject +import org.jetbrains.kotlin.idea.core.refactoring.j2k +import org.jetbrains.kotlin.idea.core.refactoring.j2kText +import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.psi.* +import java.util.HashMap + +public class JavaToKotlinPreconversionPullUpHelper( + private val data: PullUpData, + private val dummyTargetClass: PsiClass, + private val javaHelper: JavaPullUpHelper +) : PullUpHelper by javaHelper { + private val membersToDummyDeclarations = HashMap() + + private val encapsulateFieldsDescriptor = object: EncapsulateFieldsDescriptor { + override fun getSelectedFields(): Array? = arrayOf() + override fun isToEncapsulateGet() = true + override fun isToEncapsulateSet() = true + override fun isToUseAccessorsWhenAccessible() = true + override fun getFieldsVisibility() = null + override fun getAccessorsVisibility() = PsiModifier.PUBLIC + override fun getTargetClass() = dummyTargetClass + override fun getJavadocPolicy() = DocCommentPolicy.ASIS + } + + private val fieldsToUsages = HashMap>() + private val dummyAccessorByName = HashMap() + + private val platformStaticAnnotation = JetPsiFactory(data.sourceClass.project).createAnnotationEntry("kotlin.platform.platformStatic") + + companion object { + private var PsiMember.originalMember: PsiMember? by CopyableUserDataProperty(Key.create("ORIGINAL_MEMBER")) + } + + private fun collectFieldReferencesToEncapsulate(member: PsiField) { + val helper = EncapsulateFieldHelper.getHelper(member.language) ?: return + val fieldName = member.name!! + val getterName = JvmAbi.getterName(fieldName) + val setterName = JvmAbi.setterName(fieldName) + val getter = helper.generateMethodPrototype(member, getterName, true) + val setter = helper.generateMethodPrototype(member, setterName, false) + val fieldDescriptor = FieldDescriptorImpl(member, getterName, setterName, getter, setter) + getter?.let { dummyAccessorByName[getterName] = dummyTargetClass.add(it) as PsiMethod } + setter?.let { dummyAccessorByName[setterName] = dummyTargetClass.add(it) as PsiMethod } + fieldsToUsages[member] = ReferencesSearch + .search(member) + .map { helper.createUsage(encapsulateFieldsDescriptor, fieldDescriptor, it) } + .filterNotNull() + } + + override fun move(info: MemberInfo, substitutor: PsiSubstitutor) { + val member = info.member + val movingSuperInterface = member is PsiClass && info.overrides == false + + if (!movingSuperInterface) { + member.originalMember = member + } + + if (info.isStatic) { + info.isToAbstract = false + } + + if (member is PsiField && !info.isStatic) { + collectFieldReferencesToEncapsulate(member) + } + + val superInterfaceCount = getCurrentSuperInterfaceCount() + + javaHelper.move(info, substitutor) + + if (info.isStatic) { + member.removeOverrideModifier() + } + + val targetClass = data.targetClass.unwrapped as JetClass + if (member.hasModifierProperty(PsiModifier.ABSTRACT) && !movingSuperInterface) targetClass.makeAbstract() + + val psiFactory = JetPsiFactory(member.project) + + if (movingSuperInterface) { + if (getCurrentSuperInterfaceCount() == superInterfaceCount) return + + val typeText = RefactoringUtil.findReferenceToClass(dummyTargetClass.implementsList, member as PsiClass)?.j2kText() ?: return + targetClass.addDelegationSpecifier(psiFactory.createDelegatorToSuperClass(typeText)) + return + } + + val memberOwner = when { + member.hasModifierProperty(PsiModifier.STATIC) && member !is PsiClass -> targetClass.getOrCreateCompanionObject() + else -> targetClass + } + val dummyDeclaration : JetNamedDeclaration = when (member) { + is PsiField -> psiFactory.createProperty("val foo = 0") + is PsiMethod -> psiFactory.createFunction("fun foo() = 0") + is PsiClass -> psiFactory.createClass("class Foo") + else -> return + } + // postProcessMember() call order is unstable so in order to stabilize resulting member order we add dummies to target class + // and replace them after postprocessing + membersToDummyDeclarations[member] = addMemberToTarget(dummyDeclaration, memberOwner) + } + + private fun getCurrentSuperInterfaceCount() = dummyTargetClass.implementsList?.referenceElements?.size() ?: 0 + + override fun postProcessMember(member: PsiMember) { + javaHelper.postProcessMember(member) + + val originalMember = member.originalMember ?: return + originalMember.originalMember = null + + val targetClass = data.targetClass.unwrapped as? JetClass ?: return + val convertedDeclaration = member.j2k() ?: return + val newDeclaration = membersToDummyDeclarations[originalMember]?.replace(convertedDeclaration) as JetNamedDeclaration + if (targetClass.isInterface()) { + newDeclaration.removeModifier(JetTokens.ABSTRACT_KEYWORD) + } + if (member.hasModifierProperty(PsiModifier.STATIC) && newDeclaration is JetNamedFunction) { + newDeclaration.addAnnotationWithSpace(platformStaticAnnotation).addToShorteningWaitSet() + } + + if (originalMember is PsiField) { + val usages = fieldsToUsages[originalMember] ?: return + val firstUsage = usages.firstOrNull() ?: return + val fieldDescriptor = firstUsage.fieldDescriptor + val targetLightClass = (firstUsage.reference?.resolve() as? PsiField)?.containingClass ?: return + val getter = targetLightClass.findMethodBySignature(fieldDescriptor.getterPrototype, false) + val setter = targetLightClass.findMethodBySignature(fieldDescriptor.setterPrototype, false) + + for (usage in usages) { + EncapsulateFieldHelper + .getHelper(usage.element!!.language) + ?.processUsage(usage, encapsulateFieldsDescriptor, setter, getter) + } + } + } +} \ No newline at end of file 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 c82953da037..dc7999af90e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelper.kt @@ -37,14 +37,12 @@ import org.jetbrains.kotlin.idea.JetLanguage import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet import org.jetbrains.kotlin.idea.core.refactoring.createJavaField import org.jetbrains.kotlin.idea.core.refactoring.createJavaMethod -import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier -import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -377,24 +375,6 @@ class KotlinPullUpHelper( } } - private fun addMemberToTarget(targetMember: JetNamedDeclaration): JetNamedDeclaration { - data.targetClass as JetClass - - val anchor = data.targetClass.declarations.filterIsInstance(targetMember.javaClass).lastOrNull() - val movedMember = when { - anchor == null && targetMember is JetProperty -> data.targetClass.addDeclarationBefore(targetMember, null) - else -> data.targetClass.addDeclarationAfter(targetMember, anchor) - } - return movedMember as JetNamedDeclaration - } - - private fun doAddCallableMember(memberCopy: JetCallableDeclaration, clashingSuper: JetCallableDeclaration?): JetCallableDeclaration { - if (clashingSuper != null && clashingSuper.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { - return clashingSuper.replaced(memberCopy) - } - return addMemberToTarget(memberCopy) as JetCallableDeclaration - } - private fun markElements(member: JetNamedDeclaration): List { val affectedElements = ArrayList() @@ -510,12 +490,6 @@ class KotlinPullUpHelper( } } - // TODO: Formatting rules don't apply here for some reason - private fun JetNamedDeclaration.addModifierWithSpace(modifier: JetModifierKeywordToken) { - addModifier(modifier) - addAfter(JetPsiFactory(this).createWhiteSpace(), modifierList) - } - private fun moveSuperInterface(member: JetClass, substitutor: PsiSubstitutor) { val classDescriptor = data.memberDescriptors[member] as? ClassDescriptor ?: return val currentSpecifier = @@ -635,7 +609,7 @@ class KotlinPullUpHelper( memberCopy.removeModifier(JetTokens.INNER_KEYWORD) } - val movedMember = addMemberToTarget(memberCopy) as JetClassOrObject + val movedMember = addMemberToTarget(memberCopy, data.targetClass as JetClass) as JetClassOrObject member.delete() return movedMember } @@ -658,7 +632,7 @@ class KotlinPullUpHelper( makeAbstract(member, memberCopy) } - movedMember = doAddCallableMember(memberCopy, clashingSuper) + movedMember = doAddCallableMember(memberCopy, clashingSuper, data.targetClass) if (member.typeReference == null) { movedMember.typeReference?.addToShorteningWaitSet() } @@ -666,7 +640,7 @@ class KotlinPullUpHelper( removeOriginalMemberOrAddOverride(member) } else { - movedMember = doAddCallableMember(memberCopy, clashingSuper) + movedMember = doAddCallableMember(memberCopy, clashingSuper, data.targetClass) member.delete() } @@ -674,10 +648,8 @@ class KotlinPullUpHelper( movedMember.removeModifier(JetTokens.ABSTRACT_KEYWORD) } - if (!data.isInterfaceTarget - && !data.targetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD) - && (movedMember.hasModifier(JetTokens.ABSTRACT_KEYWORD))) { - data.targetClass.addModifierWithSpace(JetTokens.ABSTRACT_KEYWORD) + if (movedMember.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { + data.targetClass.makeAbstract() } return movedMember } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelperFactory.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelperFactory.kt index a59f1431efd..0bccd044cce 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelperFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpHelperFactory.kt @@ -16,19 +16,25 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp -import com.intellij.psi.PsiNamedElement +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.lang.StdLanguages +import com.intellij.psi.* +import com.intellij.refactoring.memberPullUp.JavaPullUpHelper import com.intellij.refactoring.memberPullUp.PullUpData import com.intellij.refactoring.memberPullUp.PullUpHelper import com.intellij.refactoring.memberPullUp.PullUpHelperFactory import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.idea.JetLanguage +import org.jetbrains.kotlin.idea.core.refactoring.createJavaClass +import org.jetbrains.kotlin.psi.JetClass import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.psi.JetNamedDeclaration +import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.startOffset public class KotlinPullUpHelperFactory : PullUpHelperFactory { private fun PullUpData.toKotlinPullUpData(): KotlinPullUpData? { - if (!sourceClass.isInheritor(targetClass, true)) return null val sourceClass = sourceClass.unwrapped as? JetClassOrObject ?: return null val targetClass = targetClass.unwrapped as? PsiNamedElement ?: return null val membersToMove = membersToMove @@ -39,7 +45,64 @@ public class KotlinPullUpHelperFactory : PullUpHelperFactory { } override fun createPullUpHelper(data: PullUpData): PullUpHelper<*> { - val kotlinPullUpData = data.toKotlinPullUpData() ?: return EmptyPullUpHelper - return KotlinPullUpHelper(data, kotlinPullUpData) + if (!data.sourceClass.isInheritor(data.targetClass, true)) return EmptyPullUpHelper + data.toKotlinPullUpData()?.let { return KotlinPullUpHelper(data, it) } + + if (data.targetClass.language.`is`(JetLanguage.INSTANCE) && data.sourceClass.language.`is`(StdLanguages.JAVA)) { + return JavaToKotlinPostconversionPullUpHelper(data) + } + + return EmptyPullUpHelper } } + +public class JavaToKotlinPullUpHelperFactory : PullUpHelperFactory { + private fun createJavaToKotlinPullUpHelper(data: PullUpData): JavaToKotlinPreconversionPullUpHelper? { + if (!data.sourceClass.isInheritor(data.targetClass, true)) return null + val dummyTargetClass = createDummyTargetClass(data) ?: return null + val dataForDelegate = object : PullUpData by data { + override fun getTargetClass() = dummyTargetClass + } + return JavaToKotlinPreconversionPullUpHelper(data, dummyTargetClass, JavaPullUpHelper(dataForDelegate)) + } + + private fun createDummyTargetClass(data: PullUpData): PsiClass? { + val targetClass = data.targetClass.unwrapped as? JetClass ?: return null + + val project = targetClass.project + val targetPackage = targetClass.getContainingJetFile().packageFqName.asString() + val dummyFile = PsiFileFactory.getInstance(project).createFileFromText( + "dummy.java", + JavaFileType.INSTANCE, + if (targetPackage.isNotEmpty()) "package $targetPackage;\n" else "" + ) + val elementFactory = PsiElementFactory.SERVICE.getInstance(project) + + val dummyTargetClass = createJavaClass(targetClass, null, forcePlainClass = true) + val outerClasses = targetClass.parents.filterIsInstance().toList().reverse() + + if (outerClasses.isEmpty()) return dummyFile.add(dummyTargetClass) as PsiClass + + val outerPsiClasses = outerClasses.map { + val psiClass = elementFactory.createClass(it.name!!) + if (!(it is JetClass && it.isInner())) { + psiClass.modifierList!!.setModifierProperty(PsiModifier.STATIC, true) + } + psiClass + } + return outerPsiClasses + .drop(1) + .plus(dummyTargetClass) + .fold(dummyFile.add(outerPsiClasses.first())) { parent, child -> parent.add(child) } as PsiClass + } + + override fun createPullUpHelper(data: PullUpData): PullUpHelper<*> { + createJavaToKotlinPullUpHelper(data)?.let { return it } + + return PullUpHelper.INSTANCE + .allForLanguage(StdLanguages.JAVA) + .firstOrNull { it !is JavaToKotlinPullUpHelperFactory } + ?.createPullUpHelper(data) + ?: EmptyPullUpHelper + } +} \ No newline at end of file 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 ab67f6b61c7..a2ea11de072 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt @@ -17,10 +17,10 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp import com.intellij.psi.PsiClass +import org.jetbrains.kotlin.idea.core.replaced +import org.jetbrains.kotlin.lexer.JetModifierKeywordToken import org.jetbrains.kotlin.lexer.JetTokens -import org.jetbrains.kotlin.psi.JetNamedDeclaration -import org.jetbrains.kotlin.psi.JetNamedFunction -import org.jetbrains.kotlin.psi.JetProperty +import org.jetbrains.kotlin.psi.* fun JetProperty.mustBeAbstractInInterface() = hasInitializer() || hasDelegate() || (!hasInitializer() && !hasDelegate() && accessors.isEmpty()) @@ -37,3 +37,40 @@ fun JetNamedDeclaration.canMoveMemberToJavaClass(targetClass: PsiClass): Boolean else -> false } } + +fun addMemberToTarget(targetMember: JetNamedDeclaration, targetClass: JetClassOrObject): JetNamedDeclaration { + val anchor = targetClass.declarations.filterIsInstance(targetMember.javaClass).lastOrNull() + val movedMember = when { + anchor == null && targetMember is JetProperty -> targetClass.addDeclarationBefore(targetMember, null) + else -> targetClass.addDeclarationAfter(targetMember, anchor) + } + return movedMember as JetNamedDeclaration +} + +fun doAddCallableMember( + memberCopy: JetCallableDeclaration, + clashingSuper: JetCallableDeclaration?, + targetClass: JetClass): JetCallableDeclaration { + if (clashingSuper != null && clashingSuper.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { + return clashingSuper.replaced(memberCopy) + } + return addMemberToTarget(memberCopy, targetClass) as JetCallableDeclaration +} + +// TODO: Formatting rules don't apply here for some reason +fun JetNamedDeclaration.addModifierWithSpace(modifier: JetModifierKeywordToken) { + addModifier(modifier) + addAfter(JetPsiFactory(this).createWhiteSpace(), modifierList) +} + +// TODO: Formatting rules don't apply here for some reason +fun JetNamedDeclaration.addAnnotationWithSpace(annotationEntry: JetAnnotationEntry): JetAnnotationEntry { + val result = addAnnotationEntry(annotationEntry) + addAfter(JetPsiFactory(this).createWhiteSpace(), modifierList) + return result +} + +fun JetClass.makeAbstract() { + if (isInterface() || hasModifier(JetTokens.ABSTRACT_KEYWORD)) return + addModifierWithSpace(JetTokens.ABSTRACT_KEYWORD) +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java new file mode 100644 index 00000000000..c8668c9f6fe --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java @@ -0,0 +1,43 @@ +abstract class B extends 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 { + + } +} + +class Test { + static void test() { + B b = new B() { + public int bar(String s) { + return s.length(); + } + }; + int t1 = b.x; + b.x = t1 + 1; + String t2 = b.X; + String t3 = B.X; + b.foo(1); + b.foo2(2); + B.foo2(3); + b.new X(); + new B.Y(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java.after new file mode 100644 index 00000000000..60af7edbce1 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.java.after @@ -0,0 +1,21 @@ +abstract class B extends A { +} + +class Test { + static void test() { + B b = new B() { + public int bar(String s) { + return s.length(); + } + }; + int t1 = b.getX(); + b.setX(t1 + 1); + String t2 = b.X; + String t3 = A.X; + b.foo(1); + b.foo2(2); + A.foo2(3); + b.new X(); + new B.Y(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt new file mode 100644 index 00000000000..44c8687af84 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt @@ -0,0 +1,13 @@ +open class A + +fun test() { + val b = object : B() { + override fun bar(s: String) = s.length() + } + val t1 = b.x + b.x = t1 + 1 + val t2 = B.X + b.foo(1) + B.foo2(2) + B.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt.after new file mode 100644 index 00000000000..f1a92f7af25 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClass.kt.after @@ -0,0 +1,42 @@ +import kotlin.platform.platformStatic + +abstract class A { + // INFO: {"checked": "true"} + var x = 2 * 3 + + // INFO: {"checked": "true"} + inner class X + + // INFO: {"checked": "true"} + class Y + + // INFO: {"checked": "true"} + fun foo(n: Int): Boolean { + return n > 0 + } + + // INFO: {"checked": "true"} + abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true"} + platformStatic fun foo2(n: Int): String { + return "_" + n + "_" + } + } +} + +fun test() { + val b = object : B() { + override fun bar(s: String) = s.length() + } + val t1 = b.x + b.x = t1 + 1 + val t2 = A.X + b.foo(1) + A.foo2(2) + A.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java new file mode 100644 index 00000000000..424b4e084d5 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java @@ -0,0 +1,24 @@ +abstract class B extends A { + // INFO: {"checked": "true", "toAbstract": "true"} + int x = 2*3; + // INFO: {"checked": "true", "toAbstract": "true"} + static String X = "1" + "2"; + // INFO: {"checked": "true", "toAbstract": "true"} + boolean foo(int n) { + return n > 0; + } + // INFO: {"checked": "true", "toAbstract": "true"} + static String foo2(int n) { + return "_" + n + "_"; + } + // INFO: {"checked": "true", "toAbstract": "true"} + abstract int bar(String s); + // INFO: {"checked": "true", "toAbstract": "true"} + class X { + + } + // INFO: {"checked": "true", "toAbstract": "true"} + static class Y { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java.after new file mode 100644 index 00000000000..540c6783530 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java.after @@ -0,0 +1,7 @@ +abstract class B extends A { + // INFO: {"checked": "true", "toAbstract": "true"} + @Override + boolean foo(int n) { + return n > 0; + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt new file mode 100644 index 00000000000..416fbd09ec1 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt @@ -0,0 +1 @@ +open class A \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt.after new file mode 100644 index 00000000000..18eaf67af6b --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.kt.after @@ -0,0 +1,28 @@ +import kotlin.platform.platformStatic + +abstract class A { + // INFO: {"checked": "true", "toAbstract": "true"} + var x = 2 * 3 + + // INFO: {"checked": "true", "toAbstract": "true"} + inner class X + + // INFO: {"checked": "true", "toAbstract": "true"} + class Y + + // INFO: {"checked": "true", "toAbstract": "true"} + abstract fun foo(n: Int): Boolean + + // INFO: {"checked": "true", "toAbstract": "true"} + abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true", "toAbstract": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true", "toAbstract": "true"} + platformStatic fun foo2(n: Int): String { + return "_" + n + "_" + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java new file mode 100644 index 00000000000..731aae7e832 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java @@ -0,0 +1,20 @@ +class C { + abstract class B extends A> { + // INFO: {"checked": "true"} + void foo(X x1, Z x2, Y y1, Z y2, W w1, Z w2, S s1, Z s2) { + + } + // INFO: {"checked": "true"} + class Foo extends A> implements Z { + + } + // INFO: {"checked": "true"} + X foo1; + // INFO: {"checked": "true"} + Z foo2; + // INFO: {"checked": "true"} + Y foo3; + // INFO: {"checked": "true"} + Z foo4; + } +} diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java.after new file mode 100644 index 00000000000..47fb2ba9d7c --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java.after @@ -0,0 +1,4 @@ +class C { + abstract class B extends A> { + } +} diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt new file mode 100644 index 00000000000..034505f11c1 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt @@ -0,0 +1,5 @@ +interface I + +interface Z + +open class A \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt.after b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt.after new file mode 100644 index 00000000000..b1ae7338e63 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.kt.after @@ -0,0 +1,22 @@ +interface I + +interface Z + +open class A { + // INFO: {"checked": "true"} + var foo1: T + // INFO: {"checked": "true"} + var foo2: Z + // INFO: {"checked": "true"} + var foo3: Any + // INFO: {"checked": "true"} + var foo4: Z + + // INFO: {"checked": "true"} + inner class Foo : A>(), Z + + // INFO: {"checked": "true"} + fun foo(x1: T, x2: Z, y1: Any, y2: Z, w1: I, w2: Z, s1: S, s2: Z) { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java new file mode 100644 index 00000000000..12360f4c056 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java @@ -0,0 +1,18 @@ +abstract class B implements A { + // 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"} + static class Y { + + } +} diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java.after b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java.after new file mode 100644 index 00000000000..d23ebf7ad85 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java.after @@ -0,0 +1,2 @@ +abstract class B implements A { +} diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt new file mode 100644 index 00000000000..3c30d34f09c --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt @@ -0,0 +1 @@ +interface A \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt.after b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt.after new file mode 100644 index 00000000000..6cd5ccba955 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterface.kt.after @@ -0,0 +1,24 @@ +import kotlin.platform.platformStatic + +interface A { + // INFO: {"checked": "true"} + class Y + + // INFO: {"checked": "true"} + fun foo(n: Int): Boolean { + return n > 0 + } + + // INFO: {"checked": "true"} + fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true"} + platformStatic fun foo2(n: Int): String { + return "_" + n + "_" + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java new file mode 100644 index 00000000000..8f8fb9447b6 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java @@ -0,0 +1,24 @@ +abstract class B implements 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 { + + } +} diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java.messages b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java.messages new file mode 100644 index 00000000000..6cb41e7d072 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java.messages @@ -0,0 +1,2 @@ +Class B.X is not static. It cannot be moved to the interface +Field x is not static. It cannot be moved to the interface diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.kt new file mode 100644 index 00000000000..3c30d34f09c --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.kt @@ -0,0 +1 @@ +interface A \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java new file mode 100644 index 00000000000..3fbe23f9aa0 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java @@ -0,0 +1,43 @@ +abstract class B extends T.U.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 { + + } +} + +class Test { + static void test() { + B b = new B() { + public int bar(String s) { + return s.length(); + } + }; + int t1 = b.x; + b.x = t1 + 1; + String t2 = b.X; + String t3 = B.X; + b.foo(1); + b.foo2(2); + B.foo2(3); + b.new X(); + new B.Y(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java.after b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java.after new file mode 100644 index 00000000000..58255ed1137 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java.after @@ -0,0 +1,21 @@ +abstract class B extends T.U.A { +} + +class Test { + static void test() { + B b = new B() { + public int bar(String s) { + return s.length(); + } + }; + int t1 = b.getX(); + b.setX(t1 + 1); + String t2 = b.X; + String t3 = T.U.A.X; + b.foo(1); + b.foo2(2); + T.U.A.foo2(3); + b.new X(); + new B.Y(); + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt new file mode 100644 index 00000000000..18cefa0d007 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt @@ -0,0 +1,17 @@ +class T { + class U { + open class A + } +} + +fun test() { + val b = object : B() { + override fun bar(s: String) = s.length() + } + val t1 = b.x + b.x = t1 + 1 + val t2 = B.X + b.foo(1) + B.foo2(2) + B.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt.after b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt.after new file mode 100644 index 00000000000..30d45f2a196 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.kt.after @@ -0,0 +1,46 @@ +import kotlin.platform.platformStatic + +class T { + class U { + abstract class A { + // INFO: {"checked": "true"} + var x = 2 * 3 + + // INFO: {"checked": "true"} + inner class X + + // INFO: {"checked": "true"} + class Y + + // INFO: {"checked": "true"} + fun foo(n: Int): Boolean { + return n > 0 + } + + // INFO: {"checked": "true"} + abstract fun bar(s: String): Int + + companion object { + // INFO: {"checked": "true"} + var X = "1" + "2" + + // INFO: {"checked": "true"} + platformStatic fun foo2(n: Int): String { + return "_" + n + "_" + } + } + } + } +} + +fun test() { + val b = object : B() { + override fun bar(s: String) = s.length() + } + val t1 = b.x + b.x = t1 + 1 + val t2 = T.U.A.X + b.foo(1) + T.U.A.foo2(2) + T.U.A.Y() +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java new file mode 100644 index 00000000000..c485816c056 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java @@ -0,0 +1,18 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class B extends A implements X, Y, Z { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java.after new file mode 100644 index 00000000000..a3487ab65d9 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java.after @@ -0,0 +1,18 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class B extends A implements Y { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt new file mode 100644 index 00000000000..988a056a582 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt @@ -0,0 +1 @@ +class A : Z \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt.after new file mode 100644 index 00000000000..9aade23bdd8 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.kt.after @@ -0,0 +1 @@ +class A : Z, X \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java new file mode 100644 index 00000000000..3ae63395de5 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java @@ -0,0 +1,18 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class B implements I, X, Y, Z { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java.after new file mode 100644 index 00000000000..1e29806c1b0 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java.after @@ -0,0 +1,18 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class B implements I, Y { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt new file mode 100644 index 00000000000..507746adea1 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt @@ -0,0 +1 @@ +interface I : Z \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt.after new file mode 100644 index 00000000000..dc8ddcd4b54 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.kt.after @@ -0,0 +1 @@ +interface I : Z, X \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java new file mode 100644 index 00000000000..b2d2a47836e --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java @@ -0,0 +1,22 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class P { + +} + +class B extends A implements X, Y, Z { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java.after new file mode 100644 index 00000000000..c1eef2a38b4 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java.after @@ -0,0 +1,22 @@ +// INFO: {"checked": "true"} +interface X { + +} + +// INFO: {"checked": "false"} +interface Y { + +} + +// INFO: {"checked": "true"} +interface Z { + +} + +class P { + +} + +class B extends A implements Y { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt new file mode 100644 index 00000000000..e396c968bdd --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt @@ -0,0 +1 @@ +class A : Z \ No newline at end of file diff --git a/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt.after b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt.after new file mode 100644 index 00000000000..d12819a7257 --- /dev/null +++ b/idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.kt.after @@ -0,0 +1 @@ +class A : Z, X \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/AbstractPullUpTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/AbstractPullUpTest.kt index 3a513ba9ec6..cbe626141a6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/AbstractPullUpTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/AbstractPullUpTest.kt @@ -19,18 +19,25 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp import com.google.gson.JsonParser import com.intellij.openapi.util.Key import com.intellij.openapi.util.io.FileUtil -import com.intellij.psi.PsiNamedElement +import com.intellij.psi.* +import com.intellij.psi.util.PsiTreeUtil import com.intellij.refactoring.BaseRefactoringProcessor +import com.intellij.refactoring.classMembers.MemberInfoBase +import com.intellij.refactoring.memberPullUp.PullUpConflictsUtil +import com.intellij.refactoring.memberPullUp.PullUpProcessor import com.intellij.refactoring.util.CommonRefactoringUtil +import com.intellij.refactoring.util.DocCommentPolicy +import com.intellij.refactoring.util.RefactoringHierarchyUtil +import com.intellij.refactoring.util.classMembers.MemberInfoStorage import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.util.ui.UIUtil +import org.jetbrains.kotlin.idea.core.getPackage import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.qualifiedClassNameForRendering import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.PluginTestCaseBase -import org.jetbrains.kotlin.psi.JetElement -import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.NotNullableUserDataProperty import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.JetTestUtils @@ -41,17 +48,17 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase() private data class ElementInfo(val checked: Boolean, val toAbstract: Boolean) companion object { - private var JetElement.elementInfo: ElementInfo + private var PsiElement.elementInfo: ElementInfo by NotNullableUserDataProperty(Key.create("ELEMENT_INFO"), ElementInfo(false, false)) } - override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST + override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE val fixture: JavaCodeInsightTestFixture get() = myFixture protected override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() - protected fun doTest(path: String) { + protected fun doTest(path: String, action: (mainFile: PsiFile) -> Unit) { val mainFile = File(path) val afterFile = File("$path.after") val conflictFile = File("$path.messages") @@ -60,11 +67,11 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase() val mainFileName = mainFile.getName() val mainFileBaseName = FileUtil.getNameWithoutExtension(mainFileName) - val extraFiles = mainFile.getParentFile().listFiles { file, name -> + val extraFiles = mainFile.parentFile.listFiles { file, name -> name != mainFileName && name.startsWith("$mainFileBaseName.") && (name.endsWith(".kt") || name.endsWith(".java")) } val extraFilesToPsi = extraFiles.toMap { fixture.configureByFile(it.getName()) } - val file = fixture.configureByFile(mainFileName) as JetFile + val file = fixture.configureByFile(mainFileName) val addKotlinRuntime = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// WITH_RUNTIME") != null if (addKotlinRuntime) { @@ -77,33 +84,13 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase() element.elementInfo = ElementInfo(parsedInfo["checked"]?.asBoolean ?: false, parsedInfo["toAbstract"]?.asBoolean ?: false) } - val targetClassName = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// TARGET_CLASS: ") - val helper = object: KotlinPullUpHandler.TestHelper { - override fun adjustMembers(members: List): List { - members.forEach { - val info = it.member.elementInfo - it.isChecked = info.checked - it.isToAbstract = info.toAbstract - } - return members.filter { it.isChecked } - } - - override fun chooseSuperClass(superClasses: List): PsiNamedElement { - if (targetClassName != null) { - return superClasses.single { it.qualifiedClassNameForRendering() == targetClassName } - } - return superClasses.first() - } - } - KotlinPullUpHandler().invoke(getProject(), getEditor(), file) { - if (it == KotlinPullUpHandler.PULLUP_TEST_HELPER_KEY) helper else null - } + action(file) assert(!conflictFile.exists()) { "Conflict file $conflictFile should not exist" } JetTestUtils.assertEqualsToFile(afterFile, file.text!!) for ((extraPsiFile, extraFile) in extraFilesToPsi) { - JetTestUtils.assertEqualsToFile(File("${extraFile.getPath()}.after"), extraPsiFile.getText()) + JetTestUtils.assertEqualsToFile(File("${extraFile.getPath()}.after"), extraPsiFile.text) } } catch(e: Exception) { @@ -120,4 +107,67 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase() } } } + + private fun getTargetClassName(file: PsiFile) = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// TARGET_CLASS: ") + + private fun chooseMembers>(members: List): List { + members.forEach { + val info = it.member.elementInfo + it.isChecked = info.checked + it.isToAbstract = info.toAbstract + } + return members.filter { it.isChecked } + } + + protected fun doKotlinTest(path: String) { + doTest(path) { file -> + val targetClassName = getTargetClassName(file) + val helper = object: KotlinPullUpHandler.TestHelper { + override fun adjustMembers(members: List): List { + return chooseMembers(members) + } + + override fun chooseSuperClass(superClasses: List): PsiNamedElement { + if (targetClassName != null) { + return superClasses.single { it.qualifiedClassNameForRendering() == targetClassName } + } + return superClasses.first() + } + } + KotlinPullUpHandler().invoke(getProject(), getEditor(), file) { + if (it == KotlinPullUpHandler.PULLUP_TEST_HELPER_KEY) helper else null + } + } + } + + // Based on com.intellij.refactoring.PullUpTest.doTest() + protected fun doJavaTest(path: String) { + doTest(path) { file -> + val elementAt = getFile().findElementAt(getEditor().caretModel.offset) + val sourceClass = PsiTreeUtil.getParentOfType(elementAt, javaClass())!! + + val targetClassName = getTargetClassName(file) + val superClasses = RefactoringHierarchyUtil.createBasesList(sourceClass, false, true) + val targetClass = targetClassName?.let { name -> superClasses.first { it.qualifiedName == name } } ?: superClasses.first() + + val storage = MemberInfoStorage(sourceClass) { true } + val memberInfoList = chooseMembers(storage.getClassMemberInfos(sourceClass)) + val memberInfos = memberInfoList.toTypedArray() + + val targetDirectory = targetClass.containingFile.containingDirectory + val conflicts = PullUpConflictsUtil.checkConflicts( + memberInfos, + sourceClass, + targetClass, + targetDirectory.getPackage()!!, + targetDirectory, + { psiMethod : PsiMethod -> PullUpProcessor.checkedInterfacesContain(memberInfoList, psiMethod) }, + true + ) + if (!conflicts.isEmpty) throw BaseRefactoringProcessor.ConflictsInTestsException(conflicts.values()) + + PullUpProcessor(sourceClass, targetClass, memberInfos, DocCommentPolicy(DocCommentPolicy.ASIS)).run() + UIUtil.dispatchAllInvocationEvents() + } + } } 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 9c46ab43eb1..17b13f31c2f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/pullUp/PullUpTestGenerated.java @@ -27,257 +27,332 @@ 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/pullUp") -@TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public class PullUpTestGenerated extends AbstractPullUpTest { - public void testAllFilesPresentInPullUp() throws Exception { - JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp"), Pattern.compile("^(.+)\\.kt$")); + @TestMetadata("idea/testData/refactoring/pullUp/k2k") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class K2K extends AbstractPullUpTest { + @TestMetadata("accidentalOverrides.kt") + public void testAccidentalOverrides() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/accidentalOverrides.kt"); + doKotlinTest(fileName); + } + + public void testAllFilesPresentInK2K() throws Exception { + JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp/k2k"), Pattern.compile("^(.+)\\.kt$")); + } + + @TestMetadata("clashWithSuper.kt") + public void testClashWithSuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/clashWithSuper.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToClass.kt") + public void testFromClassToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToClassMakeAbstract.kt") + public void testFromClassToClassMakeAbstract() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClassMakeAbstract.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToClassWithGenerics.kt") + public void testFromClassToClassWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClassWithGenerics.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToInterface.kt") + public void testFromClassToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToInterfaceMakeAbstract.kt") + public void testFromClassToInterfaceMakeAbstract() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToInterfaceMakeAbstract.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("implicitCompanionUsages.kt") + public void testImplicitCompanionUsages() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/implicitCompanionUsages.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("inaccessibleMemberUsed.kt") + public void testInaccessibleMemberUsed() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/inaccessibleMemberUsed.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("initializerInConstructor.kt") + public void testInitializerInConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInConstructor.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("initializerInMultipleConstructorsEq.kt") + public void testInitializerInMultipleConstructorsEq() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInMultipleConstructorsEq.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("initializerInMultipleConstructorsNonEq.kt") + public void testInitializerInMultipleConstructorsNonEq() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInMultipleConstructorsNonEq.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("innerClassToInterface.kt") + public void testInnerClassToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/innerClassToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveAllSuperInterfaces.kt") + public void testMoveAllSuperInterfaces() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveAllSuperInterfaces.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveAllSuperInterfacesWithGenerics.kt") + public void testMoveAllSuperInterfacesWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveAllSuperInterfacesWithGenerics.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfaces.kt") + public void testMoveSuperInterfaces() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfaces.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfacesToEmptySpecifierList.kt") + public void testMoveSuperInterfacesToEmptySpecifierList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfacesToEmptySpecifierList.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfaceToItSelf.kt") + public void testMoveSuperInterfaceToItSelf() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfaceToItSelf.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("multipleInitializersInConstructorsEq.kt") + public void testMultipleInitializersInConstructorsEq() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/multipleInitializersInConstructorsEq.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("noCaret.kt") + public void testNoCaret() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noCaret.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("noClashWithAbstractSuper.kt") + public void testNoClashWithAbstractSuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noClashWithAbstractSuper.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("noInitializationInInterface.kt") + public void testNoInitializationInInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noInitializationInInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("noSuperClass.kt") + public void testNoSuperClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noSuperClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("outsideOfClass.kt") + public void testOutsideOfClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/outsideOfClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("parametersInPrimaryInitializer.kt") + public void testParametersInPrimaryInitializer() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/parametersInPrimaryInitializer.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("propertyDependenceSatisfied.kt") + public void testPropertyDependenceSatisfied() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/propertyDependenceSatisfied.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("propertyDependenceUnsatisfied.kt") + public void testPropertyDependenceUnsatisfied() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/propertyDependenceUnsatisfied.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("publicToInterface.kt") + public void testPublicToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/publicToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("superToThis.kt") + public void testSuperToThis() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/superToThis.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("toIndirectSuperClass.kt") + public void testToIndirectSuperClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/toIndirectSuperClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("usedPrivateToClass.kt") + public void testUsedPrivateToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/usedPrivateToClass.kt"); + doKotlinTest(fileName); + } } - @TestMetadata("k2j/fromClassToClass.kt") - public void testK2j_FromClassToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClass.kt"); - doTest(fileName); + @TestMetadata("idea/testData/refactoring/pullUp/k2j") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class K2J extends AbstractPullUpTest { + public void testAllFilesPresentInK2J() throws Exception { + JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp/k2j"), Pattern.compile("^(.+)\\.kt$")); + } + + @TestMetadata("fromClassToClass.kt") + public void testFromClassToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToClassAndMakeAbstract.kt") + public void testFromClassToClassAndMakeAbstract() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClassAndMakeAbstract.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToClassWithGenerics.kt") + public void testFromClassToClassWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClassWithGenerics.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToInterface.kt") + public void testFromClassToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("fromClassToNestedClass.kt") + public void testFromClassToNestedClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToNestedClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfacesToClass.kt") + public void testMoveSuperInterfacesToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesToClass.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfacesToInterface.kt") + public void testMoveSuperInterfacesToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("moveSuperInterfacesWithGenerics.kt") + public void testMoveSuperInterfacesWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesWithGenerics.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("publicToInterface.kt") + public void testPublicToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/publicToInterface.kt"); + doKotlinTest(fileName); + } + + @TestMetadata("usedPrivateToClass.kt") + public void testUsedPrivateToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/usedPrivateToClass.kt"); + doKotlinTest(fileName); + } } - @TestMetadata("k2j/fromClassToClassAndMakeAbstract.kt") - public void testK2j_FromClassToClassAndMakeAbstract() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClassAndMakeAbstract.kt"); - doTest(fileName); - } + @TestMetadata("idea/testData/refactoring/pullUp/j2k") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class J2K extends AbstractPullUpTest { + public void testAllFilesPresentInJ2K() throws Exception { + JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp/j2k"), Pattern.compile("^(.+)\\.java$")); + } - @TestMetadata("k2j/fromClassToClassWithGenerics.kt") - public void testK2j_FromClassToClassWithGenerics() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClassWithGenerics.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToClass.java") + public void testFromClassToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToClass.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/fromClassToInterface.kt") - public void testK2j_FromClassToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToInterface.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToClassAndMakeAbstract.java") + public void testFromClassToClassAndMakeAbstract() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToClassAndMakeAbstract.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/fromClassToNestedClass.kt") - public void testK2j_FromClassToNestedClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToNestedClass.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToClassWithGenerics.java") + public void testFromClassToClassWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToClassWithGenerics.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/moveSuperInterfacesToClass.kt") - public void testK2j_MoveSuperInterfacesToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesToClass.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToInterface.java") + public void testFromClassToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToInterface.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/moveSuperInterfacesToInterface.kt") - public void testK2j_MoveSuperInterfacesToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesToInterface.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToInterfaceWithConflicts.java") + public void testFromClassToInterfaceWithConflicts() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToInterfaceWithConflicts.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/moveSuperInterfacesWithGenerics.kt") - public void testK2j_MoveSuperInterfacesWithGenerics() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesWithGenerics.kt"); - doTest(fileName); - } + @TestMetadata("fromClassToNestedClass.java") + public void testFromClassToNestedClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/fromClassToNestedClass.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/publicToInterface.kt") - public void testK2j_PublicToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/publicToInterface.kt"); - doTest(fileName); - } + @TestMetadata("moveSuperInterfacesToClass.java") + public void testMoveSuperInterfacesToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToClass.java"); + doJavaTest(fileName); + } - @TestMetadata("k2j/usedPrivateToClass.kt") - public void testK2j_UsedPrivateToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/usedPrivateToClass.kt"); - doTest(fileName); - } + @TestMetadata("moveSuperInterfacesToInterface.java") + public void testMoveSuperInterfacesToInterface() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesToInterface.java"); + doJavaTest(fileName); + } - @TestMetadata("k2k/accidentalOverrides.kt") - public void testK2k_AccidentalOverrides() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/accidentalOverrides.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/clashWithSuper.kt") - public void testK2k_ClashWithSuper() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/clashWithSuper.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/fromClassToClass.kt") - public void testK2k_FromClassToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClass.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/fromClassToClassMakeAbstract.kt") - public void testK2k_FromClassToClassMakeAbstract() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClassMakeAbstract.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/fromClassToClassWithGenerics.kt") - public void testK2k_FromClassToClassWithGenerics() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToClassWithGenerics.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/fromClassToInterface.kt") - public void testK2k_FromClassToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToInterface.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/fromClassToInterfaceMakeAbstract.kt") - public void testK2k_FromClassToInterfaceMakeAbstract() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/fromClassToInterfaceMakeAbstract.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/implicitCompanionUsages.kt") - public void testK2k_ImplicitCompanionUsages() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/implicitCompanionUsages.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/inaccessibleMemberUsed.kt") - public void testK2k_InaccessibleMemberUsed() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/inaccessibleMemberUsed.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/initializerInConstructor.kt") - public void testK2k_InitializerInConstructor() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInConstructor.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/initializerInMultipleConstructorsEq.kt") - public void testK2k_InitializerInMultipleConstructorsEq() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInMultipleConstructorsEq.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/initializerInMultipleConstructorsNonEq.kt") - public void testK2k_InitializerInMultipleConstructorsNonEq() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/initializerInMultipleConstructorsNonEq.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/innerClassToInterface.kt") - public void testK2k_InnerClassToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/innerClassToInterface.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/moveAllSuperInterfaces.kt") - public void testK2k_MoveAllSuperInterfaces() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveAllSuperInterfaces.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/moveAllSuperInterfacesWithGenerics.kt") - public void testK2k_MoveAllSuperInterfacesWithGenerics() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveAllSuperInterfacesWithGenerics.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/moveSuperInterfaces.kt") - public void testK2k_MoveSuperInterfaces() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfaces.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/moveSuperInterfacesToEmptySpecifierList.kt") - public void testK2k_MoveSuperInterfacesToEmptySpecifierList() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfacesToEmptySpecifierList.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/moveSuperInterfaceToItSelf.kt") - public void testK2k_MoveSuperInterfaceToItSelf() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/moveSuperInterfaceToItSelf.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/multipleInitializersInConstructorsEq.kt") - public void testK2k_MultipleInitializersInConstructorsEq() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/multipleInitializersInConstructorsEq.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/noCaret.kt") - public void testK2k_NoCaret() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noCaret.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/noClashWithAbstractSuper.kt") - public void testK2k_NoClashWithAbstractSuper() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noClashWithAbstractSuper.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/noInitializationInInterface.kt") - public void testK2k_NoInitializationInInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noInitializationInInterface.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/noSuperClass.kt") - public void testK2k_NoSuperClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/noSuperClass.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/outsideOfClass.kt") - public void testK2k_OutsideOfClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/outsideOfClass.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/parametersInPrimaryInitializer.kt") - public void testK2k_ParametersInPrimaryInitializer() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/parametersInPrimaryInitializer.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/propertyDependenceSatisfied.kt") - public void testK2k_PropertyDependenceSatisfied() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/propertyDependenceSatisfied.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/propertyDependenceUnsatisfied.kt") - public void testK2k_PropertyDependenceUnsatisfied() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/propertyDependenceUnsatisfied.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/publicToInterface.kt") - public void testK2k_PublicToInterface() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/publicToInterface.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/superToThis.kt") - public void testK2k_SuperToThis() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/superToThis.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/toIndirectSuperClass.kt") - public void testK2k_ToIndirectSuperClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/toIndirectSuperClass.kt"); - doTest(fileName); - } - - @TestMetadata("k2k/usedPrivateToClass.kt") - public void testK2k_UsedPrivateToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/usedPrivateToClass.kt"); - doTest(fileName); + @TestMetadata("moveSuperInterfacesWithGenerics.java") + public void testMoveSuperInterfacesWithGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/j2k/moveSuperInterfacesWithGenerics.java"); + doJavaTest(fileName); + } } }