Suggest dialog if all members without actual modifier

Relates to #KT-31476
This commit is contained in:
Dmitry Gridin
2019-05-23 11:26:48 +07:00
parent 8dd1389979
commit 61a740457d
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
import org.jetbrains.kotlin.idea.util.allowedValOrVar import org.jetbrains.kotlin.idea.util.allowedValOrVar
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.isEffectivelyActual
import org.jetbrains.kotlin.idea.util.liftToExpected import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -111,19 +110,21 @@ class CreateExpectedClassFix(
outerExpectedClass: KtClassOrObject?, outerExpectedClass: KtClassOrObject?,
commonModule: Module commonModule: Module
) : CreateExpectedFix<KtClassOrObject>(klass, outerExpectedClass, commonModule, block@{ project, element -> ) : CreateExpectedFix<KtClassOrObject>(klass, outerExpectedClass, commonModule, block@{ project, element ->
val originalCollection = element.collectDeclarations(false).filter(KtDeclaration::canAddActualModifier).toList() val originalElements = element.collectDeclarations(false).filter(KtDeclaration::canAddActualModifier).toList()
val collection = originalCollection.filterNot(KtDeclaration::isAlwaysActual) val members = originalElements.filterNot(KtDeclaration::isAlwaysActual)
val selectedElements = when { val selectedElements = when {
ApplicationManager.getApplication().isUnitTestMode -> collection.filter { it.isEffectivelyActual(false) } members.all(KtDeclaration::hasActualModifier) -> originalElements
collection.any(KtDeclaration::hasActualModifier) && collection.any { !it.hasActualModifier() } -> { ApplicationManager.getApplication().isUnitTestMode -> members.filter(KtDeclaration::hasActualModifier)
else -> {
val prefix = klass.fqName?.asString()?.plus(".") ?: "" val prefix = klass.fqName?.asString()?.plus(".") ?: ""
chooseMembers(project, collection, prefix) ?: return@block null chooseMembers(project, members, prefix) ?: return@block null
} }
else -> null
} }
project.executeWriteCommand("Repair actual members") { if (originalElements.isNotEmpty()) {
repairActualModifiers(originalCollection, selectedElements) project.executeWriteCommand("Repair actual members") {
repairActualModifiers(originalElements, selectedElements)
}
} }
generateClassOrObject(project, true, element, listOfNotNull(outerExpectedClass)) generateClassOrObject(project, true, element, listOfNotNull(outerExpectedClass))
@@ -140,6 +141,11 @@ private fun KtDeclaration.canAddActualModifier() = when (this) {
*/ */
private fun chooseMembers(project: Project, collection: Collection<KtDeclaration>, prefixToRemove: String): List<KtDeclaration>? { private fun chooseMembers(project: Project, collection: Collection<KtDeclaration>, prefixToRemove: String): List<KtDeclaration>? {
val classMembers = collection.map { Member(prefixToRemove, it, it.resolveToDescriptorIfAny()!!) } val classMembers = collection.map { Member(prefixToRemove, it, it.resolveToDescriptorIfAny()!!) }
val filter = if (collection.any(KtDeclaration::hasActualModifier)) {
{ declaration: KtDeclaration -> declaration.hasActualModifier() }
} else {
{ true }
}
return MemberChooser( return MemberChooser(
classMembers.toTypedArray(), classMembers.toTypedArray(),
true, true,
@@ -148,7 +154,7 @@ private fun chooseMembers(project: Project, collection: Collection<KtDeclaration
).run { ).run {
title = "Choose actual members" title = "Choose actual members"
setCopyJavadocVisible(false) setCopyJavadocVisible(false)
selectElements(classMembers.filter { (it.element as KtDeclaration).hasActualModifier() }.toTypedArray()) selectElements(classMembers.filter { filter((it.element as KtDeclaration)) }.toTypedArray())
show() show()
if (!isOK) null else selectedElements?.map { it.element as KtDeclaration }.orEmpty() if (!isOK) null else selectedElements?.map { it.element as KtDeclaration }.orEmpty()
} }
@@ -175,25 +181,24 @@ private fun KtClassOrObject.collectDeclarations(withSelf: Boolean = true): Seque
private fun repairActualModifiers( private fun repairActualModifiers(
originalElements: Collection<KtDeclaration>, originalElements: Collection<KtDeclaration>,
// If null, all class declarations are actual selectedElements: Collection<KtDeclaration>
selectedElements: Collection<KtDeclaration>?
) { ) {
if (selectedElements == null) if (originalElements.size == selectedElements.size)
for (original in originalElements) { for (original in originalElements) {
original.recursivelyMakeActual() original.makeActualWithParents()
} }
else else
for (original in originalElements) { for (original in originalElements) {
if (original.isAlwaysActual() || original in selectedElements) if (original.isAlwaysActual() || original in selectedElements)
original.recursivelyMakeActual() original.makeActualWithParents()
else else
original.makeNotActual() original.makeNotActual()
} }
} }
private tailrec fun KtDeclaration.recursivelyMakeActual() { private tailrec fun KtDeclaration.makeActualWithParents() {
makeActual() makeActual()
containingClassOrObject?.takeUnless(KtDeclaration::hasActualModifier)?.recursivelyMakeActual() containingClassOrObject?.takeUnless(KtDeclaration::hasActualModifier)?.makeActualWithParents()
} }
private fun KtDeclaration.isAlwaysActual(): Boolean = when (this) { private fun KtDeclaration.isAlwaysActual(): Boolean = when (this) {