From 2bb81e6a1842169a22e0de30776b3264d3058aba Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 21 Nov 2016 17:22:19 +0300 Subject: [PATCH] Simplify boolean with constants intention supports now == (!=) true (false) cases #KT-13777 Fixed --- .../SimplifyBooleanWithConstantsIntention.kt | 39 ++++++++++---- .../equalsConjunction.kt | 1 + .../equalsConjunction.kt.after | 1 + .../equalsDisjunction.kt | 1 + .../equalsDisjunction.kt.after | 1 + .../equalsFalse.kt | 5 ++ .../equalsFalse.kt.after | 5 ++ .../equalsTrue.kt | 5 ++ .../equalsTrue.kt.after | 5 ++ .../equalsTrueOrFalse.kt | 1 + .../equalsTrueOrFalse.kt.after | 1 + .../notEqualsFalse.kt | 5 ++ .../notEqualsFalse.kt.after | 5 ++ .../notEqualsTrue.kt | 5 ++ .../notEqualsTrue.kt.after | 5 ++ .../nullableBoolean.kt | 3 ++ .../nullableComplex.kt | 3 ++ .../simpleWithNonsensical2.kt | 6 ++- .../simpleWithNonsensical2.kt.after | 6 ++- .../intentions/IntentionTestGenerated.java | 54 +++++++++++++++++++ 20 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt.after create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/nullableBoolean.kt create mode 100644 idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt index f9d8d1f3157..08ba2d45358 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SimplifyBooleanWithConstantsIntention.kt @@ -19,13 +19,15 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.openapi.editor.Editor import com.intellij.psi.tree.IElementType import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.copied import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection -import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getType class SimplifyBooleanWithConstantsInspection : IntentionBasedInspection(SimplifyBooleanWithConstantsIntention::class) @@ -43,12 +45,13 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte is KtBinaryExpression -> { val op = element.operationToken - if ((op == KtTokens.ANDAND || op == KtTokens.OROR) && - (areThereExpressionsToBeSimplified(element.left) || - areThereExpressionsToBeSimplified(element.right))) return true + if (op == ANDAND || op == OROR || op == EQEQ || op == EXCLEQ) { + if (areThereExpressionsToBeSimplified(element.left) && element.right.hasBooleanType()) return true + if (areThereExpressionsToBeSimplified(element.right) && element.left.hasBooleanType()) return true + } } } - return element.canBeReducedToBooleanConstant(null) + return element.canBeReducedToBooleanConstant() } override fun applyTo(element: KtBinaryExpression, editor: Editor?) { @@ -88,7 +91,7 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte val left = expression.left val right = expression.right val op = expression.operationToken - if (left != null && right != null && (op == KtTokens.ANDAND || op == KtTokens.OROR)) { + if (left != null && right != null && (op == ANDAND || op == OROR || op == EQEQ || op == EXCLEQ)) { val simpleLeft = simplifyExpression(left) val simpleRight = simplifyExpression(right) return when { @@ -113,16 +116,30 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte } private fun toSimplifiedBooleanBinaryExpressionWithConstantOperand(constantOperand: Boolean, otherOperand: KtExpression, operation: IElementType): KtExpression { - return when { - constantOperand && operation == KtTokens.OROR -> KtPsiFactory(otherOperand).createExpression("true") - !constantOperand && operation == KtTokens.ANDAND -> KtPsiFactory(otherOperand).createExpression("false") - else -> toSimplifiedExpression(otherOperand) + val factory = KtPsiFactory(otherOperand) + when (operation) { + OROR -> { + if (constantOperand) return factory.createExpression("true") + } + ANDAND -> { + if (!constantOperand) return factory.createExpression("false") + } + EQEQ, EXCLEQ -> toSimplifiedExpression(otherOperand).let { + return if (constantOperand == (operation == EQEQ)) it + else factory.createExpressionByPattern("!$0", it) + } } + return toSimplifiedExpression(otherOperand) } private fun simplifyExpression(expression: KtExpression) = expression.replaced(toSimplifiedExpression(expression)) - private fun KtExpression.canBeReducedToBooleanConstant(constant: Boolean?): Boolean { + private fun KtExpression?.hasBooleanType(): Boolean { + val type = this?.getType(this.analyze()) ?: return false + return KotlinBuiltIns.isBoolean(type) + } + + private fun KtExpression.canBeReducedToBooleanConstant(constant: Boolean? = null): Boolean { return CompileTimeConstantUtils.canBeReducedToBooleanConstant(this, this.analyze(), constant) } diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt b/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt new file mode 100644 index 00000000000..9953b676454 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt @@ -0,0 +1 @@ +fun foo(x: Boolean): Boolean = true == (x && false) \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt.after new file mode 100644 index 00000000000..37be156236b --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt.after @@ -0,0 +1 @@ +fun foo(x: Boolean): Boolean = false \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt b/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt new file mode 100644 index 00000000000..1983857a0bb --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt @@ -0,0 +1 @@ +fun foo(x: Boolean, y: Boolean): Boolean = (x || y) == false \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt.after new file mode 100644 index 00000000000..8bfde165d4c --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt.after @@ -0,0 +1 @@ +fun foo(x: Boolean, y: Boolean): Boolean = !(x || y) \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt b/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt new file mode 100644 index 00000000000..e9750a831d4 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (false == arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt.after new file mode 100644 index 00000000000..15ec77e606a --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt.after @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (!arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt new file mode 100644 index 00000000000..75ae9786a4b --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (arg == true) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt.after new file mode 100644 index 00000000000..f108748a0d2 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt.after @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt new file mode 100644 index 00000000000..18ca59ad2e8 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt @@ -0,0 +1 @@ +fun foo(arg: Boolean): Boolean = arg == true || arg == false \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt.after new file mode 100644 index 00000000000..699c04e59f1 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt.after @@ -0,0 +1 @@ +fun foo(arg: Boolean): Boolean = arg || !arg \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt new file mode 100644 index 00000000000..1b9664e654e --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (arg != false) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt.after new file mode 100644 index 00000000000..f108748a0d2 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt.after @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt new file mode 100644 index 00000000000..6d25d7e0271 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (true != arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt.after new file mode 100644 index 00000000000..15ec77e606a --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt.after @@ -0,0 +1,5 @@ +fun use(arg: Boolean) { + if (!arg) { + + } +} \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/nullableBoolean.kt b/idea/testData/intentions/simplifyBooleanWithConstants/nullableBoolean.kt new file mode 100644 index 00000000000..ecb90c62011 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/nullableBoolean.kt @@ -0,0 +1,3 @@ +// IS_APPLICABLE: false + +fun foo(arg: Boolean?): Boolean = arg == true \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex.kt b/idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex.kt new file mode 100644 index 00000000000..a15992714b2 --- /dev/null +++ b/idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex.kt @@ -0,0 +1,3 @@ +// IS_APPLICABLE: false + +fun foo(arg: Boolean?): Boolean = arg == true || arg == false \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt b/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt index d75b39f588c..4ba2c9c7609 100644 --- a/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt +++ b/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt @@ -1,3 +1,7 @@ +fun bar(): Boolean { + return false +} + fun foo(y: Boolean) { - true && () && y + true && (bar()) && y } \ No newline at end of file diff --git a/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt.after b/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt.after index d34b9a8986e..4b285d1ca53 100644 --- a/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt.after +++ b/idea/testData/intentions/simplifyBooleanWithConstants/simpleWithNonsensical2.kt.after @@ -1,3 +1,7 @@ +fun bar(): Boolean { + return false +} + fun foo(y: Boolean) { - () && y + bar() && y } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 192f421dc57..6e3f2cbfe64 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -12729,6 +12729,36 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("equalsConjunction.kt") + public void testEqualsConjunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/equalsConjunction.kt"); + doTest(fileName); + } + + @TestMetadata("equalsDisjunction.kt") + public void testEqualsDisjunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/equalsDisjunction.kt"); + doTest(fileName); + } + + @TestMetadata("equalsFalse.kt") + public void testEqualsFalse() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/equalsFalse.kt"); + doTest(fileName); + } + + @TestMetadata("equalsTrue.kt") + public void testEqualsTrue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/equalsTrue.kt"); + doTest(fileName); + } + + @TestMetadata("equalsTrueOrFalse.kt") + public void testEqualsTrueOrFalse() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/equalsTrueOrFalse.kt"); + doTest(fileName); + } + @TestMetadata("inapplicableNoConstants.kt") public void testInapplicableNoConstants() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/inapplicableNoConstants.kt"); @@ -12759,6 +12789,30 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("notEqualsFalse.kt") + public void testNotEqualsFalse() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/notEqualsFalse.kt"); + doTest(fileName); + } + + @TestMetadata("notEqualsTrue.kt") + public void testNotEqualsTrue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/notEqualsTrue.kt"); + doTest(fileName); + } + + @TestMetadata("nullableBoolean.kt") + public void testNullableBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/nullableBoolean.kt"); + doTest(fileName); + } + + @TestMetadata("nullableComplex.kt") + public void testNullableComplex() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex.kt"); + doTest(fileName); + } + @TestMetadata("reduceableBinary.kt") public void testReduceableBinary() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/simplifyBooleanWithConstants/reduceableBinary.kt");