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.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
private typealias DeclPtr = SmartPsiElementPointer<KtCallableDeclaration>
|
||||||
class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAction<KtDeclaration>(declaration) {
|
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 {
|
private val myQuickFixInfo: QuickFixInfo by lazy {
|
||||||
val element = element ?: return false
|
computeState()
|
||||||
|
}
|
||||||
|
|
||||||
if (!super.isAvailable(project, editor, file) || file !is KtFile) {
|
private val containingDeclarationsNames
|
||||||
return false
|
get() = myQuickFixInfo.declNames
|
||||||
}
|
|
||||||
|
|
||||||
// When running single test 'isAvailable()' is invoked multiple times, so we need to clear lists.
|
private val overriddenNonOverridableMembers
|
||||||
overriddenNonOverridableMembers.clear()
|
get() = myQuickFixInfo.declarations
|
||||||
containingDeclarationsNames.clear()
|
|
||||||
|
|
||||||
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)) {
|
for (overriddenDescriptor in getAllDeclaredNonOverridableOverriddenDescriptors(descriptor)) {
|
||||||
assert(overriddenDescriptor.kind == DECLARATION) { "Can only be applied to declarations." }
|
assert(overriddenDescriptor.kind == DECLARATION) { "Can only be applied to declarations." }
|
||||||
val overriddenMember = DescriptorToSourceUtils.descriptorToDeclaration(overriddenDescriptor)
|
val overriddenMember = DescriptorToSourceUtils.descriptorToDeclaration(overriddenDescriptor)
|
||||||
if (overriddenMember == null || !overriddenMember.canRefactor() || overriddenMember !is KtCallableDeclaration ||
|
if (overriddenMember == null || !overriddenMember.canRefactor() || overriddenMember !is KtCallableDeclaration ||
|
||||||
overriddenMember.modifierList?.hasModifier(OPEN_KEYWORD) == true) {
|
overriddenMember.modifierList?.hasModifier(OPEN_KEYWORD) == true) {
|
||||||
return false
|
return QUICKFIX_UNAVAILABLE
|
||||||
}
|
}
|
||||||
val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString()
|
val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString()
|
||||||
overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer())
|
overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer())
|
||||||
containingDeclarationsNames.add(containingDeclarationName)
|
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 {
|
override fun getText(): String {
|
||||||
val element = element ?: return ""
|
val element = element ?: return ""
|
||||||
|
|
||||||
if (overriddenNonOverridableMembers.size == 1) {
|
if (overriddenNonOverridableMembers.size == 1) {
|
||||||
val name = containingDeclarationsNames[0] + "." + element.name
|
val name = containingDeclarationsNames[0] + "." + element.name
|
||||||
return "Make $name $OPEN_KEYWORD"
|
return "Make $name $OPEN_KEYWORD"
|
||||||
}
|
}
|
||||||
|
val sortedDeclarationNames = containingDeclarationsNames.sorted()
|
||||||
Collections.sort(containingDeclarationsNames)
|
val declarations = sortedDeclarationNames.subList(0, sortedDeclarationNames.size - 1).joinToString(", ") + " and " +
|
||||||
val declarations = containingDeclarationsNames.subList(0, containingDeclarationsNames.size - 1).joinToString(", ") + " and " +
|
sortedDeclarationNames.last()
|
||||||
containingDeclarationsNames.last()
|
|
||||||
return "Make '${element.name}' in $declarations open"
|
return "Make '${element.name}' in $declarations open"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +99,9 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
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(
|
private fun getAllDeclaredNonOverridableOverriddenDescriptors(
|
||||||
callableMemberDescriptor: CallableMemberDescriptor): Collection<CallableMemberDescriptor> {
|
callableMemberDescriptor: CallableMemberDescriptor): Collection<CallableMemberDescriptor> {
|
||||||
@@ -104,7 +115,8 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
|
|||||||
FAKE_OVERRIDE, DELEGATION ->
|
FAKE_OVERRIDE, DELEGATION ->
|
||||||
result.addAll(getAllDeclaredNonOverridableOverriddenDescriptors(overriddenDescriptor))
|
result.addAll(getAllDeclaredNonOverridableOverriddenDescriptors(overriddenDescriptor))
|
||||||
|
|
||||||
SYNTHESIZED -> {} /* do nothing */
|
SYNTHESIZED -> {
|
||||||
|
} /* do nothing */
|
||||||
|
|
||||||
else -> throw UnsupportedOperationException("Unexpected callable kind ${overriddenDescriptor.kind}")
|
else -> throw UnsupportedOperationException("Unexpected callable kind ${overriddenDescriptor.kind}")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user