Pull Up/Push Down/Extract Super: Show member dependencies in the refactoring dialog

This commit is contained in:
Alexey Sedunov
2016-09-20 20:48:07 +03:00
parent 8a5628cde5
commit 22271f0af0
15 changed files with 335 additions and 17 deletions
+1
View File
@@ -150,6 +150,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-11017`](https://youtrack.jetbrains.com/issue/KT-11017) Implement "Extract Interface" refactoring
Pull Up: Support properties declared in the primary constructor
Pull Up: Support members declared in the companion object of the original class
Pull Up: Show member dependencies in the refactoring dialog
#### Android Lint
@@ -471,4 +471,6 @@ fun KtClassOrObject.findPropertyByName(name: String): KtNamedDeclaration? {
fun isTypeConstructorReference(e: PsiElement): Boolean {
val parent = e.parent
return parent is KtUserType && parent.referenceExpression == e
}
}
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
+4
View File
@@ -707,6 +707,10 @@
order="first"
implementationClass="org.jetbrains.kotlin.idea.refactoring.pullUp.JavaToKotlinPullUpHelperFactory"/>
<lang.refactoringSupport.classMembersRefactoringSupport
language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinClassMembersRefactoringSupport"/>
<problemFileHighlightFilter implementation="org.jetbrains.kotlin.idea.projectView.KotlinProblemFileHighlightFilter"/>
<codeInsight.typeInfo language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinExpressionTypeProvider"/>
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractClass.ExtractSuper
import org.jetbrains.kotlin.idea.refactoring.introduce.extractClass.KotlinExtractInterfaceHandler
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
import org.jetbrains.kotlin.idea.refactoring.pullUp.getInterfaceContainmentVerifier
import org.jetbrains.kotlin.idea.refactoring.pullUp.mustBeAbstractInInterface
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -48,7 +49,11 @@ class KotlinExtractInterfaceDialog(
member is KtClass && member.hasModifier(KtTokens.INNER_KEYWORD)
}
extractableMemberInfos.forEach { it.isToAbstract = true }
return object : MemberInfoModelBase(extractableMemberInfos) {
return object : MemberInfoModelBase(
originalClass,
extractableMemberInfos,
getInterfaceContainmentVerifier { selectedMembers }
) {
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
val member = memberInfo.member
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface()) || member is KtParameter
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiComment
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
import com.intellij.refactoring.classMembers.MemberInfoChange
import com.intellij.refactoring.extractSuperclass.JavaExtractSuperBaseDialog
import com.intellij.refactoring.util.DocCommentPolicy
@@ -34,6 +33,7 @@ import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.idea.refactoring.introduce.extractClass.ExtractSuperInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinUsesAndInterfacesDependencyMemberInfoModel
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import java.awt.BorderLayout
@@ -58,8 +58,10 @@ abstract class KotlinExtractSuperDialogBase(
private val fileNameField = JTextField()
open class MemberInfoModelBase(
val memberInfos: List<KotlinMemberInfo>
) : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>() {
originalClass: KtClassOrObject,
val memberInfos: List<KotlinMemberInfo>,
interfaceContainmentVerifier: (KtNamedDeclaration) -> Boolean
) : KotlinUsesAndInterfacesDependencyMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(originalClass, null, false, interfaceContainmentVerifier) {
override fun isFixedAbstract(memberInfo: KotlinMemberInfo?) = true
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractClass.ExtractSuper
import org.jetbrains.kotlin.idea.refactoring.introduce.extractClass.KotlinExtractSuperclassHandler
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
import org.jetbrains.kotlin.idea.refactoring.pullUp.getInterfaceContainmentVerifier
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
@@ -44,7 +45,11 @@ class KotlinExtractSuperclassDialog(
}
override fun createMemberInfoModel(): MemberInfoModelBase {
return object : MemberInfoModelBase(extractClassMembers(originalClass)) {
return object : MemberInfoModelBase(
originalClass,
extractClassMembers(originalClass),
getInterfaceContainmentVerifier { selectedMembers }
) {
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
val member = memberInfo.member
return member is KtNamedFunction || member is KtProperty || member is KtParameter
@@ -0,0 +1,72 @@
/*
* 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.PsiNamedElement
import com.intellij.refactoring.classMembers.ClassMembersRefactoringSupport
import com.intellij.refactoring.classMembers.DependentMembersCollectorBase
import com.intellij.refactoring.classMembers.MemberInfoBase
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.refactoring.pullUp.KotlinPullUpData
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
import org.jetbrains.kotlin.util.findCallableMemberBySignature
class KotlinClassMembersRefactoringSupport : ClassMembersRefactoringSupport {
override fun isProperMember(memberInfo: MemberInfoBase<*>): Boolean {
val member = memberInfo.member
return member is KtNamedFunction
|| member is KtProperty
|| (member is KtParameter && member.isPropertyParameter())
|| (member is KtClassOrObject && memberInfo.overrides == null)
}
override fun createDependentMembersCollector(clazz: Any, superClass: Any?): DependentMembersCollectorBase<*, *> {
return object : DependentMembersCollectorBase<KtNamedDeclaration, PsiNamedElement>(
clazz as KtClassOrObject,
superClass as PsiNamedElement?
) {
override fun collect(member: KtNamedDeclaration) {
member.accept(
object : KtTreeVisitorVoid() {
private val pullUpData = superClass?.let { KotlinPullUpData(clazz as KtClassOrObject, it as PsiNamedElement, emptyList()) }
private val possibleContainingClasses =
listOf(clazz) + if (clazz is KtClass) clazz.getCompanionObjects() else emptyList()
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val referencedMember = expression.mainReference.resolve() as? KtNamedDeclaration ?: return
val containingClassOrObject = referencedMember.containingClassOrObject ?: return
if (containingClassOrObject !in possibleContainingClasses) return
if (pullUpData != null) {
val memberDescriptor = referencedMember.resolveToDescriptor() as? CallableMemberDescriptor ?: return
val memberInSuper = memberDescriptor.substitute(pullUpData.sourceToTargetClassSubstitutor) ?: return
if (pullUpData.targetClassDescriptor.findCallableMemberBySignature(memberInSuper as CallableMemberDescriptor) != null) return
}
myCollection.add(referencedMember)
}
}
)
}
}
}
}
@@ -0,0 +1,44 @@
/*
* 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.refactoring.RefactoringBundle
import com.intellij.refactoring.classMembers.DependencyMemberInfoModel
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.classMembers.MemberInfoModel
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.utils.ifEmpty
class KotlinInterfaceDependencyMemberInfoModel<T : KtNamedDeclaration, M : MemberInfoBase<T>>(
aClass: KtClassOrObject
) : DependencyMemberInfoModel<T, M>(KotlinInterfaceMemberDependencyGraph<T, M>(aClass), MemberInfoModel.WARNING) {
init {
setTooltipProvider { memberInfo ->
val dependencies = myMemberDependencyGraph.getDependenciesOf(memberInfo.member).ifEmpty { return@setTooltipProvider null }
buildString {
append(RefactoringBundle.message("interface.member.dependency.required.by.interfaces", dependencies.size))
append(" ")
dependencies.joinTo(this) { it.name ?: "" }
}
}
}
override fun isCheckedWhenDisabled(member: M) = false
override fun isFixedAbstract(member: M) = null
}
@@ -0,0 +1,51 @@
/*
* 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.PsiMember
import com.intellij.refactoring.classMembers.MemberDependencyGraph
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.util.classMembers.InterfaceMemberDependencyGraph
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import java.util.*
class KotlinInterfaceMemberDependencyGraph<T : KtNamedDeclaration, M : MemberInfoBase<T>>(
klass: KtClassOrObject
) : MemberDependencyGraph<T, M> {
private val delegateGraph = InterfaceMemberDependencyGraph<PsiMember, MemberInfoBase<PsiMember>>(klass.toLightClass())
override fun memberChanged(memberInfo: M) {
delegateGraph.memberChanged(memberInfo.toJavaMemberInfo()!!)
}
@Suppress("UNCHECKED_CAST")
override fun getDependent() = delegateGraph.dependent
.mapNotNull { it.unwrapped }
.filterIsInstanceTo(LinkedHashSet<KtNamedDeclaration>()) as Set<T>
@Suppress("UNCHECKED_CAST")
override fun getDependenciesOf(member: T): Set<T> {
val psiMember = lightElementForMemberInfo(member) ?: return emptySet()
val psiMemberDependencies = delegateGraph.getDependenciesOf(psiMember) ?: return emptySet()
return psiMemberDependencies
.mapNotNull { it.unwrapped }
.filterIsInstanceTo(LinkedHashSet<KtNamedDeclaration>()) as Set<T>
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.refactoring.memberInfo
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
@@ -78,9 +79,8 @@ class KotlinMemberInfo @JvmOverloads constructor(
}
}
fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
val declaration = member
val psiMember: PsiMember? = when (declaration) {
fun lightElementForMemberInfo(declaration: KtNamedDeclaration?): PsiMember? {
return when (declaration) {
is KtNamedFunction -> declaration.getRepresentativeLightMethod()
is KtProperty, is KtParameter -> declaration.toLightElements().let {
it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>()
@@ -88,8 +88,14 @@ fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
is KtClassOrObject -> declaration.toLightClass()
else -> null
}
val info = MemberInfo(psiMember ?: return null, isSuperClass, null)
}
fun MemberInfoBase<out KtNamedDeclaration>.toJavaMemberInfo(): MemberInfo? {
val declaration = member
val psiMember: PsiMember? = lightElementForMemberInfo(declaration)
val info = MemberInfo(psiMember ?: return null, psiMember is PsiClass && overrides != null, null)
info.isToAbstract = isToAbstract
info.isChecked = isChecked
return info
}
@@ -0,0 +1,52 @@
/*
* 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.PsiNamedElement
import com.intellij.refactoring.classMembers.ANDCombinedMemberInfoModel
import com.intellij.refactoring.classMembers.DelegatingMemberInfoModel
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.classMembers.MemberInfoModel
import com.intellij.refactoring.util.classMembers.UsesDependencyMemberInfoModel
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
open class KotlinUsesAndInterfacesDependencyMemberInfoModel<T : KtNamedDeclaration, M : MemberInfoBase<T>>(
klass: KtClassOrObject,
superClass: PsiNamedElement?,
recursive: Boolean,
interfaceContainmentVerifier: (T) -> Boolean = { false }
) : DelegatingMemberInfoModel<T, M>(
ANDCombinedMemberInfoModel(
object : KotlinUsesDependencyMemberInfoModel<T, M>(klass, superClass, recursive) {
override fun checkForProblems(memberInfo: M): Int {
val problem = super.checkForProblems(memberInfo)
if (problem == MemberInfoModel.OK) return MemberInfoModel.OK
val member = memberInfo.member
if (interfaceContainmentVerifier(member)) return MemberInfoModel.OK
return problem
}
},
KotlinInterfaceDependencyMemberInfoModel<T, M>(klass))
) {
@Suppress("UNCHECKED_CAST")
fun setSuperClass(superClass: PsiNamedElement) {
((delegatingTarget as ANDCombinedMemberInfoModel<T, M>).model1 as UsesDependencyMemberInfoModel<T, PsiNamedElement, M>).setSuperClass(superClass)
}
}
@@ -0,0 +1,43 @@
/*
* 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.PsiNamedElement
import com.intellij.refactoring.classMembers.MemberInfoBase
import com.intellij.refactoring.classMembers.MemberInfoModel
import com.intellij.refactoring.util.classMembers.UsesDependencyMemberInfoModel
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
open class KotlinUsesDependencyMemberInfoModel<T : KtNamedDeclaration, M : MemberInfoBase<T>>(
klass : KtClassOrObject,
superClass: PsiNamedElement?,
recursive: Boolean
) : UsesDependencyMemberInfoModel<T, PsiNamedElement, M>(klass, superClass, recursive) {
override fun doCheck(memberInfo: M, problem: Int): Int {
val member = memberInfo.member
val container = member.containingClassOrObject
if (problem == MemberInfoModel.ERROR
&& container is KtObjectDeclaration
&& container.isCompanion()
&& container.containingClassOrObject == myClass) return MemberInfoModel.WARNING
return problem
}
}
@@ -22,7 +22,6 @@ 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.classMembers.MemberInfoChange
import com.intellij.refactoring.classMembers.MemberInfoModel
import com.intellij.refactoring.memberPullUp.PullUpProcessor
@@ -48,7 +47,16 @@ class KotlinPullUpDialog(
init()
}
private inner class MemberInfoModelImpl : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>() {
private inner class MemberInfoModelImpl(
originalClass: KtClassOrObject,
superClass: PsiNamedElement?,
interfaceContainmentVerifier: (KtNamedDeclaration) -> Boolean
) : KotlinUsesAndInterfacesDependencyMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(
originalClass,
superClass,
false,
interfaceContainmentVerifier
) {
private var lastSuperClass: PsiNamedElement? = null
// Abstract members remain abstract
@@ -96,11 +104,13 @@ class KotlinPullUpDialog(
}
override fun memberInfoChanged(event: MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>) {
super.memberInfoChanged(event)
val superClass = superClass ?: return
if (superClass != lastSuperClass) {
lastSuperClass = superClass
val isInterface = superClass is KtClass && superClass.isInterface()
event.changedMembers.forEach { it.isToAbstract = isInterface }
setSuperClass(superClass)
}
}
}
@@ -114,7 +124,7 @@ class KotlinPullUpDialog(
override fun getSuperClass() = super.getSuperClass()
override fun createMemberInfoModel(): MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo> =
MemberInfoModelImpl()
MemberInfoModelImpl(sourceClass, preselection, getInterfaceContainmentVerifier { selectedMemberInfos })
override fun getPreselection() = mySuperClasses.firstOrNull { !it.isInterfaceClass() } ?: mySuperClasses.firstOrNull()
@@ -17,11 +17,15 @@
package org.jetbrains.kotlin.idea.refactoring.pullUp
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.lightElementForMemberInfo
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
import org.jetbrains.kotlin.lexer.KtTokens
@@ -166,4 +170,16 @@ fun addSuperTypeEntry(
val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeInTargetClass)
val newSpecifier = KtPsiFactory(targetClass).createSuperTypeEntry(renderedType)
targetClass.addSuperTypeListEntry(newSpecifier).addToShorteningWaitSet()
}
fun getInterfaceContainmentVerifier(getMemberInfos: () -> List<KotlinMemberInfo>): (KtNamedDeclaration) -> Boolean {
return result@ { member ->
val psiMethodToCheck = lightElementForMemberInfo(member) as? PsiMethod ?: return@result false
getMemberInfos().any {
if (!it.isSuperClass || it.overrides != false) return@any false
val psiSuperInterface = (it.member as? KtClass)?.toLightClass()
psiSuperInterface?.findMethodBySignature(psiMethodToCheck, true) != null
}
}
}
@@ -17,13 +17,14 @@
package org.jetbrains.kotlin.idea.refactoring.pushDown
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.JavaRefactoringSettings
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
import com.intellij.refactoring.classMembers.MemberInfoChange
import com.intellij.refactoring.classMembers.*
import com.intellij.refactoring.ui.RefactoringDialog
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinUsesDependencyMemberInfoModel
import org.jetbrains.kotlin.idea.refactoring.memberInfo.qualifiedClassNameForRendering
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -47,7 +48,7 @@ class KotlinPushDownDialog(
init()
}
private var memberInfoModel: AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>? = null
private var memberInfoModel: MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>? = null
val selectedMemberInfos: List<KotlinMemberInfo>
get() = memberInfos.filter { it.isChecked && memberInfoModel?.isMemberEnabled(it) ?: false }
@@ -79,7 +80,11 @@ class KotlinPushDownDialog(
RefactoringBundle.message("keep.abstract.column.header"))
panel.add(memberSelectionPanel, BorderLayout.CENTER)
memberInfoModel = object : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>() {
memberInfoModel = object : DelegatingMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(
ANDCombinedMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(
KotlinUsesDependencyMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(sourceClass, null, false),
UsedByDependencyMemberInfoModel<KtNamedDeclaration, PsiNamedElement, KotlinMemberInfo>(sourceClass))
) {
override fun isFixedAbstract(member: KotlinMemberInfo?) = null
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {