From 289286c8cdc84449dc06b6b87f4d5aff77961c93 Mon Sep 17 00:00:00 2001 From: fitermay Date: Thu, 1 Jun 2017 03:35:50 -0400 Subject: [PATCH] Avoid mutating state and do not rely on side effects for proper function So #KT-17740 Fixed --- .../quickfix/MakeOverriddenMemberOpenFix.kt | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeOverriddenMemberOpenFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeOverriddenMemberOpenFix.kt index a18653df7d8..26e49cf471a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeOverriddenMemberOpenFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeOverriddenMemberOpenFix.kt @@ -35,50 +35,58 @@ import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import java.util.* +private typealias DeclPtr = SmartPsiElementPointer class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAction(declaration) { - private val overriddenNonOverridableMembers = ArrayList>() - private val containingDeclarationsNames = ArrayList() - override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { - val element = element ?: return false + private val myQuickFixInfo: QuickFixInfo by lazy { + computeState() + } - if (!super.isAvailable(project, editor, file) || file !is KtFile) { - return false - } + private val containingDeclarationsNames + get() = myQuickFixInfo.declNames - // When running single test 'isAvailable()' is invoked multiple times, so we need to clear lists. - overriddenNonOverridableMembers.clear() - containingDeclarationsNames.clear() + private val overriddenNonOverridableMembers + get() = myQuickFixInfo.declarations - val descriptor = element.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? CallableMemberDescriptor ?: return false + private fun computeState(): QuickFixInfo { + val element = element ?: return QUICKFIX_UNAVAILABLE + val overriddenNonOverridableMembers = mutableListOf() + val containingDeclarationsNames = mutableListOf() + val descriptor = element.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? CallableMemberDescriptor ?: return QUICKFIX_UNAVAILABLE for (overriddenDescriptor in getAllDeclaredNonOverridableOverriddenDescriptors(descriptor)) { assert(overriddenDescriptor.kind == DECLARATION) { "Can only be applied to declarations." } val overriddenMember = DescriptorToSourceUtils.descriptorToDeclaration(overriddenDescriptor) if (overriddenMember == null || !overriddenMember.canRefactor() || overriddenMember !is KtCallableDeclaration || overriddenMember.modifierList?.hasModifier(OPEN_KEYWORD) == true) { - return false + return QUICKFIX_UNAVAILABLE } val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString() overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer()) containingDeclarationsNames.add(containingDeclarationName) } - return overriddenNonOverridableMembers.size > 0 + return QuickFixInfo(overriddenNonOverridableMembers, containingDeclarationsNames) + } + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { + + if (!super.isAvailable(project, editor, file) || file !is KtFile) { + return false + } + + return overriddenNonOverridableMembers.isNotEmpty() } override fun getText(): String { val element = element ?: return "" - if (overriddenNonOverridableMembers.size == 1) { val name = containingDeclarationsNames[0] + "." + element.name return "Make $name $OPEN_KEYWORD" } - - Collections.sort(containingDeclarationsNames) - val declarations = containingDeclarationsNames.subList(0, containingDeclarationsNames.size - 1).joinToString(", ") + " and " + - containingDeclarationsNames.last() + val sortedDeclarationNames = containingDeclarationsNames.sorted() + val declarations = sortedDeclarationNames.subList(0, sortedDeclarationNames.size - 1).joinToString(", ") + " and " + + sortedDeclarationNames.last() return "Make '${element.name}' in $declarations open" } @@ -91,6 +99,9 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc } companion object : KotlinSingleIntentionActionFactory() { + private data class QuickFixInfo(val declarations: List, val declNames: List) + + private val QUICKFIX_UNAVAILABLE = QuickFixInfo(emptyList(), emptyList()) private fun getAllDeclaredNonOverridableOverriddenDescriptors( callableMemberDescriptor: CallableMemberDescriptor): Collection { @@ -104,7 +115,8 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc FAKE_OVERRIDE, DELEGATION -> result.addAll(getAllDeclaredNonOverridableOverriddenDescriptors(overriddenDescriptor)) - SYNTHESIZED -> {} /* do nothing */ + SYNTHESIZED -> { + } /* do nothing */ else -> throw UnsupportedOperationException("Unexpected callable kind ${overriddenDescriptor.kind}") }