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
|
- [`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 properties declared in the primary constructor
|
||||||
Pull Up: Support members declared in the companion object of the original class
|
Pull Up: Support members declared in the companion object of the original class
|
||||||
|
Pull Up: Show member dependencies in the refactoring dialog
|
||||||
|
|
||||||
#### Android Lint
|
#### Android Lint
|
||||||
|
|
||||||
|
|||||||
@@ -471,4 +471,6 @@ fun KtClassOrObject.findPropertyByName(name: String): KtNamedDeclaration? {
|
|||||||
fun isTypeConstructorReference(e: PsiElement): Boolean {
|
fun isTypeConstructorReference(e: PsiElement): Boolean {
|
||||||
val parent = e.parent
|
val parent = e.parent
|
||||||
return parent is KtUserType && parent.referenceExpression == e
|
return parent is KtUserType && parent.referenceExpression == e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
|
||||||
@@ -707,6 +707,10 @@
|
|||||||
order="first"
|
order="first"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.refactoring.pullUp.JavaToKotlinPullUpHelperFactory"/>
|
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"/>
|
<problemFileHighlightFilter implementation="org.jetbrains.kotlin.idea.projectView.KotlinProblemFileHighlightFilter"/>
|
||||||
|
|
||||||
<codeInsight.typeInfo language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinExpressionTypeProvider"/>
|
<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.introduce.extractClass.KotlinExtractInterfaceHandler
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
|
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.idea.refactoring.pullUp.mustBeAbstractInInterface
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -48,7 +49,11 @@ class KotlinExtractInterfaceDialog(
|
|||||||
member is KtClass && member.hasModifier(KtTokens.INNER_KEYWORD)
|
member is KtClass && member.hasModifier(KtTokens.INNER_KEYWORD)
|
||||||
}
|
}
|
||||||
extractableMemberInfos.forEach { it.isToAbstract = true }
|
extractableMemberInfos.forEach { it.isToAbstract = true }
|
||||||
return object : MemberInfoModelBase(extractableMemberInfos) {
|
return object : MemberInfoModelBase(
|
||||||
|
originalClass,
|
||||||
|
extractableMemberInfos,
|
||||||
|
getInterfaceContainmentVerifier { selectedMembers }
|
||||||
|
) {
|
||||||
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||||
val member = memberInfo.member
|
val member = memberInfo.member
|
||||||
return member is KtNamedFunction || (member is KtProperty && !member.mustBeAbstractInInterface()) || member is KtParameter
|
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.PsiDirectory
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChange
|
import com.intellij.refactoring.classMembers.MemberInfoChange
|
||||||
import com.intellij.refactoring.extractSuperclass.JavaExtractSuperBaseDialog
|
import com.intellij.refactoring.extractSuperclass.JavaExtractSuperBaseDialog
|
||||||
import com.intellij.refactoring.util.DocCommentPolicy
|
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.introduce.extractClass.ExtractSuperInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
|
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.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
@@ -58,8 +58,10 @@ abstract class KotlinExtractSuperDialogBase(
|
|||||||
private val fileNameField = JTextField()
|
private val fileNameField = JTextField()
|
||||||
|
|
||||||
open class MemberInfoModelBase(
|
open class MemberInfoModelBase(
|
||||||
val memberInfos: List<KotlinMemberInfo>
|
originalClass: KtClassOrObject,
|
||||||
) : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>() {
|
val memberInfos: List<KotlinMemberInfo>,
|
||||||
|
interfaceContainmentVerifier: (KtNamedDeclaration) -> Boolean
|
||||||
|
) : KotlinUsesAndInterfacesDependencyMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>(originalClass, null, false, interfaceContainmentVerifier) {
|
||||||
override fun isFixedAbstract(memberInfo: KotlinMemberInfo?) = true
|
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.introduce.extractClass.KotlinExtractSuperclassHandler
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.extractClassMembers
|
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.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
@@ -44,7 +45,11 @@ class KotlinExtractSuperclassDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createMemberInfoModel(): MemberInfoModelBase {
|
override fun createMemberInfoModel(): MemberInfoModelBase {
|
||||||
return object : MemberInfoModelBase(extractClassMembers(originalClass)) {
|
return object : MemberInfoModelBase(
|
||||||
|
originalClass,
|
||||||
|
extractClassMembers(originalClass),
|
||||||
|
getInterfaceContainmentVerifier { selectedMembers }
|
||||||
|
) {
|
||||||
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||||
val member = memberInfo.member
|
val member = memberInfo.member
|
||||||
return member is KtNamedFunction || member is KtProperty || member is KtParameter
|
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
|
package org.jetbrains.kotlin.idea.refactoring.memberInfo
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiField
|
import com.intellij.psi.PsiField
|
||||||
import com.intellij.psi.PsiMember
|
import com.intellij.psi.PsiMember
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
@@ -78,9 +79,8 @@ class KotlinMemberInfo @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
|
fun lightElementForMemberInfo(declaration: KtNamedDeclaration?): PsiMember? {
|
||||||
val declaration = member
|
return when (declaration) {
|
||||||
val psiMember: PsiMember? = when (declaration) {
|
|
||||||
is KtNamedFunction -> declaration.getRepresentativeLightMethod()
|
is KtNamedFunction -> declaration.getRepresentativeLightMethod()
|
||||||
is KtProperty, is KtParameter -> declaration.toLightElements().let {
|
is KtProperty, is KtParameter -> declaration.toLightElements().let {
|
||||||
it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>()
|
it.firstIsInstanceOrNull<PsiMethod>() ?: it.firstIsInstanceOrNull<PsiField>()
|
||||||
@@ -88,8 +88,14 @@ fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
|
|||||||
is KtClassOrObject -> declaration.toLightClass()
|
is KtClassOrObject -> declaration.toLightClass()
|
||||||
else -> null
|
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.isToAbstract = isToAbstract
|
||||||
|
info.isChecked = isChecked
|
||||||
return info
|
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.PsiComment
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
import com.intellij.refactoring.JavaRefactoringSettings
|
import com.intellij.refactoring.JavaRefactoringSettings
|
||||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChange
|
import com.intellij.refactoring.classMembers.MemberInfoChange
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoModel
|
import com.intellij.refactoring.classMembers.MemberInfoModel
|
||||||
import com.intellij.refactoring.memberPullUp.PullUpProcessor
|
import com.intellij.refactoring.memberPullUp.PullUpProcessor
|
||||||
@@ -48,7 +47,16 @@ class KotlinPullUpDialog(
|
|||||||
init()
|
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
|
private var lastSuperClass: PsiNamedElement? = null
|
||||||
|
|
||||||
// Abstract members remain abstract
|
// Abstract members remain abstract
|
||||||
@@ -96,11 +104,13 @@ class KotlinPullUpDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun memberInfoChanged(event: MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>) {
|
override fun memberInfoChanged(event: MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>) {
|
||||||
|
super.memberInfoChanged(event)
|
||||||
val superClass = superClass ?: return
|
val superClass = superClass ?: return
|
||||||
if (superClass != lastSuperClass) {
|
if (superClass != lastSuperClass) {
|
||||||
lastSuperClass = superClass
|
lastSuperClass = superClass
|
||||||
val isInterface = superClass is KtClass && superClass.isInterface()
|
val isInterface = superClass is KtClass && superClass.isInterface()
|
||||||
event.changedMembers.forEach { it.isToAbstract = isInterface }
|
event.changedMembers.forEach { it.isToAbstract = isInterface }
|
||||||
|
setSuperClass(superClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +124,7 @@ class KotlinPullUpDialog(
|
|||||||
override fun getSuperClass() = super.getSuperClass()
|
override fun getSuperClass() = super.getSuperClass()
|
||||||
|
|
||||||
override fun createMemberInfoModel(): MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo> =
|
override fun createMemberInfoModel(): MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo> =
|
||||||
MemberInfoModelImpl()
|
MemberInfoModelImpl(sourceClass, preselection, getInterfaceContainmentVerifier { selectedMemberInfos })
|
||||||
|
|
||||||
override fun getPreselection() = mySuperClasses.firstOrNull { !it.isInterfaceClass() } ?: mySuperClasses.firstOrNull()
|
override fun getPreselection() = mySuperClasses.firstOrNull { !it.isInterfaceClass() } ?: mySuperClasses.firstOrNull()
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,15 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
package org.jetbrains.kotlin.idea.refactoring.pullUp
|
||||||
|
|
||||||
import com.intellij.psi.PsiClass
|
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.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.intentions.setType
|
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.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
|
import org.jetbrains.kotlin.idea.util.anonymousObjectSuperTypeOrNull
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -166,4 +170,16 @@ fun addSuperTypeEntry(
|
|||||||
val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeInTargetClass)
|
val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeInTargetClass)
|
||||||
val newSpecifier = KtPsiFactory(targetClass).createSuperTypeEntry(renderedType)
|
val newSpecifier = KtPsiFactory(targetClass).createSuperTypeEntry(renderedType)
|
||||||
targetClass.addSuperTypeListEntry(newSpecifier).addToShorteningWaitSet()
|
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
|
package org.jetbrains.kotlin.idea.refactoring.pushDown
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
import com.intellij.refactoring.JavaRefactoringSettings
|
import com.intellij.refactoring.JavaRefactoringSettings
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
import com.intellij.refactoring.classMembers.*
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChange
|
|
||||||
import com.intellij.refactoring.ui.RefactoringDialog
|
import com.intellij.refactoring.ui.RefactoringDialog
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
|
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.idea.refactoring.memberInfo.qualifiedClassNameForRendering
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
@@ -47,7 +48,7 @@ class KotlinPushDownDialog(
|
|||||||
init()
|
init()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var memberInfoModel: AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>? = null
|
private var memberInfoModel: MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>? = null
|
||||||
|
|
||||||
val selectedMemberInfos: List<KotlinMemberInfo>
|
val selectedMemberInfos: List<KotlinMemberInfo>
|
||||||
get() = memberInfos.filter { it.isChecked && memberInfoModel?.isMemberEnabled(it) ?: false }
|
get() = memberInfos.filter { it.isChecked && memberInfoModel?.isMemberEnabled(it) ?: false }
|
||||||
@@ -79,7 +80,11 @@ class KotlinPushDownDialog(
|
|||||||
RefactoringBundle.message("keep.abstract.column.header"))
|
RefactoringBundle.message("keep.abstract.column.header"))
|
||||||
panel.add(memberSelectionPanel, BorderLayout.CENTER)
|
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 isFixedAbstract(member: KotlinMemberInfo?) = null
|
||||||
|
|
||||||
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user