diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java index a7c804b..17bf65e 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.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 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; + } } } } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 1d0dc62..2f2e5e3 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -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"); } diff --git a/testData/classes/pkg/TestInvertedFloatComparison.class b/testData/classes/pkg/TestInvertedFloatComparison.class new file mode 100644 index 0000000..29c1432 Binary files /dev/null and b/testData/classes/pkg/TestInvertedFloatComparison.class differ diff --git a/testData/results/TestInvertedFloatComparison.dec b/testData/results/TestInvertedFloatComparison.dec new file mode 100644 index 0000000..e252925 --- /dev/null +++ b/testData/results/TestInvertedFloatComparison.dec @@ -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 diff --git a/testData/src/pkg/TestInvertedFloatComparison.java b/testData/src/pkg/TestInvertedFloatComparison.java new file mode 100644 index 0000000..d7a06b4 --- /dev/null +++ b/testData/src/pkg/TestInvertedFloatComparison.java @@ -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); + } +} \ No newline at end of file