Refactoring: "replace put with assignment" is now applicability-based
This commit is contained in:
+39
-51
@@ -16,73 +16,61 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||
|
||||
class ReplacePutWithAssignmentInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return object : KtVisitorVoid() {
|
||||
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
|
||||
super.visitDotQualifiedExpression(expression)
|
||||
if (isActiveFor(expression)) {
|
||||
holder.registerProblem(
|
||||
expression.callExpression!!.calleeExpression!!,
|
||||
"map.put() can be converted to assignment",
|
||||
ProblemHighlightType.WEAK_WARNING,
|
||||
ReplacePutWithAssignmentQuickfix()
|
||||
)
|
||||
class ReplacePutWithAssignmentInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): KtVisitorVoid =
|
||||
object : KtVisitorVoid() {
|
||||
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
|
||||
super.visitDotQualifiedExpression(expression)
|
||||
visitTargetElement(expression, holder, isOnTheFly)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isApplicable(element: KtDotQualifiedExpression): Boolean {
|
||||
val callExpression = element.callExpression
|
||||
if (callExpression?.valueArguments?.size != 2) return false
|
||||
|
||||
val calleeExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return false
|
||||
if (calleeExpression.getReferencedName() !in compatibleNames) return false
|
||||
|
||||
val context = element.analyze()
|
||||
if (element.isUsedAsExpression(context)) return false
|
||||
val resolvedCall = element.getResolvedCall(context)
|
||||
val receiverType = resolvedCall?.getExplicitReceiverValue()?.type ?: return false
|
||||
val receiverClass = receiverType.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
return receiverClass.isSubclassOf(DefaultBuiltIns.Instance.mutableMap)
|
||||
}
|
||||
|
||||
override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
|
||||
val expression = element.getParentOfType<KtDotQualifiedExpression>(strict = false) ?: return
|
||||
val valueArguments = expression.callExpression?.valueArguments ?: return
|
||||
expression.replace(KtPsiFactory(expression).createExpressionByPattern("$0[$1] = $2",
|
||||
expression.receiverExpression,
|
||||
valueArguments[0]?.getArgumentExpression() ?: return,
|
||||
valueArguments[1]?.getArgumentExpression() ?: return))
|
||||
}
|
||||
|
||||
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
|
||||
|
||||
override fun inspectionText(element: KtDotQualifiedExpression): String = "map.put() can be converted to assignment"
|
||||
|
||||
override val defaultFixText = "Convert put to assignment"
|
||||
|
||||
companion object {
|
||||
private val compatibleNames = setOf("put")
|
||||
|
||||
fun isActiveFor(expression: KtDotQualifiedExpression): Boolean {
|
||||
val callExpression = expression.callExpression
|
||||
if (callExpression?.valueArguments?.size != 2) return false
|
||||
|
||||
val calleeExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return false
|
||||
if (calleeExpression.getReferencedName() !in compatibleNames) return false
|
||||
|
||||
val context = expression.analyze()
|
||||
if (expression.isUsedAsExpression(context)) return false
|
||||
val resolvedCall = expression.getResolvedCall(context)
|
||||
val receiverType = resolvedCall?.getExplicitReceiverValue()?.type ?: return false
|
||||
val receiverClass = receiverType.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
return receiverClass.isSubclassOf(DefaultBuiltIns.Instance.mutableMap)
|
||||
}
|
||||
|
||||
fun simplify(expression: KtDotQualifiedExpression) {
|
||||
val valueArguments = expression.callExpression?.valueArguments ?: return
|
||||
expression.replace(KtPsiFactory(expression).createExpressionByPattern("$0[$1] = $2",
|
||||
expression.receiverExpression,
|
||||
valueArguments[0]?.getArgumentExpression() ?: return,
|
||||
valueArguments[1]?.getArgumentExpression() ?: return))
|
||||
}
|
||||
}
|
||||
|
||||
class ReplacePutWithAssignmentQuickfix : LocalQuickFix {
|
||||
override fun getName() = "Convert put to assignment"
|
||||
|
||||
override fun getFamilyName() = name
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
simplify(descriptor.psiElement.parent.parent as? KtDotQualifiedExpression ?: return)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ object J2KPostProcessingRegistrar {
|
||||
_processings.add(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing())
|
||||
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
||||
_processings.add(RemoveRedundantCastToNullableProcessing())
|
||||
_processings.add(ReplacePutWithAssignmentProcessing())
|
||||
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection())
|
||||
_processings.add(UseExpressionBodyProcessing())
|
||||
_processings.add(UnnecessaryVariableProcessing())
|
||||
|
||||
@@ -300,21 +300,6 @@ object J2KPostProcessingRegistrar {
|
||||
}
|
||||
}
|
||||
|
||||
private class ReplacePutWithAssignmentProcessing : J2kPostProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||
if (element !is KtDotQualifiedExpression) return null
|
||||
if (!ReplacePutWithAssignmentInspection.isActiveFor(element)) return null
|
||||
|
||||
return {
|
||||
if (ReplacePutWithAssignmentInspection.isActiveFor(element)) {
|
||||
ReplacePutWithAssignmentInspection.simplify(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UseExpressionBodyProcessing : J2kPostProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user