Fix false positive in +0.0 == -0.0 comparison simplification (KT-17735)

This commit is contained in:
Yan Zhulanow
2020-08-06 21:53:57 +09:00
parent 915dc6ce91
commit 9f192ba85e
7 changed files with 72 additions and 0 deletions
@@ -18,10 +18,13 @@ import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode.PARTIAL
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isFlexible
@Suppress("DEPRECATION")
@@ -47,12 +50,40 @@ class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentInte
if (areThereExpressionsToBeSimplified(element.left) && element.right.hasBooleanType()) return true
if (areThereExpressionsToBeSimplified(element.right) && element.left.hasBooleanType()) return true
}
if (isPositiveNegativeZeroComparison(element)) return false
}
}
return element.canBeReducedToBooleanConstant()
}
private fun isPositiveNegativeZeroComparison(element: KtBinaryExpression): Boolean {
val op = element.operationToken
if (op != EQEQ && op != EQEQEQ) {
return false
}
val left = element.left?.deparenthesize() as? KtExpression ?: return false
val right = element.right?.deparenthesize() as? KtExpression ?: return false
val context = element.analyze(PARTIAL)
fun KtExpression.getConstantValue() =
ConstantExpressionEvaluator.getConstant(this, context)?.toConstantValue(TypeUtils.NO_EXPECTED_TYPE)?.value
val leftValue = left.getConstantValue()
val rightValue = right.getConstantValue()
fun isPositiveZero(value: Any?) = value == +0.0 || value == +0.0f
fun isNegativeZero(value: Any?) = value == -0.0 || value == -0.0f
val hasPositiveZero = isPositiveZero(leftValue) || isPositiveZero(rightValue)
val hasNegativeZero = isNegativeZero(leftValue) || isNegativeZero(rightValue)
return hasPositiveZero && hasNegativeZero
}
override fun applyTo(element: KtBinaryExpression, editor: Editor?) {
val topBinary = element.topBinary()
val simplified = toSimplifiedExpression(topBinary)
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
fun foo() {
-0.0 <caret>== +0.0
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
fun foo() {
+0.0f <caret>== -0.0f
}
@@ -0,0 +1,3 @@
fun foo() {
+0.0f <caret>== +0.0f
}
@@ -0,0 +1,3 @@
fun foo() {
true
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
fun foo(y: Boolean) {
0.0f <caret>=== -0.0f
}
@@ -15703,6 +15703,26 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/nullableComplex2.kt");
}
@TestMetadata("positiveZeroNegativeZero1.kt")
public void testPositiveZeroNegativeZero1() throws Exception {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/positiveZeroNegativeZero1.kt");
}
@TestMetadata("positiveZeroNegativeZero2.kt")
public void testPositiveZeroNegativeZero2() throws Exception {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/positiveZeroNegativeZero2.kt");
}
@TestMetadata("positiveZeroNegativeZero3.kt")
public void testPositiveZeroNegativeZero3() throws Exception {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/positiveZeroNegativeZero3.kt");
}
@TestMetadata("positiveZeroNegativeZero4.kt")
public void testPositiveZeroNegativeZero4() throws Exception {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/positiveZeroNegativeZero4.kt");
}
@TestMetadata("reduceableBinary.kt")
public void testReduceableBinary() throws Exception {
runTest("idea/testData/intentions/simplifyBooleanWithConstants/reduceableBinary.kt");