diff --git a/ChangeLog.md b/ChangeLog.md
index 67b02b04d30..edbaa776be7 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -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
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
index a244ddbaf0c..1db8639ce3f 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt
@@ -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
-}
\ No newline at end of file
+}
+
+fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 5a3edac338d..4e38c170230 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -707,6 +707,10 @@
order="first"
implementationClass="org.jetbrains.kotlin.idea.refactoring.pullUp.JavaToKotlinPullUpHelperFactory"/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt
index 4e896430b4d..4b930d273a8 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractInterfaceDialog.kt
@@ -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
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperDialogBase.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperDialogBase.kt
index 23114aec48e..dd958bacda4 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperDialogBase.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperDialogBase.kt
@@ -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
- ) : AbstractMemberInfoModel() {
+ originalClass: KtClassOrObject,
+ val memberInfos: List,
+ interfaceContainmentVerifier: (KtNamedDeclaration) -> Boolean
+ ) : KotlinUsesAndInterfacesDependencyMemberInfoModel(originalClass, null, false, interfaceContainmentVerifier) {
override fun isFixedAbstract(memberInfo: KotlinMemberInfo?) = true
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt
index 62d391cf4c6..fad8f3cb047 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ui/KotlinExtractSuperclassDialog.kt
@@ -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
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinClassMembersRefactoringSupport.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinClassMembersRefactoringSupport.kt
new file mode 100644
index 00000000000..ebcbf295ded
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinClassMembersRefactoringSupport.kt
@@ -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(
+ 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)
+ }
+ }
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceDependencyMemberInfoModel.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceDependencyMemberInfoModel.kt
new file mode 100644
index 00000000000..9aeac6076b3
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceDependencyMemberInfoModel.kt
@@ -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>(
+ aClass: KtClassOrObject
+) : DependencyMemberInfoModel(KotlinInterfaceMemberDependencyGraph(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
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceMemberDependencyGraph.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceMemberDependencyGraph.kt
new file mode 100644
index 00000000000..9f6e5b09099
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinInterfaceMemberDependencyGraph.kt
@@ -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>(
+ klass: KtClassOrObject
+) : MemberDependencyGraph {
+ private val delegateGraph = InterfaceMemberDependencyGraph>(klass.toLightClass())
+
+ override fun memberChanged(memberInfo: M) {
+ delegateGraph.memberChanged(memberInfo.toJavaMemberInfo()!!)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun getDependent() = delegateGraph.dependent
+ .mapNotNull { it.unwrapped }
+ .filterIsInstanceTo(LinkedHashSet()) as Set
+
+ @Suppress("UNCHECKED_CAST")
+ override fun getDependenciesOf(member: T): Set {
+ val psiMember = lightElementForMemberInfo(member) ?: return emptySet()
+ val psiMemberDependencies = delegateGraph.getDependenciesOf(psiMember) ?: return emptySet()
+ return psiMemberDependencies
+ .mapNotNull { it.unwrapped }
+ .filterIsInstanceTo(LinkedHashSet()) as Set
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt
index 0dcb2fc8a8e..53632df3fd8 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinMemberInfo.kt
@@ -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() ?: it.firstIsInstanceOrNull()
@@ -88,8 +88,14 @@ fun KotlinMemberInfo.toJavaMemberInfo(): MemberInfo? {
is KtClassOrObject -> declaration.toLightClass()
else -> null
}
- val info = MemberInfo(psiMember ?: return null, isSuperClass, null)
+}
+
+fun MemberInfoBase.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
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesAndInterfacesDependencyMemberInfoModel.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesAndInterfacesDependencyMemberInfoModel.kt
new file mode 100644
index 00000000000..2d49fc1a59f
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesAndInterfacesDependencyMemberInfoModel.kt
@@ -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>(
+ klass: KtClassOrObject,
+ superClass: PsiNamedElement?,
+ recursive: Boolean,
+ interfaceContainmentVerifier: (T) -> Boolean = { false }
+) : DelegatingMemberInfoModel(
+ ANDCombinedMemberInfoModel(
+ object : KotlinUsesDependencyMemberInfoModel(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(klass))
+) {
+ @Suppress("UNCHECKED_CAST")
+ fun setSuperClass(superClass: PsiNamedElement) {
+ ((delegatingTarget as ANDCombinedMemberInfoModel).model1 as UsesDependencyMemberInfoModel).setSuperClass(superClass)
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesDependencyMemberInfoModel.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesDependencyMemberInfoModel.kt
new file mode 100644
index 00000000000..dae4f9f9a8c
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/memberInfo/KotlinUsesDependencyMemberInfoModel.kt
@@ -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>(
+ klass : KtClassOrObject,
+ superClass: PsiNamedElement?,
+ recursive: Boolean
+) : UsesDependencyMemberInfoModel(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
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt
index 2a3911714be..1d041f8c26d 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/KotlinPullUpDialog.kt
@@ -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() {
+ private inner class MemberInfoModelImpl(
+ originalClass: KtClassOrObject,
+ superClass: PsiNamedElement?,
+ interfaceContainmentVerifier: (KtNamedDeclaration) -> Boolean
+ ) : KotlinUsesAndInterfacesDependencyMemberInfoModel(
+ originalClass,
+ superClass,
+ false,
+ interfaceContainmentVerifier
+ ) {
private var lastSuperClass: PsiNamedElement? = null
// Abstract members remain abstract
@@ -96,11 +104,13 @@ class KotlinPullUpDialog(
}
override fun memberInfoChanged(event: MemberInfoChange) {
+ 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 =
- MemberInfoModelImpl()
+ MemberInfoModelImpl(sourceClass, preselection, getInterfaceContainmentVerifier { selectedMemberInfos })
override fun getPreselection() = mySuperClasses.firstOrNull { !it.isInterfaceClass() } ?: mySuperClasses.firstOrNull()
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt
index e3e2ed216b1..9d73448139d 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pullUp/pullUpUtils.kt
@@ -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): (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
+ }
+ }
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownDialog.kt
index f1ff8655716..242d4b60018 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownDialog.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/pushDown/KotlinPushDownDialog.kt
@@ -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? = null
+ private var memberInfoModel: MemberInfoModel? = null
val selectedMemberInfos: List
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() {
+ memberInfoModel = object : DelegatingMemberInfoModel(
+ ANDCombinedMemberInfoModel(
+ KotlinUsesDependencyMemberInfoModel(sourceClass, null, false),
+ UsedByDependencyMemberInfoModel(sourceClass))
+ ) {
override fun isFixedAbstract(member: KotlinMemberInfo?) = null
override fun isAbstractEnabled(memberInfo: KotlinMemberInfo): Boolean {