Simplify boolean with constants intention supports now == (!=) true (false) cases #KT-13777 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-11-21 17:22:19 +03:00
parent 20669c1b97
commit 2bb81e6a18
20 changed files with 144 additions and 13 deletions

View File

@@ -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<KtBinaryExpression>(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)
}

View File

@@ -0,0 +1 @@
fun foo(x: Boolean): Boolean = <caret>true == (x && false)

View File

@@ -0,0 +1 @@
fun foo(x: Boolean): Boolean = false

View File

@@ -0,0 +1 @@
fun foo(x: Boolean, y: Boolean): Boolean = <caret>(x || y) == false

View File

@@ -0,0 +1 @@
fun foo(x: Boolean, y: Boolean): Boolean = !(x || y)

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (false == <caret>arg) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (!arg) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (<caret>arg == true) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (arg) {
}
}

View File

@@ -0,0 +1 @@
fun foo(arg: Boolean): Boolean = <caret>arg == true || arg == false

View File

@@ -0,0 +1 @@
fun foo(arg: Boolean): Boolean = arg || !arg

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (<caret>arg != false) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (arg) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (true != <caret>arg) {
}
}

View File

@@ -0,0 +1,5 @@
fun use(arg: Boolean) {
if (!arg) {
}
}

View File

@@ -0,0 +1,3 @@
// IS_APPLICABLE: false
fun foo(arg: Boolean?): Boolean = <caret>arg == true

View File

@@ -0,0 +1,3 @@
// IS_APPLICABLE: false
fun foo(arg: Boolean?): Boolean = <caret>arg == true || arg == false

View File

@@ -1,3 +1,7 @@
fun bar(): Boolean {
return false
}
fun foo(y: Boolean) {
<caret>true && () && y
<caret>true && (bar()) && y
}

View File

@@ -1,3 +1,7 @@
fun bar(): Boolean {
return false
}
fun foo(y: Boolean) {
() && y
bar() && y
}

View File

@@ -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");