refactor: move constant collection into separate pass (#2119)

This commit is contained in:
Skylot
2024-03-30 21:51:02 +00:00
parent b865c9c687
commit ecdc4e6757
5 changed files with 73 additions and 38 deletions
@@ -54,6 +54,7 @@ import jadx.core.dex.visitors.debuginfo.DebugInfoApplyVisitor;
import jadx.core.dex.visitors.debuginfo.DebugInfoAttachVisitor;
import jadx.core.dex.visitors.finaly.MarkFinallyVisitor;
import jadx.core.dex.visitors.kotlin.ProcessKotlinInternals;
import jadx.core.dex.visitors.prepare.CollectConstValues;
import jadx.core.dex.visitors.regions.CheckRegions;
import jadx.core.dex.visitors.regions.CleanRegions;
import jadx.core.dex.visitors.regions.IfRegionVisitor;
@@ -96,6 +97,7 @@ public class Jadx {
List<IDexTreeVisitor> passes = new ArrayList<>();
passes.add(new SignatureProcessor());
passes.add(new OverrideMethodVisitor());
passes.add(new CollectConstValues());
// rename and deobfuscation
passes.add(new DeobfuscatorVisitor());
@@ -2,7 +2,6 @@ package jadx.core.dex.info;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -10,14 +9,13 @@ import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.Nullable;
import jadx.api.JadxArgs;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
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;
import jadx.core.dex.visitors.prepare.CollectConstValues;
public class ConstStorage {
@@ -75,18 +73,6 @@ public class ConstStorage {
this.replaceEnabled = args.isReplaceConsts();
}
public void processConstFields(List<FieldNode> staticFields) {
if (!replaceEnabled || staticFields.isEmpty()) {
return;
}
for (FieldNode f : staticFields) {
Object value = getFieldConstValue(f);
if (value != null) {
addConstField(f, value, f.getAccessFlags().isPublic());
}
}
}
public void addConstField(FieldNode fld, Object value, boolean isPublic) {
if (isPublic) {
addGlobalConstField(fld, value);
@@ -99,15 +85,12 @@ public class ConstStorage {
globalValues.put(value, fld);
}
/**
* Use method from CollectConstValues class
*/
@Deprecated
public static @Nullable Object getFieldConstValue(FieldNode fld) {
AccessInfo accFlags = fld.getAccessFlags();
if (accFlags.isStatic() && accFlags.isFinal()) {
EncodedValue constVal = fld.get(JadxAttrType.CONSTANT_VALUE);
if (constVal != null) {
return constVal.getValue();
}
}
return null;
return CollectConstValues.getFieldConstValue(fld);
}
public void removeForClass(ClassNode cls) {
@@ -9,7 +9,6 @@ import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -248,19 +247,15 @@ public class ClassNode extends NotificationAttrNode
if (fields.isEmpty()) {
return;
}
List<FieldNode> staticFields = fields.stream().filter(FieldNode::isStatic).collect(Collectors.toList());
for (FieldNode f : staticFields) {
if (f.getAccessFlags().isFinal() && f.get(JadxAttrType.CONSTANT_VALUE) == null) {
// incorrect initialization will be removed if assign found in constructor
f.addAttr(EncodedValue.NULL);
// bytecode can omit field initialization to 0 (of any type)
// add explicit init to all static final fields
// incorrect initializations will be removed if assign found in class init
for (FieldNode fld : fields) {
AccessInfo accFlags = fld.getAccessFlags();
if (accFlags.isStatic() && accFlags.isFinal() && fld.get(JadxAttrType.CONSTANT_VALUE) == null) {
fld.addAttr(EncodedValue.NULL);
}
}
try {
// process const fields
root().getConstValues().processConstFields(staticFields);
} catch (Exception e) {
this.addWarnComment("Failed to load initial values for static fields", e);
}
}
private boolean checkSourceFilenameAttr() {
@@ -0,0 +1,55 @@
package jadx.core.dex.visitors.prepare;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.ConstStorage;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.dex.visitors.JadxVisitor;
import jadx.core.utils.exceptions.JadxException;
@JadxVisitor(
name = "CollectConstValues",
desc = "Collect and store values from static final fields"
)
public class CollectConstValues extends AbstractVisitor {
@Override
public boolean visit(ClassNode cls) throws JadxException {
RootNode root = cls.root();
if (!root.getArgs().isReplaceConsts()) {
return true;
}
if (cls.getFields().isEmpty()) {
return true;
}
ConstStorage constStorage = root.getConstValues();
for (FieldNode fld : cls.getFields()) {
try {
Object value = getFieldConstValue(fld);
if (value != null) {
constStorage.addConstField(fld, value, fld.getAccessFlags().isPublic());
}
} catch (Exception e) {
cls.addWarnComment("Failed to process value of field: " + fld, e);
}
}
return true;
}
public static @Nullable Object getFieldConstValue(FieldNode fld) {
AccessInfo accFlags = fld.getAccessFlags();
if (accFlags.isStatic() && accFlags.isFinal()) {
EncodedValue constVal = fld.get(JadxAttrType.CONSTANT_VALUE);
if (constVal != null && constVal != EncodedValue.NULL) {
return constVal.getValue();
}
}
return null;
}
}