fix: replace constants inside annotations (#831)
This commit is contained in:
@@ -52,6 +52,8 @@ public class ClassGen {
|
||||
private final Set<ClassInfo> imports = new HashSet<>();
|
||||
private int clsDeclLine;
|
||||
|
||||
private boolean bodyGenStarted;
|
||||
|
||||
public ClassGen(ClassNode cls, JadxArgs jadxArgs) {
|
||||
this(cls, null, jadxArgs.isUseImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode());
|
||||
}
|
||||
@@ -222,6 +224,7 @@ public class ClassGen {
|
||||
|
||||
public void addClassBody(CodeWriter clsCode) throws CodegenException {
|
||||
clsCode.add('{');
|
||||
setBodyGenStarted(true);
|
||||
clsDeclLine = clsCode.getLine();
|
||||
clsCode.incIndent();
|
||||
addFields(clsCode);
|
||||
@@ -656,4 +659,12 @@ public class ClassGen {
|
||||
public boolean isFallbackMode() {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public boolean isBodyGenStarted() {
|
||||
return bodyGenStarted;
|
||||
}
|
||||
|
||||
public void setBodyGenStarted(boolean bodyGenStarted) {
|
||||
this.bodyGenStarted = bodyGenStarted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ public class InsnGen {
|
||||
ClassInfo declClass = field.getDeclClass();
|
||||
// TODO
|
||||
boolean fieldFromThisClass = clsGen.getClassNode().getClassInfo().equals(declClass);
|
||||
if (!fieldFromThisClass) {
|
||||
if (!fieldFromThisClass || !clsGen.isBodyGenStarted()) {
|
||||
// Android specific resources class handler
|
||||
if (!handleAppResField(code, clsGen, declClass)) {
|
||||
clsGen.useClass(code, declClass);
|
||||
|
||||
@@ -11,6 +11,9 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttrNode;
|
||||
import jadx.core.dex.attributes.annotations.Annotation;
|
||||
import jadx.core.dex.attributes.annotations.AnnotationsList;
|
||||
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
@@ -46,6 +49,7 @@ import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.InsnRemover;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.utils.BlockUtils.replaceInsn;
|
||||
@@ -68,6 +72,12 @@ public class ModVisitor extends AbstractVisitor {
|
||||
private static final long DOUBLE_TO_BITS = Double.doubleToLongBits(1);
|
||||
private static final long FLOAT_TO_BITS = Float.floatToIntBits(1);
|
||||
|
||||
@Override
|
||||
public boolean visit(ClassNode cls) throws JadxException {
|
||||
replaceConstInAnnotations(cls);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) {
|
||||
if (mth.isNoCode()) {
|
||||
@@ -171,6 +181,33 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceConstInAnnotations(ClassNode cls) {
|
||||
if (cls.root().getArgs().isReplaceConsts()) {
|
||||
replaceConstsInAnnotationForAttrNode(cls, cls);
|
||||
cls.getFields().forEach(f -> replaceConstsInAnnotationForAttrNode(cls, f));
|
||||
cls.getMethods().forEach(m -> replaceConstsInAnnotationForAttrNode(cls, m));
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceConstsInAnnotationForAttrNode(ClassNode parentCls, AttrNode attrNode) {
|
||||
AnnotationsList annotationsList = attrNode.get(AType.ANNOTATION_LIST);
|
||||
if (annotationsList == null) {
|
||||
return;
|
||||
}
|
||||
for (Annotation annotation : annotationsList.getAll()) {
|
||||
if (annotation.getVisibility() == Annotation.Visibility.SYSTEM) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<String, Object> entry : annotation.getValues().entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
FieldNode constField = parentCls.getConstField(value);
|
||||
if (constField != null) {
|
||||
entry.setValue(constField.getFieldInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceConst(MethodNode mth, ClassNode parentClass, BlockNode block, int i, InsnNode insn) {
|
||||
FieldNode f;
|
||||
if (insn.getType() == InsnType.CONST_STR) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package jadx.tests.integration.inner;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestRFieldRestore3 extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
@T(2131230730)
|
||||
public static class A {
|
||||
@F(2131230730)
|
||||
private int f;
|
||||
|
||||
@M(bind = 2137373737)
|
||||
private void mth() {
|
||||
}
|
||||
|
||||
@T(2137373737)
|
||||
private class D {
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface T {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD })
|
||||
@interface F {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD })
|
||||
@interface M {
|
||||
int bind();
|
||||
}
|
||||
|
||||
public static class R {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Map<Integer, String> map = new HashMap<>();
|
||||
map.put(2131230730, "id.Button");
|
||||
map.put(2137373737, "id.MyId");
|
||||
setResMap(map);
|
||||
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOnlyOnce("@T(R.id.Button)")
|
||||
.containsOnlyOnce("@T(R.id.MyId)")
|
||||
.containsOnlyOnce("@F(R.id.Button)")
|
||||
.containsOnlyOnce("@M(bind = R.id.MyId)");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package jadx.tests.integration.inner;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestReplaceConstsInAnnotations extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface A {
|
||||
int i();
|
||||
|
||||
float f();
|
||||
}
|
||||
|
||||
@A(i = -1, f = C.FLOAT_CONST)
|
||||
public static class C {
|
||||
public static final float FLOAT_CONST = 3.14f;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOnlyOnce("f = C.FLOAT_CONST");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user