diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index 91cfae4609c..7464974fd77 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -290,8 +290,6 @@ add.name.to.argument.action=Add name to argument... add.name.to.parameter.name.chooser.title=Choose parameter name split.if=Split into 2 if's split.if.family=Split If -replace.with.operator.assign.intention=Replace with an operator-assign expression -replace.with.operator.assign.intention.family=Replace with an Operator-Assign Expression replace.with.traditional.assignment.intention=Replace with traditional assignment replace.with.traditional.assignment.intention.family=Replace with Traditional Assignment simplify.boolean.with.constants=Simplify boolean expression diff --git a/idea/resources/intentionDescriptions/ReplaceWithOperatorAssignIntention/description.html b/idea/resources/intentionDescriptions/ReplaceWithOperatorAssignIntention/description.html index c00ff5a18aa..0736ef904f1 100644 --- a/idea/resources/intentionDescriptions/ReplaceWithOperatorAssignIntention/description.html +++ b/idea/resources/intentionDescriptions/ReplaceWithOperatorAssignIntention/description.html @@ -1,5 +1,5 @@ -This intention converts an expression that modifies a variable's value and reassigns it to itself to an operation-assign expression. +This intention transforms a modification of a variable with a simple assignment into an operation-assignment. \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithOperatorAssignIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithOperatorAssignIntention.kt index ada3a37b0b7..decfdd19bc9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithOperatorAssignIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithOperatorAssignIntention.kt @@ -27,94 +27,66 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.idea.util.psi.patternMatching.matches import org.jetbrains.kotlin.idea.caches.resolve.analyze -public class ReplaceWithOperatorAssignIntention : JetSelfTargetingOffsetIndependentIntention("replace.with.operator.assign.intention", javaClass()) { +public class ReplaceWithOperatorAssignIntention : JetSelfTargetingOffsetIndependentIntention(javaClass(), "Replace with an operator-assignment") { override fun isApplicableTo(element: JetBinaryExpression): Boolean { - fun isWellFormedAssignment(element : JetBinaryExpression): Boolean { - val leftExpression = element.getLeft() - val rightExpression = element.getRight() + if (element.getOperationToken() != JetTokens.EQ) return false + val left = element.getLeft() as? JetSimpleNameExpression ?: return false + val right = element.getRight() as? JetBinaryExpression ?: return false + if (right.getLeft() == null || right.getRight() == null) return false - return leftExpression is JetSimpleNameExpression && - element.getOperationToken() == JetTokens.EQ && - rightExpression is JetBinaryExpression && - rightExpression.getLeft() != null && - rightExpression.getRight() != null - } + return checkExpressionRepeat(left, right) + } - fun checkExpressionRepeat(variableExpression: JetSimpleNameExpression, expression: JetBinaryExpression): Boolean { - val context = expression.analyze() - val descriptor = context[BindingContext.REFERENCE_TARGET, expression.getOperationReference()]?.getContainingDeclaration() - val isPrimitiveOperation = descriptor is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(descriptor.getDefaultType()) + private fun checkExpressionRepeat(variableExpression: JetSimpleNameExpression, expression: JetBinaryExpression): Boolean { + val context = expression.analyze() + val descriptor = context[BindingContext.REFERENCE_TARGET, expression.getOperationReference()]?.getContainingDeclaration() + val isPrimitiveOperation = descriptor is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(descriptor.getDefaultType()) - return when { - variableExpression.matches(expression.getLeft()) -> { - val validity = expression.getOperationToken() == JetTokens.PLUS || - expression.getOperationToken() == JetTokens.MINUS || - expression.getOperationToken() == JetTokens.MUL || - expression.getOperationToken() == JetTokens.DIV || - expression.getOperationToken() == JetTokens.PERC + val operationToken = expression.getOperationToken() + setText("Replace with ${expression.getOperationReference().getText()}= expression") - if (validity) { - setText("Replace with ${expression.getOperationReference().getText()}= Expression") - } - - validity - } - - variableExpression.matches(expression.getRight()) -> { - val validity = (expression.getOperationToken() == JetTokens.PLUS || - expression.getOperationToken() == JetTokens.MUL) && - isPrimitiveOperation - - if (validity) { - setText("Replace with ${expression.getOperationReference().getText()}= Expression") - } - - validity - } - - expression.getLeft() is JetBinaryExpression -> - isPrimitiveOperation && checkExpressionRepeat(variableExpression, expression.getLeft() as JetBinaryExpression) - - else -> - false + return when { + variableExpression.matches(expression.getLeft()) -> { + operationToken == JetTokens.PLUS || operationToken == JetTokens.MINUS || operationToken == JetTokens.MUL || operationToken == JetTokens.DIV || operationToken == JetTokens.PERC } - } - if (isWellFormedAssignment(element)) { - return checkExpressionRepeat(element.getLeft() as JetSimpleNameExpression, element.getRight() as JetBinaryExpression) - } else { - return false + variableExpression.matches(expression.getRight()) -> { + isPrimitiveOperation && (operationToken == JetTokens.PLUS || operationToken == JetTokens.MUL) + } + + expression.getLeft() is JetBinaryExpression -> { + isPrimitiveOperation && checkExpressionRepeat(variableExpression, expression.getLeft() as JetBinaryExpression) + } + + else -> { + false + } } } override fun applyTo(element: JetBinaryExpression, editor: Editor) { - [tailRecursive] - fun buildReplacement(variableExpression: JetSimpleNameExpression, expression: JetBinaryExpression, replacementBuilder: StringBuilder): String { - when { - variableExpression.matches(expression.getLeft()) -> { - return "${variableExpression.getText()} ${expression.getOperationReference().getText()}= ${expression.getRight()!!.getText()} ${replacementBuilder.toString()}" - } - - variableExpression.matches(expression.getRight()) -> { - return "${variableExpression.getText()} ${expression.getOperationReference().getText()}= ${expression.getLeft()!!.getText()} ${replacementBuilder.toString()}" - } - - expression.getLeft() is JetBinaryExpression -> { - return buildReplacement(variableExpression, expression.getLeft() as JetBinaryExpression, StringBuilder("${expression.getOperationReference().getText()} ${expression.getRight()!!.getText()} ${replacementBuilder.toString()}")) - } - - else -> { - return replacementBuilder.toString() - } - } - } - - val replacement = buildReplacement( - (element.getLeft() as JetSimpleNameExpression), + val replacement = buildOperatorAssignmentText( + element.getLeft() as JetSimpleNameExpression, element.getRight() as JetBinaryExpression, - StringBuilder() + "" ) element.replace(JetPsiFactory(element).createExpression(replacement)) } + + [tailRecursive] + private fun buildOperatorAssignmentText(variableExpression: JetSimpleNameExpression, expression: JetBinaryExpression, tail: String): String { + val operationText = expression.getOperationReference().getText() + val variableName = variableExpression.getText() + return when { + variableExpression.matches(expression.getLeft()) -> "$variableName $operationText= ${expression.getRight()!!.getText()} $tail" + + variableExpression.matches(expression.getRight()) -> "$variableName $operationText= ${expression.getLeft()!!.getText()} $tail" + + expression.getLeft() is JetBinaryExpression -> + buildOperatorAssignmentText(variableExpression, expression.getLeft() as JetBinaryExpression, "$operationText ${expression.getRight()!!.getText()} $tail") + + else -> tail + } + } }