Pull Up/Push Down/Extract Super: Support references to Java-declared superinterfaces

This commit is contained in:
Alexey Sedunov
2016-09-26 13:05:31 +03:00
parent 22271f0af0
commit 924bb44862
24 changed files with 148 additions and 42 deletions
@@ -80,6 +80,7 @@ import org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateIntenti
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.string.collapseSpaces import org.jetbrains.kotlin.idea.util.string.collapseSpaces
@@ -714,7 +715,12 @@ fun FqNameUnsafe.hasIdentifiersOnly(): Boolean = pathSegments().all { KotlinName
fun FqName.hasIdentifiersOnly(): Boolean = pathSegments().all { KotlinNameSuggester.isIdentifier(it.asString().quoteIfNeeded()) } fun FqName.hasIdentifiersOnly(): Boolean = pathSegments().all { KotlinNameSuggester.isIdentifier(it.asString().quoteIfNeeded()) }
fun PsiNamedElement.isInterfaceClass(): Boolean = this is KtClass && isInterface() || this is PsiClass && isInterface fun PsiNamedElement.isInterfaceClass(): Boolean = when (this) {
is KtClass -> isInterface()
is PsiClass -> isInterface
is KtPsiClassWrapper -> psiClass.isInterface
else -> false
}
fun <ListType : KtElement> replaceListPsiAndKeepDelimiters( fun <ListType : KtElement> replaceListPsiAndKeepDelimiters(
originalList: ListType, originalList: ListType,
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
@@ -49,11 +49,11 @@ class KotlinMemberInfo @JvmOverloads constructor(
} }
init { init {
val memberDescriptor = member.resolveToDescriptor() val memberDescriptor = member.resolveToDescriptorWrapperAware()
isStatic = member.parent is KtFile isStatic = member.parent is KtFile
if (member is KtClass && isSuperClass) { if ((member is KtClass || member is KtPsiClassWrapper) && isSuperClass) {
if (member.isInterface()) { if (member.isInterfaceClass()) {
displayName = RefactoringBundle.message("member.info.implements.0", member.name) displayName = RefactoringBundle.message("member.info.implements.0", member.name)
overrides = false overrides = false
} }
@@ -86,6 +86,7 @@ fun lightElementForMemberInfo(declaration: KtNamedDeclaration?): PsiMember? {
it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>() it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>()
} as PsiMember? } as PsiMember?
is KtClassOrObject -> declaration.toLightClass() is KtClassOrObject -> declaration.toLightClass()
is KtPsiClassWrapper -> declaration.psiClass
else -> null else -> null
} }
} }
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -40,8 +40,8 @@ class KotlinMemberInfoStorage(
filter: (KtNamedDeclaration) -> Boolean = { true } filter: (KtNamedDeclaration) -> Boolean = { true }
): AbstractMemberInfoStorage<KtNamedDeclaration, PsiNamedElement, KotlinMemberInfo>(classOrObject, filter) { ): AbstractMemberInfoStorage<KtNamedDeclaration, PsiNamedElement, KotlinMemberInfo>(classOrObject, filter) {
override fun memberConflict(member1: KtNamedDeclaration, member: KtNamedDeclaration): Boolean { override fun memberConflict(member1: KtNamedDeclaration, member: KtNamedDeclaration): Boolean {
val descriptor1 = member1.resolveToDescriptor() val descriptor1 = member1.resolveToDescriptorWrapperAware()
val descriptor = member.resolveToDescriptor() val descriptor = member.resolveToDescriptorWrapperAware()
if (descriptor1.name != descriptor.name) return false if (descriptor1.name != descriptor.name) return false
return when { return when {
@@ -111,9 +111,14 @@ fun extractClassMembers(
val typeReference = it.typeReference ?: return@mapNotNull null val typeReference = it.typeReference ?: return@mapNotNull null
val type = typeReference.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference] val type = typeReference.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference]
val classDescriptor = type?.constructor?.declarationDescriptor as? ClassDescriptor val classDescriptor = type?.constructor?.declarationDescriptor as? ClassDescriptor
classDescriptor?.source?.getPsi() as? KtClass val classPsi = classDescriptor?.source?.getPsi()
when (classPsi) {
is KtClass -> classPsi
is PsiClass -> KtPsiClassWrapper(classPsi)
else -> null
}
} }
.filter { it.isInterface() } .filter { it.isInterfaceClass() }
.mapTo(result) { KotlinMemberInfo(it, true) } .mapTo(result) { KotlinMemberInfo(it, true) }
} }
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.memberInfo
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtPsiFactory
interface KtPsiClassWrapper : KtNamedDeclaration {
val psiClass: PsiClass
}
fun KtPsiClassWrapper(psiClass: PsiClass): KtPsiClassWrapper {
val dummyKtClass = KtPsiFactory(psiClass.project).createClass("class ${psiClass.name}")
return object : KtPsiClassWrapper, KtNamedDeclaration by dummyKtClass {
override fun equals(other: Any?) = psiClass == (other as? KtPsiClassWrapper)?.psiClass
override fun hashCode() = psiClass.hashCode()
override val psiClass: PsiClass
get() = psiClass
}
}
@@ -18,8 +18,12 @@ package org.jetbrains.kotlin.idea.refactoring.memberInfo
import com.intellij.psi.PsiClass import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
@@ -60,3 +64,13 @@ fun KotlinMemberInfo.getChildrenToAnalyze(): List<PsiElement> {
} }
return childrenToCheck return childrenToCheck
} }
internal fun KtNamedDeclaration.resolveToDescriptorWrapperAware(resolutionFacade: ResolutionFacade? = null): DeclarationDescriptor {
if (this is KtPsiClassWrapper) return psiClass.getJavaClassDescriptor(resolutionFacade)!!
return (resolutionFacade ?: getResolutionFacade()).resolveToDescriptor(this)
}
internal fun PsiMember.toKtDeclarationWrapperAware(): KtNamedDeclaration? {
if (this is PsiClass && this !is KtLightClass) return KtPsiClassWrapper(this)
return namedUnwrappedElement as? KtNamedDeclaration
}
@@ -20,7 +20,9 @@ import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny import org.jetbrains.kotlin.idea.refactoring.memberInfo.getClassDescriptorIfAny
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -45,11 +47,10 @@ class KotlinPullUpData(val sourceClass: KtClassOrObject,
val sourceClassDescriptor = sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, sourceClass] as ClassDescriptor val sourceClassDescriptor = sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, sourceClass] as ClassDescriptor
val memberDescriptors = membersToMove.keysToMap { val memberDescriptors = membersToMove.keysToMap {
if (it is KtParameter) { when (it) {
sourceClassContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!! is KtPsiClassWrapper -> it.psiClass.getJavaClassDescriptor(resolutionFacade)!!
} is KtParameter -> sourceClassContext[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it]!!
else { else -> sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!!
sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!!
} }
} }
@@ -29,10 +29,7 @@ import com.intellij.refactoring.util.DocCommentPolicy
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.idea.refactoring.isCompanionMemberOf import org.jetbrains.kotlin.idea.refactoring.isCompanionMemberOf
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.*
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfoStorage
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable
import org.jetbrains.kotlin.idea.refactoring.memberInfo.toJavaMemberInfo
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
class KotlinPullUpDialog( class KotlinPullUpDialog(
@@ -40,6 +40,8 @@ import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.refactoring.createJavaField import org.jetbrains.kotlin.idea.refactoring.createJavaField
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
import org.jetbrains.kotlin.idea.refactoring.isCompanionMemberOf import org.jetbrains.kotlin.idea.refactoring.isCompanionMemberOf
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.refactoring.memberInfo.toKtDeclarationWrapperAware
import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier
import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier
@@ -325,7 +327,8 @@ class KotlinPullUpHelper(
return clashingSuperDescriptor.source.getPsi() as? KtCallableDeclaration return clashingSuperDescriptor.source.getPsi() as? KtCallableDeclaration
} }
private fun moveSuperInterface(member: KtClass, substitutor: PsiSubstitutor) { private fun moveSuperInterface(member: PsiNamedElement, substitutor: PsiSubstitutor) {
val realMemberPsi = if (member is KtPsiClassWrapper) member.psiClass else member
val classDescriptor = data.memberDescriptors[member] as? ClassDescriptor ?: return val classDescriptor = data.memberDescriptors[member] as? ClassDescriptor ?: return
val currentSpecifier = data.sourceClass.getSuperTypeEntryByDescriptor(classDescriptor, data.sourceClassContext) ?: return val currentSpecifier = data.sourceClass.getSuperTypeEntryByDescriptor(classDescriptor, data.sourceClassContext) ?: return
when (data.targetClass) { when (data.targetClass) {
@@ -340,7 +343,7 @@ class KotlinPullUpHelper(
val sourcePsiClass = data.sourceClass.toLightClass() ?: return val sourcePsiClass = data.sourceClass.toLightClass() ?: return
val superRef = sourcePsiClass.implementsList val superRef = sourcePsiClass.implementsList
?.referenceElements ?.referenceElements
?.firstOrNull { it.resolve()?.unwrapped == member } ?.firstOrNull { it.resolve()?.unwrapped == realMemberPsi }
?: return ?: return
val superTypeForTarget = substitutor.substitute(elementFactory.createType(superRef)) val superTypeForTarget = substitutor.substitute(elementFactory.createType(superRef))
@@ -426,9 +429,9 @@ class KotlinPullUpHelper(
} }
override fun move(info: MemberInfoBase<PsiMember>, substitutor: PsiSubstitutor) { override fun move(info: MemberInfoBase<PsiMember>, substitutor: PsiSubstitutor) {
val member = info.member.namedUnwrappedElement as? KtNamedDeclaration ?: return val member = info.member.toKtDeclarationWrapperAware() ?: return
if (member is KtClass && info.overrides != null) { if ((member is KtClass || member is KtPsiClassWrapper) && info.overrides != null) {
moveSuperInterface(member, substitutor) moveSuperInterface(member, substitutor)
return return
} }
@@ -23,13 +23,13 @@ import com.intellij.refactoring.memberPullUp.JavaPullUpHelper
import com.intellij.refactoring.memberPullUp.PullUpData import com.intellij.refactoring.memberPullUp.PullUpData
import com.intellij.refactoring.memberPullUp.PullUpHelper import com.intellij.refactoring.memberPullUp.PullUpHelper
import com.intellij.refactoring.memberPullUp.PullUpHelperFactory import com.intellij.refactoring.memberPullUp.PullUpHelperFactory
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.refactoring.createJavaClass import org.jetbrains.kotlin.idea.refactoring.createJavaClass
import org.jetbrains.kotlin.idea.refactoring.memberInfo.toKtDeclarationWrapperAware
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -38,7 +38,7 @@ class KotlinPullUpHelperFactory : PullUpHelperFactory {
val sourceClass = sourceClass.unwrapped as? KtClassOrObject ?: return null val sourceClass = sourceClass.unwrapped as? KtClassOrObject ?: return null
val targetClass = targetClass.unwrapped as? PsiNamedElement ?: return null val targetClass = targetClass.unwrapped as? PsiNamedElement ?: return null
val membersToMove = membersToMove val membersToMove = membersToMove
.mapNotNull { it.namedUnwrappedElement as? KtNamedDeclaration } .mapNotNull { it.toKtDeclarationWrapperAware() }
.sortedBy { it.startOffset } .sortedBy { it.startOffset }
return KotlinPullUpData(sourceClass, targetClass, membersToMove) return KotlinPullUpData(sourceClass, targetClass, membersToMove)
} }
@@ -56,7 +56,7 @@ class KotlinPullUpHelperFactory : PullUpHelperFactory {
} }
class JavaToKotlinPullUpHelperFactory : PullUpHelperFactory { class JavaToKotlinPullUpHelperFactory : PullUpHelperFactory {
private fun createJavaToKotlinPullUpHelper(data: PullUpData): JavaToKotlinPreconversionPullUpHelper? { private fun createJavaToKotlinPullUpHelper(data: PullUpData): PullUpHelper<*>? {
if (!data.sourceClass.isInheritor(data.targetClass, true)) return null if (!data.sourceClass.isInheritor(data.targetClass, true)) return null
val dummyTargetClass = createDummyTargetClass(data) ?: return null val dummyTargetClass = createDummyTargetClass(data) ?: return null
val dataForDelegate = object : PullUpData by data { val dataForDelegate = object : PullUpData by data {
@@ -96,6 +96,8 @@ class JavaToKotlinPullUpHelperFactory : PullUpHelperFactory {
} }
override fun createPullUpHelper(data: PullUpData): PullUpHelper<*> { override fun createPullUpHelper(data: PullUpData): PullUpHelper<*> {
if (data.sourceClass is KtLightClass) return KotlinPullUpHelperFactory().createPullUpHelper(data)
createJavaToKotlinPullUpHelper(data)?.let { return it } createJavaToKotlinPullUpHelper(data)?.let { return it }
return PullUpHelper.INSTANCE return PullUpHelper.INSTANCE
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.getChildrenToAnalyze import org.jetbrains.kotlin.idea.refactoring.memberInfo.getChildrenToAnalyze
import org.jetbrains.kotlin.idea.refactoring.memberInfo.resolveToDescriptorWrapperAware
import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
@@ -57,7 +58,7 @@ fun checkConflicts(project: Project,
with(pullUpData) { with(pullUpData) {
for (memberInfo in memberInfos) { for (memberInfo in memberInfos) {
val member = memberInfo.member val member = memberInfo.member
val memberDescriptor = resolutionFacade.resolveToDescriptor(member) val memberDescriptor = member.resolveToDescriptorWrapperAware(resolutionFacade)
checkClashWithSuperDeclaration(member, memberDescriptor, conflicts) checkClashWithSuperDeclaration(member, memberDescriptor, conflicts)
checkAccidentalOverrides(member, memberDescriptor, conflicts) checkAccidentalOverrides(member, memberDescriptor, conflicts)
@@ -131,7 +132,7 @@ private fun KotlinPullUpData.checkAccidentalOverrides(
.filterNot { it.isSourceOrTarget(this) } .filterNot { it.isSourceOrTarget(this) }
.mapNotNull { it.unwrapped as? KtClassOrObject } .mapNotNull { it.unwrapped as? KtClassOrObject }
.forEach { .forEach {
val subClassDescriptor = resolutionFacade.resolveToDescriptor(it) as ClassDescriptor val subClassDescriptor = it.resolveToDescriptorWrapperAware(resolutionFacade) as ClassDescriptor
val substitutor = getTypeSubstitutor(targetClassDescriptor.defaultType, val substitutor = getTypeSubstitutor(targetClassDescriptor.defaultType,
subClassDescriptor.defaultType) ?: TypeSubstitutor.EMPTY subClassDescriptor.defaultType) ?: TypeSubstitutor.EMPTY
val memberDescriptorInSubClass = val memberDescriptorInSubClass =
@@ -142,7 +143,7 @@ private fun KotlinPullUpData.checkAccidentalOverrides(
val message = memberDescriptor.renderForConflicts() + val message = memberDescriptor.renderForConflicts() +
" in super class would clash with existing member of " + " in super class would clash with existing member of " +
resolutionFacade.resolveToDescriptor(it).renderForConflicts() it.resolveToDescriptorWrapperAware(resolutionFacade).renderForConflicts()
conflicts.putValue(clashingMember, message.capitalize()) conflicts.putValue(clashingMember, message.capitalize())
} }
} }
@@ -31,10 +31,12 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.refactoring.pullUp.* import org.jetbrains.kotlin.idea.refactoring.pullUp.*
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
@@ -62,7 +64,12 @@ class KotlinPushDownContext(
val memberDescriptors = membersToMove val memberDescriptors = membersToMove
.map { it.member } .map { it.member }
.keysToMap { sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!! } .keysToMap {
when (it) {
is KtPsiClassWrapper -> it.psiClass.getJavaClassDescriptor(resolutionFacade)!!
else -> sourceClassContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it]!!
}
}
} }
class KotlinPushDownProcessor( class KotlinPushDownProcessor(
@@ -161,7 +168,7 @@ class KotlinPushDownProcessor(
} }
} }
is KtClassOrObject -> { is KtClassOrObject, is KtPsiClassWrapper -> {
if (memberInfo.overrides != null) { if (memberInfo.overrides != null) {
context.sourceClass.getSuperTypeEntryByDescriptor( context.sourceClass.getSuperTypeEntryByDescriptor(
memberDescriptor as ClassDescriptor, memberDescriptor as ClassDescriptor,
@@ -202,7 +209,7 @@ class KotlinPushDownProcessor(
member.delete() member.delete()
} }
} }
is KtClassOrObject -> { is KtClassOrObject, is KtPsiClassWrapper -> {
if (memberInfo.overrides != null) { if (memberInfo.overrides != null) {
context.sourceClass.getSuperTypeEntryByDescriptor( context.sourceClass.getSuperTypeEntryByDescriptor(
memberDescriptor as ClassDescriptor, memberDescriptor as ClassDescriptor,
@@ -24,6 +24,7 @@ import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.refactoring.pullUp.renderForConflicts import org.jetbrains.kotlin.idea.refactoring.pullUp.renderForConflicts
import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
@@ -50,7 +51,7 @@ fun analyzePushDownConflicts(context: KotlinPushDownContext,
val membersToKeepAbstract = ArrayList<KtNamedDeclaration>() val membersToKeepAbstract = ArrayList<KtNamedDeclaration>()
for (info in context.membersToMove) { for (info in context.membersToMove) {
val member = info.member val member = info.member
if (!info.isChecked || (member is KtClassOrObject && info.overrides != null)) continue if (!info.isChecked || ((member is KtClassOrObject || member is KtPsiClassWrapper) && info.overrides != null)) continue
membersToPush += member membersToPush += member
if ((member is KtNamedFunction || member is KtProperty) if ((member is KtNamedFunction || member is KtProperty)
@@ -1,3 +1,8 @@
class A implements Z { class A implements Z {
} }
// INFO: {"checked": "true"}
interface J {
}
@@ -1,3 +1,8 @@
class A implements Z, X { class A implements Z, X, J {
}
// INFO: {"checked": "true"}
interface J {
} }
@@ -7,4 +7,4 @@ interface Y
// INFO: {"checked": "true"} // INFO: {"checked": "true"}
interface Z interface Z
class <caret>B: A(), X, Y, Z class <caret>B: A(), X, Y, Z, J
@@ -1,3 +1,8 @@
interface I extends Z { interface I extends Z {
} }
// INFO: {"checked": "true"}
interface J {
}
@@ -1,3 +1,8 @@
interface I extends Z, X { interface I extends Z, X, J {
}
// INFO: {"checked": "true"}
interface J {
} }
@@ -7,4 +7,4 @@ interface Y
// INFO: {"checked": "true"} // INFO: {"checked": "true"}
interface Z interface Z
class <caret>B: I, X, Y, Z class <caret>B: I, X, Y, Z, J
@@ -0,0 +1,4 @@
// INFO: {"checked": "true"}
interface J {
}
@@ -0,0 +1,4 @@
// INFO: {"checked": "true"}
interface J {
}
@@ -11,4 +11,4 @@ interface Y
// INFO: {"checked": "true"} // INFO: {"checked": "true"}
interface Z interface Z
class <caret>B: A(), X, Y, Z class <caret>B: A(), X, Y, Z, J
@@ -1,4 +1,4 @@
open class A: Z, X, Y { open class A: Z, X, Y, J {
} }
@@ -25,6 +25,7 @@ import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.classMembers.MemberInfoBase import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.util.CommonRefactoringUtil import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
@@ -64,6 +65,7 @@ abstract class AbstractMemberPullPushTest : KotlinLightCodeInsightFixtureTestCas
try { try {
markMembersInfo(file) markMembersInfo(file)
extraFilesToPsi.keys.forEach(::markMembersInfo)
action(file) action(file)
@@ -105,7 +107,8 @@ internal var PsiElement.elementInfo: ElementInfo by NotNullableUserDataProperty(
internal fun <T : MemberInfoBase<*>> chooseMembers(members: List<T>): List<T> { internal fun <T : MemberInfoBase<*>> chooseMembers(members: List<T>): List<T> {
members.forEach { members.forEach {
val info = it.member.elementInfo val memberPsi = it.member.let { if (it is KtPsiClassWrapper) it.psiClass else it }
val info = memberPsi.elementInfo
it.isChecked = info.checked it.isChecked = info.checked
it.isToAbstract = info.toAbstract it.isToAbstract = info.toAbstract
} }