Pull Up/Push Down/Extract Super: Show member dependencies in the refactoring dialog
This commit is contained in:
@@ -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()
|
||||
@@ -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"/>
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
+5
-3
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -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
|
||||
}
|
||||
+51
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+52
@@ -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)
|
||||
}
|
||||
}
|
||||
+43
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user