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 3f1de7661..a686839c3 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 @@ -295,15 +295,34 @@ public class ClassModifier extends AbstractVisitor { private static void removeEmptyMethods(MethodNode mth) { AccessInfo af = mth.getAccessFlags(); - // remove public empty constructors + // remove public empty constructors (static or default) if (af.isConstructor() && (af.isPublic() || af.isStatic()) - && mth.getArguments(false).isEmpty() - && !mth.contains(AType.JADX_ERROR)) { + && mth.getArguments(false).isEmpty()) { List bb = mth.getBasicBlocks(); if (bb == null || bb.isEmpty() || BlockUtils.isAllBlocksEmpty(bb)) { - mth.add(AFlag.DONT_GENERATE); + if (af.isStatic() && mth.getMethodInfo().isClassInit()) { + mth.add(AFlag.DONT_GENERATE); + } else { + // don't remove default constructor if other constructors exists + if (mth.isDefaultConstructor() && !isNonDefaultConstructorExists(mth)) { + mth.add(AFlag.DONT_GENERATE); + } + } } } } + + private static boolean isNonDefaultConstructorExists(MethodNode defCtor) { + ClassNode parentClass = defCtor.getParentClass(); + for (MethodNode mth : parentClass.getMethods()) { + if (mth != defCtor + && mth.getAccessFlags().isConstructor() + && mth.getMethodInfo().isConstructor() + && !mth.isDefaultConstructor()) { + return true; + } + } + return false; + } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestDefConstructorNotRemoved.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestDefConstructorNotRemoved.java new file mode 100644 index 000000000..89211412c --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestDefConstructorNotRemoved.java @@ -0,0 +1,60 @@ +package jadx.tests.integration.others; + +import org.junit.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +public class TestDefConstructorNotRemoved extends IntegrationTest { + + public static class TestCls { + + static { + // empty + } + + public static class A { + private final String s; + + public A() { + s = "a"; + } + + public A(String str) { + s = str; + } + } + + public static class B extends A { + public B() { + super(); + } + + public B(String s) { + super(s); + } + } + + public void check() { + new A(); + new A("a"); + new B(); + new B("b"); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, not(containsString("super();"))); + assertThat(code, not(containsString("static {"))); + assertThat(code, containsOne("public B() {")); + } +}