Avoid mutating state and do not rely on side effects for proper function
So #KT-17740 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
0dced8d29c
commit
289286c8cd
@@ -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<KtCallableDeclaration>
|
||||
class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAction<KtDeclaration>(declaration) {
|
||||
private val overriddenNonOverridableMembers = ArrayList<SmartPsiElementPointer<KtCallableDeclaration>>()
|
||||
private val containingDeclarationsNames = ArrayList<String>()
|
||||
|
||||
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<DeclPtr>()
|
||||
val containingDeclarationsNames = mutableListOf<String>()
|
||||
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<DeclPtr>, val declNames: List<String>)
|
||||
|
||||
private val QUICKFIX_UNAVAILABLE = QuickFixInfo(emptyList(), emptyList())
|
||||
|
||||
private fun getAllDeclaredNonOverridableOverriddenDescriptors(
|
||||
callableMemberDescriptor: CallableMemberDescriptor): Collection<CallableMemberDescriptor> {
|
||||
@@ -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}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user