From 37b57096ec12b8f9c907f712730faddd539dd63f Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 11 Apr 2024 18:55:41 +0100 Subject: [PATCH] fix: allow use `FieldInfo` as switch key (#2147) --- .../main/java/jadx/core/clsp/ClspClass.java | 6 +++ .../java/jadx/core/codegen/RegionGen.java | 43 +++++++++++++------ .../android/TestResConstReplace2.java | 33 ++++++++++++++ 3 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/android/TestResConstReplace2.java diff --git a/jadx-core/src/main/java/jadx/core/clsp/ClspClass.java b/jadx-core/src/main/java/jadx/core/clsp/ClspClass.java index 30ac8b727..4cfb344e8 100644 --- a/jadx-core/src/main/java/jadx/core/clsp/ClspClass.java +++ b/jadx-core/src/main/java/jadx/core/clsp/ClspClass.java @@ -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; } diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 69916091d..666d54a32 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -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 {"); diff --git a/jadx-core/src/test/java/jadx/tests/integration/android/TestResConstReplace2.java b/jadx-core/src/test/java/jadx/tests/integration/android/TestResConstReplace2.java new file mode 100644 index 000000000..7dfe8c5f0 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/android/TestResConstReplace2.java @@ -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:"); + } +}