diff --git a/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java b/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java index ed6b224b0..826432a8c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java @@ -2,10 +2,8 @@ package jadx.core.dex.info; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -18,31 +16,32 @@ import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.RootNode; public class ConstStorage { private static final class ValueStorage { - private final Map values = new ConcurrentHashMap<>(); + private final Map values = new ConcurrentHashMap<>(); private final Set duplicates = new HashSet<>(); - public Map getValues() { + public Map getValues() { return values; } - public FieldNode get(Object key) { + public IFieldInfoRef get(Object key) { return values.get(key); } /** * @return true if this value is duplicated */ - public boolean put(Object value, FieldNode fld) { + public boolean put(Object value, IFieldInfoRef fld) { if (duplicates.contains(value)) { values.remove(value); return true; } - FieldNode prev = values.put(value, fld); + IFieldInfoRef prev = values.put(value, fld); if (prev != null) { values.remove(value); duplicates.add(value); @@ -56,14 +55,13 @@ public class ConstStorage { } void removeForCls(ClassNode cls) { - Iterator> it = values.entrySet().iterator(); - while (it.hasNext()) { - Entry entry = it.next(); - FieldNode field = entry.getValue(); - if (field.getParentClass().equals(cls)) { - it.remove(); + values.entrySet().removeIf(entry -> { + IFieldInfoRef field = entry.getValue(); + if (field instanceof FieldNode) { + return ((FieldNode) field).getParentClass().equals(cls); } - } + return false; + }); } } @@ -77,18 +75,30 @@ public class ConstStorage { this.replaceEnabled = args.isReplaceConsts(); } - public void processConstFields(ClassNode cls, List staticFields) { + public void processConstFields(List staticFields) { if (!replaceEnabled || staticFields.isEmpty()) { return; } for (FieldNode f : staticFields) { Object value = getFieldConstValue(f); if (value != null) { - addConstField(cls, f, value, f.getAccessFlags().isPublic()); + addConstField(f, value, f.getAccessFlags().isPublic()); } } } + public void addConstField(FieldNode fld, Object value, boolean isPublic) { + if (isPublic) { + addGlobalConstField(fld, value); + } else { + getClsValues(fld.getParentClass()).put(value, fld); + } + } + + public void addGlobalConstField(IFieldInfoRef fld, Object value) { + globalValues.put(value, fld); + } + public static @Nullable Object getFieldConstValue(FieldNode fld) { AccessInfo accFlags = fld.getAccessFlags(); if (accFlags.isStatic() && accFlags.isFinal()) { @@ -105,20 +115,11 @@ public class ConstStorage { globalValues.removeForCls(cls); } - private void addConstField(ClassNode cls, FieldNode fld, Object value, boolean isPublic) { - if (isPublic) { - globalValues.put(value, fld); - } else { - getClsValues(cls).put(value, fld); - } - } - private ValueStorage getClsValues(ClassNode cls) { return classes.computeIfAbsent(cls, c -> new ValueStorage()); } - @Nullable - public FieldNode getConstField(ClassNode cls, Object value, boolean searchGlobal) { + public @Nullable IFieldInfoRef getConstField(ClassNode cls, Object value, boolean searchGlobal) { if (!replaceEnabled) { return null; } @@ -137,7 +138,7 @@ public class ConstStorage { while (current != null) { ValueStorage classValues = classes.get(current); if (classValues != null) { - FieldNode field = classValues.get(value); + IFieldInfoRef field = classValues.get(value); if (field != null) { if (foundInGlobal) { return null; @@ -182,8 +183,7 @@ public class ConstStorage { return null; } - @Nullable - public FieldNode getConstFieldByLiteralArg(ClassNode cls, LiteralArg arg) { + public @Nullable IFieldInfoRef getConstFieldByLiteralArg(ClassNode cls, LiteralArg arg) { if (!replaceEnabled) { return null; } @@ -225,7 +225,7 @@ public class ConstStorage { return resourcesNames; } - public Map getGlobalConstFields() { + public Map getGlobalConstFields() { return globalValues.getValues(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java index 9aca16df1..89b01ad42 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java @@ -5,9 +5,10 @@ import java.util.Objects; import jadx.api.plugins.input.data.IFieldRef; import jadx.core.codegen.TypeGen; import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.RootNode; -public final class FieldInfo { +public final class FieldInfo implements IFieldInfoRef { private final ClassInfo declClass; private final String name; @@ -76,6 +77,11 @@ public final class FieldInfo { return name.equals(other.name) && type.equals(other.type); } + @Override + public FieldInfo getFieldInfo() { + return this; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index 9c89fb09a..1c401fbe7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -257,7 +257,7 @@ public class ClassNode extends NotificationAttrNode } try { // process const fields - root().getConstValues().processConstFields(this, staticFields); + root().getConstValues().processConstFields(staticFields); } catch (Exception e) { this.addWarnComment("Failed to load initial values for static fields", e); } @@ -513,17 +513,15 @@ public class ClassNode extends NotificationAttrNode fields.add(fld); } - public FieldNode getConstField(Object obj) { + public @Nullable IFieldInfoRef getConstField(Object obj) { return getConstField(obj, true); } - @Nullable - public FieldNode getConstField(Object obj, boolean searchGlobal) { + public @Nullable IFieldInfoRef getConstField(Object obj, boolean searchGlobal) { return root().getConstValues().getConstField(this, obj, searchGlobal); } - @Nullable - public FieldNode getConstFieldByLiteralArg(LiteralArg arg) { + public @Nullable IFieldInfoRef getConstFieldByLiteralArg(LiteralArg arg) { return root().getConstValues().getConstFieldByLiteralArg(this, arg); } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java index b73392ccd..892758425 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java @@ -12,7 +12,7 @@ import jadx.core.dex.info.FieldInfo; import jadx.core.dex.instructions.args.ArgType; import jadx.core.utils.ListUtils; -public class FieldNode extends NotificationAttrNode implements ICodeNode { +public class FieldNode extends NotificationAttrNode implements ICodeNode, IFieldInfoRef { private final ClassNode parentClass; private final FieldInfo fieldInfo; @@ -46,6 +46,7 @@ public class FieldNode extends NotificationAttrNode implements ICodeNode { this.type = type; } + @Override public FieldInfo getFieldInfo() { return fieldInfo; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/IFieldInfoRef.java b/jadx-core/src/main/java/jadx/core/dex/nodes/IFieldInfoRef.java new file mode 100644 index 000000000..654071f83 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/IFieldInfoRef.java @@ -0,0 +1,10 @@ +package jadx.core.dex.nodes; + +import jadx.core.dex.info.FieldInfo; + +/** + * Common interface for FieldInfo and FieldNode + */ +public interface IFieldInfoRef { + FieldInfo getFieldInfo(); +} diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java index 474aada1b..a86c09252 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlineVisitor.java @@ -18,7 +18,7 @@ import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.mods.ConstructorInsn; import jadx.core.dex.nodes.BlockNode; -import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.visitors.finaly.MarkFinallyVisitor; @@ -82,7 +82,7 @@ public class ConstInlineVisitor extends AbstractVisitor { } case CONST_STR: { String s = ((ConstStringNode) insn).getString(); - FieldNode f = mth.getParentClass().getConstField(s); + IFieldInfoRef f = mth.getParentClass().getConstField(s); if (f == null) { InsnNode copy = insn.copyWithoutResult(); constArg = InsnArg.wrapArg(copy); @@ -90,7 +90,7 @@ public class ConstInlineVisitor extends AbstractVisitor { InsnNode constGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); constArg = InsnArg.wrapArg(constGet); constArg.setType(ArgType.STRING); - onSuccess = () -> f.addUseIn(mth); + onSuccess = () -> ModVisitor.addFieldUsage(f, mth); } break; } @@ -251,7 +251,7 @@ public class ConstInlineVisitor extends AbstractVisitor { return false; } // arg replaced, made some optimizations - FieldNode fieldNode = null; + IFieldInfoRef fieldNode = null; ArgType litArgType = litArg.getType(); if (litArgType.isTypeKnown()) { fieldNode = mth.getParentClass().getConstFieldByLiteralArg(litArg); @@ -261,7 +261,7 @@ public class ConstInlineVisitor extends AbstractVisitor { if (fieldNode != null) { IndexInsnNode sgetInsn = new IndexInsnNode(InsnType.SGET, fieldNode.getFieldInfo(), 0); if (litArg.wrapInstruction(mth, sgetInsn) != null) { - fieldNode.addUseIn(mth); + ModVisitor.addFieldUsage(fieldNode, mth); } } else { addExplicitCast(useInsn, litArg); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index ad6ae92d9..7cde76d31 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -44,6 +44,7 @@ import jadx.core.dex.instructions.mods.TernaryInsn; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.IMethodDetails; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; @@ -239,10 +240,10 @@ public class ModVisitor extends AbstractVisitor { int[] keys = insn.getKeys(); int len = keys.length; for (int k = 0; k < len; k++) { - FieldNode f = parentClass.getConstField(keys[k]); + IFieldInfoRef f = parentClass.getConstField(keys[k]); if (f != null) { insn.modifyKey(k, f); - f.addUseIn(mth); + addFieldUsage(f, mth); } } } @@ -313,7 +314,7 @@ public class ModVisitor extends AbstractVisitor { } return new EncodedValue(EncodedType.ENCODED_ARRAY, listVal); } - FieldNode constField = parentCls.getConstField(encodedValue.getValue()); + IFieldInfoRef constField = parentCls.getConstField(encodedValue.getValue()); if (constField != null) { return new EncodedValue(EncodedType.ENCODED_FIELD, constField.getFieldInfo()); } @@ -321,7 +322,7 @@ public class ModVisitor extends AbstractVisitor { } private static void replaceConst(MethodNode mth, ClassNode parentClass, BlockNode block, int i, InsnNode insn) { - FieldNode f; + IFieldInfoRef f; if (insn.getType() == InsnType.CONST_STR) { String s = ((ConstStringNode) insn).getString(); f = parentClass.getConstField(s); @@ -335,7 +336,7 @@ public class ModVisitor extends AbstractVisitor { InsnNode inode = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); inode.setResult(insn.getResult()); replaceInsn(mth, block, i, inode); - f.addUseIn(mth); + addFieldUsage(f, mth); } } @@ -345,11 +346,11 @@ public class ModVisitor extends AbstractVisitor { } InsnArg litArg = arithNode.getArg(1); if (litArg.isLiteral()) { - FieldNode f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg); + IFieldInfoRef f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg); if (f != null) { InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); if (arithNode.replaceArg(litArg, InsnArg.wrapArg(fGet))) { - f.addUseIn(mth); + addFieldUsage(f, mth); } } } @@ -566,11 +567,11 @@ public class ModVisitor extends AbstractVisitor { InsnNode filledArr = new FilledNewArrayNode(elType, list.size()); filledArr.setResult(newArrayNode.getResult().duplicate()); for (LiteralArg arg : list) { - FieldNode f = mth.getParentClass().getConstFieldByLiteralArg(arg); + IFieldInfoRef f = mth.getParentClass().getConstFieldByLiteralArg(arg); if (f != null) { InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); filledArr.addArg(InsnArg.wrapArg(fGet)); - f.addUseIn(mth); + addFieldUsage(f, mth); } else { filledArr.addArg(arg.duplicate()); } @@ -607,4 +608,10 @@ public class ModVisitor extends AbstractVisitor { } block.copyAttributeFrom(insn, AType.CODE_COMMENTS); // save comment } + + public static void addFieldUsage(IFieldInfoRef fieldData, MethodNode mth) { + if (fieldData instanceof FieldNode) { + ((FieldNode) fieldData).addUseIn(mth); + } + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java index c95918d99..dc99ceaaa 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java @@ -16,7 +16,7 @@ import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.BlockNode; -import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; @@ -167,11 +167,11 @@ public class ReplaceNewArray extends AbstractVisitor { private static InsnArg replaceConstInArg(MethodNode mth, InsnArg valueArg) { if (valueArg.isLiteral()) { - FieldNode f = mth.getParentClass().getConstFieldByLiteralArg((LiteralArg) valueArg); + IFieldInfoRef f = mth.getParentClass().getConstFieldByLiteralArg((LiteralArg) valueArg); if (f != null) { InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0); InsnArg arg = InsnArg.wrapArg(fGet); - f.addUseIn(mth); + ModVisitor.addFieldUsage(f, mth); return arg; } } diff --git a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java index df786a01a..2e737f23b 100644 --- a/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java @@ -170,18 +170,17 @@ public class AndroidResourcesUtils { private static Map fillResFieldsMap(ClassNode resCls) { Map resFieldsMap = new HashMap<>(); ConstStorage constStorage = resCls.root().getConstValues(); - Map constFields = constStorage.getGlobalConstFields(); - for (Map.Entry entry : constFields.entrySet()) { - Object key = entry.getKey(); - FieldNode field = entry.getValue(); - AccessInfo accessFlags = field.getAccessFlags(); - if (field.getType().equals(ArgType.INT) - && accessFlags.isStatic() - && accessFlags.isFinal() + constStorage.getGlobalConstFields().forEach((key, field) -> { + if (field.getFieldInfo().getType().equals(ArgType.INT) + && field instanceof FieldNode && key instanceof Integer) { - resFieldsMap.put((Integer) key, field); + FieldNode fldNode = (FieldNode) field; + AccessInfo accessFlags = fldNode.getAccessFlags(); + if (accessFlags.isStatic() && accessFlags.isFinal()) { + resFieldsMap.put((Integer) key, fldNode); + } } - } + }); return resFieldsMap; } } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java index d384020e5..7a0e2cbd2 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -22,6 +22,7 @@ import jadx.api.plugins.utils.ZipSecurity; import jadx.core.deobf.NameMapper; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.nodes.FieldNode; +import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.RootNode; import jadx.core.utils.BetterName; import jadx.core.utils.exceptions.JadxRuntimeException; @@ -417,7 +418,8 @@ public class ResTableParser extends CommonBinaryParser implements IResParser { if (typeName.equals("style")) { return origKeyName; } - FieldNode constField = root.getConstValues().getGlobalConstFields().get(resRef); + IFieldInfoRef fldRef = root.getConstValues().getGlobalConstFields().get(resRef); + FieldNode constField = fldRef instanceof FieldNode ? (FieldNode) fldRef : null; String resAlias = getResAlias(resRef, origKeyName, constField); resStorage.addRename(resRef, resAlias); if (constField != null) {