Commit 04e50afa authored by Skylot's avatar Skylot

core: fix synthetic method inline (fix #71)

parent 69494c92
......@@ -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<RegisterArg> inlArgs = new ArrayList<RegisterArg>();
inl.getRegisterArgs(inlArgs);
Map<RegisterArg, InsnArg> toRevert = new HashMap<RegisterArg, InsnArg>();
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<RegisterArg, InsnArg> e : toRevert.entrySet()) {
inl.replaceArg(e.getValue(), e.getKey());
}
makeInsn(inlCopy, code, Flags.BODY_ONLY);
}
return true;
}
......
......@@ -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) {
......
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;"));
}
}
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 {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment