fix: allow use FieldInfo as switch key (#2147)

This commit is contained in:
Skylot
2024-04-11 18:55:41 +01:00
parent 6aab8fabc9
commit 37b57096ec
3 changed files with 69 additions and 13 deletions
@@ -7,6 +7,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.intellij.lang.annotations.MagicConstant;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.core.dex.instructions.args.ArgType;
@@ -51,6 +53,10 @@ public class ClspClass {
return AccessFlags.hasFlag(accFlags, AccessFlags.INTERFACE);
}
public boolean hasAccFlag(@MagicConstant(flagsFromClass = AccessFlags.class) int flags) {
return AccessFlags.hasFlag(accFlags, flags);
}
public ArgType[] getParents() {
return parents;
}
@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -12,8 +13,10 @@ import jadx.api.CommentsLevel;
import jadx.api.ICodeWriter;
import jadx.api.metadata.annotations.InsnCodeOffset;
import jadx.api.metadata.annotations.VarNode;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.core.clsp.ClspClass;
import jadx.core.codegen.utils.CodeGenUtils;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
@@ -21,6 +24,7 @@ import jadx.core.dex.attributes.nodes.DeclareVariablesAttr;
import jadx.core.dex.attributes.nodes.ForceReturnAttr;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.instructions.SwitchInsn;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.CodeVar;
@@ -268,19 +272,10 @@ public class RegionGen extends InsnGen {
private void addCaseKey(ICodeWriter code, InsnArg arg, Object k) throws CodegenException {
if (k instanceof FieldNode) {
FieldNode fn = (FieldNode) k;
if (fn.getParentClass().isEnum()) {
code.add(fn.getAlias());
} else {
staticField(code, fn.getFieldInfo());
if (mth.checkCommentsLevel(CommentsLevel.INFO)) {
// print original value, sometimes replaced with incorrect field
EncodedValue constVal = fn.get(JadxAttrType.CONSTANT_VALUE);
if (constVal != null && constVal.getValue() != null) {
code.add(" /* ").add(constVal.getValue().toString()).add(" */");
}
}
}
FieldNode fld = (FieldNode) k;
useField(code, fld.getFieldInfo(), fld);
} else if (k instanceof FieldInfo) {
useField(code, (FieldInfo) k, null);
} else if (k instanceof Integer) {
code.add(TypeGen.literalToString((Integer) k, arg.getType(), mth, fallback));
} else {
@@ -288,6 +283,28 @@ public class RegionGen extends InsnGen {
}
}
private void useField(ICodeWriter code, FieldInfo fldInfo, @Nullable FieldNode fld) throws CodegenException {
boolean isEnum;
if (fld != null) {
isEnum = fld.getParentClass().isEnum();
} else {
ClspClass clsDetails = root.getClsp().getClsDetails(fldInfo.getDeclClass().getType());
isEnum = clsDetails != null && clsDetails.hasAccFlag(AccessFlags.ENUM);
}
if (isEnum) {
code.add(fldInfo.getAlias());
return;
}
staticField(code, fldInfo);
if (fld != null && mth.checkCommentsLevel(CommentsLevel.INFO)) {
// print original value, sometimes replaced with incorrect field
EncodedValue constVal = fld.get(JadxAttrType.CONSTANT_VALUE);
if (constVal != null && constVal.getValue() != null) {
code.add(" /* ").add(constVal.getValue().toString()).add(" */");
}
}
}
public void makeTryCatch(TryCatchRegion region, ICodeWriter code) throws CodegenException {
code.startLine("try {");
@@ -0,0 +1,33 @@
package jadx.tests.integration.android;
import org.junit.jupiter.api.Test;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestResConstReplace2 extends IntegrationTest {
public static class TestCls {
public int test(int i) {
switch (i) {
case 0x0101013f: // android.R.attr.minWidth
return 1;
case 0x01010140: // android.R.attr.minHeight
return 2;
default:
return 0;
}
}
}
@Test
public void test() {
disableCompilation();
assertThat(getClassNode(TestCls.class))
.code()
.containsOne("import android.R;")
.containsOne("case R.attr.minWidth:");
}
}