From dfb465c61e4fa802802254482b8cea17969ae9a3 Mon Sep 17 00:00:00 2001 From: coehlrich Date: Fri, 8 Sep 2023 19:16:25 +1200 Subject: [PATCH 1/3] Fix final variable definition getting put outside for loop --- .../modules/decompiler/MergeHelper.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java index b8811d9044..bd365b26c1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java @@ -433,6 +433,12 @@ protected static void matchFor(DoStatement stat) { return; } + // Check if any final variable assignments in the loop are + Set finalVariables = getFinalVariables(stat, new HashSet<>()); + if (finalVariables.stream().anyMatch(exp -> exp.isVarReferenced(lastExp))) { + return; + } + stat.setLooptype(DoStatement.Type.FOR); if (hasinit) { Exprent exp = preData.getExprents().remove(preData.getExprents().size() - 1); @@ -451,6 +457,38 @@ protected static void matchFor(DoStatement stat) { cleanEmptyStatements(stat, lastData); } + private static Set getFinalVariables(Statement stat, Set variables) { + if (stat.getExprents() == null) { + for (Object o : stat.getSequentialObjects()) { + if (o instanceof Statement) { + getFinalVariables((Statement) o, variables); + } else if (o instanceof Exprent) { + getFinalVariables((Exprent) o, variables); + } + } + } else { + for (Exprent exp : stat.getExprents()) { + getFinalVariables(exp, variables); + } + } + return variables; + } + + private static Set getFinalVariables(Exprent exp, Set variables) { + for (Exprent e : exp.getAllExprents(true, true)) { + if (e instanceof AssignmentExprent) { + AssignmentExprent assignment = (AssignmentExprent) e; + if (assignment.getLeft() instanceof VarExprent) { + VarExprent varExprent = (VarExprent) assignment.getLeft(); + if (varExprent.isEffectivelyFinal()) { + variables.add(varExprent); + } + } + } + } + return variables; + } + protected static void cleanEmptyStatements(DoStatement dostat, Statement stat) { if (stat != null && stat.getExprents().isEmpty()) { List lst = stat.getAllSuccessorEdges(); From f0811b8fa4c12671c6db79c1fe122c406d1a801d Mon Sep 17 00:00:00 2001 From: coehlrich Date: Fri, 8 Sep 2023 19:19:27 +1200 Subject: [PATCH 2/3] Finish writing comment --- .../java/decompiler/modules/decompiler/MergeHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java index bd365b26c1..3a259c6bae 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java @@ -433,7 +433,7 @@ protected static void matchFor(DoStatement stat) { return; } - // Check if any final variable assignments in the loop are + // Check if any final variable assignments in the loop are used in the line that is being moved to the final part of the for loop Set finalVariables = getFinalVariables(stat, new HashSet<>()); if (finalVariables.stream().anyMatch(exp -> exp.isVarReferenced(lastExp))) { return; From ed5e394827654ec833ad8e0d8827847ea5984f07 Mon Sep 17 00:00:00 2001 From: coehlrich Date: Sat, 9 Sep 2023 11:51:31 +1200 Subject: [PATCH 3/3] Add test --- .../java/decompiler/SingleClassesTest.java | 2 + testData/results/pkg/TestWhileLambda.dec | 39 +++++++++++++++++++ testData/src/java8/pkg/TestWhileLambda.java | 13 +++++++ 3 files changed, 54 insertions(+) create mode 100644 testData/results/pkg/TestWhileLambda.dec create mode 100644 testData/src/java8/pkg/TestWhileLambda.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index ca7f00b544..2c9ce28226 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -670,6 +670,8 @@ private void registerDefault() { // TODO: switch (s) decompiled as switch (s.hashCode()) register(JAVA_17, "TestSingleCaseStrSwitch"); register(JAVA_16, "TestIfPatternMatchMethod"); + + register(JAVA_8, "TestWhileLambda"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestWhileLambda.dec b/testData/results/pkg/TestWhileLambda.dec new file mode 100644 index 0000000000..346d73e27d --- /dev/null +++ b/testData/results/pkg/TestWhileLambda.dec @@ -0,0 +1,39 @@ +package pkg; + +import java.util.function.Supplier; + +public class TestWhileLambda { + public void test() { + Object o = new Object();// 7 + + while (o != null) {// 8 + Object o2 = new Object();// 9 + Supplier var3 = () -> o2;// 10 + } + }// 12 +} + +class 'pkg/TestWhileLambda' { + method 'test ()V' { + 7 6 + 8 8 + 9 8 + 13 9 + 1a 10 + 1e 12 + } + + method 'lambda$test$0 (Ljava/lang/Object;)Ljava/lang/Object;' { + 0 10 + 1 10 + } +} + +Lines mapping: +7 <-> 7 +8 <-> 9 +9 <-> 10 +10 <-> 11 +12 <-> 13 +Not mapped: +11 diff --git a/testData/src/java8/pkg/TestWhileLambda.java b/testData/src/java8/pkg/TestWhileLambda.java new file mode 100644 index 0000000000..e947bd9c0c --- /dev/null +++ b/testData/src/java8/pkg/TestWhileLambda.java @@ -0,0 +1,13 @@ +package pkg; + +import java.util.function.Supplier; + +public class TestWhileLambda { + public void test() { + Object o = new Object(); + while (o != null) { + Object o2 = new Object(); + Supplier s = () -> o2; + } + } +}