Commit 67eb55a9 authored by Skylot's avatar Skylot

gui: add type and access info to classes tree

parent fa097cc6
...@@ -12,7 +12,6 @@ public class JadxCLI { ...@@ -12,7 +12,6 @@ public class JadxCLI {
JadxArgs jadxArgs = new JadxArgs(args, true); JadxArgs jadxArgs = new JadxArgs(args, true);
Decompiler jadx = new Decompiler(jadxArgs); Decompiler jadx = new Decompiler(jadxArgs);
jadx.processAndSaveAll(); jadx.processAndSaveAll();
LOG.info("done");
System.exit(jadx.getErrorsCount()); System.exit(jadx.getErrorsCount());
} }
} }
...@@ -91,7 +91,7 @@ public final class Decompiler { ...@@ -91,7 +91,7 @@ public final class Decompiler {
return Collections.unmodifiableList(packages); return Collections.unmodifiableList(packages);
} }
public ThreadPoolExecutor saveAll(File dir) throws InterruptedException { public ThreadPoolExecutor saveAll(File dir) {
int threadsCount = args.getThreadsCount(); int threadsCount = args.getThreadsCount();
LOG.debug("processing threads count: {}", threadsCount); LOG.debug("processing threads count: {}", threadsCount);
......
package jadx.api; package jadx.api;
import jadx.core.codegen.CodeWriter; import jadx.core.codegen.CodeWriter;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.FieldNode;
...@@ -51,7 +50,7 @@ public final class JavaClass { ...@@ -51,7 +50,7 @@ public final class JavaClass {
} else { } else {
List<JavaMethod> mths = new ArrayList<JavaMethod>(methodsCount); List<JavaMethod> mths = new ArrayList<JavaMethod>(methodsCount);
for (MethodNode m : cls.getMethods()) { for (MethodNode m : cls.getMethods()) {
if (!m.getAttributes().contains(AttributeFlag.DONT_GENERATE)) { if (!m.getAccessFlags().isSynthetic()) {
mths.add(new JavaMethod(m)); mths.add(new JavaMethod(m));
} }
} }
......
package jadx.api; package jadx.api;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.FieldNode;
public class JavaField { public class JavaField {
...@@ -19,6 +20,10 @@ public class JavaField { ...@@ -19,6 +20,10 @@ public class JavaField {
return field.getAccessFlags(); return field.getAccessFlags();
} }
public ArgType getType() {
return field.getType();
}
public int getDecompiledLine() { public int getDecompiledLine() {
return field.getDecompiledLine(); return field.getDecompiledLine();
} }
......
...@@ -2,8 +2,11 @@ package jadx.api; ...@@ -2,8 +2,11 @@ package jadx.api;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.MethodInfo; import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import java.util.List;
public class JavaMethod { public class JavaMethod {
private final MethodNode mth; private final MethodNode mth;
...@@ -25,6 +28,22 @@ public class JavaMethod { ...@@ -25,6 +28,22 @@ public class JavaMethod {
return mth.getAccessFlags(); return mth.getAccessFlags();
} }
public List<ArgType> 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() { public int getDecompiledLine() {
return mth.getDecompiledLine(); return mth.getDecompiledLine();
} }
......
...@@ -481,7 +481,7 @@ public class InsnGen { ...@@ -481,7 +481,7 @@ public class InsnGen {
private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException { private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException {
MethodInfo callMth = insn.getCallMth(); MethodInfo callMth = insn.getCallMth();
// inline method if METHOD_INLINE attribute is attached // inline method
MethodNode callMthNode = mth.dex().resolveMethod(callMth); MethodNode callMthNode = mth.dex().resolveMethod(callMth);
if (callMthNode != null if (callMthNode != null
&& callMthNode.getAttributes().contains(AttributeType.METHOD_INLINE)) { && callMthNode.getAttributes().contains(AttributeType.METHOD_INLINE)) {
...@@ -507,8 +507,10 @@ public class InsnGen { ...@@ -507,8 +507,10 @@ public class InsnGen {
case STATIC: case STATIC:
ClassInfo insnCls = mth.getParentClass().getClassInfo(); ClassInfo insnCls = mth.getParentClass().getClassInfo();
if (!insnCls.equals(callMth.getDeclClass())) ClassInfo declClass = callMth.getDeclClass();
code.add(useClass(callMth.getDeclClass())).add('.'); if (!insnCls.equals(declClass)) {
code.add(useClass(declClass)).add('.');
}
break; break;
} }
code.add(callMth.getName()); code.add(callMth.getName());
......
...@@ -93,6 +93,18 @@ public class AccessInfo { ...@@ -93,6 +93,18 @@ public class AccessInfo {
return (accFlags & AccessFlags.ACC_VARARGS) != 0; 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() { public int getFlags() {
return accFlags; return accFlags;
} }
...@@ -126,10 +138,7 @@ public class AccessInfo { ...@@ -126,10 +138,7 @@ public class AccessInfo {
switch (type) { switch (type) {
case METHOD: case METHOD:
if ((accFlags & AccessFlags.ACC_SYNCHRONIZED) != 0) if (isSynchronized())
code.append("synchronized ");
if ((accFlags & AccessFlags.ACC_DECLARED_SYNCHRONIZED) != 0)
code.append("synchronized "); code.append("synchronized ");
if (isBridge()) if (isBridge())
...@@ -142,10 +151,10 @@ public class AccessInfo { ...@@ -142,10 +151,10 @@ public class AccessInfo {
break; break;
case FIELD: case FIELD:
if ((accFlags & AccessFlags.ACC_VOLATILE) != 0) if (isVolatile())
code.append("volatile "); code.append("volatile ");
if ((accFlags & AccessFlags.ACC_TRANSIENT) != 0) if (isTransient())
code.append("transient "); code.append("transient ");
break; break;
......
package jadx.core.dex.visitors; package jadx.core.dex.visitors;
import jadx.core.dex.attributes.AttributeFlag; 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.attributes.MethodInlineAttr;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InsnType;
...@@ -43,8 +43,8 @@ public class MethodInlinerVisitor extends AbstractVisitor { ...@@ -43,8 +43,8 @@ public class MethodInlinerVisitor extends AbstractVisitor {
} }
private static void addInlineAttr(MethodNode mth, InsnNode insn) { private static void addInlineAttr(MethodNode mth, InsnNode insn) {
IAttribute attr = new MethodInlineAttr(insn); AttributesList attributes = mth.getAttributes();
mth.getAttributes().add(attr); attributes.add(new MethodInlineAttr(insn));
mth.getAttributes().add(AttributeFlag.DONT_GENERATE); attributes.add(AttributeFlag.DONT_GENERATE);
} }
} }
...@@ -8,7 +8,6 @@ import jadx.core.utils.exceptions.CodegenException; ...@@ -8,7 +8,6 @@ import jadx.core.utils.exceptions.CodegenException;
import java.io.File; import java.io.File;
public class SaveCode extends AbstractVisitor { public class SaveCode extends AbstractVisitor {
private final File dir; private final File dir;
private final IJadxArgs args; private final IJadxArgs args;
...@@ -22,13 +21,10 @@ public class SaveCode extends AbstractVisitor { ...@@ -22,13 +21,10 @@ public class SaveCode extends AbstractVisitor {
CodeWriter clsCode = cls.getCode(); CodeWriter clsCode = cls.getCode();
String fileName = cls.getClassInfo().getFullPath() + ".java"; String fileName = cls.getClassInfo().getFullPath() + ".java";
if (isFallbackMode()) if (args.isFallbackMode()) {
fileName += ".jadx"; fileName += ".jadx";
}
clsCode.save(dir, fileName); clsCode.save(dir, fileName);
return false; return false;
} }
public boolean isFallbackMode() {
return args.isFallbackMode();
}
} }
...@@ -33,6 +33,7 @@ public class JClass extends DefaultMutableTreeNode implements JNode { ...@@ -33,6 +33,7 @@ public class JClass extends DefaultMutableTreeNode implements JNode {
@Override @Override
public void updateChilds() { public void updateChilds() {
removeAllChildren();
JClass currentParent = jParrent == null ? this : jParrent; JClass currentParent = jParrent == null ? this : jParrent;
for (JavaClass javaClass : cls.getInnerClasses()) { for (JavaClass javaClass : cls.getInnerClasses()) {
JClass child = new JClass(javaClass); JClass child = new JClass(javaClass);
......
...@@ -2,18 +2,22 @@ package jadx.gui.treemodel; ...@@ -2,18 +2,22 @@ package jadx.gui.treemodel;
import jadx.api.JavaField; import jadx.api.JavaField;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.gui.utils.OverlayIcon;
import jadx.gui.utils.Utils; import jadx.gui.utils.Utils;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode; 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_DEF = Utils.openIcon("field_default_obj");
private static final ImageIcon ICON_FLD_PRI = Utils.openIcon("field_private_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_PRO = Utils.openIcon("field_protected_obj");
private static final ImageIcon ICON_FLD_PUB = Utils.openIcon("field_public_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 JavaField field;
private final JClass jParent; private final JClass jParent;
...@@ -39,19 +43,14 @@ public class JField extends DefaultMutableTreeNode implements JNode { ...@@ -39,19 +43,14 @@ public class JField extends DefaultMutableTreeNode implements JNode {
@Override @Override
public Icon getIcon() { public Icon getIcon() {
AccessInfo af = field.getAccessFlags(); AccessInfo af = field.getAccessFlags();
if(af.isPublic()){ OverlayIcon icon = Utils.makeIcon(af, ICON_FLD_PUB, ICON_FLD_PRI, ICON_FLD_PRO, ICON_FLD_DEF);
return ICON_FLD_PUB; if (af.isTransient()) icon.add(ICON_TRANSIENT);
} else if(af.isPrivate()) { if (af.isVolatile()) icon.add(ICON_VOLATILE);
return ICON_FLD_PRI; return icon;
} else if(af.isProtected()) {
return ICON_FLD_PRO;
} else {
return ICON_FLD_DEF;
}
} }
@Override @Override
public String toString() { public String toString() {
return field.getName(); return Utils.typeFormat(field.getName(), field.getType());
} }
} }
...@@ -2,11 +2,14 @@ package jadx.gui.treemodel; ...@@ -2,11 +2,14 @@ package jadx.gui.treemodel;
import jadx.api.JavaMethod; import jadx.api.JavaMethod;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.gui.utils.OverlayIcon;
import jadx.gui.utils.Utils; import jadx.gui.utils.Utils;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import java.util.Iterator;
public class JMethod extends DefaultMutableTreeNode implements JNode { public class JMethod extends DefaultMutableTreeNode implements JNode {
private static final ImageIcon ICON_MTH_DEF = Utils.openIcon("methdef_obj"); private static final ImageIcon ICON_MTH_DEF = Utils.openIcon("methdef_obj");
...@@ -14,6 +17,9 @@ public class JMethod extends DefaultMutableTreeNode implements JNode { ...@@ -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_PRO = Utils.openIcon("methpro_obj");
private static final ImageIcon ICON_MTH_PUB = Utils.openIcon("methpub_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 JavaMethod mth;
private final JClass jparent; private final JClass jparent;
...@@ -38,20 +44,28 @@ public class JMethod extends DefaultMutableTreeNode implements JNode { ...@@ -38,20 +44,28 @@ public class JMethod extends DefaultMutableTreeNode implements JNode {
@Override @Override
public Icon getIcon() { public Icon getIcon() {
AccessInfo af = mth.getAccessFlags(); AccessInfo accessFlags = mth.getAccessFlags();
if (af.isPublic()) { OverlayIcon icon = Utils.makeIcon(accessFlags, ICON_MTH_PUB, ICON_MTH_PRI, ICON_MTH_PRO, ICON_MTH_DEF);
return ICON_MTH_PUB; if(accessFlags.isConstructor()) icon.add(ICON_CONSTRUCTOR);
} else if (af.isPrivate()) { if (accessFlags.isSynchronized()) icon.add(ICON_SYNC);
return ICON_MTH_PRI; return icon;
} else if (af.isProtected()) {
return ICON_MTH_PRO;
} else {
return ICON_MTH_DEF;
}
} }
@Override @Override
public String toString() { public String toString() {
return mth.getName(); if (mth.isClassInit()) {
return "{...}";
}
StringBuilder base = new StringBuilder();
base.append(mth.getName());
base.append('(');
for (Iterator<ArgType> 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());
} }
} }
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<Icon> icons = new ArrayList<Icon>(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<Icon> icons) {
icons.addAll(icons);
}
public List<Icon> getIcons() {
return icons;
}
}
package jadx.gui.utils; package jadx.gui.utils;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
...@@ -10,6 +13,11 @@ import java.net.URL; ...@@ -10,6 +13,11 @@ import java.net.URL;
public class Utils { 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) { public static ImageIcon openIcon(String name) {
String iconPath = "/icons-16/" + name + ".png"; String iconPath = "/icons-16/" + name + ".png";
URL resource = Utils.class.getResource(iconPath); URL resource = Utils.class.getResource(iconPath);
...@@ -23,4 +31,43 @@ public class Utils { ...@@ -23,4 +31,43 @@ public class Utils {
comp.getInputMap().put(key, id); comp.getInputMap().put(key, id);
comp.getActionMap().put(id, action); comp.getActionMap().put(id, action);
} }
public static String typeFormat(String name, ArgType type) {
return "<html>" + name + "<span style='color:#888888;'> : " + typeStr(type) + "</span></html>";
}
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;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment