Pull Up: Kotlin -> Java interoperability
This commit is contained in:
committed by
Alexey Sedunov
parent
ffc56a7c31
commit
a9783ffe81
@@ -462,6 +462,9 @@ public fun createJavaMethod(template: PsiMethod, targetClass: PsiClass): PsiMeth
|
||||
val method = targetClass.add(methodToAdd) as PsiMethod
|
||||
|
||||
copyModifierListItems(template.getModifierList(), method.getModifierList())
|
||||
if (targetClass.isInterface()) {
|
||||
method.getModifierList().setModifierProperty(PsiModifier.FINAL, false)
|
||||
}
|
||||
|
||||
copyTypeParameters(template, method) { method, typeParameterList ->
|
||||
method.addAfter(typeParameterList, method.getModifierList())
|
||||
|
||||
+17
-12
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.memberInfo
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoStorage
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -31,9 +33,9 @@ import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import java.util.ArrayList
|
||||
|
||||
public class KotlinMemberInfoStorage(
|
||||
classOrObject: JetClassOrObject,
|
||||
classOrObject: PsiNamedElement,
|
||||
filter: (JetNamedDeclaration) -> Boolean = { true }
|
||||
): AbstractMemberInfoStorage<JetNamedDeclaration, JetClassOrObject, KotlinMemberInfo>(classOrObject, filter) {
|
||||
): AbstractMemberInfoStorage<JetNamedDeclaration, PsiNamedElement, KotlinMemberInfo>(classOrObject, filter) {
|
||||
override fun memberConflict(member1: JetNamedDeclaration, member: JetNamedDeclaration): Boolean {
|
||||
val descriptor1 = member1.resolveToDescriptor()
|
||||
val descriptor = member.resolveToDescriptor()
|
||||
@@ -49,24 +51,27 @@ public class KotlinMemberInfoStorage(
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildSubClassesMap(aClass: JetClassOrObject) {
|
||||
val classDescriptor = aClass.resolveToDescriptor() as ClassDescriptor
|
||||
override fun buildSubClassesMap(aClass: PsiNamedElement) {
|
||||
val classDescriptor = aClass.getClassDescriptorIfAny() ?: return
|
||||
val classType = classDescriptor.defaultType
|
||||
for (supertype in classType.immediateSupertypes()) {
|
||||
val superClass = supertype.constructor.declarationDescriptor?.source?.getPsi() as? JetClassOrObject
|
||||
?: continue
|
||||
getSubclasses(superClass).add(aClass)
|
||||
buildSubClassesMap(superClass)
|
||||
val superClass = supertype.constructor.declarationDescriptor?.source?.getPsi()
|
||||
if (superClass is JetClass || superClass is PsiClass) {
|
||||
getSubclasses(superClass as PsiNamedElement).add(aClass)
|
||||
buildSubClassesMap(superClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInheritor(baseClass: JetClassOrObject, aClass: JetClassOrObject): Boolean {
|
||||
val baseDescriptor = baseClass.resolveToDescriptor() as ClassDescriptor
|
||||
val currentDescriptor = aClass.resolveToDescriptor() as ClassDescriptor
|
||||
override fun isInheritor(baseClass: PsiNamedElement, aClass: PsiNamedElement): Boolean {
|
||||
val baseDescriptor = baseClass.getClassDescriptorIfAny() ?: return false
|
||||
val currentDescriptor = aClass.getClassDescriptorIfAny() ?: return false
|
||||
return DescriptorUtils.isSubclass(currentDescriptor, baseDescriptor)
|
||||
}
|
||||
|
||||
override fun extractClassMembers(aClass: JetClassOrObject, temp: ArrayList<KotlinMemberInfo>) {
|
||||
override fun extractClassMembers(aClass: PsiNamedElement, temp: ArrayList<KotlinMemberInfo>) {
|
||||
if (aClass !is JetClassOrObject) return
|
||||
|
||||
val context = aClass.analyze()
|
||||
aClass.declarations
|
||||
.filter { it is JetNamedDeclaration
|
||||
|
||||
+4
-4
@@ -17,17 +17,17 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.memberInfo;
|
||||
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.ui.ListCellRendererWrapper;
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class JetClassOrObjectListCellRenderer extends ListCellRendererWrapper<JetClassOrObject> {
|
||||
public class KotlinOrJavaClassCellRenderer extends ListCellRendererWrapper<PsiNamedElement> {
|
||||
@Override
|
||||
public void customize(JList list, JetClassOrObject value, int index, boolean selected, boolean hasFocus) {
|
||||
public void customize(JList list, PsiNamedElement value, int index, boolean selected, boolean hasFocus) {
|
||||
if (value == null) return;
|
||||
|
||||
setText(MemberInfoPackage.qualifiedNameForRendering(value));
|
||||
setText(MemberInfoPackage.qualifiedClassNameForRendering(value));
|
||||
Icon icon = value.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS);
|
||||
if (icon != null) {
|
||||
setIcon(icon);
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.memberInfo
|
||||
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
|
||||
public fun JetClassOrObject.qualifiedNameForRendering(): String = fqName?.asString() ?: name ?: "[Anonymous]"
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.memberInfo
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
|
||||
fun PsiNamedElement.getClassDescriptorIfAny(resolutionFacade: ResolutionFacade? = null): ClassDescriptor? {
|
||||
return when (this) {
|
||||
is JetClass -> (resolutionFacade ?: getResolutionFacade()).resolveToDescriptor(this) as ClassDescriptor
|
||||
is PsiClass -> getJavaClassDescriptor()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiNamedElement.isAbstractMember(): Boolean {
|
||||
return when(this) {
|
||||
is JetNamedDeclaration -> hasModifier(JetTokens.ABSTRACT_KEYWORD)
|
||||
is PsiMember -> hasModifierProperty(PsiModifier.ABSTRACT)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// Applies to JetClassOrObject and PsiClass
|
||||
public fun PsiNamedElement.qualifiedClassNameForRendering(): String {
|
||||
val fqName = when (this) {
|
||||
is JetClassOrObject -> fqName?.asString()
|
||||
is PsiClass -> qualifiedName
|
||||
else -> throw AssertionError("Not a class: ${getElementTextWithContext()}")
|
||||
}
|
||||
return fqName ?: name ?: "[Anonymous]"
|
||||
}
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -34,7 +36,7 @@ import org.jetbrains.kotlin.utils.keysToMap
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
class KotlinPullUpData(val sourceClass: JetClassOrObject,
|
||||
val targetClass: JetClass,
|
||||
val targetClass: PsiNamedElement,
|
||||
val membersToMove: Collection<JetNamedDeclaration>) {
|
||||
val resolutionFacade = sourceClass.getResolutionFacade()
|
||||
|
||||
@@ -44,7 +46,7 @@ class KotlinPullUpData(val sourceClass: JetClassOrObject,
|
||||
|
||||
val memberDescriptors = membersToMove.keysToMap { sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!! }
|
||||
|
||||
val targetClassDescriptor = resolutionFacade.resolveToDescriptor(targetClass) as ClassDescriptor
|
||||
val targetClassDescriptor = targetClass.getClassDescriptorIfAny(resolutionFacade)!!
|
||||
|
||||
val typeParametersInSourceClassContext by lazy {
|
||||
sourceClassDescriptor.typeConstructor.parameters + sourceClass.getResolutionScope(sourceClassContext, resolutionFacade)
|
||||
@@ -71,4 +73,6 @@ class KotlinPullUpData(val sourceClass: JetClassOrObject,
|
||||
|
||||
TypeSubstitutor.create(substitution)
|
||||
}
|
||||
|
||||
val isInterfaceTarget: Boolean = targetClassDescriptor.kind == ClassKind.INTERFACE
|
||||
}
|
||||
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
||||
import com.intellij.refactoring.memberPullUp.PullUpProcessor
|
||||
@@ -30,7 +32,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
public class KotlinPullUpDialog(
|
||||
project: Project,
|
||||
private val classOrObject: JetClassOrObject,
|
||||
superClasses: List<JetClass>,
|
||||
superClasses: List<PsiNamedElement>,
|
||||
memberInfoStorage: KotlinMemberInfoStorage
|
||||
) : KotlinPullUpDialogBase(
|
||||
project, classOrObject, superClasses, memberInfoStorage, PULL_MEMBERS_UP
|
||||
@@ -53,6 +55,7 @@ public class KotlinPullUpDialog(
|
||||
*/
|
||||
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||
val superClass = superClass ?: return false
|
||||
if (superClass is PsiClass) return false
|
||||
if (!superClass.isInterface()) return true
|
||||
|
||||
val member = memberInfo.member
|
||||
@@ -60,20 +63,24 @@ public class KotlinPullUpDialog(
|
||||
}
|
||||
|
||||
override fun isAbstractWhenDisabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||
return memberInfo.member is JetProperty
|
||||
val member = memberInfo.member
|
||||
return (member is JetProperty && superClass !is PsiClass) || (member is JetNamedFunction && superClass is PsiClass)
|
||||
}
|
||||
|
||||
override fun isMemberEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||
val superClass = superClass ?: return false
|
||||
val member = memberInfo.member
|
||||
|
||||
if (superClass is PsiClass && !member.canMoveMemberToJavaClass(superClass)) return false
|
||||
if (memberInfo in memberInfoStorage.getDuplicatedMemberInfos(superClass)) return false
|
||||
if (memberInfo.member in memberInfoStorage.getExtending(superClass)) return false
|
||||
if (member in memberInfoStorage.getExtending(superClass)) return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
protected val memberInfoStorage: KotlinMemberInfoStorage get() = myMemberInfoStorage
|
||||
|
||||
protected val sourceClass: JetClassOrObject get() = myClass
|
||||
protected val sourceClass: JetClassOrObject get() = myClass as JetClassOrObject
|
||||
|
||||
override fun getDimensionServiceKey() = "#" + javaClass.name
|
||||
|
||||
@@ -96,10 +103,11 @@ public class KotlinPullUpDialog(
|
||||
|
||||
companion object {
|
||||
fun createProcessor(sourceClass: JetClassOrObject,
|
||||
targetClass: JetClass,
|
||||
targetClass: PsiNamedElement,
|
||||
memberInfos: List<KotlinMemberInfo>): PullUpProcessor {
|
||||
val targetPsiClass = targetClass as? PsiClass ?: (targetClass as JetClass).toLightClass()
|
||||
return PullUpProcessor(sourceClass.toLightClass(),
|
||||
targetClass.toLightClass(),
|
||||
targetPsiClass,
|
||||
memberInfos.map { it.toJavaMemberInfo() }.filterNotNull().toTypedArray(),
|
||||
DocCommentPolicy<PsiComment>(JavaRefactoringSettings.getInstance().PULL_UP_MEMBERS_JAVADOC))
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.pullUp;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.refactoring.memberPullUp.PullUpDialogBase;
|
||||
import com.intellij.refactoring.ui.AbstractMemberSelectionTable;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.JetClassOrObjectListCellRenderer;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinOrJavaClassCellRenderer;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfoStorage;
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject;
|
||||
@@ -32,11 +33,11 @@ import java.util.List;
|
||||
|
||||
// TODO: This is workaround which allows KotlinPullUpDialog to be compiled against both Java 6 and 8
|
||||
public abstract class KotlinPullUpDialogBase extends
|
||||
PullUpDialogBase<KotlinMemberInfoStorage, KotlinMemberInfo, JetNamedDeclaration, JetClassOrObject> {
|
||||
PullUpDialogBase<KotlinMemberInfoStorage, KotlinMemberInfo, JetNamedDeclaration, PsiNamedElement> {
|
||||
protected KotlinPullUpDialogBase(
|
||||
Project project,
|
||||
JetClassOrObject object,
|
||||
List<JetClassOrObject> superClasses,
|
||||
List<PsiNamedElement> superClasses,
|
||||
KotlinMemberInfoStorage memberInfoStorage,
|
||||
String title
|
||||
) {
|
||||
@@ -46,7 +47,7 @@ public abstract class KotlinPullUpDialogBase extends
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void initClassCombo(JComboBox classCombo) {
|
||||
classCombo.setRenderer(new JetClassOrObjectListCellRenderer());
|
||||
classCombo.setRenderer(new KotlinOrJavaClassCellRenderer());
|
||||
classCombo.addItemListener(
|
||||
new ItemListener() {
|
||||
@Override
|
||||
|
||||
@@ -22,8 +22,10 @@ import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.ScrollType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.refactoring.HelpID
|
||||
import com.intellij.refactoring.RefactoringActionHandler
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
@@ -35,7 +37,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfoStorage
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.qualifiedNameForRendering
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.qualifiedClassNameForRendering
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
@@ -49,7 +51,7 @@ public class KotlinPullUpHandler : RefactoringActionHandler, ElementsHandler {
|
||||
|
||||
interface TestHelper {
|
||||
fun adjustMembers(members: List<KotlinMemberInfo>): List<KotlinMemberInfo>
|
||||
fun chooseSuperClass(superClasses: List<JetClass>): JetClass
|
||||
fun chooseSuperClass(superClasses: List<PsiNamedElement>): PsiNamedElement
|
||||
}
|
||||
|
||||
private fun reportWrongPosition(project: Project, editor: Editor?) {
|
||||
@@ -69,7 +71,7 @@ public class KotlinPullUpHandler : RefactoringActionHandler, ElementsHandler {
|
||||
private fun reportNoSuperClasses(project: Project, editor: Editor?, classOrObject: JetClassOrObject) {
|
||||
val message = RefactoringBundle.getCannotRefactorMessage(
|
||||
RefactoringBundle.message("class.does.not.have.base.classes.interfaces.in.current.project",
|
||||
classOrObject.qualifiedNameForRendering())
|
||||
classOrObject.qualifiedClassNameForRendering())
|
||||
)
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, PULL_MEMBERS_UP, HelpID.MEMBERS_PULL_UP)
|
||||
}
|
||||
@@ -125,10 +127,11 @@ public class KotlinPullUpHandler : RefactoringActionHandler, ElementsHandler {
|
||||
.map {
|
||||
val descriptor = it.constructor.declarationDescriptor
|
||||
val declaration = descriptor?.let { DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) }
|
||||
if (declaration is JetClass && declaration.canRefactor()) declaration else null
|
||||
if ((declaration is JetClass || declaration is PsiClass)
|
||||
&& declaration.canRefactor()) declaration as PsiNamedElement else null
|
||||
}
|
||||
.filterNotNull()
|
||||
.toSortedListBy { it.qualifiedNameForRendering() }
|
||||
.toSortedListBy { it.qualifiedClassNameForRendering() }
|
||||
|
||||
if (superClasses.isEmpty()) {
|
||||
val containingClass = classOrObject.getStrictParentOfType<JetClassOrObject>()
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||
import com.intellij.psi.impl.light.LightField
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase
|
||||
@@ -28,10 +30,13 @@ import com.intellij.refactoring.util.RefactoringUtil
|
||||
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
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
|
||||
@@ -175,7 +180,7 @@ class KotlinPullUpHelper(
|
||||
}
|
||||
}
|
||||
commonInitializer?.accept(visitor)
|
||||
if (targetConstructor == data.targetClass.getPrimaryConstructor() ?: data.targetClass) {
|
||||
if (targetConstructor == (data.targetClass as? JetClass)?.getPrimaryConstructor() ?: data.targetClass) {
|
||||
property.initializer?.accept(visitor)
|
||||
}
|
||||
|
||||
@@ -192,7 +197,7 @@ class KotlinPullUpHelper(
|
||||
}
|
||||
|
||||
private val targetToSourceConstructors = LinkedHashMap<JetElement, MutableList<JetElement>>().let { result ->
|
||||
if (!data.targetClass.isInterface()) {
|
||||
if (!data.isInterfaceTarget && data.targetClass is JetClass) {
|
||||
result[data.targetClass.getPrimaryConstructor() ?: data.targetClass] = ArrayList<JetElement>()
|
||||
data.sourceClass.accept(
|
||||
object : JetTreeVisitorVoid() {
|
||||
@@ -287,7 +292,7 @@ class KotlinPullUpHelper(
|
||||
override fun setCorrectVisibility(info: MemberInfoBase<PsiMember>) {
|
||||
val member = info.member.namedUnwrappedElement as? JetNamedDeclaration ?: return
|
||||
|
||||
if (data.targetClass.isInterface()) {
|
||||
if (data.isInterfaceTarget) {
|
||||
member.removeModifier(JetTokens.PUBLIC_KEYWORD)
|
||||
return
|
||||
}
|
||||
@@ -332,7 +337,7 @@ class KotlinPullUpHelper(
|
||||
}
|
||||
|
||||
private fun makeAbstract(sourceMember: JetCallableDeclaration, targetMember: JetCallableDeclaration) {
|
||||
if (!data.targetClass.isInterface()) {
|
||||
if (!data.isInterfaceTarget) {
|
||||
targetMember.addModifierWithSpace(JetTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
|
||||
@@ -373,6 +378,8 @@ 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)
|
||||
@@ -509,11 +516,8 @@ class KotlinPullUpHelper(
|
||||
addAfter(JetPsiFactory(this).createWhiteSpace(), modifierList)
|
||||
}
|
||||
|
||||
private fun moveSuperInterface(member: JetClass) {
|
||||
val psiFactory = JetPsiFactory(member)
|
||||
|
||||
private fun moveSuperInterface(member: JetClass, substitutor: PsiSubstitutor) {
|
||||
val classDescriptor = data.memberDescriptors[member] as? ClassDescriptor ?: return
|
||||
|
||||
val currentSpecifier =
|
||||
data.sourceClass.getDelegationSpecifiers()
|
||||
.filterIsInstance<JetDelegatorToSuperClass>()
|
||||
@@ -521,48 +525,131 @@ class KotlinPullUpHelper(
|
||||
val referencedType = data.sourceClassContext[BindingContext.TYPE, it.typeReference]
|
||||
referencedType?.constructor?.declarationDescriptor == classDescriptor
|
||||
} ?: return
|
||||
data.sourceClass.removeDelegationSpecifier(currentSpecifier)
|
||||
when (data.targetClass) {
|
||||
is JetClass -> {
|
||||
data.sourceClass.removeDelegationSpecifier(currentSpecifier)
|
||||
|
||||
if (DescriptorUtils.isSubclass(data.targetClassDescriptor, classDescriptor)) return
|
||||
|
||||
val referencedType = data.sourceClassContext[BindingContext.TYPE, currentSpecifier.typeReference]!!
|
||||
val typeInTargetClass = data.sourceToTargetClassSubstitutor.substitute(referencedType, Variance.INVARIANT)
|
||||
if (!(typeInTargetClass != null && !typeInTargetClass.isError)) return
|
||||
|
||||
if (!DescriptorUtils.isSubclass(data.targetClassDescriptor, classDescriptor)) {
|
||||
val referencedType = data.sourceClassContext[BindingContext.TYPE, currentSpecifier.typeReference]!!
|
||||
val typeInTargetClass = data.sourceToTargetClassSubstitutor.substitute(referencedType, Variance.INVARIANT)
|
||||
if (typeInTargetClass != null && !typeInTargetClass.isError) {
|
||||
val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeInTargetClass)
|
||||
data.targetClass.addDelegationSpecifier(psiFactory.createDelegatorToSuperClass(renderedType)).addToShorteningWaitSet()
|
||||
val newSpecifier = JetPsiFactory(member).createDelegatorToSuperClass(renderedType)
|
||||
data.targetClass.addDelegationSpecifier(newSpecifier).addToShorteningWaitSet()
|
||||
}
|
||||
|
||||
is PsiClass -> {
|
||||
val elementFactory = JavaPsiFacade.getElementFactory(member.project)
|
||||
|
||||
val sourcePsiClass = data.sourceClass.toLightClass() ?: return
|
||||
val superRef = sourcePsiClass.implementsList
|
||||
?.referenceElements
|
||||
?.firstOrNull { it.resolve()?.unwrapped == member }
|
||||
?: return
|
||||
val superTypeForTarget = substitutor.substitute(elementFactory.createType(superRef))
|
||||
|
||||
data.sourceClass.removeDelegationSpecifier(currentSpecifier)
|
||||
|
||||
if (DescriptorUtils.isSubclass(data.targetClassDescriptor, classDescriptor)) return
|
||||
|
||||
val refList = if (data.isInterfaceTarget) data.targetClass.extendsList else data.targetClass.implementsList
|
||||
refList?.add(elementFactory.createReferenceFromText(superTypeForTarget.canonicalText, null))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
private fun removeOriginalMemberOrAddOverride(member: JetCallableDeclaration) {
|
||||
if (member.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
|
||||
member.delete()
|
||||
}
|
||||
else if (!member.hasModifier(JetTokens.OVERRIDE_KEYWORD)) {
|
||||
member.addModifierWithSpace(JetTokens.OVERRIDE_KEYWORD)
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveToJavaClass(member: JetNamedDeclaration, substitutor: PsiSubstitutor) {
|
||||
if (!(data.targetClass is PsiClass && member.canMoveMemberToJavaClass(data.targetClass))) return
|
||||
|
||||
val project = member.project
|
||||
val lightMethod = member.getRepresentativeLightMethod() ?: return
|
||||
val elementFactory = JavaPsiFacade.getElementFactory(project)
|
||||
val movedMember: PsiMember = when (member) {
|
||||
is JetProperty -> {
|
||||
val newType = substitutor.substitute(lightMethod.returnType)
|
||||
val newField = createJavaField(member, data.targetClass)
|
||||
newField.typeElement?.replace(elementFactory.createTypeElement(newType))
|
||||
member.delete()
|
||||
newField
|
||||
}
|
||||
is JetNamedFunction -> {
|
||||
val newReturnType = substitutor.substitute(lightMethod.returnType)
|
||||
val newParameterTypes = lightMethod.parameterList.parameters.map { substitutor.substitute(it.type) }
|
||||
val objectType = PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project))
|
||||
val newTypeParameterBounds = lightMethod.typeParameters.map {
|
||||
it.superTypes.map { substitutor.substitute(it) as? PsiClassType ?: objectType }
|
||||
}
|
||||
val newMethod = createJavaMethod(member, data.targetClass)
|
||||
RefactoringUtil.makeMethodAbstract(data.targetClass, newMethod)
|
||||
newMethod.returnTypeElement?.replace(elementFactory.createTypeElement(newReturnType))
|
||||
newMethod.parameterList.parameters.forEachIndexed { i, parameter ->
|
||||
parameter.typeElement?.replace(elementFactory.createTypeElement(newParameterTypes[i]))
|
||||
}
|
||||
newMethod.typeParameters.forEachIndexed { i, typeParameter ->
|
||||
typeParameter.extendsList.referenceElements.forEachIndexed { j, referenceElement ->
|
||||
referenceElement.replace(elementFactory.createReferenceElementByType(newTypeParameterBounds[i][j]))
|
||||
}
|
||||
}
|
||||
removeOriginalMemberOrAddOverride(member)
|
||||
if (!data.isInterfaceTarget && !data.targetClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
data.targetClass.modifierList?.setModifierProperty(PsiModifier.ABSTRACT, true)
|
||||
}
|
||||
newMethod
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(movedMember)
|
||||
}
|
||||
|
||||
override fun move(info: MemberInfoBase<PsiMember>, substitutor: PsiSubstitutor) {
|
||||
val member = info.member.namedUnwrappedElement as? JetNamedDeclaration ?: return
|
||||
|
||||
if (member is JetClass && info.overrides != null) {
|
||||
moveSuperInterface(member)
|
||||
moveSuperInterface(member, substitutor)
|
||||
return
|
||||
}
|
||||
|
||||
if (data.targetClass is PsiClass) {
|
||||
moveToJavaClass(member, substitutor)
|
||||
return
|
||||
}
|
||||
|
||||
val markedElements = markElements(member)
|
||||
val memberCopy = member.copy() as JetNamedDeclaration
|
||||
|
||||
fun moveClassMember(member: JetClassOrObject, memberCopy: JetClassOrObject): JetClassOrObject {
|
||||
if (data.targetClass.isInterface()) {
|
||||
fun moveClassOrObject(member: JetClassOrObject, memberCopy: JetClassOrObject): JetClassOrObject {
|
||||
if (data.isInterfaceTarget) {
|
||||
memberCopy.removeModifier(JetTokens.INNER_KEYWORD)
|
||||
}
|
||||
|
||||
val movedMember = addMemberToTarget(memberCopy) as JetClassOrObject
|
||||
member.delete()
|
||||
return movedMember
|
||||
}
|
||||
|
||||
fun moveCallableMember(member: JetCallableDeclaration, memberCopy: JetCallableDeclaration): JetCallableDeclaration {
|
||||
data.targetClass as JetClass
|
||||
|
||||
val movedMember: JetCallableDeclaration
|
||||
val clashingSuper = fixOverrideAndGetClashingSuper(member, memberCopy)
|
||||
|
||||
val originalIsAbstract = member.hasModifier(JetTokens.ABSTRACT_KEYWORD)
|
||||
val toAbstract = when {
|
||||
info.isToAbstract -> true
|
||||
!data.targetClass.isInterface() -> false
|
||||
!data.isInterfaceTarget -> false
|
||||
member is JetProperty -> member.mustBeAbstractInInterface()
|
||||
else -> false
|
||||
}
|
||||
@@ -575,23 +662,19 @@ class KotlinPullUpHelper(
|
||||
if (member.typeReference == null) {
|
||||
movedMember.typeReference?.addToShorteningWaitSet()
|
||||
}
|
||||
if (originalIsAbstract) {
|
||||
member.delete()
|
||||
}
|
||||
else if (!member.hasModifier(JetTokens.OVERRIDE_KEYWORD)) {
|
||||
member.addModifierWithSpace(JetTokens.OVERRIDE_KEYWORD)
|
||||
}
|
||||
|
||||
removeOriginalMemberOrAddOverride(member)
|
||||
}
|
||||
else {
|
||||
movedMember = doAddCallableMember(memberCopy, clashingSuper)
|
||||
member.delete()
|
||||
}
|
||||
|
||||
if (originalIsAbstract && data.targetClass.isInterface()) {
|
||||
if (originalIsAbstract && data.isInterfaceTarget) {
|
||||
movedMember.removeModifier(JetTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
|
||||
if (!data.targetClass.isInterface()
|
||||
if (!data.isInterfaceTarget
|
||||
&& !data.targetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)
|
||||
&& (movedMember.hasModifier(JetTokens.ABSTRACT_KEYWORD))) {
|
||||
data.targetClass.addModifierWithSpace(JetTokens.ABSTRACT_KEYWORD)
|
||||
@@ -602,7 +685,7 @@ class KotlinPullUpHelper(
|
||||
try {
|
||||
val movedMember = when (member) {
|
||||
is JetCallableDeclaration -> moveCallableMember(member, memberCopy as JetCallableDeclaration)
|
||||
is JetClassOrObject -> moveClassMember(member, memberCopy as JetClassOrObject)
|
||||
is JetClassOrObject -> moveClassOrObject(member, memberCopy as JetClassOrObject)
|
||||
else -> return
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
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.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
@@ -30,7 +30,7 @@ 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? JetClass ?: return null
|
||||
val targetClass = targetClass.unwrapped as? PsiNamedElement ?: return null
|
||||
val membersToMove = membersToMove
|
||||
.map { it.namedUnwrappedElement as? JetNamedDeclaration }
|
||||
.filterNotNull()
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
@@ -42,13 +43,15 @@ import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||
|
||||
fun checkConflicts(project: Project,
|
||||
sourceClass: JetClassOrObject,
|
||||
targetClass: JetClass,
|
||||
targetClass: PsiNamedElement,
|
||||
memberInfos: List<KotlinMemberInfo>,
|
||||
onShowConflicts: () -> Unit = {},
|
||||
onAccept: () -> Unit) {
|
||||
val conflicts = MultiMap<PsiElement, String>()
|
||||
|
||||
val pullUpData = KotlinPullUpData(sourceClass, targetClass, memberInfos.map { it.member })
|
||||
val pullUpData = KotlinPullUpData(sourceClass,
|
||||
targetClass,
|
||||
memberInfos.map { it.member }.filterNotNull())
|
||||
|
||||
with(pullUpData) {
|
||||
for (memberInfo in memberInfos) {
|
||||
@@ -73,7 +76,6 @@ private val CALLABLE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_I
|
||||
|
||||
private fun DeclarationDescriptor.renderForConflicts(): String {
|
||||
return when (this) {
|
||||
// todo: objects
|
||||
is ClassDescriptor -> "${DescriptorRenderer.getClassKindPrefix(this)} ${IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(this)}"
|
||||
is FunctionDescriptor -> "function '${CALLABLE_RENDERER.render(this)}'"
|
||||
is PropertyDescriptor -> "property '${CALLABLE_RENDERER.render(this)}'"
|
||||
@@ -135,7 +137,7 @@ private fun KotlinPullUpData.checkInnerClassToInterface(
|
||||
member: JetNamedDeclaration,
|
||||
memberDescriptor: DeclarationDescriptor,
|
||||
conflicts: MultiMap<PsiElement, String>) {
|
||||
if (targetClass.isInterface() && memberDescriptor is ClassDescriptor && memberDescriptor.isInner) {
|
||||
if (isInterfaceTarget && memberDescriptor is ClassDescriptor && memberDescriptor.isInner) {
|
||||
val message = "${memberDescriptor.renderForConflicts()} is an inner class. It can not be moved to the interface"
|
||||
conflicts.putValue(member, message.capitalize())
|
||||
}
|
||||
|
||||
@@ -16,7 +16,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetProperty
|
||||
|
||||
fun JetProperty.mustBeAbstractInInterface() =
|
||||
hasInitializer() || hasDelegate() || (!hasInitializer() && !hasDelegate() && accessors.isEmpty())
|
||||
|
||||
fun JetNamedDeclaration.canMoveMemberToJavaClass(targetClass: PsiClass): Boolean {
|
||||
return when (this) {
|
||||
is JetProperty -> {
|
||||
if (targetClass.isInterface) return false
|
||||
if (hasModifier(JetTokens.OPEN_KEYWORD) || hasModifier(JetTokens.ABSTRACT_KEYWORD)) return false
|
||||
if (accessors.isNotEmpty() || delegateExpression != null) return false
|
||||
true
|
||||
}
|
||||
is JetNamedFunction -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class A {
|
||||
|
||||
public final int x;
|
||||
|
||||
abstract boolean foo(int n);
|
||||
|
||||
abstract void bar(@NotNull String s);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class <caret>B: A() {
|
||||
// INFO: {"checked": "true"}
|
||||
val x = 1
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
fun foo(n: Int): Boolean = n > 0
|
||||
// INFO: {"checked": "true"}
|
||||
abstract fun bar(s: String)
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class B: A() {
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
override fun foo(n: Int): Boolean = n > 0
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class A {
|
||||
|
||||
public final int x;
|
||||
|
||||
abstract boolean foo(int n);
|
||||
|
||||
abstract void bar(@NotNull String s);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class <caret>B: A() {
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
val x = 1
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
fun foo(n: Int): Boolean = n > 0
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
abstract fun bar(s: String)
|
||||
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class B: A() {
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
override fun foo(n: Int): Boolean = n > 0
|
||||
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true", "toAbstract": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A<T extends I, U extends I, V> {
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
abstract class A<T extends I, U extends I, V> {
|
||||
|
||||
@NotNull
|
||||
public final T foo1;
|
||||
@NotNull
|
||||
public final Z<T> foo2;
|
||||
public final Object foo3;
|
||||
@NotNull
|
||||
public final Z foo4;
|
||||
@NotNull
|
||||
public final T foo5;
|
||||
@NotNull
|
||||
public final Z<T> foo6;
|
||||
public final Object foo7;
|
||||
@NotNull
|
||||
public final Z foo8;
|
||||
|
||||
abstract <S extends T> void foo(@NotNull T x1, @NotNull Z<T> x2, Object y1, @NotNull Z y2, @NotNull I w1, @NotNull Z w2, @NotNull S s1, @NotNull Z<S> s2);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// WITH_RUNTIME
|
||||
interface I
|
||||
|
||||
interface Z<T>
|
||||
|
||||
class C<W: I> {
|
||||
inner class <caret>B<X: I, Y>(x: X, y: Y): A<X, I, Z<Y>>() {
|
||||
// INFO: {"checked": "true"}
|
||||
fun foo<S : X>(x1: X, x2: Z<X>, y1: Y, y2: Z<Y>, w1: W, w2: Z<W>, s1: S, s2: Z<S>) {
|
||||
|
||||
}
|
||||
// INFO: {"checked": "true"}
|
||||
val foo1: X
|
||||
// INFO: {"checked": "true"}
|
||||
val foo2: Z<X>
|
||||
// INFO: {"checked": "true"}
|
||||
val foo3: Y
|
||||
// INFO: {"checked": "true"}
|
||||
val foo4: Z<Y>
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
val foo5 = x
|
||||
// INFO: {"checked": "true"}
|
||||
val foo6 = object: Z<X> {}
|
||||
// INFO: {"checked": "true"}
|
||||
val foo7 = y
|
||||
// INFO: {"checked": "true"}
|
||||
val foo8 = object: Z<Y> {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
interface I
|
||||
|
||||
interface Z<T>
|
||||
|
||||
class C<W: I> {
|
||||
inner class B<X: I, Y>(x: X, y: Y): A<X, I, Z<Y>>() {
|
||||
// INFO: {"checked": "true"}
|
||||
override fun foo<S : X>(x1: X, x2: Z<X>, y1: Y, y2: Z<Y>, w1: W, w2: Z<W>, s1: S, s2: Z<S>) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
interface I {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
interface I {
|
||||
|
||||
boolean foo(int n);
|
||||
|
||||
void bar(@NotNull String s);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class <caret>B: I {
|
||||
// INFO: {"checked": "true"}
|
||||
val x = 1
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
fun foo(n: Int): Boolean = n > 0
|
||||
// INFO: {"checked": "true"}
|
||||
abstract fun bar(s: String)
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class B: I {
|
||||
// INFO: {"checked": "true"}
|
||||
val x = 1
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
override fun foo(n: Int): Boolean = n > 0
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class T {
|
||||
static class A {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class T {
|
||||
static abstract class A {
|
||||
|
||||
public final int x;
|
||||
|
||||
abstract boolean foo(int n);
|
||||
|
||||
abstract void bar(@NotNull String s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class <caret>B: T.A() {
|
||||
// INFO: {"checked": "true"}
|
||||
val x = 1
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
fun foo(n: Int): Boolean = n > 0
|
||||
// INFO: {"checked": "true"}
|
||||
abstract fun bar(s: String)
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
abstract class B: T.A() {
|
||||
// INFO: {"checked": "true"}
|
||||
val y: Int get() = 2
|
||||
// INFO: {"checked": "true"}
|
||||
val z: Int by lazy { 3 }
|
||||
// INFO: {"checked": "true"}
|
||||
abstract val t: Int
|
||||
// INFO: {"checked": "true"}
|
||||
override fun foo(n: Int): Boolean = n > 0
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
inner class X {
|
||||
|
||||
}
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
class Y {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A implements Z {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A implements Z, X {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X
|
||||
|
||||
// INFO: {"checked": "false"}
|
||||
interface Y
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z
|
||||
|
||||
class <caret>B: A(), X, Y, Z
|
||||
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X
|
||||
|
||||
// INFO: {"checked": "false"}
|
||||
interface Y
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z
|
||||
|
||||
class B: A(), Y
|
||||
@@ -0,0 +1,3 @@
|
||||
interface I extends Z {
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
interface I extends Z, X {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X
|
||||
|
||||
// INFO: {"checked": "false"}
|
||||
interface Y
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z
|
||||
|
||||
class <caret>B: I, X, Y, Z
|
||||
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X
|
||||
|
||||
// INFO: {"checked": "false"}
|
||||
interface Y
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z
|
||||
|
||||
class B: I, Y
|
||||
@@ -0,0 +1,3 @@
|
||||
class A<T> implements Z<T> {
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class A<T> implements Z<T>, X, Y<T> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X<T, U>
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Y<V : Any>
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z<T>
|
||||
|
||||
class <caret>B<S : Any, U : S, V>: A<S>(), X<U, V>, Y<S>, Z<U>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// INFO: {"checked": "true"}
|
||||
interface X<T, U>
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Y<V : Any>
|
||||
|
||||
// INFO: {"checked": "true"}
|
||||
interface Z<T>
|
||||
|
||||
class B<S : Any, U : S, V>: A<S>()
|
||||
@@ -0,0 +1,3 @@
|
||||
interface I {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
interface I {
|
||||
|
||||
int foo();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class <caret>A: I {
|
||||
// INFO: {"checked": "true"}
|
||||
public fun foo(): Int = 1
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
class A: I {
|
||||
// INFO: {"checked": "true"}
|
||||
override fun foo(): Int = 1
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
abstract class A {
|
||||
|
||||
protected abstract int foo();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class <caret>B: A() {
|
||||
// INFO: {"checked": "true"}
|
||||
private fun foo(): Int = 1
|
||||
|
||||
fun bar() = foo() + 1
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class B: A() {
|
||||
// INFO: {"checked": "true"}
|
||||
protected override fun foo(): Int = 1
|
||||
|
||||
fun bar() = foo() + 1
|
||||
}
|
||||
@@ -18,15 +18,17 @@ 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.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
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.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.psi.JetClass
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
@@ -57,6 +59,11 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase()
|
||||
fixture.testDataPath = "${JetTestUtils.getHomeDirectory()}/${mainFile.getParent()}"
|
||||
|
||||
val mainFileName = mainFile.getName()
|
||||
val mainFileBaseName = FileUtil.getNameWithoutExtension(mainFileName)
|
||||
val extraFiles = mainFile.getParentFile().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 addKotlinRuntime = InTextDirectivesUtils.findStringWithPrefixes(file.text, "// WITH_RUNTIME") != null
|
||||
@@ -82,9 +89,9 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase()
|
||||
return members.filter { it.isChecked }
|
||||
}
|
||||
|
||||
override fun chooseSuperClass(superClasses: List<JetClass>): JetClass {
|
||||
override fun chooseSuperClass(superClasses: List<PsiNamedElement>): PsiNamedElement {
|
||||
if (targetClassName != null) {
|
||||
return superClasses.single { it.fqName?.asString() ?: it.name == targetClassName }
|
||||
return superClasses.single { it.qualifiedClassNameForRendering() == targetClassName }
|
||||
}
|
||||
return superClasses.first()
|
||||
}
|
||||
@@ -95,6 +102,9 @@ public abstract class AbstractPullUpTest : JetLightCodeInsightFixtureTestCase()
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
catch(e: Exception) {
|
||||
val message = when (e) {
|
||||
|
||||
@@ -35,6 +35,66 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
|
||||
JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/pullUp"), Pattern.compile("^(.+)\\.kt$"));
|
||||
}
|
||||
|
||||
@TestMetadata("k2j/fromClassToClass.kt")
|
||||
public void testK2j_FromClassToClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClass.kt");
|
||||
doTest(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("k2j/fromClassToClassWithGenerics.kt")
|
||||
public void testK2j_FromClassToClassWithGenerics() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToClassWithGenerics.kt");
|
||||
doTest(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("k2j/fromClassToNestedClass.kt")
|
||||
public void testK2j_FromClassToNestedClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/fromClassToNestedClass.kt");
|
||||
doTest(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("k2j/moveSuperInterfacesToInterface.kt")
|
||||
public void testK2j_MoveSuperInterfacesToInterface() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/moveSuperInterfacesToInterface.kt");
|
||||
doTest(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("k2j/publicToInterface.kt")
|
||||
public void testK2j_PublicToInterface() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2j/publicToInterface.kt");
|
||||
doTest(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("k2k/accidentalOverrides.kt")
|
||||
public void testK2k_AccidentalOverrides() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/accidentalOverrides.kt");
|
||||
|
||||
Reference in New Issue
Block a user