From 67eb55a95dfd853302d24a0ef8b203a4ee09c06c Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 26 Jul 2013 23:04:42 +0400 Subject: [PATCH] gui: add type and access info to classes tree --- jadx-cli/src/main/java/jadx/cli/JadxCLI.java | 1 - .../src/main/java/jadx/api/Decompiler.java | 2 +- .../src/main/java/jadx/api/JavaClass.java | 3 +- .../src/main/java/jadx/api/JavaField.java | 5 ++ .../src/main/java/jadx/api/JavaMethod.java | 19 ++++++ .../main/java/jadx/core/codegen/InsnGen.java | 8 ++- .../java/jadx/core/dex/info/AccessInfo.java | 21 +++++-- .../dex/visitors/MethodInlinerVisitor.java | 8 +-- .../java/jadx/core/dex/visitors/SaveCode.java | 8 +-- .../main/java/jadx/gui/treemodel/JClass.java | 1 + .../main/java/jadx/gui/treemodel/JField.java | 21 +++---- .../main/java/jadx/gui/treemodel/JMethod.java | 36 +++++++---- .../main/java/jadx/gui/utils/OverlayIcon.java | 58 ++++++++++++++++++ .../src/main/java/jadx/gui/utils/Utils.java | 47 ++++++++++++++ .../main/resources/icons-16/jsearch_obj.png | Bin 760 -> 0 bytes .../src/main/resources/icons-16/run_co.png | Bin 180 -> 0 bytes 16 files changed, 193 insertions(+), 45 deletions(-) create mode 100644 jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java delete mode 100644 jadx-gui/src/main/resources/icons-16/jsearch_obj.png delete mode 100644 jadx-gui/src/main/resources/icons-16/run_co.png diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java index 7e34da717..23b18d39b 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java @@ -12,7 +12,6 @@ public class JadxCLI { JadxArgs jadxArgs = new JadxArgs(args, true); Decompiler jadx = new Decompiler(jadxArgs); jadx.processAndSaveAll(); - LOG.info("done"); System.exit(jadx.getErrorsCount()); } } diff --git a/jadx-core/src/main/java/jadx/api/Decompiler.java b/jadx-core/src/main/java/jadx/api/Decompiler.java index da66a1756..2e1c3d117 100644 --- a/jadx-core/src/main/java/jadx/api/Decompiler.java +++ b/jadx-core/src/main/java/jadx/api/Decompiler.java @@ -91,7 +91,7 @@ public final class Decompiler { return Collections.unmodifiableList(packages); } - public ThreadPoolExecutor saveAll(File dir) throws InterruptedException { + public ThreadPoolExecutor saveAll(File dir) { int threadsCount = args.getThreadsCount(); LOG.debug("processing threads count: {}", threadsCount); diff --git a/jadx-core/src/main/java/jadx/api/JavaClass.java b/jadx-core/src/main/java/jadx/api/JavaClass.java index 5cacd4674..e07c551e8 100644 --- a/jadx-core/src/main/java/jadx/api/JavaClass.java +++ b/jadx-core/src/main/java/jadx/api/JavaClass.java @@ -1,7 +1,6 @@ package jadx.api; import jadx.core.codegen.CodeWriter; -import jadx.core.dex.attributes.AttributeFlag; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; @@ -51,7 +50,7 @@ public final class JavaClass { } else { List mths = new ArrayList(methodsCount); for (MethodNode m : cls.getMethods()) { - if (!m.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { + if (!m.getAccessFlags().isSynthetic()) { mths.add(new JavaMethod(m)); } } diff --git a/jadx-core/src/main/java/jadx/api/JavaField.java b/jadx-core/src/main/java/jadx/api/JavaField.java index d5f30ee38..70c007c19 100644 --- a/jadx-core/src/main/java/jadx/api/JavaField.java +++ b/jadx-core/src/main/java/jadx/api/JavaField.java @@ -1,6 +1,7 @@ package jadx.api; import jadx.core.dex.info.AccessInfo; +import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.FieldNode; public class JavaField { @@ -19,6 +20,10 @@ public class JavaField { return field.getAccessFlags(); } + public ArgType getType() { + return field.getType(); + } + public int getDecompiledLine() { return field.getDecompiledLine(); } diff --git a/jadx-core/src/main/java/jadx/api/JavaMethod.java b/jadx-core/src/main/java/jadx/api/JavaMethod.java index f65852243..e75b06841 100644 --- a/jadx-core/src/main/java/jadx/api/JavaMethod.java +++ b/jadx-core/src/main/java/jadx/api/JavaMethod.java @@ -2,8 +2,11 @@ package jadx.api; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.MethodInfo; +import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.MethodNode; +import java.util.List; + public class JavaMethod { private final MethodNode mth; @@ -25,6 +28,22 @@ public class JavaMethod { return mth.getAccessFlags(); } + public List getArguments() { + return mth.getMethodInfo().getArgumentsTypes(); + } + + public ArgType getReturnType() { + return mth.getReturnType(); + } + + public boolean isConstructor() { + return mth.getMethodInfo().isConstructor(); + } + + public boolean isClassInit() { + return mth.getMethodInfo().isClassInit(); + } + public int getDecompiledLine() { return mth.getDecompiledLine(); } diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index e2c66cba1..5786d94c5 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -481,7 +481,7 @@ public class InsnGen { private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException { MethodInfo callMth = insn.getCallMth(); - // inline method if METHOD_INLINE attribute is attached + // inline method MethodNode callMthNode = mth.dex().resolveMethod(callMth); if (callMthNode != null && callMthNode.getAttributes().contains(AttributeType.METHOD_INLINE)) { @@ -507,8 +507,10 @@ public class InsnGen { case STATIC: ClassInfo insnCls = mth.getParentClass().getClassInfo(); - if (!insnCls.equals(callMth.getDeclClass())) - code.add(useClass(callMth.getDeclClass())).add('.'); + ClassInfo declClass = callMth.getDeclClass(); + if (!insnCls.equals(declClass)) { + code.add(useClass(declClass)).add('.'); + } break; } code.add(callMth.getName()); diff --git a/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java index 48de60527..117822bf3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java @@ -93,6 +93,18 @@ public class AccessInfo { return (accFlags & AccessFlags.ACC_VARARGS) != 0; } + public boolean isSynchronized() { + return (accFlags & (AccessFlags.ACC_SYNCHRONIZED | AccessFlags.ACC_DECLARED_SYNCHRONIZED)) != 0; + } + + public boolean isTransient() { + return (accFlags & AccessFlags.ACC_TRANSIENT) != 0; + } + + public boolean isVolatile() { + return (accFlags & AccessFlags.ACC_VOLATILE) != 0; + } + public int getFlags() { return accFlags; } @@ -126,10 +138,7 @@ public class AccessInfo { switch (type) { case METHOD: - if ((accFlags & AccessFlags.ACC_SYNCHRONIZED) != 0) - code.append("synchronized "); - - if ((accFlags & AccessFlags.ACC_DECLARED_SYNCHRONIZED) != 0) + if (isSynchronized()) code.append("synchronized "); if (isBridge()) @@ -142,10 +151,10 @@ public class AccessInfo { break; case FIELD: - if ((accFlags & AccessFlags.ACC_VOLATILE) != 0) + if (isVolatile()) code.append("volatile "); - if ((accFlags & AccessFlags.ACC_TRANSIENT) != 0) + if (isTransient()) code.append("transient "); break; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlinerVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlinerVisitor.java index b673de78f..6a4004d3a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlinerVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/MethodInlinerVisitor.java @@ -1,7 +1,7 @@ package jadx.core.dex.visitors; import jadx.core.dex.attributes.AttributeFlag; -import jadx.core.dex.attributes.IAttribute; +import jadx.core.dex.attributes.AttributesList; import jadx.core.dex.attributes.MethodInlineAttr; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.instructions.InsnType; @@ -43,8 +43,8 @@ public class MethodInlinerVisitor extends AbstractVisitor { } private static void addInlineAttr(MethodNode mth, InsnNode insn) { - IAttribute attr = new MethodInlineAttr(insn); - mth.getAttributes().add(attr); - mth.getAttributes().add(AttributeFlag.DONT_GENERATE); + AttributesList attributes = mth.getAttributes(); + attributes.add(new MethodInlineAttr(insn)); + attributes.add(AttributeFlag.DONT_GENERATE); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java b/jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java index 8836386bd..0ef64f1aa 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java @@ -8,7 +8,6 @@ import jadx.core.utils.exceptions.CodegenException; import java.io.File; public class SaveCode extends AbstractVisitor { - private final File dir; private final IJadxArgs args; @@ -22,13 +21,10 @@ public class SaveCode extends AbstractVisitor { CodeWriter clsCode = cls.getCode(); String fileName = cls.getClassInfo().getFullPath() + ".java"; - if (isFallbackMode()) + if (args.isFallbackMode()) { fileName += ".jadx"; + } clsCode.save(dir, fileName); return false; } - - public boolean isFallbackMode() { - return args.isFallbackMode(); - } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java index d83910ab2..680b7f25f 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java @@ -33,6 +33,7 @@ public class JClass extends DefaultMutableTreeNode implements JNode { @Override public void updateChilds() { + removeAllChildren(); JClass currentParent = jParrent == null ? this : jParrent; for (JavaClass javaClass : cls.getInnerClasses()) { JClass child = new JClass(javaClass); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java index e840dd084..b6f4af792 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java @@ -2,18 +2,22 @@ package jadx.gui.treemodel; import jadx.api.JavaField; import jadx.core.dex.info.AccessInfo; +import jadx.gui.utils.OverlayIcon; import jadx.gui.utils.Utils; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.tree.DefaultMutableTreeNode; -public class JField extends DefaultMutableTreeNode implements JNode { +public class JField extends DefaultMutableTreeNode implements JNode { private static final ImageIcon ICON_FLD_DEF = Utils.openIcon("field_default_obj"); private static final ImageIcon ICON_FLD_PRI = Utils.openIcon("field_private_obj"); private static final ImageIcon ICON_FLD_PRO = Utils.openIcon("field_protected_obj"); private static final ImageIcon ICON_FLD_PUB = Utils.openIcon("field_public_obj"); + private static final ImageIcon ICON_TRANSIENT = Utils.openIcon("transient_co"); + private static final ImageIcon ICON_VOLATILE = Utils.openIcon("volatile_co"); + private final JavaField field; private final JClass jParent; @@ -39,19 +43,14 @@ public class JField extends DefaultMutableTreeNode implements JNode { @Override public Icon getIcon() { AccessInfo af = field.getAccessFlags(); - if(af.isPublic()){ - return ICON_FLD_PUB; - } else if(af.isPrivate()) { - return ICON_FLD_PRI; - } else if(af.isProtected()) { - return ICON_FLD_PRO; - } else { - return ICON_FLD_DEF; - } + OverlayIcon icon = Utils.makeIcon(af, ICON_FLD_PUB, ICON_FLD_PRI, ICON_FLD_PRO, ICON_FLD_DEF); + if (af.isTransient()) icon.add(ICON_TRANSIENT); + if (af.isVolatile()) icon.add(ICON_VOLATILE); + return icon; } @Override public String toString() { - return field.getName(); + return Utils.typeFormat(field.getName(), field.getType()); } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java index e1c9378c0..0d26c0531 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java @@ -2,11 +2,14 @@ package jadx.gui.treemodel; import jadx.api.JavaMethod; import jadx.core.dex.info.AccessInfo; +import jadx.core.dex.instructions.args.ArgType; +import jadx.gui.utils.OverlayIcon; import jadx.gui.utils.Utils; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.tree.DefaultMutableTreeNode; +import java.util.Iterator; public class JMethod extends DefaultMutableTreeNode implements JNode { private static final ImageIcon ICON_MTH_DEF = Utils.openIcon("methdef_obj"); @@ -14,6 +17,9 @@ public class JMethod extends DefaultMutableTreeNode implements JNode { private static final ImageIcon ICON_MTH_PRO = Utils.openIcon("methpro_obj"); private static final ImageIcon ICON_MTH_PUB = Utils.openIcon("methpub_obj"); + private static final ImageIcon ICON_CONSTRUCTOR = Utils.openIcon("constr_ovr"); + private static final ImageIcon ICON_SYNC = Utils.openIcon("synch_co"); + private final JavaMethod mth; private final JClass jparent; @@ -38,20 +44,28 @@ public class JMethod extends DefaultMutableTreeNode implements JNode { @Override public Icon getIcon() { - AccessInfo af = mth.getAccessFlags(); - if (af.isPublic()) { - return ICON_MTH_PUB; - } else if (af.isPrivate()) { - return ICON_MTH_PRI; - } else if (af.isProtected()) { - return ICON_MTH_PRO; - } else { - return ICON_MTH_DEF; - } + AccessInfo accessFlags = mth.getAccessFlags(); + OverlayIcon icon = Utils.makeIcon(accessFlags, ICON_MTH_PUB, ICON_MTH_PRI, ICON_MTH_PRO, ICON_MTH_DEF); + if(accessFlags.isConstructor()) icon.add(ICON_CONSTRUCTOR); + if (accessFlags.isSynchronized()) icon.add(ICON_SYNC); + return icon; } @Override public String toString() { - return mth.getName(); + if (mth.isClassInit()) { + return "{...}"; + } + + StringBuilder base = new StringBuilder(); + base.append(mth.getName()); + base.append('('); + for (Iterator it = mth.getArguments().iterator(); it.hasNext(); ) { + base.append(Utils.typeStr(it.next())); + if(it.hasNext()) + base.append(", "); + } + base.append(')'); + return Utils.typeFormat(base.toString(), mth.getReturnType()); } } diff --git a/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java b/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java new file mode 100644 index 000000000..b01cecd7d --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java @@ -0,0 +1,58 @@ +package jadx.gui.utils; + +import javax.swing.Icon; +import java.awt.Component; +import java.awt.Graphics; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class OverlayIcon implements Icon { + + private final Icon icon; + private final List icons = new ArrayList(4); + + private static final double A = 0.8; + private static final double B = 0.2; + private static final double[] pos = new double[]{A, B, B, B, A, A, B, A}; + + public OverlayIcon(Icon icon) { + this.icon = icon; + } + + @Override + public int getIconHeight() { + return icon.getIconHeight(); + } + + @Override + public int getIconWidth() { + return icon.getIconWidth(); + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + int w = getIconWidth(); + int h = getIconHeight(); + + icon.paintIcon(c, g, x, y); + int k = 0; + for (Icon icon : icons) { + int dx = (int) (pos[k++] * (w - icon.getIconWidth())); + int dy = (int) (pos[k++] * (h - icon.getIconHeight())); + icon.paintIcon(c, g, x + dx, y + dy); + } + } + + public void add(Icon icon) { + icons.add(icon); + } + + public void addAll(Collection icons) { + icons.addAll(icons); + } + + public List getIcons() { + return icons; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/utils/Utils.java b/jadx-gui/src/main/java/jadx/gui/utils/Utils.java index 4e34de5a4..f31cd7399 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/Utils.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/Utils.java @@ -1,8 +1,11 @@ package jadx.gui.utils; +import jadx.core.dex.info.AccessInfo; +import jadx.core.dex.instructions.args.ArgType; import jadx.core.utils.exceptions.JadxRuntimeException; import javax.swing.AbstractAction; +import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.KeyStroke; @@ -10,6 +13,11 @@ import java.net.URL; public class Utils { + private static final ImageIcon ICON_STATIC = Utils.openIcon("static_co"); + private static final ImageIcon ICON_FINAL = Utils.openIcon("final_co"); + private static final ImageIcon ICON_ABSTRACT = Utils.openIcon("abstract_co"); + private static final ImageIcon ICON_NATIVE = Utils.openIcon("native_co"); + public static ImageIcon openIcon(String name) { String iconPath = "/icons-16/" + name + ".png"; URL resource = Utils.class.getResource(iconPath); @@ -23,4 +31,43 @@ public class Utils { comp.getInputMap().put(key, id); comp.getActionMap().put(id, action); } + + public static String typeFormat(String name, ArgType type) { + return "" + name + " : " + typeStr(type) + ""; + } + + public static String typeStr(ArgType type) { + if (type.isObject()) { + String cls = type.getObject(); + int dot = cls.lastIndexOf('.'); + if (dot != -1) { + return cls.substring(dot + 1); + } else { + return cls; + } + } + if (type.isArray()) { + return typeStr(type.getArrayElement()) + "[]"; + } + return type.toString(); + } + + public static OverlayIcon makeIcon(AccessInfo af, Icon pub, Icon pri, Icon pro, Icon def) { + Icon icon; + if (af.isPublic()) { + icon = pub; + } else if (af.isPrivate()) { + icon = pri; + } else if (af.isProtected()) { + icon = pro; + } else { + 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); + return overIcon; + } } diff --git a/jadx-gui/src/main/resources/icons-16/jsearch_obj.png b/jadx-gui/src/main/resources/icons-16/jsearch_obj.png deleted file mode 100644 index c34b05813eada75f15e6f24f270799612db48e8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 760 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47#jk7LR>d2UGwDOclTsCw;v#@#hZLlPe33ugJf@xBlLx{V&&tzupwPwl99?jI`w)G2ia*`LNV_(}bj- zw>RE7zi(b`*xcH%iTQs0dA<|!{U#R$OfCupx&R1(9v_6@OEsT)Qr5?E3iIVx)9Yuf%yQOPWo$F~Z`J13iHi~f z++J88?vP8+>5@2N_}S^a)nS)O1|E~StB%jAHdt{z%W0>bg{0g4C<_*!ok~+uZthv6 zFYC1M_Mb~<@7}bnyZtPs$^V&%#@1Zx+5AT)^E>_Ba4GtD36Ik{d(Gmvwcaj=Yz(e% rxu*T}Q*6z3+wa?D_PNXdn^VW&Vqq96G2ufW&_E)H!VDyjYyB_tgPI zFaXK`!Tr^8CxH}ONswPKM0oT5CHsLQj7i?^F6?579j}2L&H|6fVj%4S#%?FG?SKqr zPZ!4!j_b)Byu7>#9EFTRd_8&&hdM4c9z1xXf$UHx3v IIVCg!0Bu7z-v9sr