Fix incorrect decompilation of inverted floating point comparisons with NaN (IDEA-196302)

PR #845

GitOrigin-RevId: 611f4af224e68ff8167f2b62f8366a022adb2054
master
malte0811 4 years ago committed by intellij-monorepo-bot
parent 1d63f7d447
commit ab4a7ddd16
  1. 30
      src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
  2. 3
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  3. BIN
      testData/classes/pkg/TestInvertedFloatComparison.class
  4. 167
      testData/results/TestInvertedFloatComparison.dec
  5. 83
      testData/src/pkg/TestInvertedFloatComparison.java

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.modules.decompiler;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -170,6 +170,17 @@ public class SecondaryFunctionsHelper {
}
if (desttype >= 0) {
if (functype != FunctionExprent.FUNCTION_LCMP) {
boolean oneForNan = functype == FunctionExprent.FUNCTION_DCMPL || functype == FunctionExprent.FUNCTION_FCMPL;
boolean trueForOne = desttype == FunctionExprent.FUNCTION_LT || desttype == FunctionExprent.FUNCTION_LE;
boolean trueForNan = oneForNan == trueForOne;
if (trueForNan) {
List<Exprent> operands = new ArrayList<>();
operands.add(new FunctionExprent(funcsnot[desttype - FunctionExprent.FUNCTION_EQ],
funcexpr.getLstOperands(), funcexpr.bytecode));
return new FunctionExprent(FunctionExprent.FUNCTION_BOOL_NOT, operands, funcexpr.bytecode);
}
}
return new FunctionExprent(desttype, funcexpr.getLstOperands(), funcexpr.bytecode);
}
}
@ -378,6 +389,7 @@ public class SecondaryFunctionsHelper {
FunctionExprent fparam = (FunctionExprent)param;
int ftype = fparam.getFuncType();
boolean canSimplify = false;
switch (ftype) {
case FunctionExprent.FUNCTION_BOOL_NOT:
Exprent newexpr = fparam.getLstOperands().get(0);
@ -394,12 +406,24 @@ public class SecondaryFunctionsHelper {
}
case FunctionExprent.FUNCTION_EQ:
case FunctionExprent.FUNCTION_NE:
canSimplify = true;
case FunctionExprent.FUNCTION_LT:
case FunctionExprent.FUNCTION_GE:
case FunctionExprent.FUNCTION_GT:
case FunctionExprent.FUNCTION_LE:
fparam.setFuncType(funcsnot[ftype - FunctionExprent.FUNCTION_EQ]);
return fparam;
if (!canSimplify) {
operands = fparam.getLstOperands();
VarType left = operands.get(0).getExprType();
VarType right = operands.get(1).getExprType();
VarType commonSupertype = VarType.getCommonSupertype(left, right);
if (commonSupertype != null) {
canSimplify = commonSupertype.type != CodeConstants.TYPE_FLOAT && commonSupertype.type != CodeConstants.TYPE_DOUBLE;
}
}
if (canSimplify) {
fparam.setFuncType(funcsnot[ftype - FunctionExprent.FUNCTION_EQ]);
return fparam;
}
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler;
import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
@ -110,6 +110,7 @@ public class SingleClassesTest {
@Test public void testMissingConstructorCallGood() { doTest("pkg/TestMissingConstructorCallGood"); }
@Test public void testMissingConstructorCallBad() { doTest("pkg/TestMissingConstructorCallBad"); }
@Test public void testEmptyBlocks() { doTest("pkg/TestEmptyBlocks"); }
@Test public void testInvertedFloatComparison() { doTest("pkg/TestInvertedFloatComparison"); }
@Test public void testPrivateEmptyConstructor() { doTest("pkg/TestPrivateEmptyConstructor"); }
@Test public void testSynchronizedUnprotected() { doTest("pkg/TestSynchronizedUnprotected"); }
@Test public void testInterfaceSuper() { doTest("pkg/TestInterfaceSuper"); }

@ -0,0 +1,167 @@
package pkg;
public class TestInvertedFloatComparison {
public boolean less(double var1, double var3) {
return var1 < var3;// 6
}
public boolean less(int var1, int var2) {
return var1 < var2;// 10
}
public boolean notLess(double var1, double var3) {
return !(var1 < var3);// 14
}
public boolean notLess(int var1, int var2) {
return var1 >= var2;// 18
}
public boolean greater(double var1, double var3) {
return var1 > var3;// 22
}
public boolean greater(int var1, int var2) {
return var1 > var2;// 26
}
public boolean notGreater(double var1, double var3) {
return !(var1 > var3);// 30
}
public boolean notGreater(int var1, int var2) {
return var1 <= var2;// 34
}
public boolean lessEqual(double var1, double var3) {
return var1 <= var3;// 38
}
public boolean lessEqual(int var1, int var2) {
return var1 <= var2;// 42
}
public boolean notLessEqual(double var1, double var3) {
return !(var1 <= var3);// 46
}
public boolean notLessEqual(int var1, int var2) {
return var1 > var2;// 50
}
public boolean greaterEqual(double var1, double var3) {
return var1 >= var3;// 54
}
public boolean greaterEqual(int var1, int var2) {
return var1 >= var2;// 58
}
public boolean notGreaterEqual(double var1, double var3) {
return !(var1 >= var3);// 62
}
public boolean notGreaterEqual(int var1, int var2) {
return var1 < var2;// 66
}
}
class 'pkg/TestInvertedFloatComparison' {
method 'less (DD)Z' {
2 4
b 4
}
method 'less (II)Z' {
2 8
a 8
}
method 'notLess (DD)Z' {
2 12
b 12
}
method 'notLess (II)Z' {
2 16
a 16
}
method 'greater (DD)Z' {
2 20
b 20
}
method 'greater (II)Z' {
2 24
a 24
}
method 'notGreater (DD)Z' {
2 28
b 28
}
method 'notGreater (II)Z' {
2 32
a 32
}
method 'lessEqual (DD)Z' {
2 36
b 36
}
method 'lessEqual (II)Z' {
2 40
a 40
}
method 'notLessEqual (DD)Z' {
2 44
b 44
}
method 'notLessEqual (II)Z' {
2 48
a 48
}
method 'greaterEqual (DD)Z' {
2 52
b 52
}
method 'greaterEqual (II)Z' {
2 56
a 56
}
method 'notGreaterEqual (DD)Z' {
2 60
b 60
}
method 'notGreaterEqual (II)Z' {
2 64
a 64
}
}
Lines mapping:
6 <-> 5
10 <-> 9
14 <-> 13
18 <-> 17
22 <-> 21
26 <-> 25
30 <-> 29
34 <-> 33
38 <-> 37
42 <-> 41
46 <-> 45
50 <-> 49
54 <-> 53
58 <-> 57
62 <-> 61
66 <-> 65

@ -0,0 +1,83 @@
/*
* Copyright 2000-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pkg;
public class TestInvertedFloatComparison {
public boolean less(double a, double b) {
return a < b;
}
public boolean less(int a, int b) {
return a < b;
}
public boolean notLess(double a, double b) {
return !(a < b);
}
public boolean notLess(int a, int b) {
return !(a < b);
}
public boolean greater(double a, double b) {
return a > b;
}
public boolean greater(int a, int b) {
return a > b;
}
public boolean notGreater(double a, double b) {
return !(a > b);
}
public boolean notGreater(int a, int b) {
return !(a > b);
}
public boolean lessEqual(double a, double b) {
return a <= b;
}
public boolean lessEqual(int a, int b) {
return a <= b;
}
public boolean notLessEqual(double a, double b) {
return !(a <= b);
}
public boolean notLessEqual(int a, int b) {
return !(a <= b);
}
public boolean greaterEqual(double a, double b) {
return a >= b;
}
public boolean greaterEqual(int a, int b) {
return a >= b;
}
public boolean notGreaterEqual(double a, double b) {
return !(a >= b);
}
public boolean notGreaterEqual(int a, int b) {
return !(a >= b);
}
}
Loading…
Cancel
Save