fix: transform loop to for with branching at end
Signed-off-by: Skylot <skylot@gmail.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -26,7 +26,10 @@ public class IfRegionVisitor extends AbstractVisitor {
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user