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
|
package org.jetbrains.kotlin.idea.inspections
|
||||||
|
|
||||||
import com.intellij.codeInspection.LocalQuickFix
|
import com.intellij.codeInspection.*
|
||||||
import com.intellij.codeInspection.ProblemDescriptor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.codeInspection.ProblemHighlightType
|
|
||||||
import com.intellij.codeInspection.ProblemsHolder
|
|
||||||
import com.intellij.openapi.project.Project
|
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.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
|
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||||
|
|
||||||
class ReplacePutWithAssignmentInspection : AbstractKotlinInspection() {
|
class ReplacePutWithAssignmentInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>() {
|
||||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): KtVisitorVoid =
|
||||||
return object : KtVisitorVoid() {
|
object : KtVisitorVoid() {
|
||||||
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
|
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
|
||||||
super.visitDotQualifiedExpression(expression)
|
super.visitDotQualifiedExpression(expression)
|
||||||
if (isActiveFor(expression)) {
|
visitTargetElement(expression, holder, isOnTheFly)
|
||||||
holder.registerProblem(
|
|
||||||
expression.callExpression!!.calleeExpression!!,
|
|
||||||
"map.put() can be converted to assignment",
|
|
||||||
ProblemHighlightType.WEAK_WARNING,
|
|
||||||
ReplacePutWithAssignmentQuickfix()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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 {
|
companion object {
|
||||||
private val compatibleNames = setOf("put")
|
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(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing())
|
||||||
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
||||||
_processings.add(RemoveRedundantCastToNullableProcessing())
|
_processings.add(RemoveRedundantCastToNullableProcessing())
|
||||||
_processings.add(ReplacePutWithAssignmentProcessing())
|
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection())
|
||||||
_processings.add(UseExpressionBodyProcessing())
|
_processings.add(UseExpressionBodyProcessing())
|
||||||
_processings.add(UnnecessaryVariableProcessing())
|
_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 {
|
private class UseExpressionBodyProcessing : J2kPostProcessing {
|
||||||
override val writeActionNeeded = true
|
override val writeActionNeeded = true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user