diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index f71e7a653..225868756 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -129,8 +129,16 @@ public class InsnGen { } private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException { - FieldNode fieldNode = mth.getParentClass().searchField(field); - if (fieldNode != null) { + ClassNode pCls = mth.getParentClass(); + FieldNode fieldNode = pCls.searchField(field); + + while ((fieldNode == null) + && (pCls.getParentClass() != pCls) && (pCls.getParentClass() != null)) + { + pCls = pCls.getParentClass(); + fieldNode = pCls.searchField(field); + } + if (fieldNode != null) { FieldReplaceAttr replace = fieldNode.get(AType.FIELD_REPLACE); if (replace != null) { FieldInfo info = replace.getFieldInfo(); diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index 9c70ac94f..8e9b15333 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -377,10 +377,7 @@ public class ClassNode extends LineAttrNode implements ILoadable { public MethodNode getDefaultConstructor() { for (MethodNode mth : methods) { - if (mth.getAccessFlags().isConstructor() - && mth.getMethodInfo().isConstructor() - && (mth.getMethodInfo().getArgsCount() == 0 - || (mth.getArguments(false) != null && mth.getArguments(false).isEmpty()))) { + if (mth.isDefaultConstructor()) { return mth; } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index 2688347f1..b393422cc 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -461,6 +461,31 @@ public class MethodNode extends LineAttrNode implements ILoadable { } return false; } + + public boolean isDefaultConstructor() { + boolean result = false; + + if (accFlags.isConstructor() && mthInfo.isConstructor()) { + int defaultArgCount = 0; + + /** workaround for non-static inner class constructor, that has + * synthetic argument */ + if ((parentClass != null) && parentClass.getClassInfo().isInner()) { + if (!parentClass.getAccessFlags().isStatic()) { + ClassNode outerCls = parentClass.getParentClass(); + if ((argsList != null) && (argsList.size() >= 1)) { + if (argsList.get(0).getType().equals(outerCls.getClassInfo().getType())) { + defaultArgCount = 1; + } + } + } + } + + result = (argsList == null) || (argsList.size() == defaultArgCount); + } + + return result; + } public int getRegsCount() { return regsCount; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index 7e9126385..dfa5be1ea 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -76,6 +76,12 @@ public class ModVisitor extends AbstractVisitor { remove = true; } } + + // remove super() call in instance initializer + if (parentClass.isAnonymous() && mth.isDefaultConstructor() && co.isSuper()) { + remove = true; + } + if (remove) { remover.add(insn); } else { diff --git a/jadx-samples/src/main/java/jadx/samples/TestInitializers.java b/jadx-samples/src/main/java/jadx/samples/TestInitializers.java new file mode 100644 index 000000000..660814c00 --- /dev/null +++ b/jadx-samples/src/main/java/jadx/samples/TestInitializers.java @@ -0,0 +1,104 @@ +package jadx.samples; + +public class TestInitializers extends AbstractTest { + + private static String a; + private static int counter; + private A c_a; + + public static class A { + public static String a; + + static { + a = "a1"; + } + + public boolean z() { + return true; + } + } + + public class B { + private int b; + private int bbb; + + public B() { + if (c_a.z()) { + b = -1; + } else { + b = 1; + } + } + + public B(int _b) { + b = _b; + } + + public void setB(int _b) { + b = _b; + } + + public int getB() { + return b; + } + + public int getBBB() { + return bbb; + } + + { + bbb = 123; + } + } + + static { + a = "a0"; + counter = 0; + } + + { + c_a = new A(); + } + + @Override + public boolean testRun() throws Exception { + assertTrue(counter == 0); + assertTrue(a.equals("a0")); + assertTrue(A.a.equals("a1")); + + B b1 = new B() { + { + TestInitializers.counter++; + setB(TestInitializers.counter); + } + }; + assertTrue(b1.getB() == 1); + + B b2 = new B() { + @SuppressWarnings("unused") + private int bb; + + public int getB() { + return super.getB(); + } + + { + bb = 100; + } + }; + assertTrue(b2.getB() == -1); + + assertTrue((new B()).getB() == -1); + assertTrue(counter == 1); + + B b3 = new B(3); + assertTrue((b3.getB() == 3) && (b3.getBBB() == 123)); + + return true; + } + + public static void main(String[] args) throws Exception { + new TestInitializers().testRun(); + } + +} diff --git a/jadx-samples/src/main/java/jadx/samples/TestInner3.java b/jadx-samples/src/main/java/jadx/samples/TestInner3.java new file mode 100644 index 000000000..0ffa7dcda --- /dev/null +++ b/jadx-samples/src/main/java/jadx/samples/TestInner3.java @@ -0,0 +1,86 @@ +package jadx.samples; + +public class TestInner3 extends AbstractTest { + + private String i0; + + public class A { + + protected String a; + + public A() { + a=""; + } + + public String a() { + return ""; + } + } + + public class I0 { + private String i0; + private String i1; + + public class I1 { + private String i0; + private String i1; + private String i2; + + public I1() { + TestInner3.this.i0 = "i0"; + I0.this.i0 = "i1"; + I0.this.i1 = "i2"; + + i0 = "i0"; + i1 = "i1"; + i2 = "i2"; + } + + public String i() { + + String result = TestInner3.this.i0 + I0.this.i0 + I0.this.i1 + i0 + i1 + i2; + + A a = new A() { + + public String a() { + TestInner3.this.i0 = "i1"; + I0.this.i0 = "i2"; + I0.this.i1 = "i3"; + I1.this.i0 = "i1"; + I1.this.i1 = "i2"; + I1.this.i2 = "i3"; + a = "a"; + + return TestInner3.this.i0 + I0.this.i0 + I0.this.i1 + I1.this.i0 + I1.this.i1 + I1.this.i2 + a; + } + }; + + return result + a.a(); + } + } + + public I0() { + TestInner3.this.i0 = "i-"; + i0 = "i0"; + i1 = "i1"; + } + + public String i() { + String result = TestInner3.this.i0 + i0 + i1; + return result + (new I1()).i(); + } + } + + @Override + public boolean testRun() throws Exception { + assertTrue((new I0()).i().equals("i-i0i1i0i1i2i0i1i2i1i2i3i1i2i3a")); + assertTrue(i0.equals("i1")); + + return true; + } + + public static void main(String[] args) throws Exception { + new TestInner2().testRun(); + } + +}