From e16f81dba9edadb3fc02492bfeff06266890e754 Mon Sep 17 00:00:00 2001 From: Yanis48 Date: Mon, 14 Dec 2020 21:15:53 +0100 Subject: Structure panel! --- .../cuchaz/enigma/analysis/StructureTreeNode.java | 109 +++++++++++++++++++++ .../cuchaz/enigma/analysis/index/JarIndex.java | 24 ++++- .../translation/representation/TypeDescriptor.java | 27 +++-- .../representation/entry/ClassEntry.java | 3 + .../translation/representation/entry/Entry.java | 7 ++ 5 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java (limited to 'enigma/src/main/java') diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java new file mode 100644 index 0000000..13f277c --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java @@ -0,0 +1,109 @@ +package cuchaz.enigma.analysis; + +import cuchaz.enigma.analysis.index.JarIndex; +import cuchaz.enigma.translation.Translator; +import cuchaz.enigma.translation.representation.TypeDescriptor; +import cuchaz.enigma.translation.representation.entry.*; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.util.List; + +public class StructureTreeNode extends DefaultMutableTreeNode { + private final Translator translator; + private final ClassEntry parentEntry; + private final ParentedEntry entry; + + public StructureTreeNode(Translator translator, ClassEntry parentEntry, ParentedEntry entry) { + this.translator = translator; + this.parentEntry = parentEntry; + this.entry = entry; + } + + /** + * Returns the parented entry corresponding to this tree node. + */ + public ParentedEntry getEntry() { + return this.entry; + } + + public void load(JarIndex jarIndex, boolean hideDeobfuscated) { + List children = jarIndex.getChildrenByClass().get(this.parentEntry); + + for (ParentedEntry child : children) { + StructureTreeNode childNode = new StructureTreeNode(this.translator, this.parentEntry, child); + + if (child instanceof ClassEntry) { + childNode = new StructureTreeNode(this.translator, (ClassEntry) child, child); + childNode.load(jarIndex, hideDeobfuscated); + } + + // don't add deobfuscated members if hideDeobfuscated is true, unless it's an inner class + if (hideDeobfuscated && this.translator.extendedTranslate(child).isDeobfuscated() && !(child instanceof ClassEntry)) { + continue; + } + + // don't add constructor methods if hideDeobfuscated is true + if (hideDeobfuscated && (child instanceof MethodEntry) && ((MethodEntry) child).isConstructor()) { + continue; + } + + this.add(childNode); + } + } + + @Override + public String toString() { + ParentedEntry translatedEntry = this.translator.extendedTranslate(this.entry).getValue(); + String result = translatedEntry.getName(); + + if (this.entry instanceof FieldDefEntry) { + FieldDefEntry field = (FieldDefEntry) translatedEntry; + String returnType = this.parseDesc(field.getDesc()); + + result = result + ": " + returnType; + } else if (this.entry instanceof MethodDefEntry) { + MethodDefEntry method = (MethodDefEntry) translatedEntry; + String args = this.parseArgs(method.getDesc().getArgumentDescs()); + String returnType = this.parseDesc(method.getDesc().getReturnDesc()); + + if (method.isConstructor()) { + result = method.getParent().getSimpleName() + args; + } else { + result = result + args + ": " + returnType; + } + } + + return result; + } + + private String parseArgs(List args) { + if (args.size() > 0) { + String result = "("; + + for (int i = 0; i < args.size(); i++) { + if (i > 0) { + result += ", "; + } + + result += this.parseDesc(args.get(i)); + } + + return result + ")"; + } + + return "()"; + } + + private String parseDesc(TypeDescriptor desc) { + if (desc.isVoid()) return "void"; + if (desc.isPrimitive()) return desc.getPrimitive().getKeyword(); + if (desc.isType()) return desc.getTypeEntry().getSimpleName(); + + if (desc.isArray()) { + if (desc.getArrayType().isPrimitive()) return desc.getArrayType().getPrimitive().getKeyword() + "[]"; + if (desc.getArrayType().isType()) return desc.getArrayType().getTypeEntry().getSimpleName() + "[]"; + } + + return null; + } +} diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java index b5ad91a..d41731f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java @@ -23,10 +23,7 @@ import cuchaz.enigma.translation.representation.Lambda; import cuchaz.enigma.translation.representation.entry.*; import cuchaz.enigma.utils.I18n; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; public class JarIndex implements JarIndexer { private final Set indexedClasses = new HashSet<>(); @@ -40,6 +37,7 @@ public class JarIndex implements JarIndexer { private final Collection indexers; private final Multimap methodImplementations = HashMultimap.create(); + private final Map> childrenByClass; public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) { this.entryIndex = entryIndex; @@ -49,6 +47,7 @@ public class JarIndex implements JarIndexer { this.packageVisibilityIndex = packageVisibilityIndex; this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); this.entryResolver = new IndexEntryResolver(this); + this.childrenByClass = new HashMap<>(); } public static JarIndex empty() { @@ -101,6 +100,11 @@ public class JarIndex implements JarIndexer { } indexers.forEach(indexer -> indexer.indexClass(classEntry)); + childrenByClass.putIfAbsent(classEntry, new ArrayList<>()); + if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) { + childrenByClass.putIfAbsent(classEntry.getParent(), new ArrayList<>()); + childrenByClass.get(classEntry.getParent()).add(classEntry); + } } @Override @@ -110,6 +114,10 @@ public class JarIndex implements JarIndexer { } indexers.forEach(indexer -> indexer.indexField(fieldEntry)); + if (!fieldEntry.getAccess().isSynthetic()) { + childrenByClass.putIfAbsent(fieldEntry.getParent(), new ArrayList<>()); + childrenByClass.get(fieldEntry.getParent()).add(fieldEntry); + } } @Override @@ -119,6 +127,10 @@ public class JarIndex implements JarIndexer { } indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); + if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("")) { + childrenByClass.putIfAbsent(methodEntry.getParent(), new ArrayList<>()); + childrenByClass.get(methodEntry.getParent()).add(methodEntry); + } if (!methodEntry.isConstructor()) { methodImplementations.put(methodEntry.getParent().getFullName(), methodEntry); @@ -176,6 +188,10 @@ public class JarIndex implements JarIndexer { return entryResolver; } + public Map> getChildrenByClass() { + return this.childrenByClass; + } + public boolean isIndexed(String internalName) { return indexedClasses.contains(internalName); } diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java index a7dccfc..6a1b82f 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java @@ -235,14 +235,14 @@ public class TypeDescriptor implements Translatable { } public enum Primitive { - BYTE('B'), - CHARACTER('C'), - SHORT('S'), - INTEGER('I'), - LONG('J'), - FLOAT('F'), - DOUBLE('D'), - BOOLEAN('Z'); + BYTE('B', "byte"), + CHARACTER('C', "char"), + SHORT('S', "short"), + INTEGER('I', "int"), + LONG('J', "long"), + FLOAT('F', "float"), + DOUBLE('D', "double"), + BOOLEAN('Z', "boolean"); private static final Map lookup; @@ -254,9 +254,11 @@ public class TypeDescriptor implements Translatable { } private char code; + private String keyword; - Primitive(char code) { + Primitive(char code, String keyword) { this.code = code; + this.keyword = keyword; } public static Primitive get(char code) { @@ -266,5 +268,12 @@ public class TypeDescriptor implements Translatable { public char getCode() { return this.code; } + + /** + * Returns the Java keyword corresponding to this primitive. + */ + public String getKeyword() { + return this.keyword; + } } } diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java index 4a50021..b4a22f1 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java @@ -134,6 +134,9 @@ public class ClassEntry extends ParentedEntry implements Comparable< return name; } + /** + * Returns whether this class entry has a parent, and therefore is an inner class. + */ public boolean isInnerClass() { return parent != null; } diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java index ff392fe..6fd412a 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java @@ -29,6 +29,13 @@ public interface Entry

> extends Translatable { return getName(); } + /** + * Returns the parent entry of this entry. + * + *

The parent entry should be a {@linkplain MethodEntry method} for local variables, + * a {@linkplain ClassEntry class} for methods, fields and inner classes, and {@code null} + * for other classes.

+ */ @Nullable P getParent(); -- cgit v1.2.3