refactor: small changes to switch region and region debug print
This commit is contained in:
@@ -28,6 +28,7 @@ import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.parser.FieldInitAttr;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SwitchRegion.CaseInfo;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.regions.TryCatchRegion;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
@@ -270,10 +271,9 @@ public class RegionGen extends InsnGen {
|
||||
code.add(") {");
|
||||
code.incIndent();
|
||||
|
||||
int size = sw.getKeys().size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
List<Object> keys = sw.getKeys().get(i);
|
||||
IContainer c = sw.getCases().get(i);
|
||||
for (CaseInfo caseInfo : sw.getCases()) {
|
||||
List<Object> keys = caseInfo.getKeys();
|
||||
IContainer c = caseInfo.getContainer();
|
||||
for (Object k : keys) {
|
||||
code.startLine("case ");
|
||||
if (k instanceof FieldNode) {
|
||||
|
||||
@@ -118,6 +118,7 @@ public abstract class AttrNode implements IAttributeNode {
|
||||
return storage.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttrStorageEmpty() {
|
||||
return storage.isEmpty();
|
||||
}
|
||||
|
||||
@@ -35,4 +35,6 @@ public interface IAttributeNode {
|
||||
List<String> getAttributesStringsList();
|
||||
|
||||
String getAttributesString();
|
||||
|
||||
boolean isAttrStorageEmpty();
|
||||
}
|
||||
|
||||
@@ -4,33 +4,50 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBranchRegion;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public final class SwitchRegion extends AbstractRegion implements IBranchRegion {
|
||||
|
||||
private final BlockNode header;
|
||||
|
||||
private final List<List<Object>> keys;
|
||||
private final List<IContainer> cases;
|
||||
private final List<CaseInfo> cases;
|
||||
private IContainer defCase;
|
||||
|
||||
public SwitchRegion(IRegion parent, BlockNode header) {
|
||||
super(parent);
|
||||
this.header = header;
|
||||
this.keys = new ArrayList<>();
|
||||
this.cases = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static final class CaseInfo {
|
||||
private final List<Object> keys;
|
||||
private final IContainer container;
|
||||
|
||||
public CaseInfo(List<Object> keys, IContainer container) {
|
||||
this.keys = keys;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public List<Object> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public IContainer getContainer() {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockNode getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void addCase(List<Object> keysList, IContainer c) {
|
||||
keys.add(keysList);
|
||||
cases.add(c);
|
||||
cases.add(new CaseInfo(keysList, c));
|
||||
}
|
||||
|
||||
public void setDefaultCase(IContainer block) {
|
||||
@@ -41,19 +58,19 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
return defCase;
|
||||
}
|
||||
|
||||
public List<List<Object>> getKeys() {
|
||||
return keys;
|
||||
public List<CaseInfo> getCases() {
|
||||
return cases;
|
||||
}
|
||||
|
||||
public List<IContainer> getCases() {
|
||||
return cases;
|
||||
public List<IContainer> getCaseContainers() {
|
||||
return Utils.collectionMap(cases, caseInfo -> caseInfo.container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<>(cases.size() + 2);
|
||||
all.add(header);
|
||||
all.addAll(cases);
|
||||
all.addAll(getCaseContainers());
|
||||
if (defCase != null) {
|
||||
all.add(defCase);
|
||||
}
|
||||
@@ -63,7 +80,7 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
@Override
|
||||
public List<IContainer> getBranches() {
|
||||
List<IContainer> branches = new ArrayList<>(cases.size() + 1);
|
||||
branches.addAll(cases);
|
||||
branches.addAll(getCaseContainers());
|
||||
if (defCase != null) {
|
||||
branches.add(defCase);
|
||||
}
|
||||
@@ -77,6 +94,16 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Switch: " + cases.size() + ", default: " + defCase;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Switch: ").append(cases.size());
|
||||
for (CaseInfo caseInfo : cases) {
|
||||
sb.append(CodeWriter.NL).append(" case ")
|
||||
.append(Utils.listToString(caseInfo.getKeys()))
|
||||
.append(" -> ").append(caseInfo.getContainer());
|
||||
}
|
||||
if (defCase != null) {
|
||||
sb.append(CodeWriter.NL).append(" default -> ").append(defCase);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package jadx.core.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.slf4j.Logger;
|
||||
@@ -12,6 +15,7 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.codegen.InsnGen;
|
||||
import jadx.core.codegen.MethodGen;
|
||||
import jadx.core.dex.attributes.IAttributeNode;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
@@ -85,51 +89,74 @@ public class DebugUtils {
|
||||
printRegions(mth, false);
|
||||
}
|
||||
|
||||
public static void printRegion(MethodNode mth, IRegion region, boolean printInsn) {
|
||||
printRegion(mth, region, "", printInsn);
|
||||
}
|
||||
|
||||
public static void printRegions(MethodNode mth, boolean printInsns) {
|
||||
LOG.debug("|{}", mth);
|
||||
printRegion(mth, mth.getRegion(), "| ", printInsns);
|
||||
printRegion(mth, mth.getRegion(), printInsns);
|
||||
}
|
||||
|
||||
private static void printRegion(MethodNode mth, IRegion region, String indent, boolean printInsns) {
|
||||
LOG.debug("{}{} {}", indent, region, region.getAttributesString());
|
||||
public static void printRegion(MethodNode mth, IRegion region, boolean printInsns) {
|
||||
CodeWriter cw = new CodeWriter();
|
||||
cw.startLine('|').add(mth.toString());
|
||||
printRegion(mth, region, cw, "| ", printInsns);
|
||||
LOG.debug("\n{}", cw.finish().getCodeStr());
|
||||
}
|
||||
|
||||
private static void printRegion(MethodNode mth, IRegion region, CodeWriter cw, String indent, boolean printInsns) {
|
||||
printWithAttributes(cw, indent, region.toString(), region);
|
||||
indent += "| ";
|
||||
for (IContainer container : region.getSubBlocks()) {
|
||||
if (container instanceof IRegion) {
|
||||
printRegion(mth, (IRegion) container, indent, printInsns);
|
||||
printRegion(mth, (IRegion) container, cw, indent, printInsns);
|
||||
} else {
|
||||
LOG.debug("{}{} {}", indent, container, container.getAttributesString());
|
||||
printWithAttributes(cw, indent, container.toString(), container);
|
||||
if (printInsns && container instanceof IBlock) {
|
||||
IBlock block = (IBlock) container;
|
||||
printInsns(mth, indent, block);
|
||||
printInsns(mth, cw, indent, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printInsns(MethodNode mth, String indent, IBlock block) {
|
||||
private static void printInsns(MethodNode mth, CodeWriter cw, String indent, IBlock block) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
try {
|
||||
MethodGen mg = MethodGen.getFallbackMethodGen(mth);
|
||||
InsnGen ig = new InsnGen(mg, true);
|
||||
CodeWriter code = new CodeWriter();
|
||||
ig.makeInsn(insn, code);
|
||||
String insnStr = code.toString().substring(CodeWriter.NL.length());
|
||||
String attrStr = insn.isAttrStorageEmpty() ? "" : '\t' + insn.getAttributesString();
|
||||
LOG.debug("{}|> {}{}", indent, insnStr, attrStr);
|
||||
String codeStr = code.finish().getCodeStr();
|
||||
|
||||
List<String> insnStrings = Arrays.stream(codeStr.split(CodeWriter.NL))
|
||||
.filter(StringUtils::notBlank)
|
||||
.map(s -> "|> " + s)
|
||||
.collect(Collectors.toList());
|
||||
Iterator<String> it = insnStrings.iterator();
|
||||
while (true) {
|
||||
String insnStr = it.next();
|
||||
if (it.hasNext()) {
|
||||
cw.startLine(indent).add(insnStr);
|
||||
} else {
|
||||
printWithAttributes(cw, indent, insnStr, insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (CodegenException e) {
|
||||
LOG.debug("{}|>!! {}", indent, insn);
|
||||
cw.startLine(indent).add(">!! ").add(insn.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void printMap(String desc, Map<?, ?> map) {
|
||||
LOG.debug("Map of {}, size: {}", desc, map.size());
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
LOG.debug(" {} : {}", entry.getKey(), entry.getValue());
|
||||
private static void printWithAttributes(CodeWriter cw, String indent, String codeStr, IAttributeNode attrNode) {
|
||||
String str = attrNode.isAttrStorageEmpty() ? codeStr : codeStr + ' ' + attrNode.getAttributesString();
|
||||
List<String> attrStrings = Arrays.stream(str.split(CodeWriter.NL))
|
||||
.filter(StringUtils::notBlank)
|
||||
.collect(Collectors.toList());
|
||||
Iterator<String> it = attrStrings.iterator();
|
||||
if (!it.hasNext()) {
|
||||
return;
|
||||
}
|
||||
cw.startLine(indent).add(it.next());
|
||||
while (it.hasNext()) {
|
||||
cw.startLine(indent).add("|+ ").add(it.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,10 @@ public class StringUtils {
|
||||
return str == null || str.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean notBlank(String str) {
|
||||
return notEmpty(str) && !str.trim().isEmpty();
|
||||
}
|
||||
|
||||
public static int countMatches(String str, String subStr) {
|
||||
if (str == null || str.isEmpty() || subStr == null || subStr.isEmpty()) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user