From 811b0e7f30db0f633bda1333bde7032a952884c2 Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 31 Dec 2014 19:39:03 +0300 Subject: [PATCH] core: fix 'break' insertion for switch/case blocks (fix #41) --- .../java/jadx/core/codegen/RegionGen.java | 17 +---- .../jadx/core/dex/nodes/IBranchRegion.java | 13 ++++ .../jadx/core/dex/regions/SwitchRegion.java | 11 ++- .../jadx/core/dex/regions/TryCatchRegion.java | 8 ++- .../core/dex/regions/conditions/IfRegion.java | 11 ++- .../core/dex/visitors/DotGraphVisitor.java | 27 +++++++- .../visitors/regions/ProcessVariables.java | 6 +- .../visitors/regions/RegionMakerVisitor.java | 41 +++++++---- .../dex/visitors/regions/ReturnVisitor.java | 16 ++--- .../main/java/jadx/core/utils/BlockUtils.java | 5 +- .../java/jadx/core/utils/RegionUtils.java | 43 ++++++++---- .../jadx/tests/api/utils/CountString.java | 3 +- .../integration/switches/TestSwitch2.java | 68 +++++++++++++++++++ .../switches/TestSwitchWithTryCatch.java | 68 +++++++++++++++++++ 14 files changed, 273 insertions(+), 64 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/core/dex/nodes/IBranchRegion.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitch2.java create mode 100644 jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchWithTryCatch.java diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 84f15c15..f968c743 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -257,30 +257,17 @@ public class RegionGen extends InsnGen { } code.add(':'); } - makeCaseBlock(c, code); + makeRegionIndent(code, c); } if (sw.getDefaultCase() != null) { code.startLine("default:"); - makeCaseBlock(sw.getDefaultCase(), code); + makeRegionIndent(code, sw.getDefaultCase()); } code.decIndent(); code.startLine('}'); return code; } - private void makeCaseBlock(IContainer c, CodeWriter code) throws CodegenException { - boolean addBreak = true; - if (RegionUtils.notEmpty(c)) { - makeRegionIndent(code, c); - if (RegionUtils.hasExitEdge(c)) { - addBreak = false; - } - } - if (addBreak) { - code.startLine().addIndent().add("break;"); - } - } - private void makeTryCatch(TryCatchRegion region, CodeWriter code) throws CodegenException { code.startLine("try {"); makeRegionIndent(code, region.getTryRegion()); diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/IBranchRegion.java b/jadx-core/src/main/java/jadx/core/dex/nodes/IBranchRegion.java new file mode 100644 index 00000000..f7375e7f --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/IBranchRegion.java @@ -0,0 +1,13 @@ +package jadx.core.dex.nodes; + +import java.util.List; + +public interface IBranchRegion extends IRegion { + + /** + * Return list of branches in this region. + * NOTE: Contains 'null' elements for indicate empty branches. + */ + List getBranches(); + +} diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java index 91f42415..14231085 100644 --- a/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java +++ b/jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java @@ -1,6 +1,7 @@ package jadx.core.dex.regions; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; @@ -8,7 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public final class SwitchRegion extends AbstractRegion { +public final class SwitchRegion extends AbstractRegion implements IBranchRegion { private final BlockNode header; @@ -59,6 +60,14 @@ public final class SwitchRegion extends AbstractRegion { return Collections.unmodifiableList(all); } + @Override + public List getBranches() { + List branches = new ArrayList(cases.size() + 1); + branches.addAll(cases); + branches.add(defCase); + return Collections.unmodifiableList(branches); + } + @Override public String baseString() { return header.baseString(); diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java index 6fe8ddae..84a38eaa 100644 --- a/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java +++ b/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java @@ -1,5 +1,6 @@ package jadx.core.dex.regions; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.trycatch.ExceptionHandler; @@ -12,7 +13,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -public final class TryCatchRegion extends AbstractRegion { +public final class TryCatchRegion extends AbstractRegion implements IBranchRegion { private final IContainer tryRegion; private Map catchRegions = Collections.emptyMap(); @@ -71,6 +72,11 @@ public final class TryCatchRegion extends AbstractRegion { return Collections.unmodifiableList(all); } + @Override + public List getBranches() { + return getSubBlocks(); + } + @Override public String baseString() { return tryRegion.baseString(); diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/conditions/IfRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/conditions/IfRegion.java index cb3c88a5..dba7632c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/regions/conditions/IfRegion.java +++ b/jadx-core/src/main/java/jadx/core/dex/regions/conditions/IfRegion.java @@ -1,6 +1,7 @@ package jadx.core.dex.regions.conditions; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.regions.AbstractRegion; @@ -9,7 +10,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public final class IfRegion extends AbstractRegion { +public final class IfRegion extends AbstractRegion implements IBranchRegion { private final BlockNode header; @@ -89,6 +90,14 @@ public final class IfRegion extends AbstractRegion { return Collections.unmodifiableList(all); } + @Override + public List getBranches() { + List branches = new ArrayList(2); + branches.add(thenRegion); + branches.add(elseRegion); + return Collections.unmodifiableList(branches); + } + @Override public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) { if (oldBlock == thenRegion) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java index 3a609b2d..8593ec5d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java @@ -6,6 +6,7 @@ import jadx.core.dex.attributes.IAttributeNode; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.InsnNode; @@ -113,7 +114,7 @@ public class DotGraphVisitor extends AbstractVisitor { processRegion(mth, h.getHandlerRegion()); } } - Set regionsBlocks = new HashSet(mth.getBasicBlocks().size()); + Set regionsBlocks = new HashSet(mth.getBasicBlocks().size()); RegionUtils.getAllRegionBlocks(mth.getRegion(), regionsBlocks); for (ExceptionHandler handler : mth.getExceptionHandlers()) { IContainer handlerRegion = handler.getHandlerRegion(); @@ -147,6 +148,8 @@ public class DotGraphVisitor extends AbstractVisitor { dot.startLine('}'); } else if (region instanceof BlockNode) { processBlock(mth, (BlockNode) region, false); + } else if (region instanceof IBlock) { + processIBlock(mth, (IBlock) region, false); } } @@ -189,6 +192,24 @@ public class DotGraphVisitor extends AbstractVisitor { } } + private void processIBlock(MethodNode mth, IBlock block, boolean error) { + String attrs = attributesString(block); + dot.startLine(makeName(block)); + dot.add(" [shape=record,"); + if (error) { + dot.add("color=red,"); + } + dot.add("label=\"{"); + if (attrs.length() != 0) { + dot.add(attrs); + } + String insns = insertInsns(mth, block); + if (insns.length() != 0) { + dot.add('|').add(insns); + } + dot.add("}\"];"); + } + private void addEdge(BlockNode from, BlockNode to, String style) { conn.startLine(makeName(from)).add(" -> ").add(makeName(to)); conn.add(style); @@ -207,13 +228,15 @@ public class DotGraphVisitor extends AbstractVisitor { String name; if (c instanceof BlockNode) { name = "Node_" + ((BlockNode) c).getId(); + } else if (c instanceof IBlock) { + name = "Node_" + c.getClass().getSimpleName() + "_" + c.hashCode(); } else { name = "cluster_" + c.getClass().getSimpleName() + "_" + c.hashCode(); } return name; } - private String insertInsns(MethodNode mth, BlockNode block) { + private String insertInsns(MethodNode mth, IBlock block) { if (rawInsn) { StringBuilder str = new StringBuilder(); for (InsnNode insn : block.getInstructions()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java index ce974335..9ce2058b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java @@ -9,12 +9,11 @@ import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.VarName; import jadx.core.dex.nodes.IBlock; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; -import jadx.core.dex.regions.SwitchRegion; -import jadx.core.dex.regions.conditions.IfRegion; import jadx.core.dex.regions.loops.ForLoop; import jadx.core.dex.regions.loops.LoopRegion; import jadx.core.dex.regions.loops.LoopType; @@ -331,8 +330,7 @@ public class ProcessVariables extends AbstractVisitor { return id; } for (IContainer c : region.getSubBlocks()) { - if (c instanceof IfRegion - || c instanceof SwitchRegion) { + if (c instanceof IBranchRegion) { // on branch set for all inner regions same order id id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, false); } else { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java index ed11de8f..3e28b641 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java @@ -1,16 +1,21 @@ package jadx.core.dex.visitors.regions; +import jadx.core.dex.instructions.InsnType; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; +import jadx.core.dex.nodes.InsnContainer; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.regions.Region; +import jadx.core.dex.regions.SwitchRegion; import jadx.core.dex.regions.SynchronizedRegion; import jadx.core.dex.regions.loops.LoopRegion; import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.utils.InstructionRemover; +import jadx.core.utils.RegionUtils; import jadx.core.utils.exceptions.JadxException; +import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; @@ -22,6 +27,8 @@ import org.slf4j.LoggerFactory; public class RegionMakerVisitor extends AbstractVisitor { private static final Logger LOG = LoggerFactory.getLogger(RegionMakerVisitor.class); + private static final PostRegionVisitor POST_REGION_VISITOR = new PostRegionVisitor(); + @Override public void visit(MethodNode mth) throws JadxException { if (mth.isNoCode()) { @@ -44,18 +51,7 @@ public class RegionMakerVisitor extends AbstractVisitor { // make try-catch regions ProcessTryCatchRegions.process(mth); - // merge conditions in loops - if (mth.getLoopsCount() != 0) { - DepthRegionTraversal.traverseAll(mth, new AbstractRegionVisitor() { - @Override - public void enterRegion(MethodNode mth, IRegion region) { - if (region instanceof LoopRegion) { - LoopRegion loop = (LoopRegion) region; - loop.mergePreCondition(); - } - } - }); - } + DepthRegionTraversal.traverse(mth, POST_REGION_VISITOR); CleanRegions.process(mth); @@ -64,6 +60,27 @@ public class RegionMakerVisitor extends AbstractVisitor { } } + private static final class PostRegionVisitor extends AbstractRegionVisitor { + @Override + public void enterRegion(MethodNode mth, IRegion region) { + if (region instanceof LoopRegion) { + // merge conditions in loops + LoopRegion loop = (LoopRegion) region; + loop.mergePreCondition(); + } else if (region instanceof SwitchRegion) { + // insert 'break' in switch cases (run after try/catch insertion) + SwitchRegion sw = (SwitchRegion) region; + for (IContainer c : sw.getBranches()) { + if (c instanceof Region && !RegionUtils.hasExitEdge(c)) { + List insns = new ArrayList(1); + insns.add(new InsnNode(InsnType.BREAK, 0)); + ((Region) c).add(new InsnContainer(insns)); + } + } + } + } + } + private static void removeSynchronized(MethodNode mth) { Region startRegion = mth.getRegion(); List subBlocks = startRegion.getSubBlocks(); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ReturnVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ReturnVisitor.java index 1e001f5e..b223cf12 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ReturnVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ReturnVisitor.java @@ -4,13 +4,11 @@ import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; -import jadx.core.dex.regions.SwitchRegion; -import jadx.core.dex.regions.TryCatchRegion; -import jadx.core.dex.regions.conditions.IfRegion; import jadx.core.dex.regions.loops.LoopRegion; import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.utils.exceptions.JadxException; @@ -28,11 +26,11 @@ public class ReturnVisitor extends AbstractVisitor { public void visit(MethodNode mth) throws JadxException { // remove useless returns in void methods if (mth.getReturnType().equals(ArgType.VOID)) { - DepthRegionTraversal.traverseAll(mth, new Process()); + DepthRegionTraversal.traverse(mth, new ReturnRemoverVisitor()); } } - private static final class Process extends TracedRegionVisitor { + private static final class ReturnRemoverVisitor extends TracedRegionVisitor { @Override public void processBlockTraced(MethodNode mth, IBlock container, IRegion currentRegion) { if (container.getClass() != BlockNode.class) { @@ -72,9 +70,7 @@ public class ReturnVisitor extends AbstractVisitor { IContainer curContainer = block; for (IRegion region : regionStack) { // ignore paths on other branches - if (region instanceof IfRegion - || region instanceof SwitchRegion - || region instanceof TryCatchRegion) { + if (region instanceof IBranchRegion) { curContainer = region; continue; } @@ -100,8 +96,8 @@ public class ReturnVisitor extends AbstractVisitor { * don't count one 'return' instruction (it will be removed later). */ private static boolean isEmpty(IContainer container) { - if (container instanceof BlockNode) { - BlockNode block = (BlockNode) container; + if (container instanceof IBlock) { + IBlock block = (IBlock) container; return block.getInstructions().isEmpty() || block.contains(AFlag.RETURN); } else if (container instanceof IRegion) { IRegion region = (IRegion) container; diff --git a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java index bbcb1170..011b254e 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -11,6 +11,7 @@ import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.mods.TernaryInsn; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.regions.conditions.IfCondition; @@ -133,13 +134,13 @@ public class BlockUtils { return false; } - public static boolean checkLastInsnType(BlockNode block, InsnType expectedType) { + public static boolean checkLastInsnType(IBlock block, InsnType expectedType) { InsnNode insn = getLastInsn(block); return insn != null && insn.getType() == expectedType; } @Nullable - public static InsnNode getLastInsn(BlockNode block) { + public static InsnNode getLastInsn(IBlock block) { List insns = block.getInstructions(); if (insns.isEmpty()) { return null; diff --git a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java index 10c2f8c1..946d2710 100644 --- a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java @@ -3,6 +3,8 @@ package jadx.core.utils; import jadx.core.dex.attributes.AType; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBlock; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.InsnNode; @@ -24,8 +26,8 @@ public class RegionUtils { } public static boolean hasExitEdge(IContainer container) { - if (container instanceof BlockNode) { - InsnNode lastInsn = BlockUtils.getLastInsn((BlockNode) container); + if (container instanceof IBlock) { + InsnNode lastInsn = BlockUtils.getLastInsn((IBlock) container); if (lastInsn == null) { return false; } @@ -34,6 +36,13 @@ public class RegionUtils { || type == InsnType.CONTINUE || type == InsnType.BREAK || type == InsnType.THROW; + } else if (container instanceof IBranchRegion) { + for (IContainer br : ((IBranchRegion) container).getBranches()) { + if (br == null || !hasExitEdge(br)) { + return false; + } + } + return true; } else if (container instanceof IRegion) { IRegion region = (IRegion) container; List blocks = region.getSubBlocks(); @@ -44,8 +53,8 @@ public class RegionUtils { } public static InsnNode getLastInsn(IContainer container) { - if (container instanceof BlockNode) { - BlockNode block = (BlockNode) container; + if (container instanceof IBlock) { + IBlock block = (IBlock) container; List insnList = block.getInstructions(); if (insnList.isEmpty()) { return null; @@ -72,6 +81,8 @@ public class RegionUtils { public static boolean hasExitBlock(IContainer container) { if (container instanceof BlockNode) { return ((BlockNode) container).getSuccessors().isEmpty(); + } else if (container instanceof IBlock) { + return true; } else if (container instanceof IRegion) { List blocks = ((IRegion) container).getSubBlocks(); return !blocks.isEmpty() @@ -82,8 +93,8 @@ public class RegionUtils { } public static boolean hasBreakInsn(IContainer container) { - if (container instanceof BlockNode) { - return BlockUtils.checkLastInsnType((BlockNode) container, InsnType.BREAK); + if (container instanceof IBlock) { + return BlockUtils.checkLastInsnType((IBlock) container, InsnType.BREAK); } else if (container instanceof IRegion) { List blocks = ((IRegion) container).getSubBlocks(); return !blocks.isEmpty() @@ -94,8 +105,8 @@ public class RegionUtils { } public static int insnsCount(IContainer container) { - if (container instanceof BlockNode) { - return ((BlockNode) container).getInstructions().size(); + if (container instanceof IBlock) { + return ((IBlock) container).getInstructions().size(); } else if (container instanceof IRegion) { IRegion region = (IRegion) container; int count = 0; @@ -113,8 +124,8 @@ public class RegionUtils { } public static boolean notEmpty(IContainer container) { - if (container instanceof BlockNode) { - return !((BlockNode) container).getInstructions().isEmpty(); + if (container instanceof IBlock) { + return !((IBlock) container).getInstructions().isEmpty(); } else if (container instanceof IRegion) { IRegion region = (IRegion) container; for (IContainer block : region.getSubBlocks()) { @@ -128,9 +139,9 @@ public class RegionUtils { } } - public static void getAllRegionBlocks(IContainer container, Set blocks) { - if (container instanceof BlockNode) { - blocks.add((BlockNode) container); + public static void getAllRegionBlocks(IContainer container, Set blocks) { + if (container instanceof IBlock) { + blocks.add((IBlock) container); } else if (container instanceof IRegion) { IRegion region = (IRegion) container; for (IContainer block : region.getSubBlocks()) { @@ -142,7 +153,7 @@ public class RegionUtils { } public static boolean isRegionContainsBlock(IContainer container, BlockNode block) { - if (container instanceof BlockNode) { + if (container instanceof IBlock) { return container == block; } else if (container instanceof IRegion) { IRegion region = (IRegion) container; @@ -231,6 +242,8 @@ public class RegionUtils { if (cont instanceof BlockNode) { BlockNode block = (BlockNode) cont; return block.isDominator(dom); + } else if (cont instanceof IBlock) { + return false; } else if (cont instanceof IRegion) { IRegion region = (IRegion) cont; for (IContainer c : region.getSubBlocks()) { @@ -250,6 +263,8 @@ public class RegionUtils { } if (cont instanceof BlockNode) { return BlockUtils.isPathExists(block, (BlockNode) cont); + } else if (cont instanceof IBlock) { + return false; } else if (cont instanceof IRegion) { IRegion region = (IRegion) cont; for (IContainer c : region.getSubBlocks()) { diff --git a/jadx-core/src/test/java/jadx/tests/api/utils/CountString.java b/jadx-core/src/test/java/jadx/tests/api/utils/CountString.java index 422ee849..48979613 100644 --- a/jadx-core/src/test/java/jadx/tests/api/utils/CountString.java +++ b/jadx-core/src/test/java/jadx/tests/api/utils/CountString.java @@ -24,8 +24,7 @@ public class CountString extends SubstringMatcher { @Override public void describeMismatchSafely(String item, Description mismatchDescription) { - mismatchDescription.appendText("found ").appendValue(count(item)) - .appendText(" in \"").appendText(item).appendText("\""); + mismatchDescription.appendText("found ").appendValue(count(item)); } private int count(String string) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitch2.java b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitch2.java new file mode 100644 index 00000000..a420b1ad --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitch2.java @@ -0,0 +1,68 @@ +package jadx.tests.integration.switches; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.countString; +import static org.junit.Assert.assertThat; + +public class TestSwitch2 extends IntegrationTest { + public static class TestCls { + boolean isLongtouchable; + boolean isMultiTouchZoom; + boolean isCanZoomIn; + boolean isCanZoomOut; + boolean isScrolling; + float multiTouchZoomOldDist; + + void test(int action) { + switch (action & 255) { + case 0: + this.isLongtouchable = true; + break; + case 1: + case 6: + if (this.isMultiTouchZoom) { + this.isMultiTouchZoom = false; + } + break; + case 2: + if (this.isMultiTouchZoom) { + float dist = multiTouchZoomOldDist; + if (Math.abs(dist - this.multiTouchZoomOldDist) > 10.0f) { + float scale = dist / this.multiTouchZoomOldDist; + if ((scale > 1.0f && this.isCanZoomIn) || (scale < 1.0f && this.isCanZoomOut)) { + this.multiTouchZoomOldDist = dist; + } + } + return; + } + break; + case 5: + this.multiTouchZoomOldDist = action; + if (this.multiTouchZoomOldDist > 10.0f) { + this.isMultiTouchZoom = true; + this.isLongtouchable = false; + return; + } + break; + } + if (this.isScrolling && action == 1) { + this.isScrolling = false; + } + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, countString(4, "break;")); + + // TODO: remove redundant returns + // assertThat(code, countString(2, "return;")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchWithTryCatch.java b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchWithTryCatch.java new file mode 100644 index 00000000..ae1874c9 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchWithTryCatch.java @@ -0,0 +1,68 @@ +package jadx.tests.integration.switches; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.countString; +import static org.junit.Assert.assertThat; + +public class TestSwitchWithTryCatch extends IntegrationTest { + public static class TestCls { + void test(int a) { + switch (a) { + case 0: + try { + exc(); + return; + } catch (Exception e) { + e.printStackTrace(); + return; + } + // no break; + + case 1: + try { + exc(); + return; + } catch (Exception e) { + e.printStackTrace(); + } + break; + + case 2: + try { + exc(); + } catch (Exception e) { + e.printStackTrace(); + return; + } + break; + + case 3: + try { + exc(); + } catch (Exception e) { + e.printStackTrace(); + } + break; + } + if (a == 10) { + System.out.println(a); + } + } + + private void exc() throws Exception { + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, countString(3, "break;")); + assertThat(code, countString(4, "return;")); + } +} -- GitLab