Commit eed65421 authored by Skylot's avatar Skylot

core: fix incorrect argument removing in anonymous constructor, inline...

core: fix incorrect argument removing in anonymous constructor, inline synthetic field increment method
parent 7accc6e5
......@@ -53,7 +53,8 @@ public class ClassModifier extends AbstractVisitor {
ClassNode fieldsCls = cls.dex().resolveClass(ClassInfo.fromType(field.getType()));
ClassInfo parentClass = cls.getClassInfo().getParentClass();
if (fieldsCls != null
&& parentClass.equals(fieldsCls.getClassInfo())) {
&& parentClass.equals(fieldsCls.getClassInfo())
&& field.getName().startsWith("this$") /* TODO: don't check name */) {
int found = 0;
for (MethodNode mth : cls.getMethods()) {
if (removeFieldUsageFromConstructor(mth, field, fieldsCls)) {
......@@ -75,7 +76,7 @@ public class ClassModifier extends AbstractVisitor {
return false;
}
List<RegisterArg> args = mth.getArguments(false);
if (args.isEmpty()) {
if (args.isEmpty() || mth.contains(AFlag.SKIP_FIRST_ARG)) {
return false;
}
RegisterArg arg = args.get(0);
......
......@@ -3,11 +3,17 @@ package jadx.core.dex.visitors;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.nodes.MethodInlineAttr;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.exceptions.JadxException;
import java.util.List;
/**
* Inline synthetic methods.
*/
......@@ -19,26 +25,48 @@ public class MethodInlineVisitor extends AbstractVisitor {
if (accessFlags.isSynthetic()
&& accessFlags.isStatic()
&& mth.getBasicBlocks().size() == 2) {
BlockNode block = mth.getBasicBlocks().get(1);
if (block.getInstructions().isEmpty()
|| block.contains(AFlag.RETURN)) {
inlineMth(mth);
BlockNode returnBlock = mth.getBasicBlocks().get(1);
if (returnBlock.contains(AFlag.RETURN) || returnBlock.getInstructions().isEmpty()) {
BlockNode firstBlock = mth.getBasicBlocks().get(0);
inlineMth(mth, firstBlock, returnBlock);
}
}
}
private static void inlineMth(MethodNode mth) {
BlockNode firstBlock = mth.getBasicBlocks().get(0);
if (firstBlock.getInstructions().isEmpty()) {
private static void inlineMth(MethodNode mth, BlockNode firstBlock, BlockNode returnBlock) {
List<InsnNode> insnList = firstBlock.getInstructions();
if (insnList.isEmpty()) {
// synthetic field getter
BlockNode block = mth.getBasicBlocks().get(1);
InsnNode insn = block.getInstructions().get(0);
// set arg from 'return' instruction
addInlineAttr(mth, InsnNode.wrapArg(insn.getArg(0)));
} else {
// synthetic field setter or method invoke
if (firstBlock.getInstructions().size() == 1) {
addInlineAttr(mth, firstBlock.getInstructions().get(0));
return;
}
// synthetic field setter or method invoke
if (insnList.size() == 1) {
addInlineAttr(mth, insnList.get(0));
return;
}
// other field operations
if (insnList.size() == 2
&& returnBlock.getInstructions().size() == 1
&& !mth.getReturnType().equals(ArgType.VOID)) {
InsnNode get = insnList.get(0);
InsnNode put = insnList.get(1);
InsnArg retArg = returnBlock.getInstructions().get(0).getArg(0);
if (get.getType() == InsnType.IGET
&& put.getType() == InsnType.IPUT
&& retArg.isRegister()
&& get.getResult().equalRegisterAndType((RegisterArg) retArg)) {
RegisterArg retReg = (RegisterArg) retArg;
retReg.getSVar().removeUse(retReg);
CodeShrinker.shrinkMethod(mth);
insnList = firstBlock.getInstructions();
if (insnList.size() == 1) {
addInlineAttr(mth, insnList.get(0));
}
}
}
}
......
package jadx.tests.integration.inner;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
public class TestAnonymousClass5 extends IntegrationTest {
public static class TestCls {
private final Map<String, TestCls> map = new HashMap<String, TestCls>();
private int a;
public Iterable<TestCls> test(String name) {
final TestCls cls = map.get(name);
if (cls == null) {
return null;
}
final int listSize = cls.size();
final Iterator<TestCls> iterator = new Iterator<TestCls>() {
int counter = 0;
@Override
public TestCls next() {
cls.a++;
counter++;
return cls;
}
@Override
public boolean hasNext() {
return counter < listSize;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return new Iterable<TestCls>() {
@Override
public Iterator<TestCls> iterator() {
return iterator;
}
};
}
private int size() {
return 7;
}
public void check() {
TestCls v = new TestCls();
v.a = 3;
map.put("a", v);
Iterable<TestCls> it = test("a");
TestCls next = it.iterator().next();
assertThat(next, sameInstance(v));
assertThat(next.a, is(4));
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("map.get(name);"));
assertThat(code, not(containsString("access$008")));
// TODO
// assertThat(code, not(containsString("synthetic")));
}
}
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