Skip to content

Commit

Permalink
fix: transform loop to for with branching at end
Browse files Browse the repository at this point in the history
Signed-off-by: Skylot <skylot@gmail.com>
  • Loading branch information
skylot committed Sep 23, 2020
1 parent dcca013 commit 33f2c3f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 7 deletions.
2 changes: 2 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,6 @@ public enum AFlag {
SOFT_CAST, // synthetic cast to help type inference

INCONSISTENT_CODE, // warning about incorrect decompilation

REQUEST_IF_REGION_OPTIMIZE, // run if region visitor again
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public void visit(MethodNode mth) {
if (mth.isNoCode()) {
return;
}
process(mth);
}

public static void process(MethodNode mth) {
DepthRegionTraversal.traverseIterative(mth, TERNARY_VISITOR);
DepthRegionTraversal.traverse(mth, PROCESS_IF_REGION_VISITOR);
DepthRegionTraversal.traverseIterative(mth, REMOVE_REDUNDANT_ELSE_VISITOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,43 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
@Override
public void visit(MethodNode mth) {
DepthRegionTraversal.traverse(mth, this);
if (mth.contains(AFlag.REQUEST_IF_REGION_OPTIMIZE)) {
IfRegionVisitor.process(mth);
mth.remove(AFlag.REQUEST_IF_REGION_OPTIMIZE);
}
}

@Override
public boolean enterRegion(MethodNode mth, IRegion region) {
if (region instanceof LoopRegion) {
processLoopRegion(mth, (LoopRegion) region);
if (processLoopRegion(mth, (LoopRegion) region)) {
// optimize `if` block after instructions remove
mth.add(AFlag.REQUEST_IF_REGION_OPTIMIZE);
}
}
return true;
}

private static void processLoopRegion(MethodNode mth, LoopRegion loopRegion) {
private static boolean processLoopRegion(MethodNode mth, LoopRegion loopRegion) {
if (loopRegion.isConditionAtEnd()) {
return;
return false;
}
IfCondition condition = loopRegion.getCondition();
if (condition == null) {
return;
return false;
}
if (checkForIndexedLoop(mth, loopRegion, condition)) {
return;
return true;
}
checkIterableForEach(mth, loopRegion, condition);
return checkIterableForEach(mth, loopRegion, condition);
}

/**
* Check for indexed loop.
*/
private static boolean checkForIndexedLoop(MethodNode mth, LoopRegion loopRegion, IfCondition condition) {
InsnNode incrInsn = RegionUtils.getLastInsn(loopRegion);
BlockNode loopEndBlock = loopRegion.getInfo().getEnd();
InsnNode incrInsn = BlockUtils.getLastInsn(BlockUtils.skipSyntheticPredecessor(loopEndBlock));
if (incrInsn == null) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package jadx.tests.integration.loops;

import org.junit.jupiter.api.Test;

import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

/**
* Issue #977
*/
public class TestArrayForEach3 extends IntegrationTest {

public static class TestCls {
public void test(String[] arr) {
for (String s : arr) {
if (s.length() > 0) {
return;
}
}
throw new IllegalArgumentException("All strings are empty");
}

public void check() {
test(new String[] { "", "a" }); // no exception
try {
test(new String[] { "", "" });
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
// expected
}
}
}

@Test
public void test() {
noDebugInfo();
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("while")
.containsOne("for (String str : strArr) {");
}
}

0 comments on commit 33f2c3f

Please sign in to comment.