Replace "||" with "&&" (and the opposite) made more clever about negating expressions

This commit is contained in:
Valentin Kipyatkov
2015-06-02 23:15:36 +03:00
parent ac6ef6b544
commit 9c0d607894
8 changed files with 66 additions and 72 deletions
@@ -59,17 +59,13 @@ public class ConvertNegatedExpressionWithDemorgansLawIntention : JetSelfTargetin
if (i > 0) {
appendFixedText(operatorText)
}
appendExpression(operand.negated())
appendExpression(operand.negate())
}
}
element.replace(newExpression)
}
private fun JetExpression.negated(): JetExpression {
return JetPsiFactory(this).createExpressionByPattern("!$0", this)
}
private fun splitBooleanSequence(expression: JetBinaryExpression): List<JetExpression>? {
val result = LinkedList<JetExpression>()
val firstOperator = expression.getOperationToken()
@@ -40,7 +40,7 @@ public class InvertIfConditionIntention : JetSelfTargetingIntention<JetIfExpress
}
override fun applyTo(element: JetIfExpression, editor: Editor) {
val newCondition = negate(element.getCondition()!!)
val newCondition = element.getCondition()!!.negate()
val newIf = handleSpecialCases(element, newCondition)
?: handleStandardCase(element, newCondition)
@@ -200,65 +200,4 @@ public class InvertIfConditionIntention : JetSelfTargetingIntention<JetIfExpress
}
return null
}
companion object {
private val NEGATABLE_OPERATORS = setOf(JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.EQEQEQ,
JetTokens.EXCLEQEQEQ, JetTokens.IS_KEYWORD, JetTokens.NOT_IS, JetTokens.IN_KEYWORD,
JetTokens.NOT_IN, JetTokens.LT, JetTokens.LTEQ, JetTokens.GT, JetTokens.GTEQ)
private fun getNegatedOperatorText(token: IElementType): String {
return when(token) {
JetTokens.EQEQ -> JetTokens.EXCLEQ.getValue()
JetTokens.EXCLEQ -> JetTokens.EQEQ.getValue()
JetTokens.EQEQEQ -> JetTokens.EXCLEQEQEQ.getValue()
JetTokens.EXCLEQEQEQ -> JetTokens.EQEQEQ.getValue()
JetTokens.IS_KEYWORD -> JetTokens.NOT_IS.getValue()
JetTokens.NOT_IS -> JetTokens.IS_KEYWORD.getValue()
JetTokens.IN_KEYWORD -> JetTokens.NOT_IN.getValue()
JetTokens.NOT_IN -> JetTokens.IN_KEYWORD.getValue()
JetTokens.LT -> JetTokens.GTEQ.getValue()
JetTokens.LTEQ -> JetTokens.GT.getValue()
JetTokens.GT -> JetTokens.LTEQ.getValue()
JetTokens.GTEQ -> JetTokens.LT.getValue()
else -> throw IllegalArgumentException("The token $token does not have a negated equivalent.")
}
}
private fun negate(expression: JetExpression): JetExpression {
val specialNegation = specialNegationText(expression)
if (specialNegation != null) return specialNegation
return JetPsiFactory(expression).createExpressionByPattern("!$0", expression)
}
private fun specialNegationText(expression: JetExpression): JetExpression? {
val factory = JetPsiFactory(expression)
when (expression) {
is JetPrefixExpression -> {
if (expression.getOperationReference().getReferencedName() == "!") {
val baseExpression = expression.getBaseExpression()
if (baseExpression != null) {
return JetPsiUtil.safeDeparenthesize(baseExpression)
}
}
}
is JetBinaryExpression -> {
val operator = expression.getOperationToken()
if (operator !in NEGATABLE_OPERATORS) return null
val left = expression.getLeft() ?: return null
val right = expression.getRight() ?: return null
return factory.createExpressionByPattern("$0 $1 $2", left, getNegatedOperatorText(operator), right)
}
is JetConstantExpression -> {
return when (expression.getText()) {
"true" -> factory.createExpression("false")
"false" -> factory.createExpression("true")
else -> null
}
}
}
return null
}
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.util.TextRange
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
@@ -128,3 +129,61 @@ fun JetQualifiedExpression.isReceiverExpressionWithValue(): Boolean {
return analyze().getType(receiver) != null
}
public fun JetExpression.negate(): JetExpression {
val specialNegation = specialNegation()
if (specialNegation != null) return specialNegation
return JetPsiFactory(this).createExpressionByPattern("!$0", this)
}
private fun JetExpression.specialNegation(): JetExpression? {
val factory = JetPsiFactory(this)
when (this) {
is JetPrefixExpression -> {
if (getOperationReference().getReferencedName() == "!") {
val baseExpression = getBaseExpression()
if (baseExpression != null) {
return JetPsiUtil.safeDeparenthesize(baseExpression)
}
}
}
is JetBinaryExpression -> {
val operator = getOperationToken()
if (operator !in NEGATABLE_OPERATORS) return null
val left = getLeft() ?: return null
val right = getRight() ?: return null
return factory.createExpressionByPattern("$0 $1 $2", left, getNegatedOperatorText(operator), right)
}
is JetConstantExpression -> {
return when (getText()) {
"true" -> factory.createExpression("false")
"false" -> factory.createExpression("true")
else -> null
}
}
}
return null
}
private val NEGATABLE_OPERATORS = setOf(JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.EQEQEQ,
JetTokens.EXCLEQEQEQ, JetTokens.IS_KEYWORD, JetTokens.NOT_IS, JetTokens.IN_KEYWORD,
JetTokens.NOT_IN, JetTokens.LT, JetTokens.LTEQ, JetTokens.GT, JetTokens.GTEQ)
private fun getNegatedOperatorText(token: IElementType): String {
return when(token) {
JetTokens.EQEQ -> JetTokens.EXCLEQ.getValue()
JetTokens.EXCLEQ -> JetTokens.EQEQ.getValue()
JetTokens.EQEQEQ -> JetTokens.EXCLEQEQEQ.getValue()
JetTokens.EXCLEQEQEQ -> JetTokens.EQEQEQ.getValue()
JetTokens.IS_KEYWORD -> JetTokens.NOT_IS.getValue()
JetTokens.NOT_IS -> JetTokens.IS_KEYWORD.getValue()
JetTokens.IN_KEYWORD -> JetTokens.NOT_IN.getValue()
JetTokens.NOT_IN -> JetTokens.IN_KEYWORD.getValue()
JetTokens.LT -> JetTokens.GTEQ.getValue()
JetTokens.LTEQ -> JetTokens.GT.getValue()
JetTokens.GT -> JetTokens.LTEQ.getValue()
JetTokens.GTEQ -> JetTokens.LT.getValue()
else -> throw IllegalArgumentException("The token $token does not have a negated equivalent.")
}
}
@@ -1,3 +1,3 @@
fun foo(a: Boolean, c: Int, d: Int) : Boolean {
return !a || !(c == d)
return !a || c != d
}
@@ -1,3 +1,3 @@
fun foo(a: Int, b: Int, c: Int, d: Int) : Boolean {
return !(a < b) || !(c == d) || !(a < d)
return a >= b || c != d || a >= d
}
@@ -3,5 +3,5 @@ fun String.not(): Boolean {
}
fun foo(a: Boolean, b: Boolean) : Boolean {
return !!"" && !b
return "" && !b
}
@@ -1,3 +1,3 @@
fun foo(a: Boolean, b: Boolean, c: Boolean) : Boolean {
return !a && !!b && !c
return !a && b && !c
}
@@ -1,3 +1,3 @@
fun foo(a: Boolean, b: Boolean) : Boolean {
return !a || !!b
return !a || b
}