Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix final variable definition that is used in a for loop being moved outside the for loop #311

Merged
merged 4 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ protected static void matchFor(DoStatement stat) {
return;
}

// 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<VarExprent> 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);
Expand All @@ -451,6 +457,38 @@ protected static void matchFor(DoStatement stat) {
cleanEmptyStatements(stat, lastData);
}

private static Set<VarExprent> getFinalVariables(Statement stat, Set<VarExprent> 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<VarExprent> getFinalVariables(Exprent exp, Set<VarExprent> 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<StatEdge> lst = stat.getAllSuccessorEdges();
Expand Down
1 change: 1 addition & 0 deletions test/org/jetbrains/java/decompiler/SingleClassesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ private void registerDefault() {
register(JAVA_16, "TestIfPatternMatchMethod");
// TODO: Param type information is lost for lambdas where a more specific type is not required by the context
register(JAVA_8, "TestLambdaParamTypes");
register(JAVA_8, "TestWhileLambda");
}

private void registerEntireClassPath() {
Expand Down
39 changes: 39 additions & 0 deletions testData/results/pkg/TestWhileLambda.dec
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions testData/src/java8/pkg/TestWhileLambda.java
Original file line number Diff line number Diff line change
@@ -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<Object> s = () -> o2;
}
}
}