refactor: move constant collection into separate pass (#2119)
This commit is contained in:
@@ -54,6 +54,7 @@ import jadx.core.dex.visitors.debuginfo.DebugInfoApplyVisitor;
|
|||||||
import jadx.core.dex.visitors.debuginfo.DebugInfoAttachVisitor;
|
import jadx.core.dex.visitors.debuginfo.DebugInfoAttachVisitor;
|
||||||
import jadx.core.dex.visitors.finaly.MarkFinallyVisitor;
|
import jadx.core.dex.visitors.finaly.MarkFinallyVisitor;
|
||||||
import jadx.core.dex.visitors.kotlin.ProcessKotlinInternals;
|
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.CheckRegions;
|
||||||
import jadx.core.dex.visitors.regions.CleanRegions;
|
import jadx.core.dex.visitors.regions.CleanRegions;
|
||||||
import jadx.core.dex.visitors.regions.IfRegionVisitor;
|
import jadx.core.dex.visitors.regions.IfRegionVisitor;
|
||||||
@@ -96,6 +97,7 @@ public class Jadx {
|
|||||||
List<IDexTreeVisitor> passes = new ArrayList<>();
|
List<IDexTreeVisitor> passes = new ArrayList<>();
|
||||||
passes.add(new SignatureProcessor());
|
passes.add(new SignatureProcessor());
|
||||||
passes.add(new OverrideMethodVisitor());
|
passes.add(new OverrideMethodVisitor());
|
||||||
|
passes.add(new CollectConstValues());
|
||||||
|
|
||||||
// rename and deobfuscation
|
// rename and deobfuscation
|
||||||
passes.add(new DeobfuscatorVisitor());
|
passes.add(new DeobfuscatorVisitor());
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package jadx.core.dex.info;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -10,14 +9,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import jadx.api.JadxArgs;
|
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.LiteralArg;
|
||||||
import jadx.core.dex.instructions.args.PrimitiveType;
|
import jadx.core.dex.instructions.args.PrimitiveType;
|
||||||
import jadx.core.dex.nodes.ClassNode;
|
import jadx.core.dex.nodes.ClassNode;
|
||||||
import jadx.core.dex.nodes.FieldNode;
|
import jadx.core.dex.nodes.FieldNode;
|
||||||
import jadx.core.dex.nodes.IFieldInfoRef;
|
import jadx.core.dex.nodes.IFieldInfoRef;
|
||||||
import jadx.core.dex.nodes.RootNode;
|
import jadx.core.dex.nodes.RootNode;
|
||||||
|
import jadx.core.dex.visitors.prepare.CollectConstValues;
|
||||||
|
|
||||||
public class ConstStorage {
|
public class ConstStorage {
|
||||||
|
|
||||||
@@ -75,18 +73,6 @@ public class ConstStorage {
|
|||||||
this.replaceEnabled = args.isReplaceConsts();
|
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) {
|
public void addConstField(FieldNode fld, Object value, boolean isPublic) {
|
||||||
if (isPublic) {
|
if (isPublic) {
|
||||||
addGlobalConstField(fld, value);
|
addGlobalConstField(fld, value);
|
||||||
@@ -99,15 +85,12 @@ public class ConstStorage {
|
|||||||
globalValues.put(value, fld);
|
globalValues.put(value, fld);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use method from CollectConstValues class
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static @Nullable Object getFieldConstValue(FieldNode fld) {
|
public static @Nullable Object getFieldConstValue(FieldNode fld) {
|
||||||
AccessInfo accFlags = fld.getAccessFlags();
|
return CollectConstValues.getFieldConstValue(fld);
|
||||||
if (accFlags.isStatic() && accFlags.isFinal()) {
|
|
||||||
EncodedValue constVal = fld.get(JadxAttrType.CONSTANT_VALUE);
|
|
||||||
if (constVal != null) {
|
|
||||||
return constVal.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeForClass(ClassNode cls) {
|
public void removeForClass(ClassNode cls) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -248,19 +247,15 @@ public class ClassNode extends NotificationAttrNode
|
|||||||
if (fields.isEmpty()) {
|
if (fields.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<FieldNode> staticFields = fields.stream().filter(FieldNode::isStatic).collect(Collectors.toList());
|
// bytecode can omit field initialization to 0 (of any type)
|
||||||
for (FieldNode f : staticFields) {
|
// add explicit init to all static final fields
|
||||||
if (f.getAccessFlags().isFinal() && f.get(JadxAttrType.CONSTANT_VALUE) == null) {
|
// incorrect initializations will be removed if assign found in class init
|
||||||
// incorrect initialization will be removed if assign found in constructor
|
for (FieldNode fld : fields) {
|
||||||
f.addAttr(EncodedValue.NULL);
|
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() {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@ import jadx.api.JavaClass;
|
|||||||
import jadx.api.JavaMethod;
|
import jadx.api.JavaMethod;
|
||||||
import jadx.api.JavaNode;
|
import jadx.api.JavaNode;
|
||||||
import jadx.api.utils.CodeUtils;
|
import jadx.api.utils.CodeUtils;
|
||||||
import jadx.core.dex.info.ConstStorage;
|
|
||||||
import jadx.core.dex.nodes.FieldNode;
|
import jadx.core.dex.nodes.FieldNode;
|
||||||
|
import jadx.core.dex.visitors.prepare.CollectConstValues;
|
||||||
import jadx.gui.JadxWrapper;
|
import jadx.gui.JadxWrapper;
|
||||||
import jadx.gui.jobs.TaskStatus;
|
import jadx.gui.jobs.TaskStatus;
|
||||||
import jadx.gui.settings.JadxSettings;
|
import jadx.gui.settings.JadxSettings;
|
||||||
@@ -70,7 +70,7 @@ public class UsageDialog extends CommonSearchDialog {
|
|||||||
private void prepareUsageData() {
|
private void prepareUsageData() {
|
||||||
if (mainWindow.getSettings().isReplaceConsts() && node instanceof JField) {
|
if (mainWindow.getSettings().isReplaceConsts() && node instanceof JField) {
|
||||||
FieldNode fld = ((JField) node).getJavaField().getFieldNode();
|
FieldNode fld = ((JField) node).getJavaField().getFieldNode();
|
||||||
boolean constField = ConstStorage.getFieldConstValue(fld) != null;
|
boolean constField = CollectConstValues.getFieldConstValue(fld) != null;
|
||||||
if (constField && !fld.getAccessFlags().isPrivate()) {
|
if (constField && !fld.getAccessFlags().isPrivate()) {
|
||||||
// run full decompilation to prepare for full code scan
|
// run full decompilation to prepare for full code scan
|
||||||
mainWindow.requestFullDecompilation();
|
mainWindow.requestFullDecompilation();
|
||||||
@@ -112,7 +112,7 @@ public class UsageDialog extends CommonSearchDialog {
|
|||||||
}
|
}
|
||||||
if (node instanceof JField && mainWindow.getSettings().isReplaceConsts()) {
|
if (node instanceof JField && mainWindow.getSettings().isReplaceConsts()) {
|
||||||
FieldNode fld = ((JField) node).getJavaField().getFieldNode();
|
FieldNode fld = ((JField) node).getJavaField().getFieldNode();
|
||||||
boolean constField = ConstStorage.getFieldConstValue(fld) != null;
|
boolean constField = CollectConstValues.getFieldConstValue(fld) != null;
|
||||||
if (constField && !fld.getAccessFlags().isPrivate()) {
|
if (constField && !fld.getAccessFlags().isPrivate()) {
|
||||||
// search all classes to collect usage of replaced constants
|
// search all classes to collect usage of replaced constants
|
||||||
map.put(fld.getJavaNode(), mainWindow.getWrapper().getIncludedClasses());
|
map.put(fld.getJavaNode(), mainWindow.getWrapper().getIncludedClasses());
|
||||||
|
|||||||
Reference in New Issue
Block a user