From 4e7ef9f4d20be2c7dc39879a3ef91707074aa988 Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 24 Apr 2013 23:49:31 +0400 Subject: [PATCH] Fix 'switch' codegen for empty case block --- src/main/java/jadx/codegen/CodeWriter.java | 7 +++ src/main/java/jadx/codegen/RegionGen.java | 48 ++++++++++++------- .../java/jadx/dex/visitors/ModVisitor.java | 11 +++-- .../dex/visitors/regions/RegionMaker.java | 10 ++-- .../java/jadx/samples/AbstractTest.java | 9 ++++ src/samples/java/jadx/samples/TestSwitch.java | 30 ++++++++++++ 6 files changed, 90 insertions(+), 25 deletions(-) diff --git a/src/main/java/jadx/codegen/CodeWriter.java b/src/main/java/jadx/codegen/CodeWriter.java index c924f1ff3..6138d4910 100644 --- a/src/main/java/jadx/codegen/CodeWriter.java +++ b/src/main/java/jadx/codegen/CodeWriter.java @@ -36,6 +36,13 @@ public class CodeWriter { return this; } + public CodeWriter startLine(char c) { + buf.append(NL); + buf.append(indentStr); + buf.append(c); + return this; + } + public CodeWriter startLine(int ind, String str) { buf.append(NL); buf.append(indentStr); diff --git a/src/main/java/jadx/codegen/RegionGen.java b/src/main/java/jadx/codegen/RegionGen.java index 64dcd8243..904393b30 100644 --- a/src/main/java/jadx/codegen/RegionGen.java +++ b/src/main/java/jadx/codegen/RegionGen.java @@ -107,7 +107,7 @@ public class RegionGen extends InsnGen { IfNode insn = region.getIfInsn(); code.add("if ").add(makeCondition(insn)).add(" {"); makeRegionIndent(code, region.getThenRegion()); - code.startLine("}"); + code.startLine('}'); IContainer els = region.getElseRegion(); if (els != null && RegionUtils.notEmpty(els)) { @@ -123,11 +123,11 @@ public class RegionGen extends InsnGen { } } - code.add("{"); + code.add('{'); code.incIndent(); makeRegion(code, els); code.decIndent(); - code.startLine("}"); + code.startLine('}'); } } @@ -136,7 +136,7 @@ public class RegionGen extends InsnGen { // infinite loop code.startLine("while (true) {"); makeRegionIndent(code, region.getBody()); - code.startLine("}"); + code.startLine('}'); return code; } @@ -144,11 +144,11 @@ public class RegionGen extends InsnGen { if (!region.isConditionAtEnd()) { code.startLine("while ").add(makeCondition(insn)).add(" {"); makeRegionIndent(code, region.getBody()); - code.startLine("}"); + code.startLine('}'); } else { code.startLine("do {"); makeRegionIndent(code, region.getBody()); - code.startLine("} while ").add(makeCondition(insn)).add(";"); + code.startLine("} while ").add(makeCondition(insn)).add(';'); } return code; } @@ -156,7 +156,7 @@ public class RegionGen extends InsnGen { private void makeSynchronizedRegion(SynchronizedRegion cont, CodeWriter code) throws CodegenException { code.startLine("synchronized(").add(arg(cont.getArg())).add(") {"); makeRegionIndent(code, cont.getRegion()); - code.startLine("}"); + code.startLine('}'); } private String makeCondition(IfNode insn) throws CodegenException { @@ -194,25 +194,37 @@ public class RegionGen extends InsnGen { List keys = sw.getKeys().get(i); IContainer c = sw.getCases().get(i); for (Integer k : keys) { - code.startLine("case ") - .add(TypeGen.literalToString(k, arg.getType())) - .add(":"); + code.startLine("case "); + code.add(TypeGen.literalToString(k, arg.getType())); + code.add(':'); } - makeRegionIndent(code, c); - if (RegionUtils.hasExitEdge(c)) - code.startLine(1, "break;"); + makeCaseBlock(c, code); } if (sw.getDefaultCase() != null) { code.startLine("default:"); - makeRegionIndent(code, sw.getDefaultCase()); - if (RegionUtils.hasExitEdge(sw.getDefaultCase())) - code.startLine(1, "break;"); + makeCaseBlock(sw.getDefaultCase(), code); } code.decIndent(); - code.startLine("}"); + code.startLine('}'); return code; } + private void makeCaseBlock(IContainer c, CodeWriter code) throws CodegenException { + if (RegionUtils.notEmpty(c)) { + boolean closeBlock = RegionUtils.hasExitEdge(c); + if (closeBlock) { + code.add(" {"); + } + makeRegionIndent(code, c); + if (closeBlock) { + code.startLine(1, "break;"); + code.startLine('}'); + } + } else { + code.startLine(1, "break;"); + } + } + private void makeTryCatch(IContainer region, TryCatchBlock tryCatchBlock, CodeWriter code) throws CodegenException { code.startLine("try {"); @@ -235,7 +247,7 @@ public class RegionGen extends InsnGen { code.startLine("} finally {"); makeRegionIndent(code, tryCatchBlock.getFinalBlock()); } - code.startLine("}"); + code.startLine('}'); } private void makeCatchBlock(CodeWriter code, ExceptionHandler handler) diff --git a/src/main/java/jadx/dex/visitors/ModVisitor.java b/src/main/java/jadx/dex/visitors/ModVisitor.java index 5d47d9149..c9bbae85d 100644 --- a/src/main/java/jadx/dex/visitors/ModVisitor.java +++ b/src/main/java/jadx/dex/visitors/ModVisitor.java @@ -148,10 +148,13 @@ public class ModVisitor extends AbstractVisitor { break; case RETURN: - if (insn.getArgsCount() == 0 - && mth.getBasicBlocks().size() == 1 - && i == size - 1) - remover.add(insn); + if (insn.getArgsCount() == 0) { + if (mth.getBasicBlocks().size() == 1 && i == size - 1) { + remover.add(insn); + } else if (mth.getMethodInfo().isClassInit()) { + remover.add(insn); + } + } break; default: diff --git a/src/main/java/jadx/dex/visitors/regions/RegionMaker.java b/src/main/java/jadx/dex/visitors/regions/RegionMaker.java index 9dfaa6a3a..653cc6c56 100644 --- a/src/main/java/jadx/dex/visitors/regions/RegionMaker.java +++ b/src/main/java/jadx/dex/visitors/regions/RegionMaker.java @@ -404,7 +404,6 @@ public class RegionMaker { } Map> blocksMap = new LinkedHashMap>(len); - for (Entry> entry : casesMap.entrySet()) { BlockNode c = BlockUtils.getBlockByOffset(entry.getKey(), block.getSuccessors()); assert c != null; @@ -413,7 +412,7 @@ public class RegionMaker { BitSet succ = BlockUtils.blocksToBitSet(mth, block.getSuccessors()); BitSet domsOn = BlockUtils.blocksToBitSet(mth, block.getDominatesOn()); - domsOn.andNot(succ); // filter 'out' block + domsOn.and(succ); // filter 'out' block BlockNode defCase = BlockUtils.getBlockByOffset(insn.getDefaultCaseOffset(), block.getSuccessors()); if (defCase != null) { @@ -458,7 +457,12 @@ public class RegionMaker { } for (Entry> entry : blocksMap.entrySet()) { BlockNode c = entry.getKey(); - sw.addCase(entry.getValue(), makeRegion(c, stack)); + if (stack.containsExit(c)) { + // empty case block + sw.addCase(entry.getValue(), new Region(stack.peekRegion())); + } else { + sw.addCase(entry.getValue(), makeRegion(c, stack)); + } } stack.pop(); diff --git a/src/samples/java/jadx/samples/AbstractTest.java b/src/samples/java/jadx/samples/AbstractTest.java index 5c126b987..94c86aa75 100644 --- a/src/samples/java/jadx/samples/AbstractTest.java +++ b/src/samples/java/jadx/samples/AbstractTest.java @@ -15,4 +15,13 @@ public abstract class AbstractTest { throw new AssertionError(a1 + " != " + a2); } } + + public static void assertEquals(Object a1, Object a2) { + if (a1 == null) { + if (a2 != null) + throw new AssertionError(a1 + " != " + a2); + } else if (!a1.equals(a2)) { + throw new AssertionError(a1 + " != " + a2); + } + } } diff --git a/src/samples/java/jadx/samples/TestSwitch.java b/src/samples/java/jadx/samples/TestSwitch.java index 38c40b5db..08acab6ee 100644 --- a/src/samples/java/jadx/samples/TestSwitch.java +++ b/src/samples/java/jadx/samples/TestSwitch.java @@ -78,13 +78,43 @@ public class TestSwitch extends AbstractTest { return -1; } + public String escape(String str) { + int len = str.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + char c = str.charAt(i); + switch (c) { + case '.': + case '/': + sb.append('_'); + break; + + case ']': + sb.append('A'); + break; + + case '?': + break; + + default: + sb.append(c); + break; + } + } + return sb.toString(); + } + @Override public boolean testRun() { assertTrue(test1(25) == 2); assertTrue(test2(5) == 3); assertTrue(test3(1, 0) == 0); assertTrue(test4(2) == 1); + assertEquals(escape("a.b/c]d?e"), "a_b_cAde"); return true; } + public static void main(String[] args) { + new TestSwitch().testRun(); + } }