core: fix 'this' reference in anonymous classes
This commit is contained in:
@@ -2,6 +2,7 @@ package jadx.core.codegen;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.FieldReplaceAttr;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.dex.attributes.MethodInlineAttr;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
@@ -141,8 +142,15 @@ public class InsnGen {
|
||||
|
||||
private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
|
||||
FieldNode fieldNode = mth.getParentClass().searchField(field);
|
||||
if (fieldNode != null && fieldNode.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
|
||||
return;
|
||||
if (fieldNode != null) {
|
||||
FieldReplaceAttr replace = (FieldReplaceAttr) fieldNode.getAttributes().get(AttributeType.FIELD_REPLACE);
|
||||
if (replace != null) {
|
||||
FieldInfo info = replace.getFieldInfo();
|
||||
if (replace.isOuterClass()) {
|
||||
code.add(useClass(info.getDeclClass())).add(".this");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
int len = code.length();
|
||||
addArg(code, arg);
|
||||
|
||||
@@ -19,6 +19,7 @@ public enum AttributeType {
|
||||
|
||||
JADX_ERROR(true),
|
||||
METHOD_INLINE(true),
|
||||
FIELD_REPLACE(true),
|
||||
|
||||
ENUM_CLASS(true),
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package jadx.core.dex.attributes;
|
||||
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
|
||||
public class FieldReplaceAttr implements IAttribute {
|
||||
|
||||
private final FieldInfo fieldInfo;
|
||||
private final boolean isOuterClass;
|
||||
|
||||
public FieldReplaceAttr(FieldInfo fieldInfo, boolean isOuterClass) {
|
||||
this.fieldInfo = fieldInfo;
|
||||
this.isOuterClass = isOuterClass;
|
||||
}
|
||||
|
||||
public FieldInfo getFieldInfo() {
|
||||
return fieldInfo;
|
||||
}
|
||||
|
||||
public boolean isOuterClass() {
|
||||
return isOuterClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeType getType() {
|
||||
return AttributeType.FIELD_REPLACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "REPLACE: " + fieldInfo;
|
||||
}
|
||||
}
|
||||
@@ -7,20 +7,22 @@ import com.android.dx.io.FieldId;
|
||||
|
||||
public class FieldInfo {
|
||||
|
||||
private final ClassInfo declClass;
|
||||
private final String name;
|
||||
private final ArgType type;
|
||||
|
||||
private final ClassInfo declClass;
|
||||
|
||||
public static FieldInfo fromDex(DexNode dex, int index) {
|
||||
return new FieldInfo(dex, index);
|
||||
FieldId field = dex.getFieldId(index);
|
||||
return new FieldInfo(
|
||||
ClassInfo.fromDex(dex, field.getDeclaringClassIndex()),
|
||||
dex.getString(field.getNameIndex()),
|
||||
dex.getType(field.getTypeIndex()));
|
||||
}
|
||||
|
||||
private FieldInfo(DexNode dex, int ind) {
|
||||
FieldId field = dex.getFieldId(ind);
|
||||
this.name = dex.getString(field.getNameIndex());
|
||||
this.type = dex.getType(field.getTypeIndex());
|
||||
this.declClass = ClassInfo.fromDex(dex, field.getDeclaringClassIndex());
|
||||
public FieldInfo(ClassInfo declClass, String name, ArgType type) {
|
||||
this.declClass = declClass;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static String getNameById(DexNode dex, int ind) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributesList;
|
||||
import jadx.core.dex.attributes.FieldReplaceAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
@@ -48,24 +50,27 @@ public class ClassModifier extends AbstractVisitor {
|
||||
for (FieldNode field : cls.getFields()) {
|
||||
if (field.getAccessFlags().isSynthetic() && field.getType().isObject()) {
|
||||
ClassNode fieldsCls = cls.dex().resolveClass(ClassInfo.fromType(field.getType()));
|
||||
ClassInfo parentClass = cls.getClassInfo().getParentClass();
|
||||
if (fieldsCls != null
|
||||
&& cls.getClassInfo().getParentClass().equals(fieldsCls.getClassInfo())) {
|
||||
&& parentClass.equals(fieldsCls.getClassInfo())) {
|
||||
int found = 0;
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
if (removeFieldUsage(field, fieldsCls, mth)) {
|
||||
if (removeFieldUsageFromConstructor(mth, field, fieldsCls)) {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (found != 0) {
|
||||
// TODO: make new flag for skip field generation and usage
|
||||
field.getAttributes().add(AttributeFlag.DONT_GENERATE);
|
||||
AttributesList attributes = field.getAttributes();
|
||||
FieldInfo replace = new FieldInfo(parentClass, "this", parentClass.getType());
|
||||
attributes.add(new FieldReplaceAttr(replace, true));
|
||||
attributes.add(AttributeFlag.DONT_GENERATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean removeFieldUsage(FieldNode field, ClassNode fieldsCls, MethodNode mth) {
|
||||
private static boolean removeFieldUsageFromConstructor(MethodNode mth, FieldNode field, ClassNode fieldsCls) {
|
||||
if (!mth.getAccessFlags().isConstructor()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,11 @@ public class TestSyntheticInline extends InternalJadxTest {
|
||||
assertThat(code, not(containsString("synthetic")));
|
||||
assertThat(code, not(containsString("access$")));
|
||||
assertThat(code, not(containsString("x0")));
|
||||
assertThat(code, containsString("return f;"));
|
||||
assertThat(code, containsString("return func();"));
|
||||
assertThat(code, containsString("f = v;"));
|
||||
// assertThat(code, containsString("return f;"));
|
||||
// assertThat(code, containsString("return func();"));
|
||||
// Temporary solution
|
||||
assertThat(code, containsString("return TestSyntheticInline$TestCls.this.f;"));
|
||||
assertThat(code, containsString("return TestSyntheticInline$TestCls.this.func();"));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.tests.internal;
|
||||
package jadx.tests.internal.inner;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
@@ -0,0 +1,62 @@
|
||||
package jadx.tests.internal.inner;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestAnonymousClass2 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
public static class Inner {
|
||||
private int f;
|
||||
|
||||
public Runnable test() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
f = 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Runnable test2() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Object obj = Inner.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
/*
|
||||
public Runnable test3() {
|
||||
final int i = f + 2;
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
f = i;
|
||||
}
|
||||
};
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, not(containsString("synthetic")));
|
||||
assertThat(code, not(containsString("AnonymousClass_")));
|
||||
assertThat(code, containsString("f = 1;"));
|
||||
// assertThat(code, containsString("f = i;"));
|
||||
assertThat(code, not(containsString("Inner obj = ;")));
|
||||
assertThat(code, containsString("Inner.this;"));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.tests.internal;
|
||||
package jadx.tests.internal.inner;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.tests.internal;
|
||||
package jadx.tests.internal.inner;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
Reference in New Issue
Block a user