fix code style issues
This commit is contained in:
@@ -68,25 +68,25 @@ public final class JadxCLIArgs implements IJadxArgs {
|
||||
System.exit(0);
|
||||
}
|
||||
try {
|
||||
if (threadsCount <= 0)
|
||||
if (threadsCount <= 0) {
|
||||
throw new JadxException("Threads count must be positive");
|
||||
|
||||
}
|
||||
if (files != null) {
|
||||
for (String fileName : files) {
|
||||
File file = new File(fileName);
|
||||
if (file.exists())
|
||||
if (file.exists()) {
|
||||
input.add(file);
|
||||
else
|
||||
} else {
|
||||
throw new JadxException("File not found: " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input.size() > 1)
|
||||
if (input.size() > 1) {
|
||||
throw new JadxException("Only one input file is supported");
|
||||
|
||||
if (outDirName != null)
|
||||
}
|
||||
if (outDirName != null) {
|
||||
outputDir = new File(outDirName);
|
||||
|
||||
}
|
||||
if (isVerbose()) {
|
||||
ch.qos.logback.classic.Logger rootLogger =
|
||||
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
@@ -114,8 +114,9 @@ public final class JadxCLIArgs implements IJadxArgs {
|
||||
int maxNamesLen = 0;
|
||||
for (ParameterDescription p : params) {
|
||||
int len = p.getNames().length();
|
||||
if (len > maxNamesLen)
|
||||
if (len > maxNamesLen) {
|
||||
maxNamesLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
@@ -137,8 +138,9 @@ public final class JadxCLIArgs implements IJadxArgs {
|
||||
}
|
||||
|
||||
private static void addSpaces(StringBuilder str, int count) {
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int i = 0; i < count; i++) {
|
||||
str.append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
public List<File> getInput() {
|
||||
|
||||
@@ -16,7 +16,6 @@ import jadx.core.utils.files.InputFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@@ -80,7 +79,7 @@ public final class Decompiler {
|
||||
}
|
||||
|
||||
public void loadFile(File file) throws IOException, DecodeException {
|
||||
loadFiles(Arrays.asList(file));
|
||||
loadFiles(Collections.singletonList(file));
|
||||
}
|
||||
|
||||
public void loadFiles(List<File> files) throws IOException, DecodeException {
|
||||
@@ -110,15 +109,20 @@ public final class Decompiler {
|
||||
int threadsCount = args.getThreadsCount();
|
||||
LOG.debug("processing threads count: {}", threadsCount);
|
||||
|
||||
ArrayList<IDexTreeVisitor> passList = new ArrayList<IDexTreeVisitor>(passes);
|
||||
final List<IDexTreeVisitor> passList = new ArrayList<IDexTreeVisitor>(passes);
|
||||
SaveCode savePass = new SaveCode(outDir, args);
|
||||
passList.add(savePass);
|
||||
|
||||
LOG.info("processing ...");
|
||||
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadsCount);
|
||||
for (ClassNode cls : root.getClasses(false)) {
|
||||
for (final ClassNode cls : root.getClasses(false)) {
|
||||
if (cls.getCode() == null) {
|
||||
ProcessClass job = new ProcessClass(cls, passList);
|
||||
Runnable job = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ProcessClass.process(cls, passList);
|
||||
}
|
||||
};
|
||||
executor.execute(job);
|
||||
} else {
|
||||
try {
|
||||
@@ -183,13 +187,8 @@ public final class Decompiler {
|
||||
}
|
||||
|
||||
void processClass(ClassNode cls) {
|
||||
try {
|
||||
ProcessClass job = new ProcessClass(cls, passes);
|
||||
LOG.info("processing class {} ...", cls);
|
||||
job.run();
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Process class error", e);
|
||||
}
|
||||
LOG.info("processing class {} ...", cls);
|
||||
ProcessClass.process(cls, passes);
|
||||
}
|
||||
|
||||
RootNode getRoot() {
|
||||
|
||||
@@ -10,7 +10,7 @@ import jadx.core.dex.visitors.DotGraphVisitor;
|
||||
import jadx.core.dex.visitors.EnumVisitor;
|
||||
import jadx.core.dex.visitors.FallbackModeVisitor;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.core.dex.visitors.MethodInlinerVisitor;
|
||||
import jadx.core.dex.visitors.MethodInlineVisitor;
|
||||
import jadx.core.dex.visitors.ModVisitor;
|
||||
import jadx.core.dex.visitors.SimplifyVisitor;
|
||||
import jadx.core.dex.visitors.regions.CheckRegions;
|
||||
@@ -79,7 +79,7 @@ public class Jadx {
|
||||
passes.add(new DotGraphVisitor(outDir, true));
|
||||
}
|
||||
|
||||
passes.add(new MethodInlinerVisitor());
|
||||
passes.add(new MethodInlineVisitor());
|
||||
passes.add(new ClassModifier());
|
||||
}
|
||||
passes.add(new CodeGen(args));
|
||||
|
||||
@@ -10,19 +10,13 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class ProcessClass implements Runnable {
|
||||
public final class ProcessClass {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ProcessClass.class);
|
||||
|
||||
private final ClassNode cls;
|
||||
private final List<IDexTreeVisitor> passes;
|
||||
|
||||
public ProcessClass(ClassNode cls, List<IDexTreeVisitor> passes) {
|
||||
this.cls = cls;
|
||||
this.passes = passes;
|
||||
private ProcessClass() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public static void process(ClassNode cls, List<IDexTreeVisitor> passes) {
|
||||
try {
|
||||
cls.load();
|
||||
for (IDexTreeVisitor visitor : passes) {
|
||||
@@ -30,6 +24,8 @@ public final class ProcessClass implements Runnable {
|
||||
}
|
||||
} catch (DecodeException e) {
|
||||
LOG.error("Decode exception: " + cls, e);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Class process exception: " + cls, e);
|
||||
} finally {
|
||||
cls.unload();
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class AnnotationGen {
|
||||
code.add('@');
|
||||
code.add(classGen.useClass(a.getType()));
|
||||
Map<String, Object> vl = a.getValues();
|
||||
if (vl.size() != 0) {
|
||||
if (!vl.isEmpty()) {
|
||||
code.add('(');
|
||||
if (vl.size() == 1 && vl.containsKey("value")) {
|
||||
code.add(encValueToString(vl.get("value")));
|
||||
|
||||
@@ -379,11 +379,10 @@ public class ClassGen {
|
||||
if (searchCollision(cls.dex(), useCls, shortName)) {
|
||||
return clsStr;
|
||||
}
|
||||
for (ClassInfo cls : imports) {
|
||||
if (!cls.equals(classInfo)) {
|
||||
if (cls.getShortName().equals(shortName)) {
|
||||
return clsStr;
|
||||
}
|
||||
for (ClassInfo importCls : imports) {
|
||||
if (!importCls.equals(classInfo)
|
||||
&& importCls.getShortName().equals(shortName)) {
|
||||
return clsStr;
|
||||
}
|
||||
}
|
||||
addImport(classInfo);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class CodeWriter {
|
||||
attachAnnotation(entry.getKey(), line + entry.getValue());
|
||||
}
|
||||
line += code.line;
|
||||
buf.append(code.toString());
|
||||
buf.append(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public class CodeWriter {
|
||||
return this;
|
||||
}
|
||||
|
||||
private static final String[] INDENT_CACHE = new String[]{
|
||||
private static final String[] INDENT_CACHE = {
|
||||
"",
|
||||
INDENT,
|
||||
INDENT + INDENT,
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ConditionGen {
|
||||
}
|
||||
return sb.toString();
|
||||
default:
|
||||
return "??" + condition.toString();
|
||||
return "??" + condition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ public class InsnGen {
|
||||
|
||||
public String assignVar(InsnNode insn) throws CodegenException {
|
||||
RegisterArg arg = insn.getResult();
|
||||
if (insn.getAttributes().contains(AttributeType.DECLARE_VARIABLE)) {
|
||||
if (insn.getAttributes().contains(AttributeFlag.DECLARE_VAR)) {
|
||||
return declareVar(arg);
|
||||
} else {
|
||||
return arg(arg).toString();
|
||||
@@ -125,7 +125,7 @@ public class InsnGen {
|
||||
return useType(arg.getType()) + " " + mgen.assignArg(arg);
|
||||
}
|
||||
|
||||
private String lit(LiteralArg arg) {
|
||||
private static String lit(LiteralArg arg) {
|
||||
return TypeGen.literalToString(arg.getLiteral(), arg.getType());
|
||||
}
|
||||
|
||||
@@ -483,7 +483,8 @@ public class InsnGen {
|
||||
if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) {
|
||||
ErrorsCounter.methodError(mth,
|
||||
"Incorrect type for fill-array insn " + InsnUtils.formatOffset(insn.getOffset())
|
||||
+ ", element type: " + elType + ", insn element type: " + insnElementType);
|
||||
+ ", element type: " + elType + ", insn element type: " + insnElementType
|
||||
);
|
||||
if (!elType.isTypeKnown()) {
|
||||
elType = insnElementType.isTypeKnown() ? insnElementType : elType.selectFirst();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@ public class MethodGen {
|
||||
} else {
|
||||
LOG.warn(ErrorsCounter.formatErrorMsg(mth,
|
||||
"Incorrect number of args for enum constructor: " + args.size()
|
||||
+ " (expected >= 2)"));
|
||||
+ " (expected >= 2)"
|
||||
));
|
||||
}
|
||||
}
|
||||
code.add(makeArguments(args));
|
||||
@@ -269,7 +270,7 @@ public class MethodGen {
|
||||
code.startLine("*/");
|
||||
}
|
||||
|
||||
private void makeFallbackMethod(CodeWriter code, MethodNode mth) {
|
||||
private static void makeFallbackMethod(CodeWriter code, MethodNode mth) {
|
||||
if (mth.getInstructions() == null) {
|
||||
// loadFile original instructions
|
||||
try {
|
||||
|
||||
@@ -2,19 +2,13 @@ package jadx.core.codegen;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.DeclareVariableAttr;
|
||||
import jadx.core.dex.attributes.DeclareVariablesAttr;
|
||||
import jadx.core.dex.attributes.ForceReturnAttr;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.instructions.ArithNode;
|
||||
import jadx.core.dex.instructions.IfOp;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.SwitchNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
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.IBlock;
|
||||
@@ -22,7 +16,6 @@ import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.Compare;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
@@ -32,7 +25,6 @@ import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
|
||||
@@ -49,22 +41,12 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
|
||||
public void makeRegion(CodeWriter code, IContainer cont) throws CodegenException {
|
||||
assert cont != null;
|
||||
|
||||
if (cont instanceof IBlock) {
|
||||
makeSimpleBlock((IBlock) cont, code);
|
||||
} else if (cont instanceof IRegion) {
|
||||
declareVars(code, cont);
|
||||
if (cont instanceof Region) {
|
||||
Region r = (Region) cont;
|
||||
CatchAttr tc = (CatchAttr) r.getAttributes().get(AttributeType.CATCH_BLOCK);
|
||||
if (tc != null) {
|
||||
makeTryCatch(cont, tc.getTryBlock(), code);
|
||||
} else {
|
||||
for (IContainer c : r.getSubBlocks()) {
|
||||
makeRegion(code, c);
|
||||
}
|
||||
}
|
||||
makeSimpleRegion(code, (Region) cont);
|
||||
} else if (cont instanceof IfRegion) {
|
||||
makeIf((IfRegion) cont, code, true);
|
||||
} else if (cont instanceof SwitchRegion) {
|
||||
@@ -75,13 +57,13 @@ public class RegionGen extends InsnGen {
|
||||
makeSynchronizedRegion((SynchronizedRegion) cont, code);
|
||||
}
|
||||
} else {
|
||||
throw new CodegenException("Not processed container: " + cont.toString());
|
||||
throw new CodegenException("Not processed container: " + cont);
|
||||
}
|
||||
}
|
||||
|
||||
private void declareVars(CodeWriter code, IContainer cont) {
|
||||
DeclareVariableAttr declVars =
|
||||
(DeclareVariableAttr) cont.getAttributes().get(AttributeType.DECLARE_VARIABLE);
|
||||
DeclareVariablesAttr declVars =
|
||||
(DeclareVariablesAttr) cont.getAttributes().get(AttributeType.DECLARE_VARIABLES);
|
||||
if (declVars != null) {
|
||||
for (RegisterArg v : declVars.getVars()) {
|
||||
code.startLine(declareVar(v)).add(';');
|
||||
@@ -89,6 +71,17 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSimpleRegion(CodeWriter code, Region region) throws CodegenException {
|
||||
CatchAttr tc = (CatchAttr) region.getAttributes().get(AttributeType.CATCH_BLOCK);
|
||||
if (tc != null) {
|
||||
makeTryCatch(region, tc.getTryBlock(), code);
|
||||
} else {
|
||||
for (IContainer c : region.getSubBlocks()) {
|
||||
makeRegion(code, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void makeRegionIndent(CodeWriter code, IContainer region) throws CodegenException {
|
||||
code.incIndent();
|
||||
makeRegion(code, region);
|
||||
@@ -125,26 +118,33 @@ public class RegionGen extends InsnGen {
|
||||
IContainer els = region.getElseRegion();
|
||||
if (els != null && RegionUtils.notEmpty(els)) {
|
||||
code.add(" else ");
|
||||
|
||||
// connect if-else-if block
|
||||
if (els instanceof Region) {
|
||||
Region re = (Region) els;
|
||||
List<IContainer> subBlocks = re.getSubBlocks();
|
||||
if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
|
||||
IfRegion ifRegion = (IfRegion) subBlocks.get(0);
|
||||
if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
|
||||
makeIf(ifRegion, code, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (connectElseIf(code, els)) {
|
||||
return;
|
||||
}
|
||||
|
||||
code.add('{');
|
||||
makeRegionIndent(code, els);
|
||||
code.startLine('}');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect if-else-if block
|
||||
*/
|
||||
private boolean connectElseIf(CodeWriter code, IContainer els) throws CodegenException {
|
||||
if (els instanceof Region) {
|
||||
Region re = (Region) els;
|
||||
List<IContainer> subBlocks = re.getSubBlocks();
|
||||
if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
|
||||
IfRegion ifRegion = (IfRegion) subBlocks.get(0);
|
||||
if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
|
||||
makeIf(ifRegion, code, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private CodeWriter makeLoop(LoopRegion region, CodeWriter code) throws CodegenException {
|
||||
BlockNode header = region.getHeader();
|
||||
if (header != null) {
|
||||
@@ -152,7 +152,8 @@ public class RegionGen extends InsnGen {
|
||||
if (headerInsns.size() > 1) {
|
||||
// write not inlined instructions from header
|
||||
mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE);
|
||||
for (int i = 0; i < headerInsns.size() - 1; i++) {
|
||||
int last = headerInsns.size() - 1;
|
||||
for (int i = 0; i < last; i++) {
|
||||
InsnNode insn = headerInsns.get(i);
|
||||
makeInsn(insn, code);
|
||||
}
|
||||
@@ -187,75 +188,6 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
private String makeCondition(IfCondition condition) throws CodegenException {
|
||||
switch (condition.getMode()) {
|
||||
case COMPARE:
|
||||
return makeCompare(condition.getCompare());
|
||||
case NOT:
|
||||
return "!" + makeCondition(condition.getArgs().get(0));
|
||||
case AND:
|
||||
case OR:
|
||||
String mode = condition.getMode() == IfCondition.Mode.AND ? " && " : " || ";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (IfCondition arg : condition.getArgs()) {
|
||||
if (sb.length() != 0) {
|
||||
sb.append(mode);
|
||||
}
|
||||
String s = makeCondition(arg);
|
||||
if (arg.isCompare()) {
|
||||
sb.append(s);
|
||||
} else {
|
||||
sb.append('(').append(s).append(')');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
default:
|
||||
return "??" + condition.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String makeCompare(Compare compare) throws CodegenException {
|
||||
IfOp op = compare.getOp();
|
||||
InsnArg firstArg = compare.getA();
|
||||
InsnArg secondArg = compare.getB();
|
||||
if (firstArg.getType().equals(ArgType.BOOLEAN)
|
||||
&& secondArg.isLiteral()
|
||||
&& secondArg.getType().equals(ArgType.BOOLEAN)) {
|
||||
LiteralArg lit = (LiteralArg) secondArg;
|
||||
if (lit.getLiteral() == 0) {
|
||||
op = op.invert();
|
||||
}
|
||||
if (op == IfOp.EQ) {
|
||||
return arg(firstArg, false).toString(); // == true
|
||||
} else if (op == IfOp.NE) {
|
||||
return "!" + arg(firstArg); // != true
|
||||
}
|
||||
LOG.warn(ErrorsCounter.formatErrorMsg(mth, "Unsupported boolean condition " + op.getSymbol()));
|
||||
}
|
||||
return arg(firstArg, isWrapNeeded(firstArg))
|
||||
+ " " + op.getSymbol() + " "
|
||||
+ arg(secondArg, isWrapNeeded(secondArg));
|
||||
}
|
||||
|
||||
private boolean isWrapNeeded(InsnArg arg) {
|
||||
if (!arg.isInsnWrap()) {
|
||||
return false;
|
||||
}
|
||||
InsnNode insn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
if (insn.getType() == InsnType.ARITH) {
|
||||
ArithNode arith = ((ArithNode) insn);
|
||||
switch (arith.getOp()) {
|
||||
case ADD:
|
||||
case SUB:
|
||||
case MUL:
|
||||
case DIV:
|
||||
case REM:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private CodeWriter makeSwitch(SwitchRegion sw, CodeWriter code) throws CodegenException {
|
||||
SwitchNode insn = (SwitchNode) sw.getHeader().getInstructions().get(0);
|
||||
InsnArg arg = insn.getArg(0);
|
||||
@@ -324,7 +256,7 @@ public class RegionGen extends InsnGen {
|
||||
private void makeCatchBlock(CodeWriter code, ExceptionHandler handler)
|
||||
throws CodegenException {
|
||||
IContainer region = handler.getHandlerRegion();
|
||||
if (region != null /* && RegionUtils.notEmpty(region) */) {
|
||||
if (region != null) {
|
||||
code.startLine("} catch (");
|
||||
code.add(handler.isCatchAll() ? "Throwable" : useClass(handler.getCatchType()));
|
||||
code.add(' ');
|
||||
|
||||
@@ -61,7 +61,8 @@ public class NameMapper {
|
||||
"void",
|
||||
"volatile",
|
||||
"while",
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
public static boolean isReserved(String str) {
|
||||
return RESERVED_NAMES.contains(str);
|
||||
|
||||
@@ -12,6 +12,8 @@ public enum AttributeFlag {
|
||||
BREAK,
|
||||
RETURN, // block contains only return instruction
|
||||
|
||||
DECLARE_VAR,
|
||||
|
||||
DONT_SHRINK,
|
||||
DONT_GENERATE,
|
||||
SKIP,
|
||||
|
||||
@@ -27,7 +27,8 @@ public enum AttributeType {
|
||||
|
||||
SOURCE_FILE(true),
|
||||
|
||||
DECLARE_VARIABLE(true);
|
||||
// for regions
|
||||
DECLARE_VARIABLES(true);
|
||||
|
||||
private static final int NOT_UNIQ_COUNT;
|
||||
private final boolean uniq;
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class BlockRegState {
|
||||
if (str.length() != 0) {
|
||||
str.append(", ");
|
||||
}
|
||||
str.append(reg.toString());
|
||||
str.append(reg);
|
||||
}
|
||||
}
|
||||
return str.toString();
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package jadx.core.dex.attributes;
|
||||
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DeclareVariableAttr implements IAttribute {
|
||||
|
||||
private final List<RegisterArg> vars;
|
||||
|
||||
public DeclareVariableAttr() {
|
||||
this.vars = null; // for instruction use result
|
||||
}
|
||||
|
||||
public DeclareVariableAttr(List<RegisterArg> vars) {
|
||||
this.vars = vars; // for regions
|
||||
}
|
||||
|
||||
public List<RegisterArg> getVars() {
|
||||
return vars;
|
||||
}
|
||||
|
||||
public void addVar(RegisterArg arg) {
|
||||
int i;
|
||||
if ((i = vars.indexOf(arg)) != -1) {
|
||||
if (vars.get(i).getType().equals(arg.getType())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
vars.add(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeType getType() {
|
||||
return AttributeType.DECLARE_VARIABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DECL_VAR: " + Utils.listToString(vars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package jadx.core.dex.attributes;
|
||||
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* List of variables to be declared at region start.
|
||||
*/
|
||||
public class DeclareVariablesAttr implements IAttribute {
|
||||
|
||||
private final List<RegisterArg> vars = new LinkedList<RegisterArg>();
|
||||
|
||||
public Iterable<RegisterArg> getVars() {
|
||||
return vars;
|
||||
}
|
||||
|
||||
public void addVar(RegisterArg arg) {
|
||||
vars.add(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeType getType() {
|
||||
return AttributeType.DECLARE_VARIABLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DECL_VAR: " + Utils.listToString(vars);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class JadxErrorAttr implements IAttribute {
|
||||
if (cause == null) {
|
||||
str.append("null");
|
||||
} else {
|
||||
str.append(cause.getClass().toString());
|
||||
str.append(cause.getClass());
|
||||
str.append(":");
|
||||
str.append(cause.getMessage());
|
||||
str.append("\n");
|
||||
|
||||
@@ -32,11 +32,7 @@ public class JumpAttribute implements IAttribute {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + dest;
|
||||
result = prime * result + src;
|
||||
return result;
|
||||
return 31 * dest + src;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,37 +58,37 @@ public final class ClassInfo {
|
||||
String fullObjectName = type.getObject();
|
||||
assert fullObjectName.indexOf('/') == -1 : "Raw type: " + type;
|
||||
|
||||
String name;
|
||||
String clsName;
|
||||
int dot = fullObjectName.lastIndexOf('.');
|
||||
if (dot == -1) {
|
||||
// rename default package if it used from class with package (often for obfuscated apps),
|
||||
pkg = Consts.DEFAULT_PACKAGE_NAME;
|
||||
name = fullObjectName;
|
||||
clsName = fullObjectName;
|
||||
} else {
|
||||
pkg = fullObjectName.substring(0, dot);
|
||||
name = fullObjectName.substring(dot + 1);
|
||||
clsName = fullObjectName.substring(dot + 1);
|
||||
}
|
||||
|
||||
int sep = name.lastIndexOf('$');
|
||||
if (canBeInner && sep > 0 && sep != name.length() - 1) {
|
||||
String parClsName = pkg + '.' + name.substring(0, sep);
|
||||
int sep = clsName.lastIndexOf('$');
|
||||
if (canBeInner && sep > 0 && sep != clsName.length() - 1) {
|
||||
String parClsName = pkg + '.' + clsName.substring(0, sep);
|
||||
parentClass = fromName(parClsName);
|
||||
name = name.substring(sep + 1);
|
||||
clsName = clsName.substring(sep + 1);
|
||||
} else {
|
||||
parentClass = null;
|
||||
}
|
||||
|
||||
char firstChar = name.charAt(0);
|
||||
char firstChar = clsName.charAt(0);
|
||||
if (Character.isDigit(firstChar)) {
|
||||
name = Consts.ANONYMOUS_CLASS_PREFIX + name;
|
||||
clsName = Consts.ANONYMOUS_CLASS_PREFIX + clsName;
|
||||
} else if (firstChar == '$') {
|
||||
name = "_" + name;
|
||||
clsName = "_" + clsName;
|
||||
}
|
||||
if (NameMapper.isReserved(name)) {
|
||||
name += "_";
|
||||
if (NameMapper.isReserved(clsName)) {
|
||||
clsName += "_";
|
||||
}
|
||||
this.fullName = (parentClass != null ? parentClass.getFullName() : pkg) + "." + name;
|
||||
this.name = name;
|
||||
this.fullName = (parentClass != null ? parentClass.getFullName() : pkg) + "." + clsName;
|
||||
this.name = clsName;
|
||||
}
|
||||
|
||||
public String getFullPath() {
|
||||
|
||||
@@ -88,11 +88,9 @@ public final class MethodInfo {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + declClass.hashCode();
|
||||
result = prime * result + retType.hashCode();
|
||||
result = prime * result + shortId.hashCode();
|
||||
int result = declClass.hashCode();
|
||||
result = 31 * result + retType.hashCode();
|
||||
result = 31 * result + shortId.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ public abstract class ArgType {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return arrayElement.toString() + "[]";
|
||||
return arrayElement + "[]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public class RegisterArg extends InsnArg {
|
||||
public boolean isThis() {
|
||||
if (isRegister()) {
|
||||
String name = getTypedVar().getName();
|
||||
if (name != null && name.equals("this")) {
|
||||
if ("this".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
// maybe it was moved from 'this' register
|
||||
@@ -120,13 +120,7 @@ public class RegisterArg extends InsnArg {
|
||||
return false;
|
||||
}
|
||||
RegisterArg other = (RegisterArg) obj;
|
||||
if (regNum != other.regNum) {
|
||||
return false;
|
||||
}
|
||||
if (!typedVar.equals(other.typedVar)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return regNum == other.regNum && typedVar.equals(other.typedVar);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,9 +51,9 @@ public class TypedVar {
|
||||
}
|
||||
|
||||
public void mergeName(TypedVar arg) {
|
||||
String name = arg.getName();
|
||||
if (name != null) {
|
||||
setName(name);
|
||||
String argName = arg.getName();
|
||||
if (argName != null) {
|
||||
setName(argName);
|
||||
} else if (getName() != null) {
|
||||
arg.setName(getName());
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
|
||||
int offset = cls.getAnnotationsOffset();
|
||||
if (offset != 0) {
|
||||
try {
|
||||
new AnnotationsParser(this, offset);
|
||||
new AnnotationsParser(this).parse(offset);
|
||||
} catch (DecodeException e) {
|
||||
LOG.error("Error parsing annotations in " + this, e);
|
||||
}
|
||||
|
||||
@@ -91,13 +91,11 @@ public class InsnNode extends LineAttrNode {
|
||||
InsnArg arg = arguments.get(i);
|
||||
if (arg == from) {
|
||||
// TODO correct remove from use list
|
||||
// from.getTypedVar().getUseList().remove(from);
|
||||
setArg(i, to);
|
||||
return true;
|
||||
} else if (arg.isInsnWrap()) {
|
||||
if (((InsnWrapArg) arg).getWrapInsn().replaceArg(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (arg.isInsnWrap() && ((InsnWrapArg) arg).getWrapInsn().replaceArg(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -47,7 +47,7 @@ public class RootNode {
|
||||
initInnerClasses(classes);
|
||||
}
|
||||
|
||||
private void initClassPath(List<ClassNode> classes) throws IOException, DecodeException {
|
||||
private static void initClassPath(List<ClassNode> classes) throws IOException, DecodeException {
|
||||
ClspGraph clsp = new ClspGraph();
|
||||
clsp.load();
|
||||
clsp.addApp(classes);
|
||||
|
||||
@@ -4,6 +4,7 @@ import jadx.core.dex.attributes.annotations.Annotation;
|
||||
import jadx.core.dex.attributes.annotations.Annotation.Visibility;
|
||||
import jadx.core.dex.attributes.annotations.AnnotationsList;
|
||||
import jadx.core.dex.attributes.annotations.MethodParameters;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
@@ -20,9 +21,14 @@ import com.android.dx.io.DexBuffer.Section;
|
||||
public class AnnotationsParser {
|
||||
|
||||
private final DexNode dex;
|
||||
private final ClassNode cls;
|
||||
|
||||
public AnnotationsParser(ClassNode cls, int offset) throws DecodeException {
|
||||
public AnnotationsParser(ClassNode cls) {
|
||||
this.cls = cls;
|
||||
this.dex = cls.dex();
|
||||
}
|
||||
|
||||
public void parse(int offset) throws DecodeException {
|
||||
Section section = dex.openSection(offset);
|
||||
|
||||
// TODO read as unsigned int
|
||||
@@ -70,10 +76,10 @@ public class AnnotationsParser {
|
||||
return new AnnotationsList(list);
|
||||
}
|
||||
|
||||
private static final Annotation.Visibility[] VISIBILITIES = new Annotation.Visibility[]{
|
||||
Annotation.Visibility.BUILD,
|
||||
Annotation.Visibility.RUNTIME,
|
||||
Annotation.Visibility.SYSTEM
|
||||
private static final Annotation.Visibility[] VISIBILITIES = {
|
||||
Visibility.BUILD,
|
||||
Visibility.RUNTIME,
|
||||
Visibility.SYSTEM
|
||||
};
|
||||
|
||||
public static Annotation readAnnotation(DexNode dex, Section s, boolean readVisibility) throws DecodeException {
|
||||
@@ -89,6 +95,11 @@ public class AnnotationsParser {
|
||||
String name = dex.getString(s.readUleb128());
|
||||
values.put(name, parser.parseValue());
|
||||
}
|
||||
return new Annotation(visibility, dex.getType(typeIndex), values);
|
||||
ArgType type = dex.getType(typeIndex);
|
||||
Annotation annotation = new Annotation(visibility, type, values);
|
||||
if (!type.isObject()) {
|
||||
throw new DecodeException("Incorrect type for annotation: " + annotation);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,12 @@ public class DebugInfoParser {
|
||||
private static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
|
||||
private static final int DBG_SET_FILE = 0x09;
|
||||
|
||||
private static final int DBG_FIRST_SPECIAL = 0x0a; // the smallest special opcode
|
||||
private static final int DBG_LINE_BASE = -4; // the smallest line number increment
|
||||
private static final int DBG_LINE_RANGE = 15; // the number of line increments represented
|
||||
// the smallest special opcode
|
||||
private static final int DBG_FIRST_SPECIAL = 0x0a;
|
||||
// the smallest line number increment
|
||||
private static final int DBG_LINE_BASE = -4;
|
||||
// the number of line increments represented
|
||||
private static final int DBG_LINE_RANGE = 15;
|
||||
|
||||
private final MethodNode mth;
|
||||
private final Section section;
|
||||
@@ -42,8 +45,9 @@ public class DebugInfoParser {
|
||||
this.dex = mth.dex();
|
||||
this.section = dex.openSection(debugOffset);
|
||||
|
||||
this.locals = new LocalVar[mth.getRegsCount()];
|
||||
this.activeRegisters = new InsnArg[mth.getRegsCount()];
|
||||
int regsCount = mth.getRegsCount();
|
||||
this.locals = new LocalVar[regsCount];
|
||||
this.activeRegisters = new InsnArg[regsCount];
|
||||
this.insnByOffset = insnByOffset;
|
||||
}
|
||||
|
||||
@@ -51,7 +55,7 @@ public class DebugInfoParser {
|
||||
int addr = 0;
|
||||
int line = section.readUleb128();
|
||||
|
||||
int paramsCount = section.readUleb128(); // exclude 'this'
|
||||
int paramsCount = section.readUleb128();
|
||||
List<RegisterArg> mthArgs = mth.getArguments(false);
|
||||
assert paramsCount == mthArgs.size();
|
||||
|
||||
@@ -69,7 +73,8 @@ public class DebugInfoParser {
|
||||
activeRegisters[rn] = arg;
|
||||
}
|
||||
|
||||
addrChange(-1, 1, line); // process '0' instruction
|
||||
// process '0' instruction
|
||||
addrChange(-1, 1, line);
|
||||
|
||||
int c = section.readByte() & 0xFF;
|
||||
while (c != DBG_END_SEQUENCE) {
|
||||
@@ -139,7 +144,7 @@ public class DebugInfoParser {
|
||||
if (c >= DBG_FIRST_SPECIAL) {
|
||||
int adjustedOpcode = c - DBG_FIRST_SPECIAL;
|
||||
line += DBG_LINE_BASE + (adjustedOpcode % DBG_LINE_RANGE);
|
||||
int addrInc = (adjustedOpcode / DBG_LINE_RANGE);
|
||||
int addrInc = adjustedOpcode / DBG_LINE_RANGE;
|
||||
addr = addrChange(addr, addrInc, line);
|
||||
} else {
|
||||
throw new DecodeException("Unknown debug insn code: " + c);
|
||||
@@ -213,10 +218,10 @@ public class DebugInfoParser {
|
||||
}
|
||||
|
||||
private static void merge(InsnArg arg, LocalVar var) {
|
||||
if (arg != null && arg.isRegister()) {
|
||||
if (var.getRegNum() == ((RegisterArg) arg).getRegNum()) {
|
||||
arg.mergeDebugInfo(var);
|
||||
}
|
||||
if (arg != null
|
||||
&& arg.isRegister()
|
||||
&& var.getRegNum() == ((RegisterArg) arg).getRegNum()) {
|
||||
arg.mergeDebugInfo(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ public final class LoopRegion extends AbstractRegion {
|
||||
|
||||
// loop header contains one 'if' insn, equals null for infinite loop
|
||||
private IfCondition condition;
|
||||
private BlockNode conditionBlock;
|
||||
private final BlockNode conditionBlock;
|
||||
// instruction which must be executed before condition in every loop
|
||||
private BlockNode preCondition = null;
|
||||
private BlockNode preCondition;
|
||||
private IContainer body;
|
||||
private final boolean conditionAtEnd;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class TernaryRegion extends AbstractRegion {
|
||||
private IBlock container;
|
||||
private final IBlock container;
|
||||
|
||||
public TernaryRegion(IRegion parent, BlockNode block) {
|
||||
super(parent);
|
||||
|
||||
@@ -17,10 +17,12 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.SplitterBlockAttr;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -223,7 +225,7 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static void computeDominators(MethodNode mth) {
|
||||
List<BlockNode> basicBlocks = mth.getBasicBlocks();
|
||||
List<BlockNode> basicBlocks = Collections.unmodifiableList(mth.getBasicBlocks());
|
||||
int nBlocks = basicBlocks.size();
|
||||
for (int i = 0; i < nBlocks; i++) {
|
||||
BlockNode block = basicBlocks.get(i);
|
||||
@@ -245,13 +247,15 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
continue;
|
||||
}
|
||||
BitSet d = block.getDoms();
|
||||
dset.clear();
|
||||
dset.or(d);
|
||||
if (!changed) {
|
||||
dset.clear();
|
||||
dset.or(d);
|
||||
}
|
||||
for (BlockNode pred : block.getPredecessors()) {
|
||||
d.and(pred.getDoms());
|
||||
}
|
||||
d.set(block.getId());
|
||||
if (!d.equals(dset)) {
|
||||
if (!changed && !d.equals(dset)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -315,12 +319,9 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
private static void markReturnBlocks(MethodNode mth) {
|
||||
mth.getExitBlocks().clear();
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
List<InsnNode> insns = block.getInstructions();
|
||||
if (insns.size() == 1) {
|
||||
if (insns.get(0).getType() == InsnType.RETURN) {
|
||||
block.getAttributes().add(AttributeFlag.RETURN);
|
||||
mth.getExitBlocks().add(block);
|
||||
}
|
||||
if (BlockUtils.lastInsnType(block, InsnType.RETURN)) {
|
||||
block.getAttributes().add(AttributeFlag.RETURN);
|
||||
mth.getExitBlocks().add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,11 +111,9 @@ public class ClassModifier extends AbstractVisitor {
|
||||
AccessInfo af = mth.getAccessFlags();
|
||||
|
||||
// remove bridge methods
|
||||
if (af.isBridge() && af.isSynthetic()) {
|
||||
if (!isMethodUniq(cls, mth)) {
|
||||
// TODO add more checks before method deletion
|
||||
it.remove();
|
||||
}
|
||||
if (af.isBridge() && af.isSynthetic() && !isMethodUniq(cls, mth)) {
|
||||
// TODO add more checks before method deletion
|
||||
it.remove();
|
||||
}
|
||||
|
||||
// remove synthetic constructor for inner non-static classes
|
||||
@@ -135,11 +133,11 @@ public class ClassModifier extends AbstractVisitor {
|
||||
private static boolean isMethodUniq(ClassNode cls, MethodNode mth) {
|
||||
MethodInfo mi = mth.getMethodInfo();
|
||||
for (MethodNode otherMth : cls.getMethods()) {
|
||||
MethodInfo omi = otherMth.getMethodInfo();
|
||||
if (omi.getName().equals(mi.getName())
|
||||
&& otherMth != mth) {
|
||||
if (omi.getArgumentsTypes().size() == mi.getArgumentsTypes().size()) {
|
||||
// TODO: check to args objects types
|
||||
if (otherMth != mth) {
|
||||
MethodInfo omi = otherMth.getMethodInfo();
|
||||
if (omi.getName().equals(mi.getName())
|
||||
&& omi.getArgumentsTypes().size() == mi.getArgumentsTypes().size()) {
|
||||
// TODO: check objects types
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,10 +231,8 @@ public class CodeShrinker extends AbstractVisitor {
|
||||
List<RegisterArg> args = ArgsInfo.getArgs(assignInsn);
|
||||
boolean startCheck = false;
|
||||
for (InsnNode insn : assignBlock.getInstructions()) {
|
||||
if (startCheck) {
|
||||
if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
|
||||
return false;
|
||||
}
|
||||
if (startCheck && (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args))) {
|
||||
return false;
|
||||
}
|
||||
if (insn == assignInsn) {
|
||||
startCheck = true;
|
||||
|
||||
@@ -116,11 +116,10 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
break;
|
||||
|
||||
case IPUT:
|
||||
case SPUT: {
|
||||
case SPUT:
|
||||
IndexInsnNode node = (IndexInsnNode) insn;
|
||||
insn.getArg(0).merge(((FieldInfo) node.getIndex()).getType());
|
||||
break;
|
||||
}
|
||||
|
||||
case IF: {
|
||||
InsnArg arg0 = insn.getArg(0);
|
||||
@@ -133,7 +132,7 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
break;
|
||||
}
|
||||
case CMP_G:
|
||||
case CMP_L: {
|
||||
case CMP_L:
|
||||
InsnArg arg0 = insn.getArg(0);
|
||||
InsnArg arg1 = insn.getArg(1);
|
||||
if (arg0 == litArg) {
|
||||
@@ -142,7 +141,6 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
arg1.merge(arg0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RETURN:
|
||||
if (insn.getArgsCount() != 0) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
@@ -94,7 +93,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
IRegion r = (IRegion) region;
|
||||
String attrs = attributesString(r);
|
||||
dot.startLine("subgraph " + makeName(region) + " {");
|
||||
dot.startLine("label = \"" + r.toString()
|
||||
dot.startLine("label = \"" + r
|
||||
+ (attrs.length() == 0 ? "" : " | " + attrs)
|
||||
+ "\";");
|
||||
dot.startLine("node [shape=record,color=blue];");
|
||||
@@ -136,12 +135,6 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
for (BlockNode next : block.getDominatesOn()) {
|
||||
conn.startLine(makeName(block) + " -> " + makeName(next) + "[style=dotted];");
|
||||
}
|
||||
// add all dominators connections
|
||||
if (false) {
|
||||
for (BlockNode next : BlockUtils.bitsetToBlocks(mth, block.getDoms())) {
|
||||
conn.startLine(makeName(block) + " -> " + makeName(next) + "[style=dotted, color=green];");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String attributesString(IAttributeNode block) {
|
||||
@@ -152,7 +145,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
return attrs.toString();
|
||||
}
|
||||
|
||||
private String makeName(IContainer c) {
|
||||
private static String makeName(IContainer c) {
|
||||
String name;
|
||||
if (c instanceof BlockNode) {
|
||||
name = "Node_" + ((BlockNode) c).getId();
|
||||
@@ -166,7 +159,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
if (rawInsn) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
str.append(escape(insn.toString() + " " + insn.getAttributes()));
|
||||
str.append(escape(insn + " " + insn.getAttributes()));
|
||||
str.append(NL);
|
||||
}
|
||||
return str.toString();
|
||||
@@ -181,7 +174,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private String escape(String string) {
|
||||
private static String escape(String string) {
|
||||
return string
|
||||
.replace("\\", "") // TODO replace \"
|
||||
.replace("/", "\\/")
|
||||
|
||||
+10
-7
@@ -10,17 +10,20 @@ import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
public class MethodInlinerVisitor extends AbstractVisitor {
|
||||
/**
|
||||
* Inline synthetic methods.
|
||||
*/
|
||||
public class MethodInlineVisitor extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
AccessInfo accessFlags = mth.getAccessFlags();
|
||||
if (accessFlags.isSynthetic() && accessFlags.isStatic()) {
|
||||
if (mth.getBasicBlocks().size() == 2) {
|
||||
BlockNode block = mth.getBasicBlocks().get(1);
|
||||
if (block.getAttributes().contains(AttributeFlag.RETURN)) {
|
||||
inlineMth(mth);
|
||||
}
|
||||
if (accessFlags.isSynthetic()
|
||||
&& accessFlags.isStatic()
|
||||
&& mth.getBasicBlocks().size() == 2) {
|
||||
BlockNode block = mth.getBasicBlocks().get(1);
|
||||
if (block.getAttributes().contains(AttributeFlag.RETURN)) {
|
||||
inlineMth(mth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceStep(MethodNode mth) {
|
||||
private static void replaceStep(MethodNode mth) {
|
||||
ClassNode parentClass = mth.getParentClass();
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
InstructionRemover remover = new InstructionRemover(block.getInstructions());
|
||||
@@ -147,7 +147,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
/**
|
||||
* Remove unnecessary instructions
|
||||
*/
|
||||
private void removeStep(MethodNode mth) {
|
||||
private static void removeStep(MethodNode mth) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
InstructionRemover remover = new InstructionRemover(block.getInstructions());
|
||||
|
||||
@@ -193,7 +193,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void processExceptionHander(MethodNode mth, BlockNode block) {
|
||||
private static void processExceptionHander(MethodNode mth, BlockNode block) {
|
||||
ExcHandlerAttr handlerAttr = (ExcHandlerAttr) block.getAttributes().get(AttributeType.EXC_HANDLER);
|
||||
if (handlerAttr == null) {
|
||||
return;
|
||||
@@ -252,7 +252,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
block.getInstructions().set(i, insn);
|
||||
}
|
||||
|
||||
private void checkArgsNames(MethodNode mth) {
|
||||
private static void checkArgsNames(MethodNode mth) {
|
||||
for (RegisterArg arg : mth.getArguments(false)) {
|
||||
String name = arg.getTypedVar().getName();
|
||||
if (name != null && NameMapper.isReserved(name)) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package jadx.core.dex.visitors.regions;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
@@ -33,7 +32,6 @@ public class CheckRegions extends AbstractVisitor {
|
||||
public void processBlock(MethodNode mth, IBlock container) {
|
||||
if (container instanceof BlockNode) {
|
||||
blocksInRegions.add((BlockNode) container);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -41,16 +39,11 @@ public class CheckRegions extends AbstractVisitor {
|
||||
|
||||
if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
if (!blocksInRegions.contains(block)) {
|
||||
if (!block.getInstructions().isEmpty()
|
||||
&& !block.getAttributes().contains(AttributeFlag.SKIP)) {
|
||||
mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE);
|
||||
if (Consts.DEBUG) {
|
||||
LOG.debug(" Missing block: {} in {}", block, mth);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blocksInRegions.contains(block)
|
||||
&& !block.getInstructions().isEmpty()
|
||||
&& !block.getAttributes().contains(AttributeFlag.SKIP)) {
|
||||
mth.getAttributes().add(AttributeFlag.INCONSISTENT_CODE);
|
||||
LOG.debug(" Missing block: {} in {}", block, mth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
assert bs != null;
|
||||
|
||||
// intersect to get dominator of dominators
|
||||
List<BlockNode> domBlocks = BlockUtils.bitsetToBlocks(mth, bs);
|
||||
List<BlockNode> domBlocks = BlockUtils.bitSetToBlocks(mth, bs);
|
||||
for (BlockNode block : domBlocks) {
|
||||
bs.andNot(block.getDoms());
|
||||
}
|
||||
domBlocks = BlockUtils.bitsetToBlocks(mth, bs);
|
||||
domBlocks = BlockUtils.bitSetToBlocks(mth, bs);
|
||||
if (domBlocks.size() != 1) {
|
||||
throw new JadxRuntimeException(
|
||||
"Exception block dominator not found, method:" + mth + ". bs: " + bs);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package jadx.core.dex.visitors.regions;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.DeclareVariableAttr;
|
||||
import jadx.core.dex.attributes.DeclareVariablesAttr;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
@@ -125,7 +126,7 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
for (IRegion assignRegion : u.getAssigns()) {
|
||||
if (u.getArgRegion() == assignRegion
|
||||
&& canDeclareInRegion(u, assignRegion)) {
|
||||
u.getArg().getParentInsn().getAttributes().add(new DeclareVariableAttr());
|
||||
u.getArg().getParentInsn().getAttributes().add(AttributeFlag.DECLARE_VAR);
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
@@ -167,17 +168,16 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void declareVar(IContainer region, RegisterArg arg) {
|
||||
DeclareVariableAttr dv =
|
||||
(DeclareVariableAttr) region.getAttributes().get(AttributeType.DECLARE_VARIABLE);
|
||||
private static void declareVar(IContainer region, RegisterArg arg) {
|
||||
DeclareVariablesAttr dv = (DeclareVariablesAttr) region.getAttributes().get(AttributeType.DECLARE_VARIABLES);
|
||||
if (dv == null) {
|
||||
dv = new DeclareVariableAttr(new ArrayList<RegisterArg>());
|
||||
dv = new DeclareVariablesAttr();
|
||||
region.getAttributes().add(dv);
|
||||
}
|
||||
dv.addVar(arg);
|
||||
}
|
||||
|
||||
private boolean canDeclareInRegion(Usage u, IRegion region) {
|
||||
private static boolean canDeclareInRegion(Usage u, IRegion region) {
|
||||
for (IRegion r : u.getAssigns()) {
|
||||
if (!RegionUtils.isRegionContainsRegion(region, r)) {
|
||||
return false;
|
||||
|
||||
@@ -350,7 +350,7 @@ public class RegionMaker {
|
||||
/**
|
||||
* Traverse from monitor-enter thru successors and collect blocks contains monitor-exit
|
||||
*/
|
||||
private void traverseMonitorExits(InsnArg arg, BlockNode block, Set<BlockNode> exits, Set<BlockNode> visited) {
|
||||
private static void traverseMonitorExits(InsnArg arg, BlockNode block, Set<BlockNode> exits, Set<BlockNode> visited) {
|
||||
visited.add(block);
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
if (insn.getType() == InsnType.MONITOR_EXIT
|
||||
@@ -370,7 +370,7 @@ public class RegionMaker {
|
||||
/**
|
||||
* Traverse from monitor-enter thru successors and search for exit paths cross
|
||||
*/
|
||||
private BlockNode traverseMonitorExitsCross(BlockNode block, Set<BlockNode> exits, Set<BlockNode> visited) {
|
||||
private static BlockNode traverseMonitorExitsCross(BlockNode block, Set<BlockNode> exits, Set<BlockNode> visited) {
|
||||
visited.add(block);
|
||||
for (BlockNode node : block.getCleanSuccessors()) {
|
||||
boolean cross = true;
|
||||
@@ -543,7 +543,7 @@ public class RegionMaker {
|
||||
return result;
|
||||
}
|
||||
|
||||
private BlockNode getIfNode(BlockNode block) {
|
||||
private static BlockNode getIfNode(BlockNode block) {
|
||||
if (block != null && !block.getAttributes().contains(AttributeType.LOOP)) {
|
||||
List<InsnNode> insns = block.getInstructions();
|
||||
if (insns.size() == 1 && insns.get(0).getType() == InsnType.IF) {
|
||||
@@ -603,7 +603,7 @@ public class RegionMaker {
|
||||
|
||||
Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<BlockNode, List<Object>>(len);
|
||||
for (Entry<Integer, List<Object>> entry : casesMap.entrySet()) {
|
||||
BlockNode c = getBlockByOffset((int) entry.getKey(), block.getSuccessors());
|
||||
BlockNode c = getBlockByOffset(entry.getKey(), block.getSuccessors());
|
||||
assert c != null;
|
||||
blocksMap.put(c, entry.getValue());
|
||||
}
|
||||
@@ -648,7 +648,7 @@ public class RegionMaker {
|
||||
if (out != null) {
|
||||
stack.addExit(out);
|
||||
} else {
|
||||
for (BlockNode e : BlockUtils.bitsetToBlocks(mth, domsOn)) {
|
||||
for (BlockNode e : BlockUtils.bitSetToBlocks(mth, domsOn)) {
|
||||
stack.addExit(e);
|
||||
}
|
||||
}
|
||||
@@ -689,7 +689,7 @@ public class RegionMaker {
|
||||
handler.getHandlerRegion().getAttributes().add(excHandlerAttr);
|
||||
}
|
||||
|
||||
private boolean isEqualReturns(BlockNode b1, BlockNode b2) {
|
||||
private static boolean isEqualReturns(BlockNode b1, BlockNode b2) {
|
||||
if (b1 == b2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public abstract class TracedRegionVisitor implements IRegionVisitor {
|
||||
|
||||
@Override
|
||||
public void processBlock(MethodNode mth, IBlock container) {
|
||||
final IRegion curRegion = regionStack.peek();
|
||||
IRegion curRegion = regionStack.peek();
|
||||
processBlockTraced(mth, container, curRegion);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package jadx.core.dex.visitors.typeresolver;
|
||||
|
||||
import jadx.core.dex.attributes.BlockRegState;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
@@ -34,20 +35,18 @@ public class TypeResolver extends AbstractVisitor {
|
||||
/**
|
||||
* Check argument types (can be broken after merging debug info)
|
||||
*/
|
||||
private void prepare(MethodNode mth) {
|
||||
private static void prepare(MethodNode mth) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
switch (insn.getType()) {
|
||||
case CHECK_CAST:
|
||||
ArgType castType = (ArgType) ((IndexInsnNode) insn).getIndex();
|
||||
insn.getResult().getTypedVar().forceSetType(castType);
|
||||
break;
|
||||
if (insn.getType() == InsnType.CHECK_CAST) {
|
||||
ArgType castType = (ArgType) ((IndexInsnNode) insn).getIndex();
|
||||
insn.getResult().getTypedVar().forceSetType(castType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitBlocks(MethodNode mth) {
|
||||
private static void visitBlocks(MethodNode mth) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
BlockRegState state = new BlockRegState(mth);
|
||||
|
||||
@@ -94,7 +93,7 @@ public class TypeResolver extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean connectEdges(MethodNode mth, BlockNode from, BlockNode to, boolean back) {
|
||||
private static boolean connectEdges(MethodNode mth, BlockNode from, BlockNode to, boolean back) {
|
||||
BlockRegState end = from.getEndState();
|
||||
BlockRegState start = to.getStartState();
|
||||
|
||||
|
||||
+4
-5
@@ -8,11 +8,10 @@ import jadx.core.utils.ErrorsCounter;
|
||||
public class CheckTypeVisitor {
|
||||
|
||||
public static void visit(MethodNode mth, InsnNode insn) {
|
||||
if (insn.getResult() != null) {
|
||||
if (!insn.getResult().getType().isTypeKnown()) {
|
||||
error("Wrong return type", mth, insn);
|
||||
return;
|
||||
}
|
||||
if (insn.getResult() != null
|
||||
&& !insn.getResult().getType().isTypeKnown()) {
|
||||
error("Wrong return type", mth, insn);
|
||||
return;
|
||||
}
|
||||
|
||||
for (InsnArg arg : insn.getArguments()) {
|
||||
|
||||
@@ -51,6 +51,9 @@ public class BlockUtils {
|
||||
}
|
||||
|
||||
public static boolean isBackEdge(BlockNode from, BlockNode to) {
|
||||
if (to == null) {
|
||||
return false;
|
||||
}
|
||||
if (from.getCleanSuccessors().contains(to)) {
|
||||
return false; // already checked
|
||||
}
|
||||
@@ -69,16 +72,6 @@ public class BlockUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockNode canMergeNextBlock(BlockNode block) {
|
||||
BlockNode next = getNextBlock(block);
|
||||
if (next != null) {
|
||||
if (next.getIDom() == block) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if instruction contains in block (use == for comparison, not equals)
|
||||
*/
|
||||
@@ -118,7 +111,7 @@ public class BlockUtils {
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static List<BlockNode> bitsetToBlocks(MethodNode mth, BitSet bs) {
|
||||
public static List<BlockNode> bitSetToBlocks(MethodNode mth, BitSet bs) {
|
||||
List<BlockNode> blocks = new ArrayList<BlockNode>(bs.cardinality());
|
||||
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
|
||||
BlockNode block = mth.getBasicBlocks().get(i);
|
||||
|
||||
@@ -16,7 +16,7 @@ public class ErrorsCounter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ErrorsCounter.class);
|
||||
|
||||
private static final Set<Object> ERROR_NODES = new HashSet<Object>();
|
||||
private static int errorsCount = 0;
|
||||
private static int errorsCount;
|
||||
|
||||
public static int getErrorCount() {
|
||||
return errorsCount;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class InsnUtils {
|
||||
if (index instanceof String) {
|
||||
return "\"" + index + "\"";
|
||||
} else {
|
||||
return " " + index.toString();
|
||||
return " " + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ public class RegionUtils {
|
||||
if (container == region) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (container instanceof IRegion) {
|
||||
IRegion r = (IRegion) container;
|
||||
|
||||
@@ -92,10 +91,9 @@ public class RegionUtils {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (tb.getFinalBlock() != null) {
|
||||
if (isRegionContainsRegion(tb.getFinalBlock(), region)) {
|
||||
return true;
|
||||
}
|
||||
if (tb.getFinalBlock() != null
|
||||
&& isRegionContainsRegion(tb.getFinalBlock(), region)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (isRegionContainsRegion(b, region)) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.api;
|
||||
|
||||
import jadx.core.Jadx;
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.visitors.DepthTraverser;
|
||||
@@ -19,6 +20,7 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
@@ -65,6 +67,7 @@ public abstract class InternalJadxTest {
|
||||
for (IDexTreeVisitor visitor : passes) {
|
||||
DepthTraverser.visit(visitor, cls);
|
||||
}
|
||||
assertFalse(cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE));
|
||||
return cls;
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package jadx.tests.internal.inline;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestSyntheticInline extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
private int f;
|
||||
|
||||
private int func() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public class A {
|
||||
public int getF() {
|
||||
return f;
|
||||
}
|
||||
|
||||
public void setF(int v) {
|
||||
f = v;
|
||||
}
|
||||
|
||||
public int callFunc() {
|
||||
return func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, not(containsString("synthetic")));
|
||||
assertThat(code, not(containsString("access$")));
|
||||
assertThat(code, not(containsString("x0")));
|
||||
assertThat(code, containsString("return f;"));
|
||||
assertThat(code, containsString("return func();"));
|
||||
assertThat(code, containsString("f = v;"));
|
||||
}
|
||||
}
|
||||
@@ -45,20 +45,19 @@ public class JClass extends JNode {
|
||||
if (!loaded) {
|
||||
cls.decompile();
|
||||
loaded = true;
|
||||
updateChilds();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateChilds() {
|
||||
public synchronized void update() {
|
||||
removeAllChildren();
|
||||
if (!loaded) {
|
||||
add(new TextNode(NLS.str("tree.loading")));
|
||||
} else {
|
||||
for (JavaClass javaClass : cls.getInnerClasses()) {
|
||||
JClass child = new JClass(javaClass, this);
|
||||
add(child);
|
||||
child.updateChilds();
|
||||
JClass innerCls = new JClass(javaClass, this);
|
||||
add(innerCls);
|
||||
innerCls.update();
|
||||
}
|
||||
for (JavaField f : cls.getFields()) {
|
||||
add(new JField(f, this));
|
||||
|
||||
@@ -27,10 +27,6 @@ public class JField extends JNode {
|
||||
this.jParent = jClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChilds() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return jParent;
|
||||
|
||||
@@ -29,10 +29,6 @@ public class JMethod extends JNode {
|
||||
this.jParent = jClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChilds() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return jParent;
|
||||
|
||||
@@ -16,7 +16,5 @@ public abstract class JNode extends DefaultMutableTreeNode {
|
||||
|
||||
public abstract int getLine();
|
||||
|
||||
public abstract void updateChilds();
|
||||
|
||||
public abstract Icon getIcon();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
|
||||
for (JavaClass javaClass : javaClasses) {
|
||||
classes.add(new JClass(javaClass));
|
||||
}
|
||||
updateChilds();
|
||||
update();
|
||||
}
|
||||
|
||||
public JPackage(String name) {
|
||||
@@ -33,15 +33,14 @@ public class JPackage extends JNode implements Comparable<JPackage> {
|
||||
this.classes = new ArrayList<JClass>(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChilds() {
|
||||
public void update() {
|
||||
removeAllChildren();
|
||||
for (JPackage pkg : innerPackages) {
|
||||
pkg.updateChilds();
|
||||
pkg.update();
|
||||
add(pkg);
|
||||
}
|
||||
for (JClass cls : classes) {
|
||||
cls.updateChilds();
|
||||
cls.update();
|
||||
add(cls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,10 @@ public class JRoot extends JNode {
|
||||
|
||||
public JRoot(JadxWrapper wrapper) {
|
||||
this.wrapper = wrapper;
|
||||
updateChilds();
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChilds() {
|
||||
public void update() {
|
||||
removeAllChildren();
|
||||
if (flatPackages) {
|
||||
for (JavaPackage pkg : wrapper.getPackages()) {
|
||||
@@ -41,7 +40,7 @@ public class JRoot extends JNode {
|
||||
// build packages hierarchy
|
||||
List<JPackage> rootPkgs = getHierarchyPackages(wrapper.getPackages());
|
||||
for (JPackage jPackage : rootPkgs) {
|
||||
jPackage.updateChilds();
|
||||
jPackage.update();
|
||||
add(jPackage);
|
||||
}
|
||||
}
|
||||
@@ -88,7 +87,7 @@ public class JRoot extends JNode {
|
||||
}
|
||||
|
||||
// use identity set for collect inner packages
|
||||
Set<JPackage> innerPackages = Collections.newSetFromMap(new IdentityHashMap<JPackage,Boolean>());
|
||||
Set<JPackage> innerPackages = Collections.newSetFromMap(new IdentityHashMap<JPackage, Boolean>());
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
innerPackages.addAll(pkg.getInnerPackages());
|
||||
}
|
||||
@@ -131,7 +130,7 @@ public class JRoot extends JNode {
|
||||
public void setFlatPackages(boolean flatPackages) {
|
||||
if (this.flatPackages != flatPackages) {
|
||||
this.flatPackages = flatPackages;
|
||||
updateChilds();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@ public class TextNode extends JNode {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChilds() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return null;
|
||||
|
||||
@@ -67,10 +67,18 @@ public class Utils {
|
||||
icon = def;
|
||||
}
|
||||
OverlayIcon overIcon = new OverlayIcon(icon);
|
||||
if (af.isFinal()) overIcon.add(ICON_FINAL);
|
||||
if (af.isStatic()) overIcon.add(ICON_STATIC);
|
||||
if (af.isAbstract()) overIcon.add(ICON_ABSTRACT);
|
||||
if (af.isNative()) overIcon.add(ICON_NATIVE);
|
||||
if (af.isFinal()) {
|
||||
overIcon.add(ICON_FINAL);
|
||||
}
|
||||
if (af.isStatic()) {
|
||||
overIcon.add(ICON_STATIC);
|
||||
}
|
||||
if (af.isAbstract()) {
|
||||
overIcon.add(ICON_ABSTRACT);
|
||||
}
|
||||
if (af.isNative()) {
|
||||
overIcon.add(ICON_NATIVE);
|
||||
}
|
||||
return overIcon;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user