From 9c0d6078942dc43cbcc35a639d9276c7eed6e11b Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 2 Jun 2015 23:15:36 +0300 Subject: [PATCH] Replace "||" with "&&" (and the opposite) made more clever about negating expressions --- ...atedExpressionWithDemorgansLawIntention.kt | 6 +- .../intentions/InvertIfConditionIntention.kt | 63 +------------------ .../jetbrains/kotlin/idea/intentions/Utils.kt | 59 +++++++++++++++++ .../complexNegation1.kt.after | 2 +- .../complexNegation2.kt.after | 2 +- .../doubleNegation.kt.after | 2 +- .../longMixedExpression.kt.after | 2 +- .../mixedExpression.kt.after | 2 +- 8 files changed, 66 insertions(+), 72 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedExpressionWithDemorgansLawIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedExpressionWithDemorgansLawIntention.kt index 1aee63036a3..9db60b3a2a5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedExpressionWithDemorgansLawIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertNegatedExpressionWithDemorgansLawIntention.kt @@ -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? { val result = LinkedList() val firstOperator = expression.getOperationToken() diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/InvertIfConditionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/InvertIfConditionIntention.kt index 3ce71118abd..1e8742deb9b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/InvertIfConditionIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/InvertIfConditionIntention.kt @@ -40,7 +40,7 @@ public class InvertIfConditionIntention : JetSelfTargetingIntention 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 - } - } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index 84383778437..c4f38d23d4a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -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.") + } +} diff --git a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation1.kt.after b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation1.kt.after index c89fffeb01a..2cba8015942 100644 --- a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation1.kt.after +++ b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation1.kt.after @@ -1,3 +1,3 @@ fun foo(a: Boolean, c: Int, d: Int) : Boolean { - return !a || !(c == d) + return !a || c != d } \ No newline at end of file diff --git a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation2.kt.after b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation2.kt.after index bf55eb732a6..4a292565c6a 100644 --- a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation2.kt.after +++ b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/complexNegation2.kt.after @@ -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 } \ No newline at end of file diff --git a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/doubleNegation.kt.after b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/doubleNegation.kt.after index b8c77df713c..d347eb23746 100644 --- a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/doubleNegation.kt.after +++ b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/doubleNegation.kt.after @@ -3,5 +3,5 @@ fun String.not(): Boolean { } fun foo(a: Boolean, b: Boolean) : Boolean { - return !!"" && !b + return "" && !b } diff --git a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/longMixedExpression.kt.after b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/longMixedExpression.kt.after index 20439b9bb45..86e6bf3d935 100644 --- a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/longMixedExpression.kt.after +++ b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/longMixedExpression.kt.after @@ -1,3 +1,3 @@ fun foo(a: Boolean, b: Boolean, c: Boolean) : Boolean { - return !a && !!b && !c + return !a && b && !c } diff --git a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/mixedExpression.kt.after b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/mixedExpression.kt.after index 8f1f01023fa..47d4eb7495a 100644 --- a/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/mixedExpression.kt.after +++ b/idea/testData/intentions/convertNegatedExpressionWithDemorgansLaw/mixedExpression.kt.after @@ -1,3 +1,3 @@ fun foo(a: Boolean, b: Boolean) : Boolean { - return !a || !!b + return !a || b } \ No newline at end of file