diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java index 318ac0dff..f9a6542b5 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java @@ -9,6 +9,7 @@ import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.RegisterArg; +import jadx.core.dex.instructions.mods.ConstructorInsn; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; @@ -26,7 +27,12 @@ public class ClassModifier extends AbstractVisitor { for (ClassNode inner : cls.getInnerClasses()) { visit(inner); } - + if (cls.getAccessFlags().isSynthetic() + && cls.getFields().isEmpty() + && cls.getMethods().isEmpty()) { + cls.getAttributes().add(AttributeFlag.DONT_GENERATE); + return false; + } removeSyntheticFields(cls); removeSyntheticMethods(cls); removeEmptyMethods(cls); @@ -110,6 +116,18 @@ public class ClassModifier extends AbstractVisitor { it.remove(); } } + + // remove synthetic constructor for inner non-static classes + if (af.isSynthetic() && af.isConstructor() && mth.getBasicBlocks().size() == 2) { + List insns = mth.getBasicBlocks().get(0).getInstructions(); + if (insns.size() == 1 && insns.get(0).getType() == InsnType.CONSTRUCTOR) { + ConstructorInsn constr = (ConstructorInsn) insns.get(0); + if (constr.isThis() && mth.getArguments(false).size() >= 1) { + mth.removeFirstArgument(); + mth.getAttributes().add(AttributeFlag.DONT_GENERATE); + } + } + } } } diff --git a/jadx-core/src/test/java/jadx/tests/internal/TestInnerClass2.java b/jadx-core/src/test/java/jadx/tests/internal/TestInnerClass2.java new file mode 100644 index 000000000..7b9141a87 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/internal/TestInnerClass2.java @@ -0,0 +1,41 @@ +package jadx.tests.internal; + +import jadx.api.InternalJadxTest; +import jadx.core.dex.nodes.ClassNode; + +import java.util.Timer; +import java.util.TimerTask; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; + +public class TestInnerClass2 extends InternalJadxTest { + + public static class TestCls { + private static class TerminateTask extends TimerTask { + @Override + public void run() { + System.err.println("Test timed out"); + } + } + + public void test() { + new Timer().schedule(new TerminateTask(), 1000); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsString("new Timer().schedule(new TerminateTask(), 1000);")); + assertThat(code, not(containsString("synthetic"))); + assertThat(code, not(containsString("this"))); + assertThat(code, not(containsString("null"))); + assertThat(code, not(containsString("AnonymousClass"))); + } +}