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 d0c07388d..36339048e 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -36,6 +36,7 @@ import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; +import jadx.core.utils.ErrorsCounter; import jadx.core.utils.RegionUtils; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.CodegenException; @@ -44,10 +45,8 @@ import jadx.core.utils.exceptions.JadxRuntimeException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import org.jetbrains.annotations.Nullable; @@ -557,6 +556,11 @@ public class InsnGen { private void inlineAnonymousConstr(CodeWriter code, ClassNode cls, ConstructorInsn insn) throws CodegenException { // anonymous class construction + if (cls.contains(AFlag.DONT_GENERATE)) { + code.add("/* anonymous class already generated */"); + ErrorsCounter.methodError(mth, "Anonymous class already generated: " + cls); + return; + } ArgType parent; if (cls.getInterfaces().size() == 1) { parent = cls.getInterfaces().get(0); @@ -734,9 +738,9 @@ public class InsnGen { regs[callArg.getRegNum()] = arg; } // replace args + InsnNode inlCopy = inl.copy(); List inlArgs = new ArrayList(); - inl.getRegisterArgs(inlArgs); - Map toRevert = new HashMap(); + inlCopy.getRegisterArgs(inlArgs); for (RegisterArg r : inlArgs) { int regNum = r.getRegNum(); if (regNum >= regs.length) { @@ -746,16 +750,11 @@ public class InsnGen { if (repl == null) { LOG.warn("Not passed register {} in method call: {} from {}", r, callMthNode, mth); } else { - inl.replaceArg(r, repl); - toRevert.put(r, repl); + inlCopy.replaceArg(r, repl); } } } - makeInsn(inl, code, Flags.BODY_ONLY); - // revert changes in 'MethodInlineAttr' - for (Map.Entry e : toRevert.entrySet()) { - inl.replaceArg(e.getValue(), e.getKey()); - } + makeInsn(inlCopy, code, Flags.BODY_ONLY); } return true; } diff --git a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java index 62f31cccb..25905b1b9 100644 --- a/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java +++ b/jadx-core/src/main/java/jadx/core/utils/ErrorsCounter.java @@ -57,8 +57,8 @@ public class ErrorsCounter { return msg; } - public static String classError(ClassNode mth, String errorMsg) { - return classError(mth, errorMsg, null); + public static String classError(ClassNode cls, String errorMsg) { + return classError(cls, errorMsg, null); } public static String methodError(MethodNode mth, String errorMsg, Throwable e) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass12.java b/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass12.java new file mode 100644 index 000000000..c38d130f8 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass12.java @@ -0,0 +1,46 @@ +package jadx.tests.integration.inner; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestAnonymousClass12 extends IntegrationTest { + + public static class TestCls { + + public abstract static class BasicAbstract { + public abstract void doSomething(); + } + + private BasicAbstract outer; + private BasicAbstract inner; + + public void test() { + outer = new BasicAbstract() { + @Override + public void doSomething() { + inner = new BasicAbstract() { + @Override + public void doSomething() { + inner = null; + } + }; + } + }; + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("outer = new BasicAbstract() {")); + assertThat(code, containsOne("inner = new BasicAbstract() {")); + assertThat(code, containsOne("inner = null;")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass5.java b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass5.java new file mode 100644 index 000000000..1f5e5b707 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass5.java @@ -0,0 +1,99 @@ +package jadx.tests.integration.inner; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class TestInnerClass5 extends IntegrationTest { + + public static class TestCls { + + 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() { + TestCls.this.i0 = "i0"; + I0.this.i0 = "i1"; + I0.this.i1 = "i2"; + + i0 = "i0"; + i1 = "i1"; + i2 = "i2"; + } + + public String i() { + + String result = TestCls.this.i0 + I0.this.i0 + I0.this.i1 + i0 + i1 + i2; + + A a = new A() { + + public String a() { + TestCls.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 TestCls.this.i0 + I0.this.i0 + I0.this.i1 + I1.this.i0 + I1.this.i1 + I1.this.i2 + a; + } + }; + + return result + a.a(); + } + } + + public I0() { + TestCls.this.i0 = "i-"; + i0 = "i0"; + i1 = "i1"; + } + + public String i() { + String result = TestCls.this.i0 + i0 + i1; + return result + new I1().i(); + } + } + + public void check() throws Exception { + assertTrue(new I0().i().equals("i-i0i1i0i1i2i0i1i2i1i2i3i1i2i3a")); + assertTrue(i0.equals("i1")); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("public class I0 {")); + assertThat(code, containsOne("public class I1 {")); + } +}