diff options
| author | 2017-03-08 08:17:04 +0100 | |
|---|---|---|
| committer | 2017-03-08 08:17:04 +0100 | |
| commit | 6e464ea251cab63c776ece0b2a356f1498ffa294 (patch) | |
| tree | 5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/analysis | |
| parent | Drop unix case style and implement hashCode when equals is overrided (diff) | |
| download | enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip | |
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis')
20 files changed, 3025 insertions, 3044 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/Access.java b/src/main/java/cuchaz/enigma/analysis/Access.java index b8a7b2c..547d85e 100644 --- a/src/main/java/cuchaz/enigma/analysis/Access.java +++ b/src/main/java/cuchaz/enigma/analysis/Access.java | |||
| @@ -8,40 +8,41 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | 11 | ||
| 13 | import java.lang.reflect.Modifier; | 12 | package cuchaz.enigma.analysis; |
| 14 | 13 | ||
| 15 | import javassist.CtBehavior; | 14 | import javassist.CtBehavior; |
| 16 | import javassist.CtField; | 15 | import javassist.CtField; |
| 17 | 16 | ||
| 17 | import java.lang.reflect.Modifier; | ||
| 18 | |||
| 18 | public enum Access { | 19 | public enum Access { |
| 19 | 20 | ||
| 20 | PUBLIC, PROTECTED, PACKAGE, PRIVATE; | 21 | PUBLIC, PROTECTED, PACKAGE, PRIVATE; |
| 21 | 22 | ||
| 22 | public static Access get(CtBehavior behavior) { | 23 | public static Access get(CtBehavior behavior) { |
| 23 | return get(behavior.getModifiers()); | 24 | return get(behavior.getModifiers()); |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | public static Access get(CtField field) { | 27 | public static Access get(CtField field) { |
| 27 | return get(field.getModifiers()); | 28 | return get(field.getModifiers()); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | public static Access get(int modifiers) { | 31 | public static Access get(int modifiers) { |
| 31 | boolean isPublic = Modifier.isPublic(modifiers); | 32 | boolean isPublic = Modifier.isPublic(modifiers); |
| 32 | boolean isProtected = Modifier.isProtected(modifiers); | 33 | boolean isProtected = Modifier.isProtected(modifiers); |
| 33 | boolean isPrivate = Modifier.isPrivate(modifiers); | 34 | boolean isPrivate = Modifier.isPrivate(modifiers); |
| 34 | 35 | ||
| 35 | if (isPublic && !isProtected && !isPrivate) { | 36 | if (isPublic && !isProtected && !isPrivate) { |
| 36 | return PUBLIC; | 37 | return PUBLIC; |
| 37 | } else if (!isPublic && isProtected && !isPrivate) { | 38 | } else if (!isPublic && isProtected && !isPrivate) { |
| 38 | return PROTECTED; | 39 | return PROTECTED; |
| 39 | } else if (!isPublic && !isProtected && isPrivate) { | 40 | } else if (!isPublic && !isProtected && isPrivate) { |
| 40 | return PRIVATE; | 41 | return PRIVATE; |
| 41 | } else if (!isPublic && !isProtected && !isPrivate) { | 42 | } else if (!isPublic && !isProtected && !isPrivate) { |
| 42 | return PACKAGE; | 43 | return PACKAGE; |
| 43 | } | 44 | } |
| 44 | // assume public by default | 45 | // assume public by default |
| 45 | return PUBLIC; | 46 | return PUBLIC; |
| 46 | } | 47 | } |
| 47 | } | 48 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 52d5b31..6556b2c 100644 --- a/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Sets; | 14 | import com.google.common.collect.Sets; |
| @@ -20,85 +21,73 @@ import javax.swing.tree.TreeNode; | |||
| 20 | import java.util.Set; | 21 | import java.util.Set; |
| 21 | 22 | ||
| 22 | public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode | 23 | public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode |
| 23 | implements ReferenceTreeNode<BehaviorEntry, BehaviorEntry> | 24 | implements ReferenceTreeNode<BehaviorEntry, BehaviorEntry> { |
| 24 | { | ||
| 25 | 25 | ||
| 26 | private Translator deobfuscatingTranslator; | 26 | private Translator deobfuscatingTranslator; |
| 27 | private BehaviorEntry entry; | 27 | private BehaviorEntry entry; |
| 28 | private EntryReference<BehaviorEntry, BehaviorEntry> reference; | 28 | private EntryReference<BehaviorEntry, BehaviorEntry> reference; |
| 29 | private Access access; | 29 | private Access access; |
| 30 | 30 | ||
| 31 | public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) | 31 | public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) { |
| 32 | { | 32 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 33 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 33 | this.entry = entry; |
| 34 | this.entry = entry; | 34 | this.reference = null; |
| 35 | this.reference = null; | 35 | } |
| 36 | } | ||
| 37 | 36 | ||
| 38 | public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, | 37 | public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, |
| 39 | EntryReference<BehaviorEntry, BehaviorEntry> reference, Access access) | 38 | EntryReference<BehaviorEntry, BehaviorEntry> reference, Access access) { |
| 40 | { | 39 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 41 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 40 | this.entry = reference.entry; |
| 42 | this.entry = reference.entry; | 41 | this.reference = reference; |
| 43 | this.reference = reference; | 42 | this.access = access; |
| 44 | this.access = access; | 43 | } |
| 45 | } | ||
| 46 | 44 | ||
| 47 | @Override public BehaviorEntry getEntry() | 45 | @Override |
| 48 | { | 46 | public BehaviorEntry getEntry() { |
| 49 | return this.entry; | 47 | return this.entry; |
| 50 | } | 48 | } |
| 51 | 49 | ||
| 52 | @Override public EntryReference<BehaviorEntry, BehaviorEntry> getReference() | 50 | @Override |
| 53 | { | 51 | public EntryReference<BehaviorEntry, BehaviorEntry> getReference() { |
| 54 | return this.reference; | 52 | return this.reference; |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | @Override public String toString() | 55 | @Override |
| 58 | { | 56 | public String toString() { |
| 59 | if (this.reference != null) | 57 | if (this.reference != null) { |
| 60 | { | 58 | return String.format("%s (%s)", this.deobfuscatingTranslator.translateEntry(this.reference.context), |
| 61 | return String.format("%s (%s)", this.deobfuscatingTranslator.translateEntry(this.reference.context), | 59 | this.access); |
| 62 | this.access); | 60 | } |
| 63 | } | 61 | return this.deobfuscatingTranslator.translateEntry(this.entry).toString(); |
| 64 | return this.deobfuscatingTranslator.translateEntry(this.entry).toString(); | 62 | } |
| 65 | } | ||
| 66 | 63 | ||
| 67 | public void load(JarIndex index, boolean recurse) | 64 | public void load(JarIndex index, boolean recurse) { |
| 68 | { | 65 | // get all the child nodes |
| 69 | // get all the child nodes | 66 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : index.getBehaviorReferences(this.entry)) { |
| 70 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : index.getBehaviorReferences(this.entry)) | 67 | add(new BehaviorReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.entry))); |
| 71 | { | 68 | } |
| 72 | add(new BehaviorReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.entry))); | ||
| 73 | } | ||
| 74 | 69 | ||
| 75 | if (recurse && this.children != null) | 70 | if (recurse && this.children != null) { |
| 76 | { | 71 | for (Object child : this.children) { |
| 77 | for (Object child : this.children) | 72 | if (child instanceof BehaviorReferenceTreeNode) { |
| 78 | { | 73 | BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode) child; |
| 79 | if (child instanceof BehaviorReferenceTreeNode) | ||
| 80 | { | ||
| 81 | BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode) child; | ||
| 82 | 74 | ||
| 83 | // don't recurse into ancestor | 75 | // don't recurse into ancestor |
| 84 | Set<Entry> ancestors = Sets.newHashSet(); | 76 | Set<Entry> ancestors = Sets.newHashSet(); |
| 85 | TreeNode n = node; | 77 | TreeNode n = node; |
| 86 | while (n.getParent() != null) | 78 | while (n.getParent() != null) { |
| 87 | { | 79 | n = n.getParent(); |
| 88 | n = n.getParent(); | 80 | if (n instanceof BehaviorReferenceTreeNode) { |
| 89 | if (n instanceof BehaviorReferenceTreeNode) | 81 | ancestors.add(((BehaviorReferenceTreeNode) n).getEntry()); |
| 90 | { | 82 | } |
| 91 | ancestors.add(((BehaviorReferenceTreeNode) n).getEntry()); | 83 | } |
| 92 | } | 84 | if (ancestors.contains(node.getEntry())) { |
| 93 | } | 85 | continue; |
| 94 | if (ancestors.contains(node.getEntry())) | 86 | } |
| 95 | { | ||
| 96 | continue; | ||
| 97 | } | ||
| 98 | 87 | ||
| 99 | node.load(index, true); | 88 | node.load(index, true); |
| 100 | } | 89 | } |
| 101 | } | 90 | } |
| 102 | } | 91 | } |
| 103 | } | 92 | } |
| 104 | } | 93 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/BridgeMarker.java b/src/main/java/cuchaz/enigma/analysis/BridgeMarker.java index 0f4be7d..81e750c 100644 --- a/src/main/java/cuchaz/enigma/analysis/BridgeMarker.java +++ b/src/main/java/cuchaz/enigma/analysis/BridgeMarker.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import cuchaz.enigma.mapping.EntryFactory; | 14 | import cuchaz.enigma.mapping.EntryFactory; |
| @@ -18,26 +19,26 @@ import javassist.bytecode.AccessFlag; | |||
| 18 | 19 | ||
| 19 | public class BridgeMarker { | 20 | public class BridgeMarker { |
| 20 | 21 | ||
| 21 | private JarIndex jarIndex; | 22 | private JarIndex jarIndex; |
| 22 | 23 | ||
| 23 | public BridgeMarker(JarIndex jarIndex) { | 24 | public BridgeMarker(JarIndex jarIndex) { |
| 24 | this.jarIndex = jarIndex; | 25 | this.jarIndex = jarIndex; |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | public void markBridges(CtClass c) { | 28 | public void markBridges(CtClass c) { |
| 28 | 29 | ||
| 29 | for (CtMethod method : c.getDeclaredMethods()) { | 30 | for (CtMethod method : c.getDeclaredMethods()) { |
| 30 | MethodEntry methodEntry = EntryFactory.getMethodEntry(method); | 31 | MethodEntry methodEntry = EntryFactory.getMethodEntry(method); |
| 31 | 32 | ||
| 32 | // is this a bridge method? | 33 | // is this a bridge method? |
| 33 | MethodEntry bridgedMethodEntry = this.jarIndex.getBridgedMethod(methodEntry); | 34 | MethodEntry bridgedMethodEntry = this.jarIndex.getBridgedMethod(methodEntry); |
| 34 | if (bridgedMethodEntry != null) { | 35 | if (bridgedMethodEntry != null) { |
| 35 | 36 | ||
| 36 | // it's a bridge method! add the bridge flag | 37 | // it's a bridge method! add the bridge flag |
| 37 | int flags = method.getMethodInfo().getAccessFlags(); | 38 | int flags = method.getMethodInfo().getAccessFlags(); |
| 38 | flags |= AccessFlag.BRIDGE; | 39 | flags |= AccessFlag.BRIDGE; |
| 39 | method.getMethodInfo().setAccessFlags(flags); | 40 | method.getMethodInfo().setAccessFlags(flags); |
| 40 | } | 41 | } |
| 41 | } | 42 | } |
| 42 | } | 43 | } |
| 43 | } | 44 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index 70ece24..f2fb2f8 100644 --- a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | |||
| @@ -8,69 +8,68 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | |||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.ClassEntry; | 15 | import cuchaz.enigma.mapping.ClassEntry; |
| 20 | import cuchaz.enigma.mapping.MethodEntry; | 16 | import cuchaz.enigma.mapping.MethodEntry; |
| 21 | import cuchaz.enigma.mapping.Translator; | 17 | import cuchaz.enigma.mapping.Translator; |
| 22 | 18 | ||
| 19 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 20 | import java.util.List; | ||
| 21 | |||
| 23 | public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { | 22 | public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { |
| 24 | 23 | ||
| 25 | private Translator deobfuscatingTranslator; | 24 | private Translator deobfuscatingTranslator; |
| 26 | private ClassEntry entry; | 25 | private ClassEntry entry; |
| 27 | 26 | ||
| 28 | public ClassImplementationsTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) { | 27 | public ClassImplementationsTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) { |
| 29 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 28 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 30 | this.entry = entry; | 29 | this.entry = entry; |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | public ClassEntry getClassEntry() { | 32 | public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) { |
| 34 | return this.entry; | 33 | // is this the node? |
| 35 | } | 34 | if (node.entry.equals(entry.getClassEntry())) { |
| 35 | return node; | ||
| 36 | } | ||
| 36 | 37 | ||
| 37 | public String getDeobfClassName() { | 38 | // recurse |
| 38 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); | 39 | for (int i = 0; i < node.getChildCount(); i++) { |
| 39 | } | 40 | ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); |
| 41 | if (foundNode != null) { | ||
| 42 | return foundNode; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | return null; | ||
| 46 | } | ||
| 40 | 47 | ||
| 41 | @Override | 48 | public ClassEntry getClassEntry() { |
| 42 | public String toString() { | 49 | return this.entry; |
| 43 | String className = getDeobfClassName(); | 50 | } |
| 44 | if (className == null) { | ||
| 45 | className = this.entry.getClassName(); | ||
| 46 | } | ||
| 47 | return className; | ||
| 48 | } | ||
| 49 | 51 | ||
| 50 | public void load(JarIndex index) { | 52 | public String getDeobfClassName() { |
| 51 | // get all method implementations | 53 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); |
| 52 | List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); | 54 | } |
| 53 | for (String implementingClassName : index.getImplementingClasses(this.entry.getClassName())) { | ||
| 54 | nodes.add(new ClassImplementationsTreeNode(this.deobfuscatingTranslator, new ClassEntry(implementingClassName))); | ||
| 55 | } | ||
| 56 | 55 | ||
| 57 | // add them to this node | 56 | @Override |
| 58 | nodes.forEach(this::add); | 57 | public String toString() { |
| 59 | } | 58 | String className = getDeobfClassName(); |
| 59 | if (className == null) { | ||
| 60 | className = this.entry.getClassName(); | ||
| 61 | } | ||
| 62 | return className; | ||
| 63 | } | ||
| 60 | 64 | ||
| 61 | public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) { | 65 | public void load(JarIndex index) { |
| 62 | // is this the node? | 66 | // get all method implementations |
| 63 | if (node.entry.equals(entry.getClassEntry())) { | 67 | List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 64 | return node; | 68 | for (String implementingClassName : index.getImplementingClasses(this.entry.getClassName())) { |
| 65 | } | 69 | nodes.add(new ClassImplementationsTreeNode(this.deobfuscatingTranslator, new ClassEntry(implementingClassName))); |
| 70 | } | ||
| 66 | 71 | ||
| 67 | // recurse | 72 | // add them to this node |
| 68 | for (int i = 0; i < node.getChildCount(); i++) { | 73 | nodes.forEach(this::add); |
| 69 | ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); | 74 | } |
| 70 | if (foundNode != null) { | ||
| 71 | return foundNode; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | return null; | ||
| 75 | } | ||
| 76 | } | 75 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index 8a60fc7..24e7cb0 100644 --- a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | |||
| @@ -8,74 +8,73 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | |||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.ClassEntry; | 15 | import cuchaz.enigma.mapping.ClassEntry; |
| 20 | import cuchaz.enigma.mapping.Translator; | 16 | import cuchaz.enigma.mapping.Translator; |
| 21 | 17 | ||
| 18 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 19 | import java.util.List; | ||
| 20 | |||
| 22 | public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { | 21 | public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { |
| 23 | 22 | ||
| 24 | private Translator deobfuscatingTranslator; | 23 | private Translator deobfuscatingTranslator; |
| 25 | private String obfClassName; | 24 | private String obfClassName; |
| 26 | 25 | ||
| 27 | public ClassInheritanceTreeNode(Translator deobfuscatingTranslator, String obfClassName) { | 26 | public ClassInheritanceTreeNode(Translator deobfuscatingTranslator, String obfClassName) { |
| 28 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 27 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 29 | this.obfClassName = obfClassName; | 28 | this.obfClassName = obfClassName; |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | public String getObfClassName() { | 31 | public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) { |
| 33 | return this.obfClassName; | 32 | // is this the node? |
| 34 | } | 33 | if (node.getObfClassName().equals(entry.getName())) { |
| 34 | return node; | ||
| 35 | } | ||
| 35 | 36 | ||
| 36 | public String getDeobfClassName() { | 37 | // recurse |
| 37 | return this.deobfuscatingTranslator.translateClass(this.obfClassName); | 38 | for (int i = 0; i < node.getChildCount(); i++) { |
| 38 | } | 39 | ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); |
| 40 | if (foundNode != null) { | ||
| 41 | return foundNode; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | return null; | ||
| 45 | } | ||
| 39 | 46 | ||
| 40 | @Override | 47 | public String getObfClassName() { |
| 41 | public String toString() { | 48 | return this.obfClassName; |
| 42 | String deobfClassName = getDeobfClassName(); | 49 | } |
| 43 | if (deobfClassName != null) { | ||
| 44 | return deobfClassName; | ||
| 45 | } | ||
| 46 | return this.obfClassName; | ||
| 47 | } | ||
| 48 | 50 | ||
| 49 | public void load(TranslationIndex ancestries, boolean recurse) { | 51 | public String getDeobfClassName() { |
| 50 | // get all the child nodes | 52 | return this.deobfuscatingTranslator.translateClass(this.obfClassName); |
| 51 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); | 53 | } |
| 52 | for (ClassEntry subclassEntry : ancestries.getSubclass(new ClassEntry(this.obfClassName))) { | ||
| 53 | nodes.add(new ClassInheritanceTreeNode(this.deobfuscatingTranslator, subclassEntry.getName())); | ||
| 54 | } | ||
| 55 | 54 | ||
| 56 | // add them to this node | 55 | @Override |
| 57 | nodes.forEach(this::add); | 56 | public String toString() { |
| 57 | String deobfClassName = getDeobfClassName(); | ||
| 58 | if (deobfClassName != null) { | ||
| 59 | return deobfClassName; | ||
| 60 | } | ||
| 61 | return this.obfClassName; | ||
| 62 | } | ||
| 58 | 63 | ||
| 59 | if (recurse) { | 64 | public void load(TranslationIndex ancestries, boolean recurse) { |
| 60 | for (ClassInheritanceTreeNode node : nodes) { | 65 | // get all the child nodes |
| 61 | node.load(ancestries, true); | 66 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); |
| 62 | } | 67 | for (ClassEntry subclassEntry : ancestries.getSubclass(new ClassEntry(this.obfClassName))) { |
| 63 | } | 68 | nodes.add(new ClassInheritanceTreeNode(this.deobfuscatingTranslator, subclassEntry.getName())); |
| 64 | } | 69 | } |
| 65 | 70 | ||
| 66 | public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) { | 71 | // add them to this node |
| 67 | // is this the node? | 72 | nodes.forEach(this::add); |
| 68 | if (node.getObfClassName().equals(entry.getName())) { | ||
| 69 | return node; | ||
| 70 | } | ||
| 71 | 73 | ||
| 72 | // recurse | 74 | if (recurse) { |
| 73 | for (int i = 0; i < node.getChildCount(); i++) { | 75 | for (ClassInheritanceTreeNode node : nodes) { |
| 74 | ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); | 76 | node.load(ancestries, true); |
| 75 | if (foundNode != null) { | 77 | } |
| 76 | return foundNode; | 78 | } |
| 77 | } | 79 | } |
| 78 | } | ||
| 79 | return null; | ||
| 80 | } | ||
| 81 | } | 80 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/src/main/java/cuchaz/enigma/analysis/EntryReference.java index ad4baf8..3761fca 100644 --- a/src/main/java/cuchaz/enigma/analysis/EntryReference.java +++ b/src/main/java/cuchaz/enigma/analysis/EntryReference.java | |||
| @@ -8,116 +8,117 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | 11 | ||
| 13 | import java.util.Arrays; | 12 | package cuchaz.enigma.analysis; |
| 14 | import java.util.List; | ||
| 15 | 13 | ||
| 16 | import cuchaz.enigma.mapping.ClassEntry; | 14 | import cuchaz.enigma.mapping.ClassEntry; |
| 17 | import cuchaz.enigma.mapping.ConstructorEntry; | 15 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 18 | import cuchaz.enigma.mapping.Entry; | 16 | import cuchaz.enigma.mapping.Entry; |
| 19 | import cuchaz.enigma.utils.Utils; | 17 | import cuchaz.enigma.utils.Utils; |
| 20 | 18 | ||
| 19 | import java.util.Arrays; | ||
| 20 | import java.util.List; | ||
| 21 | |||
| 21 | public class EntryReference<E extends Entry, C extends Entry> { | 22 | public class EntryReference<E extends Entry, C extends Entry> { |
| 22 | 23 | ||
| 23 | private static final List<String> ConstructorNonNames = Arrays.asList("this", "super", "static"); | 24 | private static final List<String> ConstructorNonNames = Arrays.asList("this", "super", "static"); |
| 24 | public E entry; | 25 | public E entry; |
| 25 | public C context; | 26 | public C context; |
| 26 | 27 | ||
| 27 | private boolean sourceName; | 28 | private boolean sourceName; |
| 28 | 29 | ||
| 29 | public EntryReference(E entry, String sourceName) { | 30 | public EntryReference(E entry, String sourceName) { |
| 30 | this(entry, sourceName, null); | 31 | this(entry, sourceName, null); |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | public EntryReference(E entry, String sourceName, C context) { | 34 | public EntryReference(E entry, String sourceName, C context) { |
| 34 | if (entry == null) { | 35 | if (entry == null) { |
| 35 | throw new IllegalArgumentException("Entry cannot be null!"); | 36 | throw new IllegalArgumentException("Entry cannot be null!"); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | this.entry = entry; | 39 | this.entry = entry; |
| 39 | this.context = context; | 40 | this.context = context; |
| 40 | 41 | ||
| 41 | this.sourceName = sourceName != null && sourceName.length() > 0; | 42 | this.sourceName = sourceName != null && !sourceName.isEmpty(); |
| 42 | if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) { | 43 | if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) { |
| 43 | this.sourceName = false; | 44 | this.sourceName = false; |
| 44 | } | 45 | } |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | public EntryReference(E entry, C context, EntryReference<E, C> other) { | 48 | public EntryReference(E entry, C context, EntryReference<E, C> other) { |
| 48 | this.entry = entry; | 49 | this.entry = entry; |
| 49 | this.context = context; | 50 | this.context = context; |
| 50 | this.sourceName = other.sourceName; | 51 | this.sourceName = other.sourceName; |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | public ClassEntry getLocationClassEntry() { | 54 | public ClassEntry getLocationClassEntry() { |
| 54 | if (context != null) { | 55 | if (context != null) { |
| 55 | return context.getClassEntry(); | 56 | return context.getClassEntry(); |
| 56 | } | 57 | } |
| 57 | return entry.getClassEntry(); | 58 | return entry.getClassEntry(); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | public boolean isNamed() { | 61 | public boolean isNamed() { |
| 61 | return this.sourceName; | 62 | return this.sourceName; |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | public Entry getNameableEntry() { | 65 | public Entry getNameableEntry() { |
| 65 | if (entry instanceof ConstructorEntry) { | 66 | if (entry instanceof ConstructorEntry) { |
| 66 | // renaming a constructor really means renaming the class | 67 | // renaming a constructor really means renaming the class |
| 67 | return entry.getClassEntry(); | 68 | return entry.getClassEntry(); |
| 68 | } | 69 | } |
| 69 | return entry; | 70 | return entry; |
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | public String getNamableName() { | 73 | public String getNamableName() { |
| 73 | if (getNameableEntry() instanceof ClassEntry) { | 74 | if (getNameableEntry() instanceof ClassEntry) { |
| 74 | ClassEntry classEntry = (ClassEntry) getNameableEntry(); | 75 | ClassEntry classEntry = (ClassEntry) getNameableEntry(); |
| 75 | if (classEntry.isInnerClass()) { | 76 | if (classEntry.isInnerClass()) { |
| 76 | // make sure we only rename the inner class name | 77 | // make sure we only rename the inner class name |
| 77 | return classEntry.getInnermostClassName(); | 78 | return classEntry.getInnermostClassName(); |
| 78 | } | 79 | } |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | return getNameableEntry().getName(); | 82 | return getNameableEntry().getName(); |
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | @Override | 85 | @Override |
| 85 | public int hashCode() { | 86 | public int hashCode() { |
| 86 | if (context != null) { | 87 | if (context != null) { |
| 87 | return Utils.combineHashesOrdered(entry.hashCode(), context.hashCode()); | 88 | return Utils.combineHashesOrdered(entry.hashCode(), context.hashCode()); |
| 88 | } | 89 | } |
| 89 | return entry.hashCode(); | 90 | return entry.hashCode(); |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | @Override | 93 | @Override |
| 93 | public boolean equals(Object other) { | 94 | public boolean equals(Object other) { |
| 94 | return other instanceof EntryReference && equals((EntryReference<?, ?>) other); | 95 | return other instanceof EntryReference && equals((EntryReference<?, ?>) other); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | public boolean equals(EntryReference<?, ?> other) { | 98 | public boolean equals(EntryReference<?, ?> other) { |
| 98 | // check entry first | 99 | // check entry first |
| 99 | boolean isEntrySame = entry.equals(other.entry); | 100 | boolean isEntrySame = entry.equals(other.entry); |
| 100 | if (!isEntrySame) { | 101 | if (!isEntrySame) { |
| 101 | return false; | 102 | return false; |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | // check caller | 105 | // check caller |
| 105 | if (context == null && other.context == null) { | 106 | if (context == null && other.context == null) { |
| 106 | return true; | 107 | return true; |
| 107 | } else if (context != null && other.context != null) { | 108 | } else if (context != null && other.context != null) { |
| 108 | return context.equals(other.context); | 109 | return context.equals(other.context); |
| 109 | } | 110 | } |
| 110 | return false; | 111 | return false; |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | @Override | 114 | @Override |
| 114 | public String toString() { | 115 | public String toString() { |
| 115 | StringBuilder buf = new StringBuilder(); | 116 | StringBuilder buf = new StringBuilder(); |
| 116 | buf.append(entry); | 117 | buf.append(entry); |
| 117 | if (context != null) { | 118 | if (context != null) { |
| 118 | buf.append(" called from "); | 119 | buf.append(" called from "); |
| 119 | buf.append(context); | 120 | buf.append(context); |
| 120 | } | 121 | } |
| 121 | return buf.toString(); | 122 | return buf.toString(); |
| 122 | } | 123 | } |
| 123 | } | 124 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java b/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java index 7233fcf..75806c3 100644 --- a/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java | |||
| @@ -8,140 +8,140 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | import com.google.common.collect.Multimap; | 15 | import com.google.common.collect.Multimap; |
| 15 | import com.google.common.collect.Sets; | 16 | import com.google.common.collect.Sets; |
| 17 | import cuchaz.enigma.mapping.*; | ||
| 16 | 18 | ||
| 17 | import java.util.AbstractMap; | 19 | import java.util.AbstractMap; |
| 18 | import java.util.List; | 20 | import java.util.List; |
| 19 | import java.util.Map; | 21 | import java.util.Map; |
| 20 | import java.util.Set; | 22 | import java.util.Set; |
| 21 | 23 | ||
| 22 | import cuchaz.enigma.mapping.*; | ||
| 23 | |||
| 24 | public class EntryRenamer { | 24 | public class EntryRenamer { |
| 25 | 25 | ||
| 26 | public static <T> void renameClassesInSet(Map<String, String> renames, Set<T> set) { | 26 | public static <T> void renameClassesInSet(Map<String, String> renames, Set<T> set) { |
| 27 | List<T> entries = Lists.newArrayList(); | 27 | List<T> entries = Lists.newArrayList(); |
| 28 | for (T val : set) { | 28 | for (T val : set) { |
| 29 | entries.add(renameClassesInThing(renames, val)); | 29 | entries.add(renameClassesInThing(renames, val)); |
| 30 | } | 30 | } |
| 31 | set.clear(); | 31 | set.clear(); |
| 32 | set.addAll(entries); | 32 | set.addAll(entries); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | public static <Key, Val> void renameClassesInMap(Map<String, String> renames, Map<Key, Val> map) { | 35 | public static <Key, Val> void renameClassesInMap(Map<String, String> renames, Map<Key, Val> map) { |
| 36 | // for each key/value pair... | 36 | // for each key/value pair... |
| 37 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); | 37 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); |
| 38 | for (Map.Entry<Key, Val> entry : map.entrySet()) { | 38 | for (Map.Entry<Key, Val> entry : map.entrySet()) { |
| 39 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameClassesInThing(renames, entry.getKey()), renameClassesInThing(renames, entry.getValue()))); | 39 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameClassesInThing(renames, entry.getKey()), renameClassesInThing(renames, entry.getValue()))); |
| 40 | } | 40 | } |
| 41 | map.clear(); | 41 | map.clear(); |
| 42 | for (Map.Entry<Key, Val> entry : entriesToAdd) { | 42 | for (Map.Entry<Key, Val> entry : entriesToAdd) { |
| 43 | map.put(entry.getKey(), entry.getValue()); | 43 | map.put(entry.getKey(), entry.getValue()); |
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | public static <Key, Val> void renameClassesInMultimap(Map<String, String> renames, Multimap<Key, Val> map) { | 47 | public static <Key, Val> void renameClassesInMultimap(Map<String, String> renames, Multimap<Key, Val> map) { |
| 48 | // for each key/value pair... | 48 | // for each key/value pair... |
| 49 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); | 49 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); |
| 50 | for (Map.Entry<Key, Val> entry : map.entries()) { | 50 | for (Map.Entry<Key, Val> entry : map.entries()) { |
| 51 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameClassesInThing(renames, entry.getKey()), renameClassesInThing(renames, entry.getValue()))); | 51 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameClassesInThing(renames, entry.getKey()), renameClassesInThing(renames, entry.getValue()))); |
| 52 | } | 52 | } |
| 53 | map.clear(); | 53 | map.clear(); |
| 54 | for (Map.Entry<Key, Val> entry : entriesToAdd) { | 54 | for (Map.Entry<Key, Val> entry : entriesToAdd) { |
| 55 | map.put(entry.getKey(), entry.getValue()); | 55 | map.put(entry.getKey(), entry.getValue()); |
| 56 | } | 56 | } |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | public static <Key, Val> void renameMethodsInMultimap(Map<MethodEntry, MethodEntry> renames, Multimap<Key, Val> map) { | 59 | public static <Key, Val> void renameMethodsInMultimap(Map<MethodEntry, MethodEntry> renames, Multimap<Key, Val> map) { |
| 60 | // for each key/value pair... | 60 | // for each key/value pair... |
| 61 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); | 61 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); |
| 62 | for (Map.Entry<Key, Val> entry : map.entries()) { | 62 | for (Map.Entry<Key, Val> entry : map.entries()) { |
| 63 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameMethodsInThing(renames, entry.getKey()), renameMethodsInThing(renames, entry.getValue()))); | 63 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameMethodsInThing(renames, entry.getKey()), renameMethodsInThing(renames, entry.getValue()))); |
| 64 | } | 64 | } |
| 65 | map.clear(); | 65 | map.clear(); |
| 66 | for (Map.Entry<Key, Val> entry : entriesToAdd) { | 66 | for (Map.Entry<Key, Val> entry : entriesToAdd) { |
| 67 | map.put(entry.getKey(), entry.getValue()); | 67 | map.put(entry.getKey(), entry.getValue()); |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | public static <Key, Val> void renameMethodsInMap(Map<MethodEntry, MethodEntry> renames, Map<Key, Val> map) { | 71 | public static <Key, Val> void renameMethodsInMap(Map<MethodEntry, MethodEntry> renames, Map<Key, Val> map) { |
| 72 | // for each key/value pair... | 72 | // for each key/value pair... |
| 73 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); | 73 | Set<Map.Entry<Key, Val>> entriesToAdd = Sets.newHashSet(); |
| 74 | for (Map.Entry<Key, Val> entry : map.entrySet()) { | 74 | for (Map.Entry<Key, Val> entry : map.entrySet()) { |
| 75 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameMethodsInThing(renames, entry.getKey()), renameMethodsInThing(renames, entry.getValue()))); | 75 | entriesToAdd.add(new AbstractMap.SimpleEntry<>(renameMethodsInThing(renames, entry.getKey()), renameMethodsInThing(renames, entry.getValue()))); |
| 76 | } | 76 | } |
| 77 | map.clear(); | 77 | map.clear(); |
| 78 | for (Map.Entry<Key, Val> entry : entriesToAdd) { | 78 | for (Map.Entry<Key, Val> entry : entriesToAdd) { |
| 79 | map.put(entry.getKey(), entry.getValue()); | 79 | map.put(entry.getKey(), entry.getValue()); |
| 80 | } | 80 | } |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | @SuppressWarnings("unchecked") | 83 | @SuppressWarnings("unchecked") |
| 84 | public static <T> T renameMethodsInThing(Map<MethodEntry,MethodEntry> renames, T thing) { | 84 | public static <T> T renameMethodsInThing(Map<MethodEntry, MethodEntry> renames, T thing) { |
| 85 | if (thing instanceof MethodEntry) { | 85 | if (thing instanceof MethodEntry) { |
| 86 | MethodEntry methodEntry = (MethodEntry)thing; | 86 | MethodEntry methodEntry = (MethodEntry) thing; |
| 87 | MethodEntry newMethodEntry = renames.get(methodEntry); | 87 | MethodEntry newMethodEntry = renames.get(methodEntry); |
| 88 | if (newMethodEntry != null) { | 88 | if (newMethodEntry != null) { |
| 89 | return (T)new MethodEntry( | 89 | return (T) new MethodEntry( |
| 90 | methodEntry.getClassEntry(), | 90 | methodEntry.getClassEntry(), |
| 91 | newMethodEntry.getName(), | 91 | newMethodEntry.getName(), |
| 92 | methodEntry.getSignature() | 92 | methodEntry.getSignature() |
| 93 | ); | 93 | ); |
| 94 | } | 94 | } |
| 95 | return thing; | 95 | return thing; |
| 96 | } else if (thing instanceof ArgumentEntry) { | 96 | } else if (thing instanceof ArgumentEntry) { |
| 97 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; | 97 | ArgumentEntry argumentEntry = (ArgumentEntry) thing; |
| 98 | return (T)new ArgumentEntry( | 98 | return (T) new ArgumentEntry( |
| 99 | renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()), | 99 | renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()), |
| 100 | argumentEntry.getIndex(), | 100 | argumentEntry.getIndex(), |
| 101 | argumentEntry.getName() | 101 | argumentEntry.getName() |
| 102 | ); | 102 | ); |
| 103 | } else if (thing instanceof EntryReference) { | 103 | } else if (thing instanceof EntryReference) { |
| 104 | EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; | 104 | EntryReference<Entry, Entry> reference = (EntryReference<Entry, Entry>) thing; |
| 105 | reference.entry = renameMethodsInThing(renames, reference.entry); | 105 | reference.entry = renameMethodsInThing(renames, reference.entry); |
| 106 | reference.context = renameMethodsInThing(renames, reference.context); | 106 | reference.context = renameMethodsInThing(renames, reference.context); |
| 107 | return thing; | 107 | return thing; |
| 108 | } | 108 | } |
| 109 | return thing; | 109 | return thing; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | @SuppressWarnings("unchecked") | 112 | @SuppressWarnings("unchecked") |
| 113 | public static <T> T renameClassesInThing(final Map<String, String> renames, T thing) { | 113 | public static <T> T renameClassesInThing(final Map<String, String> renames, T thing) { |
| 114 | if (thing instanceof String) { | 114 | if (thing instanceof String) { |
| 115 | String stringEntry = (String) thing; | 115 | String stringEntry = (String) thing; |
| 116 | if (renames.containsKey(stringEntry)) { | 116 | if (renames.containsKey(stringEntry)) { |
| 117 | return (T) renames.get(stringEntry); | 117 | return (T) renames.get(stringEntry); |
| 118 | } | 118 | } |
| 119 | } else if (thing instanceof ClassEntry) { | 119 | } else if (thing instanceof ClassEntry) { |
| 120 | ClassEntry classEntry = (ClassEntry) thing; | 120 | ClassEntry classEntry = (ClassEntry) thing; |
| 121 | return (T) new ClassEntry(renameClassesInThing(renames, classEntry.getClassName())); | 121 | return (T) new ClassEntry(renameClassesInThing(renames, classEntry.getClassName())); |
| 122 | } else if (thing instanceof FieldEntry) { | 122 | } else if (thing instanceof FieldEntry) { |
| 123 | FieldEntry fieldEntry = (FieldEntry) thing; | 123 | FieldEntry fieldEntry = (FieldEntry) thing; |
| 124 | return (T) new FieldEntry(renameClassesInThing(renames, fieldEntry.getClassEntry()), fieldEntry.getName(), renameClassesInThing(renames, fieldEntry.getType())); | 124 | return (T) new FieldEntry(renameClassesInThing(renames, fieldEntry.getClassEntry()), fieldEntry.getName(), renameClassesInThing(renames, fieldEntry.getType())); |
| 125 | } else if (thing instanceof ConstructorEntry) { | 125 | } else if (thing instanceof ConstructorEntry) { |
| 126 | ConstructorEntry constructorEntry = (ConstructorEntry) thing; | 126 | ConstructorEntry constructorEntry = (ConstructorEntry) thing; |
| 127 | return (T) new ConstructorEntry(renameClassesInThing(renames, constructorEntry.getClassEntry()), renameClassesInThing(renames, constructorEntry.getSignature())); | 127 | return (T) new ConstructorEntry(renameClassesInThing(renames, constructorEntry.getClassEntry()), renameClassesInThing(renames, constructorEntry.getSignature())); |
| 128 | } else if (thing instanceof MethodEntry) { | 128 | } else if (thing instanceof MethodEntry) { |
| 129 | MethodEntry methodEntry = (MethodEntry) thing; | 129 | MethodEntry methodEntry = (MethodEntry) thing; |
| 130 | return (T) new MethodEntry(renameClassesInThing(renames, methodEntry.getClassEntry()), methodEntry.getName(), renameClassesInThing(renames, methodEntry.getSignature())); | 130 | return (T) new MethodEntry(renameClassesInThing(renames, methodEntry.getClassEntry()), methodEntry.getName(), renameClassesInThing(renames, methodEntry.getSignature())); |
| 131 | } else if (thing instanceof ArgumentEntry) { | 131 | } else if (thing instanceof ArgumentEntry) { |
| 132 | ArgumentEntry argumentEntry = (ArgumentEntry) thing; | 132 | ArgumentEntry argumentEntry = (ArgumentEntry) thing; |
| 133 | return (T) new ArgumentEntry(renameClassesInThing(renames, argumentEntry.getBehaviorEntry()), argumentEntry.getIndex(), argumentEntry.getName()); | 133 | return (T) new ArgumentEntry(renameClassesInThing(renames, argumentEntry.getBehaviorEntry()), argumentEntry.getIndex(), argumentEntry.getName()); |
| 134 | } else if (thing instanceof EntryReference) { | 134 | } else if (thing instanceof EntryReference) { |
| 135 | EntryReference<Entry, Entry> reference = (EntryReference<Entry, Entry>) thing; | 135 | EntryReference<Entry, Entry> reference = (EntryReference<Entry, Entry>) thing; |
| 136 | reference.entry = renameClassesInThing(renames, reference.entry); | 136 | reference.entry = renameClassesInThing(renames, reference.entry); |
| 137 | reference.context = renameClassesInThing(renames, reference.context); | 137 | reference.context = renameClassesInThing(renames, reference.context); |
| 138 | return thing; | 138 | return thing; |
| 139 | } else if (thing instanceof Signature) { | 139 | } else if (thing instanceof Signature) { |
| 140 | return (T) new Signature((Signature) thing, className -> renameClassesInThing(renames, className)); | 140 | return (T) new Signature((Signature) thing, className -> renameClassesInThing(renames, className)); |
| 141 | } else if (thing instanceof Type) { | 141 | } else if (thing instanceof Type) { |
| 142 | return (T) new Type((Type) thing, className -> renameClassesInThing(renames, className)); | 142 | return (T) new Type((Type) thing, className -> renameClassesInThing(renames, className)); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | return thing; | 145 | return thing; |
| 146 | } | 146 | } |
| 147 | } | 147 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 70cd059..34d2eff 100644 --- a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java | |||
| @@ -8,72 +8,73 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | ||
| 12 | 11 | ||
| 13 | import javax.swing.tree.DefaultMutableTreeNode; | 12 | package cuchaz.enigma.analysis; |
| 14 | 13 | ||
| 15 | import cuchaz.enigma.mapping.BehaviorEntry; | 14 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 16 | import cuchaz.enigma.mapping.FieldEntry; | 15 | import cuchaz.enigma.mapping.FieldEntry; |
| 17 | import cuchaz.enigma.mapping.Translator; | 16 | import cuchaz.enigma.mapping.Translator; |
| 18 | 17 | ||
| 18 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 19 | |||
| 19 | public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, BehaviorEntry> { | 20 | public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, BehaviorEntry> { |
| 20 | 21 | ||
| 21 | private Translator deobfuscatingTranslator; | 22 | private Translator deobfuscatingTranslator; |
| 22 | private FieldEntry entry; | 23 | private FieldEntry entry; |
| 23 | private EntryReference<FieldEntry, BehaviorEntry> reference; | 24 | private EntryReference<FieldEntry, BehaviorEntry> reference; |
| 24 | private Access access; | 25 | private Access access; |
| 25 | 26 | ||
| 26 | public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) { | 27 | public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) { |
| 27 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 28 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 28 | this.entry = entry; | 29 | this.entry = entry; |
| 29 | this.reference = null; | 30 | this.reference = null; |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<FieldEntry, BehaviorEntry> reference, Access access) { | 33 | private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<FieldEntry, BehaviorEntry> reference, Access access) { |
| 33 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 34 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 34 | this.entry = reference.entry; | 35 | this.entry = reference.entry; |
| 35 | this.reference = reference; | 36 | this.reference = reference; |
| 36 | this.access = access; | 37 | this.access = access; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | @Override | 40 | @Override |
| 40 | public FieldEntry getEntry() { | 41 | public FieldEntry getEntry() { |
| 41 | return this.entry; | 42 | return this.entry; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | @Override | 45 | @Override |
| 45 | public EntryReference<FieldEntry, BehaviorEntry> getReference() { | 46 | public EntryReference<FieldEntry, BehaviorEntry> getReference() { |
| 46 | return this.reference; | 47 | return this.reference; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | @Override | 50 | @Override |
| 50 | public String toString() { | 51 | public String toString() { |
| 51 | if (this.reference != null) { | 52 | if (this.reference != null) { |
| 52 | return String.format("%s (%s)", this.deobfuscatingTranslator.translateEntry(this.reference.context), this.access); | 53 | return String.format("%s (%s)", this.deobfuscatingTranslator.translateEntry(this.reference.context), this.access); |
| 53 | } | 54 | } |
| 54 | return this.deobfuscatingTranslator.translateEntry(this.entry).toString(); | 55 | return this.deobfuscatingTranslator.translateEntry(this.entry).toString(); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | public void load(JarIndex index, boolean recurse) { | 58 | public void load(JarIndex index, boolean recurse) { |
| 58 | // get all the child nodes | 59 | // get all the child nodes |
| 59 | if (this.reference == null) { | 60 | if (this.reference == null) { |
| 60 | for (EntryReference<FieldEntry, BehaviorEntry> reference : index.getFieldReferences(this.entry)) { | 61 | for (EntryReference<FieldEntry, BehaviorEntry> reference : index.getFieldReferences(this.entry)) { |
| 61 | add(new FieldReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.entry))); | 62 | add(new FieldReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.entry))); |
| 62 | } | 63 | } |
| 63 | } else { | 64 | } else { |
| 64 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : index.getBehaviorReferences(this.reference.context)) { | 65 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : index.getBehaviorReferences(this.reference.context)) { |
| 65 | add(new BehaviorReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.reference.context))); | 66 | add(new BehaviorReferenceTreeNode(this.deobfuscatingTranslator, reference, index.getAccess(this.reference.context))); |
| 66 | } | 67 | } |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | if (recurse && children != null) { | 70 | if (recurse && children != null) { |
| 70 | for (Object node : children) { | 71 | for (Object node : children) { |
| 71 | if (node instanceof BehaviorReferenceTreeNode) { | 72 | if (node instanceof BehaviorReferenceTreeNode) { |
| 72 | ((BehaviorReferenceTreeNode) node).load(index, true); | 73 | ((BehaviorReferenceTreeNode) node).load(index, true); |
| 73 | } else if (node instanceof FieldReferenceTreeNode) { | 74 | } else if (node instanceof FieldReferenceTreeNode) { |
| 74 | ((FieldReferenceTreeNode) node).load(index, true); | 75 | ((FieldReferenceTreeNode) node).load(index, true); |
| 75 | } | 76 | } |
| 76 | } | 77 | } |
| 77 | } | 78 | } |
| 78 | } | 79 | } |
| 79 | } | 80 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java b/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java index 0d18105..87d3797 100644 --- a/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java | |||
| @@ -8,9 +8,17 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 15 | import cuchaz.enigma.Constants; | ||
| 16 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 17 | import javassist.ByteArrayClassPath; | ||
| 18 | import javassist.ClassPool; | ||
| 19 | import javassist.CtClass; | ||
| 20 | import javassist.NotFoundException; | ||
| 21 | import javassist.bytecode.Descriptor; | ||
| 14 | 22 | ||
| 15 | import java.io.ByteArrayOutputStream; | 23 | import java.io.ByteArrayOutputStream; |
| 16 | import java.io.IOException; | 24 | import java.io.IOException; |
| @@ -21,103 +29,95 @@ import java.util.List; | |||
| 21 | import java.util.jar.JarEntry; | 29 | import java.util.jar.JarEntry; |
| 22 | import java.util.jar.JarFile; | 30 | import java.util.jar.JarFile; |
| 23 | 31 | ||
| 24 | import cuchaz.enigma.Constants; | ||
| 25 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 26 | import javassist.ByteArrayClassPath; | ||
| 27 | import javassist.ClassPool; | ||
| 28 | import javassist.CtClass; | ||
| 29 | import javassist.NotFoundException; | ||
| 30 | import javassist.bytecode.Descriptor; | ||
| 31 | |||
| 32 | public class JarClassIterator implements Iterator<CtClass> { | 32 | public class JarClassIterator implements Iterator<CtClass> { |
| 33 | 33 | ||
| 34 | private JarFile jar; | 34 | private JarFile jar; |
| 35 | private Iterator<JarEntry> iter; | 35 | private Iterator<JarEntry> iter; |
| 36 | 36 | ||
| 37 | public JarClassIterator(JarFile jar) { | 37 | public JarClassIterator(JarFile jar) { |
| 38 | this.jar = jar; | 38 | this.jar = jar; |
| 39 | 39 | ||
| 40 | // get the jar entries that correspond to classes | 40 | // get the jar entries that correspond to classes |
| 41 | List<JarEntry> classEntries = Lists.newArrayList(); | 41 | List<JarEntry> classEntries = Lists.newArrayList(); |
| 42 | Enumeration<JarEntry> entries = this.jar.entries(); | 42 | Enumeration<JarEntry> entries = this.jar.entries(); |
| 43 | while (entries.hasMoreElements()) { | 43 | while (entries.hasMoreElements()) { |
| 44 | JarEntry entry = entries.nextElement(); | 44 | JarEntry entry = entries.nextElement(); |
| 45 | 45 | ||
| 46 | // is this a class file? | 46 | // is this a class file? |
| 47 | if (entry.getName().endsWith(".class")) { | 47 | if (entry.getName().endsWith(".class")) { |
| 48 | classEntries.add(entry); | 48 | classEntries.add(entry); |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | this.iter = classEntries.iterator(); | 51 | this.iter = classEntries.iterator(); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | @Override | 54 | public static List<ClassEntry> getClassEntries(JarFile jar) { |
| 55 | public boolean hasNext() { | 55 | List<ClassEntry> classEntries = Lists.newArrayList(); |
| 56 | return this.iter.hasNext(); | 56 | Enumeration<JarEntry> entries = jar.entries(); |
| 57 | } | 57 | while (entries.hasMoreElements()) { |
| 58 | 58 | JarEntry entry = entries.nextElement(); | |
| 59 | @Override | 59 | |
| 60 | public CtClass next() { | 60 | // is this a class file? |
| 61 | JarEntry entry = this.iter.next(); | 61 | if (!entry.isDirectory() && entry.getName().endsWith(".class")) { |
| 62 | try { | 62 | classEntries.add(getClassEntry(entry)); |
| 63 | return getClass(this.jar, entry); | 63 | } |
| 64 | } catch (IOException | NotFoundException ex) { | 64 | } |
| 65 | throw new Error("Unable to load class: " + entry.getName()); | 65 | return classEntries; |
| 66 | } | 66 | } |
| 67 | } | 67 | |
| 68 | 68 | public static Iterable<CtClass> classes(final JarFile jar) { | |
| 69 | @Override | 69 | return () -> new JarClassIterator(jar); |
| 70 | public void remove() { | 70 | } |
| 71 | throw new UnsupportedOperationException(); | 71 | |
| 72 | } | 72 | private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException { |
| 73 | 73 | // read the class into a buffer | |
| 74 | public static List<ClassEntry> getClassEntries(JarFile jar) { | 74 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| 75 | List<ClassEntry> classEntries = Lists.newArrayList(); | 75 | byte[] buf = new byte[Constants.KiB]; |
| 76 | Enumeration<JarEntry> entries = jar.entries(); | 76 | int totalNumBytesRead = 0; |
| 77 | while (entries.hasMoreElements()) { | 77 | InputStream in = jar.getInputStream(entry); |
| 78 | JarEntry entry = entries.nextElement(); | 78 | while (in.available() > 0) { |
| 79 | 79 | int numBytesRead = in.read(buf); | |
| 80 | // is this a class file? | 80 | if (numBytesRead < 0) { |
| 81 | if (!entry.isDirectory() && entry.getName().endsWith(".class")) { | 81 | break; |
| 82 | classEntries.add(getClassEntry(entry)); | 82 | } |
| 83 | } | 83 | bos.write(buf, 0, numBytesRead); |
| 84 | } | 84 | |
| 85 | return classEntries; | 85 | // sanity checking |
| 86 | } | 86 | totalNumBytesRead += numBytesRead; |
| 87 | 87 | if (totalNumBytesRead > Constants.MiB) { | |
| 88 | public static Iterable<CtClass> classes(final JarFile jar) { | 88 | throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!"); |
| 89 | return () -> new JarClassIterator(jar); | 89 | } |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException { | 92 | // get a javassist handle for the class |
| 93 | // read the class into a buffer | 93 | String className = Descriptor.toJavaName(getClassEntry(entry).getName()); |
| 94 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); | 94 | ClassPool classPool = new ClassPool(); |
| 95 | byte[] buf = new byte[Constants.KiB]; | 95 | classPool.appendSystemPath(); |
| 96 | int totalNumBytesRead = 0; | 96 | classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray())); |
| 97 | InputStream in = jar.getInputStream(entry); | 97 | return classPool.get(className); |
| 98 | while (in.available() > 0) { | 98 | } |
| 99 | int numBytesRead = in.read(buf); | 99 | |
| 100 | if (numBytesRead < 0) { | 100 | private static ClassEntry getClassEntry(JarEntry entry) { |
| 101 | break; | 101 | return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length())); |
| 102 | } | 102 | } |
| 103 | bos.write(buf, 0, numBytesRead); | 103 | |
| 104 | 104 | @Override | |
| 105 | // sanity checking | 105 | public boolean hasNext() { |
| 106 | totalNumBytesRead += numBytesRead; | 106 | return this.iter.hasNext(); |
| 107 | if (totalNumBytesRead > Constants.MiB) { | 107 | } |
| 108 | throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!"); | 108 | |
| 109 | } | 109 | @Override |
| 110 | } | 110 | public CtClass next() { |
| 111 | 111 | JarEntry entry = this.iter.next(); | |
| 112 | // get a javassist handle for the class | 112 | try { |
| 113 | String className = Descriptor.toJavaName(getClassEntry(entry).getName()); | 113 | return getClass(this.jar, entry); |
| 114 | ClassPool classPool = new ClassPool(); | 114 | } catch (IOException | NotFoundException ex) { |
| 115 | classPool.appendSystemPath(); | 115 | throw new Error("Unable to load class: " + entry.getName()); |
| 116 | classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray())); | 116 | } |
| 117 | return classPool.get(className); | 117 | } |
| 118 | } | 118 | |
| 119 | 119 | @Override | |
| 120 | private static ClassEntry getClassEntry(JarEntry entry) { | 120 | public void remove() { |
| 121 | return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length())); | 121 | throw new UnsupportedOperationException(); |
| 122 | } | 122 | } |
| 123 | } | 123 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java index e8f74cc..ea87dda 100644 --- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -8,825 +8,824 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.*; | 14 | import com.google.common.collect.*; |
| 14 | |||
| 15 | import java.lang.reflect.Modifier; | ||
| 16 | import java.util.*; | ||
| 17 | import java.util.jar.JarFile; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.*; | 15 | import cuchaz.enigma.mapping.*; |
| 20 | import cuchaz.enigma.mapping.Translator; | 16 | import cuchaz.enigma.mapping.Translator; |
| 21 | import javassist.*; | 17 | import javassist.*; |
| 22 | import javassist.bytecode.*; | 18 | import javassist.bytecode.*; |
| 23 | import javassist.expr.*; | 19 | import javassist.expr.*; |
| 24 | 20 | ||
| 21 | import java.lang.reflect.Modifier; | ||
| 22 | import java.util.*; | ||
| 23 | import java.util.jar.JarFile; | ||
| 24 | |||
| 25 | public class JarIndex { | 25 | public class JarIndex { |
| 26 | 26 | ||
| 27 | private Set<ClassEntry> obfClassEntries; | 27 | private Set<ClassEntry> obfClassEntries; |
| 28 | private TranslationIndex translationIndex; | 28 | private TranslationIndex translationIndex; |
| 29 | private Map<Entry, Access> access; | 29 | private Map<Entry, Access> access; |
| 30 | private Multimap<ClassEntry, FieldEntry> fields; | 30 | private Multimap<ClassEntry, FieldEntry> fields; |
| 31 | private Multimap<ClassEntry, BehaviorEntry> behaviors; | 31 | private Multimap<ClassEntry, BehaviorEntry> behaviors; |
| 32 | private Multimap<String, MethodEntry> methodImplementations; | 32 | private Multimap<String, MethodEntry> methodImplementations; |
| 33 | private Multimap<BehaviorEntry, EntryReference<BehaviorEntry, BehaviorEntry>> behaviorReferences; | 33 | private Multimap<BehaviorEntry, EntryReference<BehaviorEntry, BehaviorEntry>> behaviorReferences; |
| 34 | private Multimap<FieldEntry, EntryReference<FieldEntry, BehaviorEntry>> fieldReferences; | 34 | private Multimap<FieldEntry, EntryReference<FieldEntry, BehaviorEntry>> fieldReferences; |
| 35 | private Multimap<ClassEntry, ClassEntry> innerClassesByOuter; | 35 | private Multimap<ClassEntry, ClassEntry> innerClassesByOuter; |
| 36 | private Map<ClassEntry, ClassEntry> outerClassesByInner; | 36 | private Map<ClassEntry, ClassEntry> outerClassesByInner; |
| 37 | private Map<ClassEntry, BehaviorEntry> anonymousClasses; | 37 | private Map<ClassEntry, BehaviorEntry> anonymousClasses; |
| 38 | private Map<MethodEntry, MethodEntry> bridgedMethods; | 38 | private Map<MethodEntry, MethodEntry> bridgedMethods; |
| 39 | private Set<MethodEntry> syntheticMethods; | 39 | private Set<MethodEntry> syntheticMethods; |
| 40 | 40 | ||
| 41 | public JarIndex() { | 41 | public JarIndex() { |
| 42 | this.obfClassEntries = Sets.newHashSet(); | 42 | this.obfClassEntries = Sets.newHashSet(); |
| 43 | this.translationIndex = new TranslationIndex(); | 43 | this.translationIndex = new TranslationIndex(); |
| 44 | this.access = Maps.newHashMap(); | 44 | this.access = Maps.newHashMap(); |
| 45 | this.fields = HashMultimap.create(); | 45 | this.fields = HashMultimap.create(); |
| 46 | this.behaviors = HashMultimap.create(); | 46 | this.behaviors = HashMultimap.create(); |
| 47 | this.methodImplementations = HashMultimap.create(); | 47 | this.methodImplementations = HashMultimap.create(); |
| 48 | this.behaviorReferences = HashMultimap.create(); | 48 | this.behaviorReferences = HashMultimap.create(); |
| 49 | this.fieldReferences = HashMultimap.create(); | 49 | this.fieldReferences = HashMultimap.create(); |
| 50 | this.innerClassesByOuter = HashMultimap.create(); | 50 | this.innerClassesByOuter = HashMultimap.create(); |
| 51 | this.outerClassesByInner = Maps.newHashMap(); | 51 | this.outerClassesByInner = Maps.newHashMap(); |
| 52 | this.anonymousClasses = Maps.newHashMap(); | 52 | this.anonymousClasses = Maps.newHashMap(); |
| 53 | this.bridgedMethods = Maps.newHashMap(); | 53 | this.bridgedMethods = Maps.newHashMap(); |
| 54 | this.syntheticMethods = Sets.newHashSet(); | 54 | this.syntheticMethods = Sets.newHashSet(); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | public void indexJar(JarFile jar, boolean buildInnerClasses) { | 57 | public void indexJar(JarFile jar, boolean buildInnerClasses) { |
| 58 | 58 | ||
| 59 | // step 1: read the class names | 59 | // step 1: read the class names |
| 60 | this.obfClassEntries.addAll(JarClassIterator.getClassEntries(jar)); | 60 | this.obfClassEntries.addAll(JarClassIterator.getClassEntries(jar)); |
| 61 | 61 | ||
| 62 | // step 2: index field/method/constructor access | 62 | // step 2: index field/method/constructor access |
| 63 | for (CtClass c : JarClassIterator.classes(jar)) { | 63 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 64 | for (CtField field : c.getDeclaredFields()) { | 64 | for (CtField field : c.getDeclaredFields()) { |
| 65 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); | 65 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 66 | this.access.put(fieldEntry, Access.get(field)); | 66 | this.access.put(fieldEntry, Access.get(field)); |
| 67 | this.fields.put(fieldEntry.getClassEntry(), fieldEntry); | 67 | this.fields.put(fieldEntry.getClassEntry(), fieldEntry); |
| 68 | } | 68 | } |
| 69 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 69 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 70 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); | 70 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 71 | this.access.put(behaviorEntry, Access.get(behavior)); | 71 | this.access.put(behaviorEntry, Access.get(behavior)); |
| 72 | this.behaviors.put(behaviorEntry.getClassEntry(), behaviorEntry); | 72 | this.behaviors.put(behaviorEntry.getClassEntry(), behaviorEntry); |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | // step 3: index extends, implements, fields, and methods | 76 | // step 3: index extends, implements, fields, and methods |
| 77 | for (CtClass c : JarClassIterator.classes(jar)) { | 77 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 78 | this.translationIndex.indexClass(c); | 78 | this.translationIndex.indexClass(c); |
| 79 | String className = Descriptor.toJvmName(c.getName()); | 79 | String className = Descriptor.toJvmName(c.getName()); |
| 80 | for (String interfaceName : c.getClassFile().getInterfaces()) { | 80 | for (String interfaceName : c.getClassFile().getInterfaces()) { |
| 81 | className = Descriptor.toJvmName(className); | 81 | className = Descriptor.toJvmName(className); |
| 82 | interfaceName = Descriptor.toJvmName(interfaceName); | 82 | interfaceName = Descriptor.toJvmName(interfaceName); |
| 83 | if (className.equals(interfaceName)) { | 83 | if (className.equals(interfaceName)) { |
| 84 | throw new IllegalArgumentException("Class cannot be its own interface! " + className); | 84 | throw new IllegalArgumentException("Class cannot be its own interface! " + className); |
| 85 | } | 85 | } |
| 86 | } | 86 | } |
| 87 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 87 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 88 | indexBehavior(behavior); | 88 | indexBehavior(behavior); |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | // step 4: index field, method, constructor references | 92 | // step 4: index field, method, constructor references |
| 93 | for (CtClass c : JarClassIterator.classes(jar)) { | 93 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 94 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 94 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 95 | indexBehaviorReferences(behavior); | 95 | indexBehaviorReferences(behavior); |
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | if (buildInnerClasses) { | 99 | if (buildInnerClasses) { |
| 100 | 100 | ||
| 101 | // step 5: index inner classes and anonymous classes | 101 | // step 5: index inner classes and anonymous classes |
| 102 | for (CtClass c : JarClassIterator.classes(jar)) { | 102 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 103 | ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); | 103 | ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); |
| 104 | ClassEntry outerClassEntry = findOuterClass(c); | 104 | ClassEntry outerClassEntry = findOuterClass(c); |
| 105 | if (outerClassEntry != null) { | 105 | if (outerClassEntry != null) { |
| 106 | this.innerClassesByOuter.put(outerClassEntry, innerClassEntry); | 106 | this.innerClassesByOuter.put(outerClassEntry, innerClassEntry); |
| 107 | boolean innerWasAdded = this.outerClassesByInner.put(innerClassEntry, outerClassEntry) == null; | 107 | boolean innerWasAdded = this.outerClassesByInner.put(innerClassEntry, outerClassEntry) == null; |
| 108 | assert (innerWasAdded); | 108 | assert (innerWasAdded); |
| 109 | 109 | ||
| 110 | BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassEntry); | 110 | BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassEntry); |
| 111 | if (enclosingBehavior != null) { | 111 | if (enclosingBehavior != null) { |
| 112 | this.anonymousClasses.put(innerClassEntry, enclosingBehavior); | 112 | this.anonymousClasses.put(innerClassEntry, enclosingBehavior); |
| 113 | 113 | ||
| 114 | // DEBUG | 114 | // DEBUG |
| 115 | //System.out.println("ANONYMOUS: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); | 115 | //System.out.println("ANONYMOUS: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); |
| 116 | }/* else { | 116 | }/* else { |
| 117 | // DEBUG | 117 | // DEBUG |
| 118 | //System.out.println("INNER: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); | 118 | //System.out.println("INNER: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); |
| 119 | }*/ | 119 | }*/ |
| 120 | } | 120 | } |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | // step 6: update other indices with inner class info | 123 | // step 6: update other indices with inner class info |
| 124 | Map<String, String> renames = Maps.newHashMap(); | 124 | Map<String, String> renames = Maps.newHashMap(); |
| 125 | for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) { | 125 | for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) { |
| 126 | String newName = innerClassEntry.buildClassEntry(getObfClassChain(innerClassEntry)).getName(); | 126 | String newName = innerClassEntry.buildClassEntry(getObfClassChain(innerClassEntry)).getName(); |
| 127 | if (!innerClassEntry.getName().equals(newName)) { | 127 | if (!innerClassEntry.getName().equals(newName)) { |
| 128 | // DEBUG | 128 | // DEBUG |
| 129 | //System.out.println("REPLACE: " + innerClassEntry.getName() + " WITH " + newName); | 129 | //System.out.println("REPLACE: " + innerClassEntry.getName() + " WITH " + newName); |
| 130 | renames.put(innerClassEntry.getName(), newName); | 130 | renames.put(innerClassEntry.getName(), newName); |
| 131 | } | 131 | } |
| 132 | } | 132 | } |
| 133 | EntryRenamer.renameClassesInSet(renames, this.obfClassEntries); | 133 | EntryRenamer.renameClassesInSet(renames, this.obfClassEntries); |
| 134 | this.translationIndex.renameClasses(renames); | 134 | this.translationIndex.renameClasses(renames); |
| 135 | EntryRenamer.renameClassesInMultimap(renames, this.methodImplementations); | 135 | EntryRenamer.renameClassesInMultimap(renames, this.methodImplementations); |
| 136 | EntryRenamer.renameClassesInMultimap(renames, this.behaviorReferences); | 136 | EntryRenamer.renameClassesInMultimap(renames, this.behaviorReferences); |
| 137 | EntryRenamer.renameClassesInMultimap(renames, this.fieldReferences); | 137 | EntryRenamer.renameClassesInMultimap(renames, this.fieldReferences); |
| 138 | EntryRenamer.renameClassesInMap(renames, this.access); | 138 | EntryRenamer.renameClassesInMap(renames, this.access); |
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | private void indexBehavior(CtBehavior behavior) { | 142 | private void indexBehavior(CtBehavior behavior) { |
| 143 | // get the behavior entry | 143 | // get the behavior entry |
| 144 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); | 144 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 145 | if (behaviorEntry instanceof MethodEntry) { | 145 | if (behaviorEntry instanceof MethodEntry) { |
| 146 | MethodEntry methodEntry = (MethodEntry) behaviorEntry; | 146 | MethodEntry methodEntry = (MethodEntry) behaviorEntry; |
| 147 | 147 | ||
| 148 | // is synthetic | 148 | // is synthetic |
| 149 | if ((behavior.getModifiers() & AccessFlag.SYNTHETIC) != 0) { | 149 | if ((behavior.getModifiers() & AccessFlag.SYNTHETIC) != 0) { |
| 150 | syntheticMethods.add(methodEntry); | 150 | syntheticMethods.add(methodEntry); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | // index implementation | 153 | // index implementation |
| 154 | this.methodImplementations.put(behaviorEntry.getClassName(), methodEntry); | 154 | this.methodImplementations.put(behaviorEntry.getClassName(), methodEntry); |
| 155 | 155 | ||
| 156 | // look for bridge and bridged methods | 156 | // look for bridge and bridged methods |
| 157 | CtMethod bridgedMethod = getBridgedMethod((CtMethod) behavior); | 157 | CtMethod bridgedMethod = getBridgedMethod((CtMethod) behavior); |
| 158 | if (bridgedMethod != null) { | 158 | if (bridgedMethod != null) { |
| 159 | this.bridgedMethods.put(methodEntry, EntryFactory.getMethodEntry(bridgedMethod)); | 159 | this.bridgedMethods.put(methodEntry, EntryFactory.getMethodEntry(bridgedMethod)); |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | // looks like we don't care about constructors here | 162 | // looks like we don't care about constructors here |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | private void indexBehaviorReferences(CtBehavior behavior) { | 165 | private void indexBehaviorReferences(CtBehavior behavior) { |
| 166 | // index method calls | 166 | // index method calls |
| 167 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); | 167 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 168 | try { | 168 | try { |
| 169 | behavior.instrument(new ExprEditor() { | 169 | behavior.instrument(new ExprEditor() { |
| 170 | @Override | 170 | @Override |
| 171 | public void edit(MethodCall call) { | 171 | public void edit(MethodCall call) { |
| 172 | MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call); | 172 | MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call); |
| 173 | ClassEntry resolvedClassEntry = translationIndex.resolveEntryClass(calledMethodEntry); | 173 | ClassEntry resolvedClassEntry = translationIndex.resolveEntryClass(calledMethodEntry); |
| 174 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { | 174 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { |
| 175 | calledMethodEntry = new MethodEntry( | 175 | calledMethodEntry = new MethodEntry( |
| 176 | resolvedClassEntry, | 176 | resolvedClassEntry, |
| 177 | calledMethodEntry.getName(), | 177 | calledMethodEntry.getName(), |
| 178 | calledMethodEntry.getSignature() | 178 | calledMethodEntry.getSignature() |
| 179 | ); | 179 | ); |
| 180 | } | 180 | } |
| 181 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( | 181 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( |
| 182 | calledMethodEntry, | 182 | calledMethodEntry, |
| 183 | call.getMethodName(), | 183 | call.getMethodName(), |
| 184 | behaviorEntry | 184 | behaviorEntry |
| 185 | ); | 185 | ); |
| 186 | behaviorReferences.put(calledMethodEntry, reference); | 186 | behaviorReferences.put(calledMethodEntry, reference); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | @Override | 189 | @Override |
| 190 | public void edit(FieldAccess call) { | 190 | public void edit(FieldAccess call) { |
| 191 | FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call); | 191 | FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call); |
| 192 | ClassEntry resolvedClassEntry = translationIndex.resolveEntryClass(calledFieldEntry); | 192 | ClassEntry resolvedClassEntry = translationIndex.resolveEntryClass(calledFieldEntry); |
| 193 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { | 193 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { |
| 194 | calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); | 194 | calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); |
| 195 | } | 195 | } |
| 196 | EntryReference<FieldEntry, BehaviorEntry> reference = new EntryReference<>( | 196 | EntryReference<FieldEntry, BehaviorEntry> reference = new EntryReference<>( |
| 197 | calledFieldEntry, | 197 | calledFieldEntry, |
| 198 | call.getFieldName(), | 198 | call.getFieldName(), |
| 199 | behaviorEntry | 199 | behaviorEntry |
| 200 | ); | 200 | ); |
| 201 | fieldReferences.put(calledFieldEntry, reference); | 201 | fieldReferences.put(calledFieldEntry, reference); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | @Override | 204 | @Override |
| 205 | public void edit(ConstructorCall call) { | 205 | public void edit(ConstructorCall call) { |
| 206 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); | 206 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); |
| 207 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( | 207 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( |
| 208 | calledConstructorEntry, | 208 | calledConstructorEntry, |
| 209 | call.getMethodName(), | 209 | call.getMethodName(), |
| 210 | behaviorEntry | 210 | behaviorEntry |
| 211 | ); | 211 | ); |
| 212 | behaviorReferences.put(calledConstructorEntry, reference); | 212 | behaviorReferences.put(calledConstructorEntry, reference); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | @Override | 215 | @Override |
| 216 | public void edit(NewExpr call) { | 216 | public void edit(NewExpr call) { |
| 217 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); | 217 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); |
| 218 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( | 218 | EntryReference<BehaviorEntry, BehaviorEntry> reference = new EntryReference<>( |
| 219 | calledConstructorEntry, | 219 | calledConstructorEntry, |
| 220 | call.getClassName(), | 220 | call.getClassName(), |
| 221 | behaviorEntry | 221 | behaviorEntry |
| 222 | ); | 222 | ); |
| 223 | behaviorReferences.put(calledConstructorEntry, reference); | 223 | behaviorReferences.put(calledConstructorEntry, reference); |
| 224 | } | 224 | } |
| 225 | }); | 225 | }); |
| 226 | } catch (CannotCompileException ex) { | 226 | } catch (CannotCompileException ex) { |
| 227 | throw new Error(ex); | 227 | throw new Error(ex); |
| 228 | } | 228 | } |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | private CtMethod getBridgedMethod(CtMethod method) { | 231 | private CtMethod getBridgedMethod(CtMethod method) { |
| 232 | 232 | ||
| 233 | // bridge methods just call another method, cast it to the return type, and return the result | 233 | // bridge methods just call another method, cast it to the return type, and return the result |
| 234 | // let's see if we can detect this scenario | 234 | // let's see if we can detect this scenario |
| 235 | 235 | ||
| 236 | // skip non-synthetic methods | 236 | // skip non-synthetic methods |
| 237 | if ((method.getModifiers() & AccessFlag.SYNTHETIC) == 0) { | 237 | if ((method.getModifiers() & AccessFlag.SYNTHETIC) == 0) { |
| 238 | return null; | 238 | return null; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | // get all the called methods | 241 | // get all the called methods |
| 242 | final List<MethodCall> methodCalls = Lists.newArrayList(); | 242 | final List<MethodCall> methodCalls = Lists.newArrayList(); |
| 243 | try { | 243 | try { |
| 244 | method.instrument(new ExprEditor() { | 244 | method.instrument(new ExprEditor() { |
| 245 | @Override | 245 | @Override |
| 246 | public void edit(MethodCall call) { | 246 | public void edit(MethodCall call) { |
| 247 | methodCalls.add(call); | 247 | methodCalls.add(call); |
| 248 | } | 248 | } |
| 249 | }); | 249 | }); |
| 250 | } catch (CannotCompileException ex) { | 250 | } catch (CannotCompileException ex) { |
| 251 | // this is stupid... we're not even compiling anything | 251 | // this is stupid... we're not even compiling anything |
| 252 | throw new Error(ex); | 252 | throw new Error(ex); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | // is there just one? | 255 | // is there just one? |
| 256 | if (methodCalls.size() != 1) { | 256 | if (methodCalls.size() != 1) { |
| 257 | return null; | 257 | return null; |
| 258 | } | 258 | } |
| 259 | MethodCall call = methodCalls.get(0); | 259 | MethodCall call = methodCalls.get(0); |
| 260 | 260 | ||
| 261 | try { | 261 | try { |
| 262 | // we have a bridge method! | 262 | // we have a bridge method! |
| 263 | return call.getMethod(); | 263 | return call.getMethod(); |
| 264 | } catch (NotFoundException ex) { | 264 | } catch (NotFoundException ex) { |
| 265 | // can't find the type? not a bridge method | 265 | // can't find the type? not a bridge method |
| 266 | return null; | 266 | return null; |
| 267 | } | 267 | } |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | private ClassEntry findOuterClass(CtClass c) { | 270 | private ClassEntry findOuterClass(CtClass c) { |
| 271 | 271 | ||
| 272 | ClassEntry classEntry = EntryFactory.getClassEntry(c); | 272 | ClassEntry classEntry = EntryFactory.getClassEntry(c); |
| 273 | 273 | ||
| 274 | // does this class already have an outer class? | 274 | // does this class already have an outer class? |
| 275 | if (classEntry.isInnerClass()) { | 275 | if (classEntry.isInnerClass()) { |
| 276 | return classEntry.getOuterClassEntry(); | 276 | return classEntry.getOuterClassEntry(); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | // inner classes: | 279 | // inner classes: |
| 280 | // have constructors that can (illegally) set synthetic fields | 280 | // have constructors that can (illegally) set synthetic fields |
| 281 | // the outer class is the only class that calls constructors | 281 | // the outer class is the only class that calls constructors |
| 282 | 282 | ||
| 283 | // use the synthetic fields to find the synthetic constructors | 283 | // use the synthetic fields to find the synthetic constructors |
| 284 | for (CtConstructor constructor : c.getDeclaredConstructors()) { | 284 | for (CtConstructor constructor : c.getDeclaredConstructors()) { |
| 285 | Set<String> syntheticFieldTypes = Sets.newHashSet(); | 285 | Set<String> syntheticFieldTypes = Sets.newHashSet(); |
| 286 | if (!isIllegalConstructor(syntheticFieldTypes, constructor)) { | 286 | if (!isIllegalConstructor(syntheticFieldTypes, constructor)) { |
| 287 | continue; | 287 | continue; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); | 290 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); |
| 291 | 291 | ||
| 292 | // gather the classes from the illegally-set synthetic fields | 292 | // gather the classes from the illegally-set synthetic fields |
| 293 | Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); | 293 | Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); |
| 294 | for (String type : syntheticFieldTypes) { | 294 | for (String type : syntheticFieldTypes) { |
| 295 | if (type.startsWith("L")) { | 295 | if (type.startsWith("L")) { |
| 296 | ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1)); | 296 | ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1)); |
| 297 | if (isSaneOuterClass(outerClassEntry, classEntry)) { | 297 | if (isSaneOuterClass(outerClassEntry, classEntry)) { |
| 298 | illegallySetClasses.add(outerClassEntry); | 298 | illegallySetClasses.add(outerClassEntry); |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | // who calls this constructor? | 303 | // who calls this constructor? |
| 304 | Set<ClassEntry> callerClasses = Sets.newHashSet(); | 304 | Set<ClassEntry> callerClasses = Sets.newHashSet(); |
| 305 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : getBehaviorReferences(constructorEntry)) { | 305 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : getBehaviorReferences(constructorEntry)) { |
| 306 | 306 | ||
| 307 | // make sure it's not a call to super | 307 | // make sure it's not a call to super |
| 308 | if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { | 308 | if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { |
| 309 | 309 | ||
| 310 | // is the entry a superclass of the context? | 310 | // is the entry a superclass of the context? |
| 311 | ClassEntry calledClassEntry = reference.entry.getClassEntry(); | 311 | ClassEntry calledClassEntry = reference.entry.getClassEntry(); |
| 312 | ClassEntry superclassEntry = this.translationIndex.getSuperclass(reference.context.getClassEntry()); | 312 | ClassEntry superclassEntry = this.translationIndex.getSuperclass(reference.context.getClassEntry()); |
| 313 | if (superclassEntry != null && superclassEntry.equals(calledClassEntry)) { | 313 | if (superclassEntry != null && superclassEntry.equals(calledClassEntry)) { |
| 314 | // it's a super call, skip | 314 | // it's a super call, skip |
| 315 | continue; | 315 | continue; |
| 316 | } | 316 | } |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) { | 319 | if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) { |
| 320 | callerClasses.add(reference.context.getClassEntry()); | 320 | callerClasses.add(reference.context.getClassEntry()); |
| 321 | } | 321 | } |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | // do we have an answer yet? | 324 | // do we have an answer yet? |
| 325 | if (callerClasses.isEmpty()) { | 325 | if (callerClasses.isEmpty()) { |
| 326 | if (illegallySetClasses.size() == 1) { | 326 | if (illegallySetClasses.size() == 1) { |
| 327 | return illegallySetClasses.iterator().next(); | 327 | return illegallySetClasses.iterator().next(); |
| 328 | } else { | 328 | } else { |
| 329 | System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); | 329 | System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); |
| 330 | } | 330 | } |
| 331 | } else { | 331 | } else { |
| 332 | if (callerClasses.size() == 1) { | 332 | if (callerClasses.size() == 1) { |
| 333 | return callerClasses.iterator().next(); | 333 | return callerClasses.iterator().next(); |
| 334 | } else { | 334 | } else { |
| 335 | // multiple callers, do the illegally set classes narrow it down? | 335 | // multiple callers, do the illegally set classes narrow it down? |
| 336 | Set<ClassEntry> intersection = Sets.newHashSet(callerClasses); | 336 | Set<ClassEntry> intersection = Sets.newHashSet(callerClasses); |
| 337 | intersection.retainAll(illegallySetClasses); | 337 | intersection.retainAll(illegallySetClasses); |
| 338 | if (intersection.size() == 1) { | 338 | if (intersection.size() == 1) { |
| 339 | return intersection.iterator().next(); | 339 | return intersection.iterator().next(); |
| 340 | } else { | 340 | } else { |
| 341 | System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); | 341 | System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); |
| 342 | } | 342 | } |
| 343 | } | 343 | } |
| 344 | } | 344 | } |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | return null; | 347 | return null; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) { | 350 | private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) { |
| 351 | 351 | ||
| 352 | // clearly this would be silly | 352 | // clearly this would be silly |
| 353 | if (outerClassEntry.equals(innerClassEntry)) { | 353 | if (outerClassEntry.equals(innerClassEntry)) { |
| 354 | return false; | 354 | return false; |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | // is the outer class in the jar? | 357 | // is the outer class in the jar? |
| 358 | return this.obfClassEntries.contains(outerClassEntry); | 358 | return this.obfClassEntries.contains(outerClassEntry); |
| 359 | 359 | ||
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | @SuppressWarnings("unchecked") | 362 | @SuppressWarnings("unchecked") |
| 363 | private boolean isIllegalConstructor(Set<String> syntheticFieldTypes, CtConstructor constructor) { | 363 | private boolean isIllegalConstructor(Set<String> syntheticFieldTypes, CtConstructor constructor) { |
| 364 | 364 | ||
| 365 | // illegal constructors only set synthetic member fields, then call super() | 365 | // illegal constructors only set synthetic member fields, then call super() |
| 366 | String className = constructor.getDeclaringClass().getName(); | 366 | String className = constructor.getDeclaringClass().getName(); |
| 367 | 367 | ||
| 368 | // collect all the field accesses, constructor calls, and method calls | 368 | // collect all the field accesses, constructor calls, and method calls |
| 369 | final List<FieldAccess> illegalFieldWrites = Lists.newArrayList(); | 369 | final List<FieldAccess> illegalFieldWrites = Lists.newArrayList(); |
| 370 | final List<ConstructorCall> constructorCalls = Lists.newArrayList(); | 370 | final List<ConstructorCall> constructorCalls = Lists.newArrayList(); |
| 371 | try { | 371 | try { |
| 372 | constructor.instrument(new ExprEditor() { | 372 | constructor.instrument(new ExprEditor() { |
| 373 | @Override | 373 | @Override |
| 374 | public void edit(FieldAccess fieldAccess) { | 374 | public void edit(FieldAccess fieldAccess) { |
| 375 | if (fieldAccess.isWriter() && constructorCalls.isEmpty()) { | 375 | if (fieldAccess.isWriter() && constructorCalls.isEmpty()) { |
| 376 | illegalFieldWrites.add(fieldAccess); | 376 | illegalFieldWrites.add(fieldAccess); |
| 377 | } | 377 | } |
| 378 | } | 378 | } |
| 379 | 379 | ||
| 380 | @Override | 380 | @Override |
| 381 | public void edit(ConstructorCall constructorCall) { | 381 | public void edit(ConstructorCall constructorCall) { |
| 382 | constructorCalls.add(constructorCall); | 382 | constructorCalls.add(constructorCall); |
| 383 | } | 383 | } |
| 384 | }); | 384 | }); |
| 385 | } catch (CannotCompileException ex) { | 385 | } catch (CannotCompileException ex) { |
| 386 | // we're not compiling anything... this is stupid | 386 | // we're not compiling anything... this is stupid |
| 387 | throw new Error(ex); | 387 | throw new Error(ex); |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | // are there any illegal field writes? | 390 | // are there any illegal field writes? |
| 391 | if (illegalFieldWrites.isEmpty()) { | 391 | if (illegalFieldWrites.isEmpty()) { |
| 392 | return false; | 392 | return false; |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | // are all the writes to synthetic fields? | 395 | // are all the writes to synthetic fields? |
| 396 | for (FieldAccess fieldWrite : illegalFieldWrites) { | 396 | for (FieldAccess fieldWrite : illegalFieldWrites) { |
| 397 | 397 | ||
| 398 | // all illegal writes have to be to the local class | 398 | // all illegal writes have to be to the local class |
| 399 | if (!fieldWrite.getClassName().equals(className)) { | 399 | if (!fieldWrite.getClassName().equals(className)) { |
| 400 | System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName())); | 400 | System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName())); |
| 401 | return false; | 401 | return false; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | // find the field | 404 | // find the field |
| 405 | FieldInfo fieldInfo = null; | 405 | FieldInfo fieldInfo = null; |
| 406 | for (FieldInfo info : (List<FieldInfo>) constructor.getDeclaringClass().getClassFile().getFields()) { | 406 | for (FieldInfo info : (List<FieldInfo>) constructor.getDeclaringClass().getClassFile().getFields()) { |
| 407 | if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) { | 407 | if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) { |
| 408 | fieldInfo = info; | 408 | fieldInfo = info; |
| 409 | break; | 409 | break; |
| 410 | } | 410 | } |
| 411 | } | 411 | } |
| 412 | if (fieldInfo == null) { | 412 | if (fieldInfo == null) { |
| 413 | // field is in a superclass or something, can't be a local synthetic member | 413 | // field is in a superclass or something, can't be a local synthetic member |
| 414 | return false; | 414 | return false; |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | // is this field synthetic? | 417 | // is this field synthetic? |
| 418 | boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; | 418 | boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; |
| 419 | if (isSynthetic) { | 419 | if (isSynthetic) { |
| 420 | syntheticFieldTypes.add(fieldInfo.getDescriptor()); | 420 | syntheticFieldTypes.add(fieldInfo.getDescriptor()); |
| 421 | } else { | 421 | } else { |
| 422 | System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName())); | 422 | System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName())); |
| 423 | return false; | 423 | return false; |
| 424 | } | 424 | } |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | // we passed all the tests! | 427 | // we passed all the tests! |
| 428 | return true; | 428 | return true; |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | private BehaviorEntry isAnonymousClass(CtClass c, ClassEntry outerClassEntry) { | 431 | private BehaviorEntry isAnonymousClass(CtClass c, ClassEntry outerClassEntry) { |
| 432 | 432 | ||
| 433 | // is this class already marked anonymous? | 433 | // is this class already marked anonymous? |
| 434 | EnclosingMethodAttribute enclosingMethodAttribute = (EnclosingMethodAttribute) c.getClassFile().getAttribute(EnclosingMethodAttribute.tag); | 434 | EnclosingMethodAttribute enclosingMethodAttribute = (EnclosingMethodAttribute) c.getClassFile().getAttribute(EnclosingMethodAttribute.tag); |
| 435 | if (enclosingMethodAttribute != null) { | 435 | if (enclosingMethodAttribute != null) { |
| 436 | if (enclosingMethodAttribute.methodIndex() > 0) { | 436 | if (enclosingMethodAttribute.methodIndex() > 0) { |
| 437 | return EntryFactory.getBehaviorEntry( | 437 | return EntryFactory.getBehaviorEntry( |
| 438 | Descriptor.toJvmName(enclosingMethodAttribute.className()), | 438 | Descriptor.toJvmName(enclosingMethodAttribute.className()), |
| 439 | enclosingMethodAttribute.methodName(), | 439 | enclosingMethodAttribute.methodName(), |
| 440 | enclosingMethodAttribute.methodDescriptor() | 440 | enclosingMethodAttribute.methodDescriptor() |
| 441 | ); | 441 | ); |
| 442 | } else { | 442 | } else { |
| 443 | // an attribute but no method? assume not anonymous | 443 | // an attribute but no method? assume not anonymous |
| 444 | return null; | 444 | return null; |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | // if there's an inner class attribute, but not an enclosing method attribute, then it's not anonymous | 448 | // if there's an inner class attribute, but not an enclosing method attribute, then it's not anonymous |
| 449 | InnerClassesAttribute innerClassesAttribute = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag); | 449 | InnerClassesAttribute innerClassesAttribute = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag); |
| 450 | if (innerClassesAttribute != null) { | 450 | if (innerClassesAttribute != null) { |
| 451 | return null; | 451 | return null; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 454 | ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
| 455 | 455 | ||
| 456 | // anonymous classes: | 456 | // anonymous classes: |
| 457 | // can't be abstract | 457 | // can't be abstract |
| 458 | // have only one constructor | 458 | // have only one constructor |
| 459 | // it's called exactly once by the outer class | 459 | // it's called exactly once by the outer class |
| 460 | // the type the instance is assigned to can't be this type | 460 | // the type the instance is assigned to can't be this type |
| 461 | 461 | ||
| 462 | // is abstract? | 462 | // is abstract? |
| 463 | if (Modifier.isAbstract(c.getModifiers())) { | 463 | if (Modifier.isAbstract(c.getModifiers())) { |
| 464 | return null; | 464 | return null; |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | // is there exactly one constructor? | 467 | // is there exactly one constructor? |
| 468 | if (c.getDeclaredConstructors().length != 1) { | 468 | if (c.getDeclaredConstructors().length != 1) { |
| 469 | return null; | 469 | return null; |
| 470 | } | 470 | } |
| 471 | CtConstructor constructor = c.getDeclaredConstructors()[0]; | 471 | CtConstructor constructor = c.getDeclaredConstructors()[0]; |
| 472 | 472 | ||
| 473 | // is this constructor called exactly once? | 473 | // is this constructor called exactly once? |
| 474 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); | 474 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); |
| 475 | Collection<EntryReference<BehaviorEntry, BehaviorEntry>> references = getBehaviorReferences(constructorEntry); | 475 | Collection<EntryReference<BehaviorEntry, BehaviorEntry>> references = getBehaviorReferences(constructorEntry); |
| 476 | if (references.size() != 1) { | 476 | if (references.size() != 1) { |
| 477 | return null; | 477 | return null; |
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | // does the caller use this type? | 480 | // does the caller use this type? |
| 481 | BehaviorEntry caller = references.iterator().next().context; | 481 | BehaviorEntry caller = references.iterator().next().context; |
| 482 | for (FieldEntry fieldEntry : getReferencedFields(caller)) { | 482 | for (FieldEntry fieldEntry : getReferencedFields(caller)) { |
| 483 | if (fieldEntry.getType().hasClass() && fieldEntry.getType().getClassEntry().equals(innerClassEntry)) { | 483 | if (fieldEntry.getType().hasClass() && fieldEntry.getType().getClassEntry().equals(innerClassEntry)) { |
| 484 | // caller references this type, so it can't be anonymous | 484 | // caller references this type, so it can't be anonymous |
| 485 | return null; | 485 | return null; |
| 486 | } | 486 | } |
| 487 | } | 487 | } |
| 488 | for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) { | 488 | for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) { |
| 489 | if (behaviorEntry.getSignature().hasClass(innerClassEntry)) { | 489 | if (behaviorEntry.getSignature().hasClass(innerClassEntry)) { |
| 490 | return null; | 490 | return null; |
| 491 | } | 491 | } |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | return caller; | 494 | return caller; |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | public Set<ClassEntry> getObfClassEntries() { | 497 | public Set<ClassEntry> getObfClassEntries() { |
| 498 | return this.obfClassEntries; | 498 | return this.obfClassEntries; |
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | public Collection<FieldEntry> getObfFieldEntries() { | 501 | public Collection<FieldEntry> getObfFieldEntries() { |
| 502 | return this.fields.values(); | 502 | return this.fields.values(); |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | public Collection<FieldEntry> getObfFieldEntries(ClassEntry classEntry) { | 505 | public Collection<FieldEntry> getObfFieldEntries(ClassEntry classEntry) { |
| 506 | return this.fields.get(classEntry); | 506 | return this.fields.get(classEntry); |
| 507 | } | 507 | } |
| 508 | 508 | ||
| 509 | public Collection<BehaviorEntry> getObfBehaviorEntries() { | 509 | public Collection<BehaviorEntry> getObfBehaviorEntries() { |
| 510 | return this.behaviors.values(); | 510 | return this.behaviors.values(); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | public Collection<BehaviorEntry> getObfBehaviorEntries(ClassEntry classEntry) { | 513 | public Collection<BehaviorEntry> getObfBehaviorEntries(ClassEntry classEntry) { |
| 514 | return this.behaviors.get(classEntry); | 514 | return this.behaviors.get(classEntry); |
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | public TranslationIndex getTranslationIndex() { | 517 | public TranslationIndex getTranslationIndex() { |
| 518 | return this.translationIndex; | 518 | return this.translationIndex; |
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | public Access getAccess(Entry entry) { | 521 | public Access getAccess(Entry entry) { |
| 522 | return this.access.get(entry); | 522 | return this.access.get(entry); |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { | 525 | public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { |
| 526 | 526 | ||
| 527 | // get the root node | 527 | // get the root node |
| 528 | List<String> ancestry = Lists.newArrayList(); | 528 | List<String> ancestry = Lists.newArrayList(); |
| 529 | ancestry.add(obfClassEntry.getName()); | 529 | ancestry.add(obfClassEntry.getName()); |
| 530 | for (ClassEntry classEntry : this.translationIndex.getAncestry(obfClassEntry)) { | 530 | for (ClassEntry classEntry : this.translationIndex.getAncestry(obfClassEntry)) { |
| 531 | if (containsObfClass(classEntry)) { | 531 | if (containsObfClass(classEntry)) { |
| 532 | ancestry.add(classEntry.getName()); | 532 | ancestry.add(classEntry.getName()); |
| 533 | } | 533 | } |
| 534 | } | 534 | } |
| 535 | ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( | 535 | ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( |
| 536 | deobfuscatingTranslator, | 536 | deobfuscatingTranslator, |
| 537 | ancestry.get(ancestry.size() - 1) | 537 | ancestry.get(ancestry.size() - 1) |
| 538 | ); | 538 | ); |
| 539 | 539 | ||
| 540 | // expand all children recursively | 540 | // expand all children recursively |
| 541 | rootNode.load(this.translationIndex, true); | 541 | rootNode.load(this.translationIndex, true); |
| 542 | 542 | ||
| 543 | return rootNode; | 543 | return rootNode; |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { | 546 | public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { |
| 547 | 547 | ||
| 548 | // is this even an interface? | 548 | // is this even an interface? |
| 549 | if (isInterface(obfClassEntry.getClassName())) { | 549 | if (isInterface(obfClassEntry.getClassName())) { |
| 550 | ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry); | 550 | ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry); |
| 551 | node.load(this); | 551 | node.load(this); |
| 552 | return node; | 552 | return node; |
| 553 | } | 553 | } |
| 554 | return null; | 554 | return null; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { | 557 | public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { |
| 558 | 558 | ||
| 559 | // travel to the ancestor implementation | 559 | // travel to the ancestor implementation |
| 560 | ClassEntry baseImplementationClassEntry = obfMethodEntry.getClassEntry(); | 560 | ClassEntry baseImplementationClassEntry = obfMethodEntry.getClassEntry(); |
| 561 | for (ClassEntry ancestorClassEntry : this.translationIndex.getAncestry(obfMethodEntry.getClassEntry())) { | 561 | for (ClassEntry ancestorClassEntry : this.translationIndex.getAncestry(obfMethodEntry.getClassEntry())) { |
| 562 | MethodEntry ancestorMethodEntry = new MethodEntry( | 562 | MethodEntry ancestorMethodEntry = new MethodEntry( |
| 563 | new ClassEntry(ancestorClassEntry), | 563 | new ClassEntry(ancestorClassEntry), |
| 564 | obfMethodEntry.getName(), | 564 | obfMethodEntry.getName(), |
| 565 | obfMethodEntry.getSignature() | 565 | obfMethodEntry.getSignature() |
| 566 | ); | 566 | ); |
| 567 | if (containsObfBehavior(ancestorMethodEntry)) { | 567 | if (containsObfBehavior(ancestorMethodEntry)) { |
| 568 | baseImplementationClassEntry = ancestorClassEntry; | 568 | baseImplementationClassEntry = ancestorClassEntry; |
| 569 | } | 569 | } |
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | // make a root node at the base | 572 | // make a root node at the base |
| 573 | MethodEntry methodEntry = new MethodEntry( | 573 | MethodEntry methodEntry = new MethodEntry( |
| 574 | baseImplementationClassEntry, | 574 | baseImplementationClassEntry, |
| 575 | obfMethodEntry.getName(), | 575 | obfMethodEntry.getName(), |
| 576 | obfMethodEntry.getSignature() | 576 | obfMethodEntry.getSignature() |
| 577 | ); | 577 | ); |
| 578 | MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( | 578 | MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( |
| 579 | deobfuscatingTranslator, | 579 | deobfuscatingTranslator, |
| 580 | methodEntry, | 580 | methodEntry, |
| 581 | containsObfBehavior(methodEntry) | 581 | containsObfBehavior(methodEntry) |
| 582 | ); | 582 | ); |
| 583 | 583 | ||
| 584 | // expand the full tree | 584 | // expand the full tree |
| 585 | rootNode.load(this, true); | 585 | rootNode.load(this, true); |
| 586 | 586 | ||
| 587 | return rootNode; | 587 | return rootNode; |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | public List<MethodImplementationsTreeNode> getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { | 590 | public List<MethodImplementationsTreeNode> getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { |
| 591 | 591 | ||
| 592 | List<MethodEntry> interfaceMethodEntries = Lists.newArrayList(); | 592 | List<MethodEntry> interfaceMethodEntries = Lists.newArrayList(); |
| 593 | 593 | ||
| 594 | // is this method on an interface? | 594 | // is this method on an interface? |
| 595 | if (isInterface(obfMethodEntry.getClassName())) { | 595 | if (isInterface(obfMethodEntry.getClassName())) { |
| 596 | interfaceMethodEntries.add(obfMethodEntry); | 596 | interfaceMethodEntries.add(obfMethodEntry); |
| 597 | } else { | 597 | } else { |
| 598 | // get the interface class | 598 | // get the interface class |
| 599 | for (ClassEntry interfaceEntry : getInterfaces(obfMethodEntry.getClassName())) { | 599 | for (ClassEntry interfaceEntry : getInterfaces(obfMethodEntry.getClassName())) { |
| 600 | 600 | ||
| 601 | // is this method defined in this interface? | 601 | // is this method defined in this interface? |
| 602 | MethodEntry methodInterface = new MethodEntry( | 602 | MethodEntry methodInterface = new MethodEntry( |
| 603 | interfaceEntry, | 603 | interfaceEntry, |
| 604 | obfMethodEntry.getName(), | 604 | obfMethodEntry.getName(), |
| 605 | obfMethodEntry.getSignature() | 605 | obfMethodEntry.getSignature() |
| 606 | ); | 606 | ); |
| 607 | if (containsObfBehavior(methodInterface)) { | 607 | if (containsObfBehavior(methodInterface)) { |
| 608 | interfaceMethodEntries.add(methodInterface); | 608 | interfaceMethodEntries.add(methodInterface); |
| 609 | } | 609 | } |
| 610 | } | 610 | } |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); | 613 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 614 | if (!interfaceMethodEntries.isEmpty()) { | 614 | if (!interfaceMethodEntries.isEmpty()) { |
| 615 | for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) { | 615 | for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) { |
| 616 | MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); | 616 | MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); |
| 617 | node.load(this); | 617 | node.load(this); |
| 618 | nodes.add(node); | 618 | nodes.add(node); |
| 619 | } | 619 | } |
| 620 | } | 620 | } |
| 621 | return nodes; | 621 | return nodes; |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) { | 624 | public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) { |
| 625 | Set<MethodEntry> methodEntries = Sets.newHashSet(); | 625 | Set<MethodEntry> methodEntries = Sets.newHashSet(); |
| 626 | getRelatedMethodImplementations(methodEntries, getMethodInheritance(new Translator(), obfMethodEntry)); | 626 | getRelatedMethodImplementations(methodEntries, getMethodInheritance(new Translator(), obfMethodEntry)); |
| 627 | return methodEntries; | 627 | return methodEntries; |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) { | 630 | private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) { |
| 631 | MethodEntry methodEntry = node.getMethodEntry(); | 631 | MethodEntry methodEntry = node.getMethodEntry(); |
| 632 | 632 | ||
| 633 | if (containsObfBehavior(methodEntry)) { | 633 | if (containsObfBehavior(methodEntry)) { |
| 634 | // collect the entry | 634 | // collect the entry |
| 635 | methodEntries.add(methodEntry); | 635 | methodEntries.add(methodEntry); |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | // look at bridged methods! | 638 | // look at bridged methods! |
| 639 | MethodEntry bridgedEntry = getBridgedMethod(methodEntry); | 639 | MethodEntry bridgedEntry = getBridgedMethod(methodEntry); |
| 640 | while (bridgedEntry != null) { | 640 | while (bridgedEntry != null) { |
| 641 | methodEntries.addAll(getRelatedMethodImplementations(bridgedEntry)); | 641 | methodEntries.addAll(getRelatedMethodImplementations(bridgedEntry)); |
| 642 | bridgedEntry = getBridgedMethod(bridgedEntry); | 642 | bridgedEntry = getBridgedMethod(bridgedEntry); |
| 643 | } | 643 | } |
| 644 | 644 | ||
| 645 | // look at interface methods too | 645 | // look at interface methods too |
| 646 | for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(new Translator(), methodEntry)) { | 646 | for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(new Translator(), methodEntry)) { |
| 647 | getRelatedMethodImplementations(methodEntries, implementationsNode); | 647 | getRelatedMethodImplementations(methodEntries, implementationsNode); |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | // recurse | 650 | // recurse |
| 651 | for (int i = 0; i < node.getChildCount(); i++) { | 651 | for (int i = 0; i < node.getChildCount(); i++) { |
| 652 | getRelatedMethodImplementations(methodEntries, (MethodInheritanceTreeNode) node.getChildAt(i)); | 652 | getRelatedMethodImplementations(methodEntries, (MethodInheritanceTreeNode) node.getChildAt(i)); |
| 653 | } | 653 | } |
| 654 | } | 654 | } |
| 655 | 655 | ||
| 656 | private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) { | 656 | private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) { |
| 657 | MethodEntry methodEntry = node.getMethodEntry(); | 657 | MethodEntry methodEntry = node.getMethodEntry(); |
| 658 | if (containsObfBehavior(methodEntry)) { | 658 | if (containsObfBehavior(methodEntry)) { |
| 659 | // collect the entry | 659 | // collect the entry |
| 660 | methodEntries.add(methodEntry); | 660 | methodEntries.add(methodEntry); |
| 661 | } | 661 | } |
| 662 | 662 | ||
| 663 | // look at bridged methods! | 663 | // look at bridged methods! |
| 664 | MethodEntry bridgedEntry = getBridgedMethod(methodEntry); | 664 | MethodEntry bridgedEntry = getBridgedMethod(methodEntry); |
| 665 | while (bridgedEntry != null) { | 665 | while (bridgedEntry != null) { |
| 666 | methodEntries.addAll(getRelatedMethodImplementations(bridgedEntry)); | 666 | methodEntries.addAll(getRelatedMethodImplementations(bridgedEntry)); |
| 667 | bridgedEntry = getBridgedMethod(bridgedEntry); | 667 | bridgedEntry = getBridgedMethod(bridgedEntry); |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | // recurse | 670 | // recurse |
| 671 | for (int i = 0; i < node.getChildCount(); i++) { | 671 | for (int i = 0; i < node.getChildCount(); i++) { |
| 672 | getRelatedMethodImplementations(methodEntries, (MethodImplementationsTreeNode) node.getChildAt(i)); | 672 | getRelatedMethodImplementations(methodEntries, (MethodImplementationsTreeNode) node.getChildAt(i)); |
| 673 | } | 673 | } |
| 674 | } | 674 | } |
| 675 | 675 | ||
| 676 | public Collection<EntryReference<FieldEntry, BehaviorEntry>> getFieldReferences(FieldEntry fieldEntry) { | 676 | public Collection<EntryReference<FieldEntry, BehaviorEntry>> getFieldReferences(FieldEntry fieldEntry) { |
| 677 | return this.fieldReferences.get(fieldEntry); | 677 | return this.fieldReferences.get(fieldEntry); |
| 678 | } | 678 | } |
| 679 | 679 | ||
| 680 | public Collection<FieldEntry> getReferencedFields(BehaviorEntry behaviorEntry) { | 680 | public Collection<FieldEntry> getReferencedFields(BehaviorEntry behaviorEntry) { |
| 681 | // linear search is fast enough for now | 681 | // linear search is fast enough for now |
| 682 | Set<FieldEntry> fieldEntries = Sets.newHashSet(); | 682 | Set<FieldEntry> fieldEntries = Sets.newHashSet(); |
| 683 | for (EntryReference<FieldEntry, BehaviorEntry> reference : this.fieldReferences.values()) { | 683 | for (EntryReference<FieldEntry, BehaviorEntry> reference : this.fieldReferences.values()) { |
| 684 | if (reference.context == behaviorEntry) { | 684 | if (reference.context == behaviorEntry) { |
| 685 | fieldEntries.add(reference.entry); | 685 | fieldEntries.add(reference.entry); |
| 686 | } | 686 | } |
| 687 | } | 687 | } |
| 688 | return fieldEntries; | 688 | return fieldEntries; |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | public Collection<EntryReference<BehaviorEntry, BehaviorEntry>> getBehaviorReferences(BehaviorEntry behaviorEntry) { | 691 | public Collection<EntryReference<BehaviorEntry, BehaviorEntry>> getBehaviorReferences(BehaviorEntry behaviorEntry) { |
| 692 | return this.behaviorReferences.get(behaviorEntry); | 692 | return this.behaviorReferences.get(behaviorEntry); |
| 693 | } | 693 | } |
| 694 | 694 | ||
| 695 | public Collection<BehaviorEntry> getReferencedBehaviors(BehaviorEntry behaviorEntry) { | 695 | public Collection<BehaviorEntry> getReferencedBehaviors(BehaviorEntry behaviorEntry) { |
| 696 | // linear search is fast enough for now | 696 | // linear search is fast enough for now |
| 697 | Set<BehaviorEntry> behaviorEntries = Sets.newHashSet(); | 697 | Set<BehaviorEntry> behaviorEntries = Sets.newHashSet(); |
| 698 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : this.behaviorReferences.values()) { | 698 | for (EntryReference<BehaviorEntry, BehaviorEntry> reference : this.behaviorReferences.values()) { |
| 699 | if (reference.context == behaviorEntry) { | 699 | if (reference.context == behaviorEntry) { |
| 700 | behaviorEntries.add(reference.entry); | 700 | behaviorEntries.add(reference.entry); |
| 701 | } | 701 | } |
| 702 | } | 702 | } |
| 703 | return behaviorEntries; | 703 | return behaviorEntries; |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | public Collection<ClassEntry> getInnerClasses(ClassEntry obfOuterClassEntry) { | 706 | public Collection<ClassEntry> getInnerClasses(ClassEntry obfOuterClassEntry) { |
| 707 | return this.innerClassesByOuter.get(obfOuterClassEntry); | 707 | return this.innerClassesByOuter.get(obfOuterClassEntry); |
| 708 | } | 708 | } |
| 709 | 709 | ||
| 710 | public ClassEntry getOuterClass(ClassEntry obfInnerClassEntry) { | 710 | public ClassEntry getOuterClass(ClassEntry obfInnerClassEntry) { |
| 711 | return this.outerClassesByInner.get(obfInnerClassEntry); | 711 | return this.outerClassesByInner.get(obfInnerClassEntry); |
| 712 | } | 712 | } |
| 713 | 713 | ||
| 714 | public boolean isAnonymousClass(ClassEntry obfInnerClassEntry) { | 714 | public boolean isAnonymousClass(ClassEntry obfInnerClassEntry) { |
| 715 | return this.anonymousClasses.containsKey(obfInnerClassEntry); | 715 | return this.anonymousClasses.containsKey(obfInnerClassEntry); |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | public boolean isSyntheticMethod(MethodEntry methodEntry) { | 718 | public boolean isSyntheticMethod(MethodEntry methodEntry) { |
| 719 | return this.syntheticMethods.contains(methodEntry); | 719 | return this.syntheticMethods.contains(methodEntry); |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) { | 722 | public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) { |
| 723 | return this.anonymousClasses.get(obfInnerClassName); | 723 | return this.anonymousClasses.get(obfInnerClassName); |
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | public Set<ClassEntry> getInterfaces(String className) { | 726 | public Set<ClassEntry> getInterfaces(String className) { |
| 727 | ClassEntry classEntry = new ClassEntry(className); | 727 | ClassEntry classEntry = new ClassEntry(className); |
| 728 | Set<ClassEntry> interfaces = new HashSet<>(); | 728 | Set<ClassEntry> interfaces = new HashSet<>(); |
| 729 | interfaces.addAll(this.translationIndex.getInterfaces(classEntry)); | 729 | interfaces.addAll(this.translationIndex.getInterfaces(classEntry)); |
| 730 | for (ClassEntry ancestor : this.translationIndex.getAncestry(classEntry)) { | 730 | for (ClassEntry ancestor : this.translationIndex.getAncestry(classEntry)) { |
| 731 | interfaces.addAll(this.translationIndex.getInterfaces(ancestor)); | 731 | interfaces.addAll(this.translationIndex.getInterfaces(ancestor)); |
| 732 | } | 732 | } |
| 733 | return interfaces; | 733 | return interfaces; |
| 734 | } | 734 | } |
| 735 | 735 | ||
| 736 | public Set<String> getImplementingClasses(String targetInterfaceName) { | 736 | public Set<String> getImplementingClasses(String targetInterfaceName) { |
| 737 | 737 | ||
| 738 | // linear search is fast enough for now | 738 | // linear search is fast enough for now |
| 739 | Set<String> classNames = Sets.newHashSet(); | 739 | Set<String> classNames = Sets.newHashSet(); |
| 740 | for (Map.Entry<ClassEntry, ClassEntry> entry : this.translationIndex.getClassInterfaces()) { | 740 | for (Map.Entry<ClassEntry, ClassEntry> entry : this.translationIndex.getClassInterfaces()) { |
| 741 | ClassEntry classEntry = entry.getKey(); | 741 | ClassEntry classEntry = entry.getKey(); |
| 742 | ClassEntry interfaceEntry = entry.getValue(); | 742 | ClassEntry interfaceEntry = entry.getValue(); |
| 743 | if (interfaceEntry.getName().equals(targetInterfaceName)) { | 743 | if (interfaceEntry.getName().equals(targetInterfaceName)) { |
| 744 | String className = classEntry.getClassName(); | 744 | String className = classEntry.getClassName(); |
| 745 | classNames.add(className); | 745 | classNames.add(className); |
| 746 | if (isInterface(className)) { | 746 | if (isInterface(className)) { |
| 747 | classNames.addAll(getImplementingClasses(className)); | 747 | classNames.addAll(getImplementingClasses(className)); |
| 748 | } | 748 | } |
| 749 | 749 | ||
| 750 | this.translationIndex.getSubclassNamesRecursively(classNames, classEntry); | 750 | this.translationIndex.getSubclassNamesRecursively(classNames, classEntry); |
| 751 | } | 751 | } |
| 752 | } | 752 | } |
| 753 | return classNames; | 753 | return classNames; |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | public boolean isInterface(String className) { | 756 | public boolean isInterface(String className) { |
| 757 | return this.translationIndex.isInterface(new ClassEntry(className)); | 757 | return this.translationIndex.isInterface(new ClassEntry(className)); |
| 758 | } | 758 | } |
| 759 | 759 | ||
| 760 | public boolean containsObfClass(ClassEntry obfClassEntry) { | 760 | public boolean containsObfClass(ClassEntry obfClassEntry) { |
| 761 | return this.obfClassEntries.contains(obfClassEntry); | 761 | return this.obfClassEntries.contains(obfClassEntry); |
| 762 | } | 762 | } |
| 763 | 763 | ||
| 764 | public boolean containsObfField(FieldEntry obfFieldEntry) { | 764 | public boolean containsObfField(FieldEntry obfFieldEntry) { |
| 765 | return this.access.containsKey(obfFieldEntry); | 765 | return this.access.containsKey(obfFieldEntry); |
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) { | 768 | public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) { |
| 769 | return this.access.containsKey(obfBehaviorEntry); | 769 | return this.access.containsKey(obfBehaviorEntry); |
| 770 | } | 770 | } |
| 771 | 771 | ||
| 772 | public boolean containsEntryWithSameName(Entry entry) | 772 | public boolean containsEntryWithSameName(Entry entry) { |
| 773 | { | 773 | for (Entry target : this.access.keySet()) |
| 774 | for (Entry target : this.access.keySet()) | 774 | if (target.getName().equals(entry.getName()) && entry.getClass().isInstance(target.getClass())) |
| 775 | if (target.getName().equals(entry.getName()) && entry.getClass().isInstance(target.getClass())) | 775 | return true; |
| 776 | return true; | 776 | return false; |
| 777 | return false; | 777 | } |
| 778 | } | 778 | |
| 779 | 779 | public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { | |
| 780 | public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { | 780 | // check the behavior |
| 781 | // check the behavior | 781 | if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { |
| 782 | if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { | 782 | return false; |
| 783 | return false; | 783 | } |
| 784 | } | 784 | |
| 785 | 785 | // check the argument | |
| 786 | // check the argument | 786 | return obfArgumentEntry.getIndex() < obfArgumentEntry.getBehaviorEntry().getSignature().getArgumentTypes().size(); |
| 787 | return obfArgumentEntry.getIndex() < obfArgumentEntry.getBehaviorEntry().getSignature().getArgumentTypes().size(); | 787 | |
| 788 | 788 | } | |
| 789 | } | 789 | |
| 790 | 790 | public boolean containsObfEntry(Entry obfEntry) { | |
| 791 | public boolean containsObfEntry(Entry obfEntry) { | 791 | if (obfEntry instanceof ClassEntry) { |
| 792 | if (obfEntry instanceof ClassEntry) { | 792 | return containsObfClass((ClassEntry) obfEntry); |
| 793 | return containsObfClass((ClassEntry) obfEntry); | 793 | } else if (obfEntry instanceof FieldEntry) { |
| 794 | } else if (obfEntry instanceof FieldEntry) { | 794 | return containsObfField((FieldEntry) obfEntry); |
| 795 | return containsObfField((FieldEntry) obfEntry); | 795 | } else if (obfEntry instanceof BehaviorEntry) { |
| 796 | } else if (obfEntry instanceof BehaviorEntry) { | 796 | return containsObfBehavior((BehaviorEntry) obfEntry); |
| 797 | return containsObfBehavior((BehaviorEntry) obfEntry); | 797 | } else if (obfEntry instanceof ArgumentEntry) { |
| 798 | } else if (obfEntry instanceof ArgumentEntry) { | 798 | return containsObfArgument((ArgumentEntry) obfEntry); |
| 799 | return containsObfArgument((ArgumentEntry) obfEntry); | 799 | } else if (obfEntry instanceof LocalVariableEntry) { |
| 800 | } else if (obfEntry instanceof LocalVariableEntry) { | 800 | // TODO: Implement it |
| 801 | // TODO: Implement it | 801 | return false; |
| 802 | return false; | 802 | } else { |
| 803 | } else { | 803 | throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); |
| 804 | throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); | 804 | } |
| 805 | } | 805 | } |
| 806 | } | 806 | |
| 807 | 807 | public MethodEntry getBridgedMethod(MethodEntry bridgeMethodEntry) { | |
| 808 | public MethodEntry getBridgedMethod(MethodEntry bridgeMethodEntry) { | 808 | return this.bridgedMethods.get(bridgeMethodEntry); |
| 809 | return this.bridgedMethods.get(bridgeMethodEntry); | 809 | } |
| 810 | } | 810 | |
| 811 | 811 | public List<ClassEntry> getObfClassChain(ClassEntry obfClassEntry) { | |
| 812 | public List<ClassEntry> getObfClassChain(ClassEntry obfClassEntry) { | 812 | |
| 813 | 813 | // build class chain in inner-to-outer order | |
| 814 | // build class chain in inner-to-outer order | 814 | List<ClassEntry> obfClassChain = Lists.newArrayList(obfClassEntry); |
| 815 | List<ClassEntry> obfClassChain = Lists.newArrayList(obfClassEntry); | 815 | ClassEntry checkClassEntry = obfClassEntry; |
| 816 | ClassEntry checkClassEntry = obfClassEntry; | 816 | while (true) { |
| 817 | while (true) { | 817 | ClassEntry obfOuterClassEntry = getOuterClass(checkClassEntry); |
| 818 | ClassEntry obfOuterClassEntry = getOuterClass(checkClassEntry); | 818 | if (obfOuterClassEntry != null) { |
| 819 | if (obfOuterClassEntry != null) { | 819 | obfClassChain.add(obfOuterClassEntry); |
| 820 | obfClassChain.add(obfOuterClassEntry); | 820 | checkClassEntry = obfOuterClassEntry; |
| 821 | checkClassEntry = obfOuterClassEntry; | 821 | } else { |
| 822 | } else { | 822 | break; |
| 823 | break; | 823 | } |
| 824 | } | 824 | } |
| 825 | } | 825 | |
| 826 | 826 | // switch to outer-to-inner order | |
| 827 | // switch to outer-to-inner order | 827 | Collections.reverse(obfClassChain); |
| 828 | Collections.reverse(obfClassChain); | 828 | |
| 829 | 829 | return obfClassChain; | |
| 830 | return obfClassChain; | 830 | } |
| 831 | } | ||
| 832 | } | 831 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 9bd6219..bacb1aa 100644 --- a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | |||
| @@ -8,87 +8,86 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | |||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.ClassEntry; | 15 | import cuchaz.enigma.mapping.ClassEntry; |
| 20 | import cuchaz.enigma.mapping.MethodEntry; | 16 | import cuchaz.enigma.mapping.MethodEntry; |
| 21 | import cuchaz.enigma.mapping.Translator; | 17 | import cuchaz.enigma.mapping.Translator; |
| 22 | 18 | ||
| 19 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 20 | import java.util.List; | ||
| 21 | |||
| 23 | public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { | 22 | public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { |
| 24 | 23 | ||
| 25 | private Translator deobfuscatingTranslator; | 24 | private Translator deobfuscatingTranslator; |
| 26 | private MethodEntry entry; | 25 | private MethodEntry entry; |
| 27 | 26 | ||
| 28 | public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) { | 27 | public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) { |
| 29 | if (entry == null) { | 28 | if (entry == null) { |
| 30 | throw new IllegalArgumentException("Entry cannot be null!"); | 29 | throw new IllegalArgumentException("Entry cannot be null!"); |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 32 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 34 | this.entry = entry; | 33 | this.entry = entry; |
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | public MethodEntry getMethodEntry() { | 36 | public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) { |
| 38 | return this.entry; | 37 | // is this the node? |
| 39 | } | 38 | if (node.getMethodEntry().equals(entry)) { |
| 40 | 39 | return node; | |
| 41 | public String getDeobfClassName() { | 40 | } |
| 42 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); | 41 | |
| 43 | } | 42 | // recurse |
| 44 | 43 | for (int i = 0; i < node.getChildCount(); i++) { | |
| 45 | public String getDeobfMethodName() { | 44 | MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); |
| 46 | return this.deobfuscatingTranslator.translate(this.entry); | 45 | if (foundNode != null) { |
| 47 | } | 46 | return foundNode; |
| 48 | 47 | } | |
| 49 | @Override | 48 | } |
| 50 | public String toString() { | 49 | return null; |
| 51 | String className = getDeobfClassName(); | 50 | } |
| 52 | if (className == null) { | 51 | |
| 53 | className = this.entry.getClassName(); | 52 | public MethodEntry getMethodEntry() { |
| 54 | } | 53 | return this.entry; |
| 55 | 54 | } | |
| 56 | String methodName = getDeobfMethodName(); | 55 | |
| 57 | if (methodName == null) { | 56 | public String getDeobfClassName() { |
| 58 | methodName = this.entry.getName(); | 57 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); |
| 59 | } | 58 | } |
| 60 | return className + "." + methodName + "()"; | 59 | |
| 61 | } | 60 | public String getDeobfMethodName() { |
| 62 | 61 | return this.deobfuscatingTranslator.translate(this.entry); | |
| 63 | public void load(JarIndex index) { | 62 | } |
| 64 | 63 | ||
| 65 | // get all method implementations | 64 | @Override |
| 66 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); | 65 | public String toString() { |
| 67 | for (String implementingClassName : index.getImplementingClasses(this.entry.getClassName())) { | 66 | String className = getDeobfClassName(); |
| 68 | MethodEntry methodEntry = new MethodEntry(new ClassEntry(implementingClassName), this.entry.getName(), this.entry.getSignature() | 67 | if (className == null) { |
| 69 | ); | 68 | className = this.entry.getClassName(); |
| 70 | if (index.containsObfBehavior(methodEntry)) { | 69 | } |
| 71 | nodes.add(new MethodImplementationsTreeNode(this.deobfuscatingTranslator, methodEntry)); | 70 | |
| 72 | } | 71 | String methodName = getDeobfMethodName(); |
| 73 | } | 72 | if (methodName == null) { |
| 74 | 73 | methodName = this.entry.getName(); | |
| 75 | // add them to this node | 74 | } |
| 76 | nodes.forEach(this::add); | 75 | return className + "." + methodName + "()"; |
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) { | 78 | public void load(JarIndex index) { |
| 80 | // is this the node? | 79 | |
| 81 | if (node.getMethodEntry().equals(entry)) { | 80 | // get all method implementations |
| 82 | return node; | 81 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 83 | } | 82 | for (String implementingClassName : index.getImplementingClasses(this.entry.getClassName())) { |
| 84 | 83 | MethodEntry methodEntry = new MethodEntry(new ClassEntry(implementingClassName), this.entry.getName(), this.entry.getSignature() | |
| 85 | // recurse | 84 | ); |
| 86 | for (int i = 0; i < node.getChildCount(); i++) { | 85 | if (index.containsObfBehavior(methodEntry)) { |
| 87 | MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); | 86 | nodes.add(new MethodImplementationsTreeNode(this.deobfuscatingTranslator, methodEntry)); |
| 88 | if (foundNode != null) { | 87 | } |
| 89 | return foundNode; | 88 | } |
| 90 | } | 89 | |
| 91 | } | 90 | // add them to this node |
| 92 | return null; | 91 | nodes.forEach(this::add); |
| 93 | } | 92 | } |
| 94 | } | 93 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index b65b8c1..4f84dd0 100644 --- a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | |||
| @@ -8,97 +8,96 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | |||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 19 | import cuchaz.enigma.mapping.ClassEntry; | 15 | import cuchaz.enigma.mapping.ClassEntry; |
| 20 | import cuchaz.enigma.mapping.MethodEntry; | 16 | import cuchaz.enigma.mapping.MethodEntry; |
| 21 | import cuchaz.enigma.mapping.Translator; | 17 | import cuchaz.enigma.mapping.Translator; |
| 22 | 18 | ||
| 19 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 20 | import java.util.List; | ||
| 21 | |||
| 23 | public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { | 22 | public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { |
| 24 | 23 | ||
| 25 | private Translator deobfuscatingTranslator; | 24 | private Translator deobfuscatingTranslator; |
| 26 | private MethodEntry entry; | 25 | private MethodEntry entry; |
| 27 | private boolean isImplemented; | 26 | private boolean isImplemented; |
| 28 | 27 | ||
| 29 | public MethodInheritanceTreeNode(Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented) { | 28 | public MethodInheritanceTreeNode(Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented) { |
| 30 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 29 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 31 | this.entry = entry; | 30 | this.entry = entry; |
| 32 | this.isImplemented = isImplemented; | 31 | this.isImplemented = isImplemented; |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | public MethodEntry getMethodEntry() { | 34 | public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) { |
| 36 | return this.entry; | 35 | // is this the node? |
| 37 | } | 36 | if (node.getMethodEntry().equals(entry)) { |
| 38 | 37 | return node; | |
| 39 | public String getDeobfClassName() { | 38 | } |
| 40 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); | 39 | |
| 41 | } | 40 | // recurse |
| 42 | 41 | for (int i = 0; i < node.getChildCount(); i++) { | |
| 43 | public String getDeobfMethodName() { | 42 | MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); |
| 44 | return this.deobfuscatingTranslator.translate(this.entry); | 43 | if (foundNode != null) { |
| 45 | } | 44 | return foundNode; |
| 46 | 45 | } | |
| 47 | public boolean isImplemented() { | 46 | } |
| 48 | return this.isImplemented; | 47 | return null; |
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | @Override | 50 | public MethodEntry getMethodEntry() { |
| 52 | public String toString() { | 51 | return this.entry; |
| 53 | String className = getDeobfClassName(); | 52 | } |
| 54 | if (className == null) { | 53 | |
| 55 | className = this.entry.getClassName(); | 54 | public String getDeobfClassName() { |
| 56 | } | 55 | return this.deobfuscatingTranslator.translateClass(this.entry.getClassName()); |
| 57 | 56 | } | |
| 58 | if (!this.isImplemented) { | 57 | |
| 59 | return className; | 58 | public String getDeobfMethodName() { |
| 60 | } else { | 59 | return this.deobfuscatingTranslator.translate(this.entry); |
| 61 | String methodName = getDeobfMethodName(); | 60 | } |
| 62 | if (methodName == null) { | 61 | |
| 63 | methodName = this.entry.getName(); | 62 | public boolean isImplemented() { |
| 64 | } | 63 | return this.isImplemented; |
| 65 | return className + "." + methodName + "()"; | 64 | } |
| 66 | } | 65 | |
| 67 | } | 66 | @Override |
| 68 | 67 | public String toString() { | |
| 69 | public void load(JarIndex index, boolean recurse) { | 68 | String className = getDeobfClassName(); |
| 70 | // get all the child nodes | 69 | if (className == null) { |
| 71 | List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); | 70 | className = this.entry.getClassName(); |
| 72 | for (ClassEntry subclassEntry : index.getTranslationIndex().getSubclass(this.entry.getClassEntry())) { | 71 | } |
| 73 | MethodEntry methodEntry = new MethodEntry(subclassEntry, this.entry.getName(), this.entry.getSignature() | 72 | |
| 74 | ); | 73 | if (!this.isImplemented) { |
| 75 | nodes.add(new MethodInheritanceTreeNode(this.deobfuscatingTranslator, methodEntry, index.containsObfBehavior(methodEntry) | 74 | return className; |
| 76 | )); | 75 | } else { |
| 77 | } | 76 | String methodName = getDeobfMethodName(); |
| 78 | 77 | if (methodName == null) { | |
| 79 | // add them to this node | 78 | methodName = this.entry.getName(); |
| 80 | nodes.forEach(this::add); | 79 | } |
| 81 | 80 | return className + "." + methodName + "()"; | |
| 82 | if (recurse) { | 81 | } |
| 83 | for (MethodInheritanceTreeNode node : nodes) { | 82 | } |
| 84 | node.load(index, true); | 83 | |
| 85 | } | 84 | public void load(JarIndex index, boolean recurse) { |
| 86 | } | 85 | // get all the child nodes |
| 87 | } | 86 | List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); |
| 88 | 87 | for (ClassEntry subclassEntry : index.getTranslationIndex().getSubclass(this.entry.getClassEntry())) { | |
| 89 | public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) { | 88 | MethodEntry methodEntry = new MethodEntry(subclassEntry, this.entry.getName(), this.entry.getSignature() |
| 90 | // is this the node? | 89 | ); |
| 91 | if (node.getMethodEntry().equals(entry)) { | 90 | nodes.add(new MethodInheritanceTreeNode(this.deobfuscatingTranslator, methodEntry, index.containsObfBehavior(methodEntry) |
| 92 | return node; | 91 | )); |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | // recurse | 94 | // add them to this node |
| 96 | for (int i = 0; i < node.getChildCount(); i++) { | 95 | nodes.forEach(this::add); |
| 97 | MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); | 96 | |
| 98 | if (foundNode != null) { | 97 | if (recurse) { |
| 99 | return foundNode; | 98 | for (MethodInheritanceTreeNode node : nodes) { |
| 100 | } | 99 | node.load(index, true); |
| 101 | } | 100 | } |
| 102 | return null; | 101 | } |
| 103 | } | 102 | } |
| 104 | } | 103 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java index 9392346..0469363 100644 --- a/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java | |||
| @@ -8,12 +8,13 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import cuchaz.enigma.mapping.Entry; | 14 | import cuchaz.enigma.mapping.Entry; |
| 14 | 15 | ||
| 15 | public interface ReferenceTreeNode<E extends Entry, C extends Entry> { | 16 | public interface ReferenceTreeNode<E extends Entry, C extends Entry> { |
| 16 | E getEntry(); | 17 | E getEntry(); |
| 17 | 18 | ||
| 18 | EntryReference<E, C> getReference(); | 19 | EntryReference<E, C> getReference(); |
| 19 | } | 20 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java index 719930e..19250c8 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java | |||
| @@ -8,174 +8,173 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.HashMultimap; | 14 | import com.google.common.collect.HashMultimap; |
| 14 | import com.google.common.collect.Lists; | 15 | import com.google.common.collect.Lists; |
| 15 | import com.google.common.collect.Maps; | 16 | import com.google.common.collect.Maps; |
| 16 | import com.google.common.collect.Multimap; | 17 | import com.google.common.collect.Multimap; |
| 17 | |||
| 18 | import com.strobel.decompiler.languages.Region; | 18 | import com.strobel.decompiler.languages.Region; |
| 19 | import com.strobel.decompiler.languages.java.ast.AstNode; | 19 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 20 | import com.strobel.decompiler.languages.java.ast.Identifier; | 20 | import com.strobel.decompiler.languages.java.ast.Identifier; |
| 21 | import cuchaz.enigma.mapping.Entry; | ||
| 21 | 22 | ||
| 22 | import java.util.Collection; | 23 | import java.util.Collection; |
| 23 | import java.util.List; | 24 | import java.util.List; |
| 24 | import java.util.Map; | 25 | import java.util.Map; |
| 25 | import java.util.TreeMap; | 26 | import java.util.TreeMap; |
| 26 | 27 | ||
| 27 | import cuchaz.enigma.mapping.Entry; | ||
| 28 | |||
| 29 | public class SourceIndex { | 28 | public class SourceIndex { |
| 30 | 29 | ||
| 31 | private String source; | 30 | private String source; |
| 32 | private TreeMap<Token, EntryReference<Entry, Entry>> tokenToReference; | 31 | private TreeMap<Token, EntryReference<Entry, Entry>> tokenToReference; |
| 33 | private Multimap<EntryReference<Entry, Entry>, Token> referenceToTokens; | 32 | private Multimap<EntryReference<Entry, Entry>, Token> referenceToTokens; |
| 34 | private Map<Entry, Token> declarationToToken; | 33 | private Map<Entry, Token> declarationToToken; |
| 35 | private List<Integer> lineOffsets; | 34 | private List<Integer> lineOffsets; |
| 36 | private boolean ignoreBadTokens; | 35 | private boolean ignoreBadTokens; |
| 37 | 36 | ||
| 38 | public SourceIndex(String source) { | 37 | public SourceIndex(String source) { |
| 39 | this(source, true); | 38 | this(source, true); |
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | public SourceIndex(String source, boolean ignoreBadTokens) { | 41 | public SourceIndex(String source, boolean ignoreBadTokens) { |
| 43 | this.source = source; | 42 | this.source = source; |
| 44 | this.ignoreBadTokens = ignoreBadTokens; | 43 | this.ignoreBadTokens = ignoreBadTokens; |
| 45 | this.tokenToReference = Maps.newTreeMap(); | 44 | this.tokenToReference = Maps.newTreeMap(); |
| 46 | this.referenceToTokens = HashMultimap.create(); | 45 | this.referenceToTokens = HashMultimap.create(); |
| 47 | this.declarationToToken = Maps.newHashMap(); | 46 | this.declarationToToken = Maps.newHashMap(); |
| 48 | this.lineOffsets = Lists.newArrayList(); | 47 | this.lineOffsets = Lists.newArrayList(); |
| 49 | 48 | ||
| 50 | // count the lines | 49 | // count the lines |
| 51 | this.lineOffsets.add(0); | 50 | this.lineOffsets.add(0); |
| 52 | for (int i = 0; i < source.length(); i++) { | 51 | for (int i = 0; i < source.length(); i++) { |
| 53 | if (source.charAt(i) == '\n') { | 52 | if (source.charAt(i) == '\n') { |
| 54 | this.lineOffsets.add(i + 1); | 53 | this.lineOffsets.add(i + 1); |
| 55 | } | 54 | } |
| 56 | } | 55 | } |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | public String getSource() { | 58 | public String getSource() { |
| 60 | return this.source; | 59 | return this.source; |
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | public Token getToken(AstNode node) { | 62 | public Token getToken(AstNode node) { |
| 64 | 63 | ||
| 65 | // get the text of the node | 64 | // get the text of the node |
| 66 | String name = ""; | 65 | String name = ""; |
| 67 | if (node instanceof Identifier) { | 66 | if (node instanceof Identifier) { |
| 68 | name = ((Identifier) node).getName(); | 67 | name = ((Identifier) node).getName(); |
| 69 | } | 68 | } |
| 70 | 69 | ||
| 71 | // get a token for this node's region | 70 | // get a token for this node's region |
| 72 | Region region = node.getRegion(); | 71 | Region region = node.getRegion(); |
| 73 | if (region.getBeginLine() == 0 || region.getEndLine() == 0) { | 72 | if (region.getBeginLine() == 0 || region.getEndLine() == 0) { |
| 74 | // DEBUG | 73 | // DEBUG |
| 75 | System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); | 74 | System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); |
| 76 | return null; | 75 | return null; |
| 77 | } | 76 | } |
| 78 | Token token = new Token(toPos(region.getBeginLine(), region.getBeginColumn()), toPos(region.getEndLine(), region.getEndColumn()), this.source); | 77 | Token token = new Token(toPos(region.getBeginLine(), region.getBeginColumn()), toPos(region.getEndLine(), region.getEndColumn()), this.source); |
| 79 | if (token.start == 0) { | 78 | if (token.start == 0) { |
| 80 | // DEBUG | 79 | // DEBUG |
| 81 | System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); | 80 | System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); |
| 82 | return null; | 81 | return null; |
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | // DEBUG | 84 | // DEBUG |
| 86 | // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); | 85 | // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); |
| 87 | 86 | ||
| 88 | // if the token has a $ in it, something's wrong. Ignore this token | 87 | // if the token has a $ in it, something's wrong. Ignore this token |
| 89 | if (name.lastIndexOf('$') >= 0 && this.ignoreBadTokens) { | 88 | if (name.lastIndexOf('$') >= 0 && this.ignoreBadTokens) { |
| 90 | // DEBUG | 89 | // DEBUG |
| 91 | System.err.println(String.format("WARNING: %s \"%s\" is probably a bad token. It was ignored", node.getNodeType(), name)); | 90 | System.err.println(String.format("WARNING: %s \"%s\" is probably a bad token. It was ignored", node.getNodeType(), name)); |
| 92 | return null; | 91 | return null; |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | return token; | 94 | return token; |
| 96 | } | 95 | } |
| 97 | 96 | ||
| 98 | public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) { | 97 | public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) { |
| 99 | Token token = getToken(node); | 98 | Token token = getToken(node); |
| 100 | if (token != null) { | 99 | if (token != null) { |
| 101 | EntryReference<Entry, Entry> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); | 100 | EntryReference<Entry, Entry> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); |
| 102 | this.tokenToReference.put(token, deobfReference); | 101 | this.tokenToReference.put(token, deobfReference); |
| 103 | this.referenceToTokens.put(deobfReference, token); | 102 | this.referenceToTokens.put(deobfReference, token); |
| 104 | } | 103 | } |
| 105 | } | 104 | } |
| 106 | 105 | ||
| 107 | public void addDeclaration(AstNode node, Entry deobfEntry) { | 106 | public void addDeclaration(AstNode node, Entry deobfEntry) { |
| 108 | Token token = getToken(node); | 107 | Token token = getToken(node); |
| 109 | if (token != null) { | 108 | if (token != null) { |
| 110 | EntryReference<Entry, Entry> reference = new EntryReference<>(deobfEntry, token.text); | 109 | EntryReference<Entry, Entry> reference = new EntryReference<>(deobfEntry, token.text); |
| 111 | this.tokenToReference.put(token, reference); | 110 | this.tokenToReference.put(token, reference); |
| 112 | this.referenceToTokens.put(reference, token); | 111 | this.referenceToTokens.put(reference, token); |
| 113 | this.declarationToToken.put(deobfEntry, token); | 112 | this.declarationToToken.put(deobfEntry, token); |
| 114 | } | 113 | } |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | public Token getReferenceToken(int pos) { | 116 | public Token getReferenceToken(int pos) { |
| 118 | Token token = this.tokenToReference.floorKey(new Token(pos, pos, null)); | 117 | Token token = this.tokenToReference.floorKey(new Token(pos, pos, null)); |
| 119 | if (token != null && token.contains(pos)) { | 118 | if (token != null && token.contains(pos)) { |
| 120 | return token; | 119 | return token; |
| 121 | } | 120 | } |
| 122 | return null; | 121 | return null; |
| 123 | } | 122 | } |
| 124 | 123 | ||
| 125 | public Collection<Token> getReferenceTokens(EntryReference<Entry, Entry> deobfReference) { | 124 | public Collection<Token> getReferenceTokens(EntryReference<Entry, Entry> deobfReference) { |
| 126 | return this.referenceToTokens.get(deobfReference); | 125 | return this.referenceToTokens.get(deobfReference); |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | public EntryReference<Entry, Entry> getDeobfReference(Token token) { | 128 | public EntryReference<Entry, Entry> getDeobfReference(Token token) { |
| 130 | if (token == null) { | 129 | if (token == null) { |
| 131 | return null; | 130 | return null; |
| 132 | } | 131 | } |
| 133 | return this.tokenToReference.get(token); | 132 | return this.tokenToReference.get(token); |
| 134 | } | 133 | } |
| 135 | 134 | ||
| 136 | public void replaceDeobfReference(Token token, EntryReference<Entry, Entry> newDeobfReference) { | 135 | public void replaceDeobfReference(Token token, EntryReference<Entry, Entry> newDeobfReference) { |
| 137 | EntryReference<Entry, Entry> oldDeobfReference = this.tokenToReference.get(token); | 136 | EntryReference<Entry, Entry> oldDeobfReference = this.tokenToReference.get(token); |
| 138 | this.tokenToReference.put(token, newDeobfReference); | 137 | this.tokenToReference.put(token, newDeobfReference); |
| 139 | Collection<Token> tokens = this.referenceToTokens.get(oldDeobfReference); | 138 | Collection<Token> tokens = this.referenceToTokens.get(oldDeobfReference); |
| 140 | this.referenceToTokens.removeAll(oldDeobfReference); | 139 | this.referenceToTokens.removeAll(oldDeobfReference); |
| 141 | this.referenceToTokens.putAll(newDeobfReference, tokens); | 140 | this.referenceToTokens.putAll(newDeobfReference, tokens); |
| 142 | } | 141 | } |
| 143 | 142 | ||
| 144 | public Iterable<Token> referenceTokens() { | 143 | public Iterable<Token> referenceTokens() { |
| 145 | return this.tokenToReference.keySet(); | 144 | return this.tokenToReference.keySet(); |
| 146 | } | 145 | } |
| 147 | 146 | ||
| 148 | public Iterable<Token> declarationTokens() { | 147 | public Iterable<Token> declarationTokens() { |
| 149 | return this.declarationToToken.values(); | 148 | return this.declarationToToken.values(); |
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | public Iterable<Entry> declarations() { | 151 | public Iterable<Entry> declarations() { |
| 153 | return this.declarationToToken.keySet(); | 152 | return this.declarationToToken.keySet(); |
| 154 | } | 153 | } |
| 155 | 154 | ||
| 156 | public Token getDeclarationToken(Entry deobfEntry) { | 155 | public Token getDeclarationToken(Entry deobfEntry) { |
| 157 | return this.declarationToToken.get(deobfEntry); | 156 | return this.declarationToToken.get(deobfEntry); |
| 158 | } | 157 | } |
| 159 | 158 | ||
| 160 | public int getLineNumber(int pos) { | 159 | public int getLineNumber(int pos) { |
| 161 | // line number is 1-based | 160 | // line number is 1-based |
| 162 | int line = 0; | 161 | int line = 0; |
| 163 | for (Integer offset : this.lineOffsets) { | 162 | for (Integer offset : this.lineOffsets) { |
| 164 | if (offset > pos) { | 163 | if (offset > pos) { |
| 165 | break; | 164 | break; |
| 166 | } | 165 | } |
| 167 | line++; | 166 | line++; |
| 168 | } | 167 | } |
| 169 | return line; | 168 | return line; |
| 170 | } | 169 | } |
| 171 | 170 | ||
| 172 | public int getColumnNumber(int pos) { | 171 | public int getColumnNumber(int pos) { |
| 173 | // column number is 1-based | 172 | // column number is 1-based |
| 174 | return pos - this.lineOffsets.get(getLineNumber(pos) - 1) + 1; | 173 | return pos - this.lineOffsets.get(getLineNumber(pos) - 1) + 1; |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | private int toPos(int line, int col) { | 176 | private int toPos(int line, int col) { |
| 178 | // line and col are 1-based | 177 | // line and col are 1-based |
| 179 | return this.lineOffsets.get(line - 1) + col - 1; | 178 | return this.lineOffsets.get(line - 1) + col - 1; |
| 180 | } | 179 | } |
| 181 | } | 180 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index bfd5a56..4febf25 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.HashMultimap; | 14 | import com.google.common.collect.HashMultimap; |
| @@ -26,186 +27,179 @@ import java.util.Map; | |||
| 26 | 27 | ||
| 27 | public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | 28 | public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { |
| 28 | 29 | ||
| 29 | private BehaviorEntry behaviorEntry; | 30 | private BehaviorEntry behaviorEntry; |
| 30 | 31 | ||
| 31 | // TODO: Really fix Procyon index problem with inner classes | 32 | // TODO: Really fix Procyon index problem with inner classes |
| 32 | private int argumentPosition; | 33 | private int argumentPosition; |
| 33 | private int localsPosition; | 34 | private int localsPosition; |
| 34 | private Multimap<String, Identifier> unmatchedIdentifier = HashMultimap.create(); | 35 | private Multimap<String, Identifier> unmatchedIdentifier = HashMultimap.create(); |
| 35 | private Map<String, Entry> identifierEntryCache = new HashMap<>(); | 36 | private Map<String, Entry> identifierEntryCache = new HashMap<>(); |
| 36 | 37 | ||
| 37 | public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { | 38 | public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { |
| 38 | this.behaviorEntry = behaviorEntry; | 39 | this.behaviorEntry = behaviorEntry; |
| 39 | this.argumentPosition = 0; | 40 | this.argumentPosition = 0; |
| 40 | this.localsPosition = 0; | 41 | this.localsPosition = 0; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | @Override | 44 | @Override |
| 44 | public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { | 45 | public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { |
| 45 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 46 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 46 | 47 | ||
| 47 | // get the behavior entry | 48 | // get the behavior entry |
| 48 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 49 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 49 | BehaviorEntry behaviorEntry = null; | 50 | BehaviorEntry behaviorEntry = null; |
| 50 | if (ref instanceof MethodReference) { | 51 | if (ref instanceof MethodReference) { |
| 51 | MethodReference methodRef = (MethodReference) ref; | 52 | MethodReference methodRef = (MethodReference) ref; |
| 52 | if (methodRef.isConstructor()) { | 53 | if (methodRef.isConstructor()) { |
| 53 | behaviorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); | 54 | behaviorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); |
| 54 | } else if (methodRef.isTypeInitializer()) { | 55 | } else if (methodRef.isTypeInitializer()) { |
| 55 | behaviorEntry = new ConstructorEntry(classEntry); | 56 | behaviorEntry = new ConstructorEntry(classEntry); |
| 56 | } else { | 57 | } else { |
| 57 | behaviorEntry = new MethodEntry(classEntry, ref.getName(), new Signature(ref.getErasedSignature())); | 58 | behaviorEntry = new MethodEntry(classEntry, ref.getName(), new Signature(ref.getErasedSignature())); |
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| 60 | if (behaviorEntry != null) { | 61 | if (behaviorEntry != null) { |
| 61 | // get the node for the token | 62 | // get the node for the token |
| 62 | AstNode tokenNode = null; | 63 | AstNode tokenNode = null; |
| 63 | if (node.getTarget() instanceof MemberReferenceExpression) { | 64 | if (node.getTarget() instanceof MemberReferenceExpression) { |
| 64 | tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); | 65 | tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); |
| 65 | } else if (node.getTarget() instanceof SuperReferenceExpression) { | 66 | } else if (node.getTarget() instanceof SuperReferenceExpression) { |
| 66 | tokenNode = node.getTarget(); | 67 | tokenNode = node.getTarget(); |
| 67 | } else if (node.getTarget() instanceof ThisReferenceExpression) { | 68 | } else if (node.getTarget() instanceof ThisReferenceExpression) { |
| 68 | tokenNode = node.getTarget(); | 69 | tokenNode = node.getTarget(); |
| 69 | } | 70 | } |
| 70 | if (tokenNode != null) { | 71 | if (tokenNode != null) { |
| 71 | index.addReference(tokenNode, behaviorEntry, this.behaviorEntry); | 72 | index.addReference(tokenNode, behaviorEntry, this.behaviorEntry); |
| 72 | } | 73 | } |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | // Check for identifier | 76 | // Check for identifier |
| 76 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) | 77 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) |
| 77 | .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); | 78 | .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); |
| 78 | return recurse(node, index); | 79 | return recurse(node, index); |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | @Override | 82 | @Override |
| 82 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { | 83 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { |
| 83 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 84 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 84 | if (ref != null) { | 85 | if (ref != null) { |
| 85 | // make sure this is actually a field | 86 | // make sure this is actually a field |
| 86 | if (ref.getErasedSignature().indexOf('(') >= 0) { | 87 | if (ref.getErasedSignature().indexOf('(') >= 0) { |
| 87 | throw new Error("Expected a field here! got " + ref); | 88 | throw new Error("Expected a field here! got " + ref); |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 91 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 91 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); | 92 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); |
| 92 | index.addReference(node.getMemberNameToken(), fieldEntry, this.behaviorEntry); | 93 | index.addReference(node.getMemberNameToken(), fieldEntry, this.behaviorEntry); |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | return recurse(node, index); | 96 | return recurse(node, index); |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | @Override | 99 | @Override |
| 99 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | 100 | public Void visitSimpleType(SimpleType node, SourceIndex index) { |
| 100 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | 101 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); |
| 101 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | 102 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { |
| 102 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | 103 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); |
| 103 | index.addReference(node.getIdentifierToken(), classEntry, this.behaviorEntry); | 104 | index.addReference(node.getIdentifierToken(), classEntry, this.behaviorEntry); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | return recurse(node, index); | 107 | return recurse(node, index); |
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | @Override | 110 | @Override |
| 110 | public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { | 111 | public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { |
| 111 | ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); | 112 | ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); |
| 112 | if (def.getMethod() instanceof MemberReference && def.getMethod() instanceof MethodReference) | 113 | if (def.getMethod() instanceof MemberReference && def.getMethod() instanceof MethodReference) { |
| 113 | { | 114 | ArgumentEntry argumentEntry = new ArgumentEntry(ProcyonEntryFactory.getBehaviorEntry((MethodReference) def.getMethod()), |
| 114 | ArgumentEntry argumentEntry = new ArgumentEntry(ProcyonEntryFactory.getBehaviorEntry((MethodReference) def.getMethod()), | 115 | argumentPosition++, node.getName()); |
| 115 | argumentPosition++, node.getName()); | 116 | Identifier identifier = node.getNameToken(); |
| 116 | Identifier identifier = node.getNameToken(); | 117 | // cache the argument entry and the identifier |
| 117 | // cache the argument entry and the identifier | 118 | identifierEntryCache.put(identifier.getName(), argumentEntry); |
| 118 | identifierEntryCache.put(identifier.getName(), argumentEntry); | 119 | index.addDeclaration(identifier, argumentEntry); |
| 119 | index.addDeclaration(identifier, argumentEntry); | 120 | } |
| 120 | } | 121 | |
| 121 | 122 | return recurse(node, index); | |
| 122 | return recurse(node, index); | 123 | } |
| 123 | } | 124 | |
| 124 | 125 | @Override | |
| 125 | @Override | 126 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { |
| 126 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { | 127 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 127 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 128 | if (ref != null) { |
| 128 | if (ref != null) { | 129 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 129 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 130 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); |
| 130 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); | 131 | index.addReference(node.getIdentifierToken(), fieldEntry, this.behaviorEntry); |
| 131 | index.addReference(node.getIdentifierToken(), fieldEntry, this.behaviorEntry); | 132 | } else |
| 132 | } | 133 | this.checkIdentifier(node, index); |
| 133 | else | 134 | return recurse(node, index); |
| 134 | this.checkIdentifier(node, index); | 135 | } |
| 135 | return recurse(node, index); | 136 | |
| 136 | } | 137 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) { |
| 137 | 138 | if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | |
| 138 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) | 139 | index.addDeclaration(node.getIdentifierToken(), identifierEntryCache.get(node.getIdentifier())); |
| 139 | { | 140 | else |
| 140 | if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | 141 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! |
| 141 | index.addDeclaration(node.getIdentifierToken(), identifierEntryCache.get(node.getIdentifier())); | 142 | } |
| 142 | else | 143 | |
| 143 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! | 144 | private void addDeclarationToUnmatched(String key, SourceIndex index) { |
| 144 | } | 145 | Entry entry = identifierEntryCache.get(key); |
| 145 | 146 | ||
| 146 | private void addDeclarationToUnmatched(String key, SourceIndex index) | 147 | // This cannot happened in theory |
| 147 | { | 148 | if (entry == null) |
| 148 | Entry entry = identifierEntryCache.get(key); | 149 | return; |
| 149 | 150 | for (Identifier identifier : unmatchedIdentifier.get(key)) | |
| 150 | // This cannot happened in theory | 151 | index.addDeclaration(identifier, entry); |
| 151 | if (entry == null) | 152 | unmatchedIdentifier.removeAll(key); |
| 152 | return; | 153 | } |
| 153 | for (Identifier identifier : unmatchedIdentifier.get(key)) | 154 | |
| 154 | index.addDeclaration(identifier, entry); | 155 | @Override |
| 155 | unmatchedIdentifier.removeAll(key); | 156 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { |
| 156 | } | 157 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 157 | 158 | if (ref != null) { | |
| 158 | @Override | 159 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 159 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { | 160 | ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); |
| 160 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 161 | if (node.getType() instanceof SimpleType) { |
| 161 | if (ref != null) { | 162 | SimpleType simpleTypeNode = (SimpleType) node.getType(); |
| 162 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 163 | index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, this.behaviorEntry); |
| 163 | ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); | 164 | } |
| 164 | if (node.getType() instanceof SimpleType) { | 165 | } |
| 165 | SimpleType simpleTypeNode = (SimpleType) node.getType(); | 166 | |
| 166 | index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, this.behaviorEntry); | 167 | return recurse(node, index); |
| 167 | } | 168 | } |
| 168 | } | 169 | |
| 169 | 170 | @Override | |
| 170 | return recurse(node, index); | 171 | public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { |
| 171 | } | 172 | if (node.getVariableType() instanceof SimpleType) { |
| 172 | 173 | SimpleType type = (SimpleType) node.getVariableType(); | |
| 173 | @Override | 174 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); |
| 174 | public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { | 175 | Identifier identifier = node.getVariableNameToken(); |
| 175 | if (node.getVariableType() instanceof SimpleType) | 176 | String signature = Descriptor.of(typeReference.getErasedDescription()); |
| 176 | { | 177 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, identifier.getName(), new Type(signature)); |
| 177 | SimpleType type = (SimpleType) node.getVariableType(); | 178 | identifierEntryCache.put(identifier.getName(), localVariableEntry); |
| 178 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); | 179 | addDeclarationToUnmatched(identifier.getName(), index); |
| 179 | Identifier identifier = node.getVariableNameToken(); | 180 | index.addDeclaration(identifier, localVariableEntry); |
| 180 | String signature = Descriptor.of(typeReference.getErasedDescription()); | 181 | } |
| 181 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, identifier.getName(), new Type(signature)); | 182 | return recurse(node, index); |
| 182 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | 183 | } |
| 183 | addDeclarationToUnmatched(identifier.getName(), index); | 184 | |
| 184 | index.addDeclaration(identifier, localVariableEntry); | 185 | @Override |
| 185 | } | 186 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { |
| 186 | return recurse(node, index); | 187 | AstNodeCollection<VariableInitializer> variables = node.getVariables(); |
| 187 | } | 188 | |
| 188 | 189 | // Single assignation | |
| 189 | @Override | 190 | if (variables.size() == 1) { |
| 190 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { | 191 | VariableInitializer initializer = variables.firstOrNullObject(); |
| 191 | AstNodeCollection<VariableInitializer> variables = node.getVariables(); | 192 | if (initializer != null && node.getType() instanceof SimpleType) { |
| 192 | 193 | SimpleType type = (SimpleType) node.getType(); | |
| 193 | // Single assignation | 194 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); |
| 194 | if (variables.size() == 1) | 195 | String signature = Descriptor.of(typeReference.getErasedDescription()); |
| 195 | { | 196 | Identifier identifier = initializer.getNameToken(); |
| 196 | VariableInitializer initializer = variables.firstOrNullObject(); | 197 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, initializer.getName(), new Type(signature)); |
| 197 | if (initializer != null && node.getType() instanceof SimpleType) | 198 | identifierEntryCache.put(identifier.getName(), localVariableEntry); |
| 198 | { | 199 | addDeclarationToUnmatched(identifier.getName(), index); |
| 199 | SimpleType type = (SimpleType) node.getType(); | 200 | index.addDeclaration(identifier, localVariableEntry); |
| 200 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); | 201 | } |
| 201 | String signature = Descriptor.of(typeReference.getErasedDescription()); | 202 | } |
| 202 | Identifier identifier = initializer.getNameToken(); | 203 | return recurse(node, index); |
| 203 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, initializer.getName(), new Type(signature)); | 204 | } |
| 204 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | ||
| 205 | addDeclarationToUnmatched(identifier.getName(), index); | ||
| 206 | index.addDeclaration(identifier, localVariableEntry); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | return recurse(node, index); | ||
| 210 | } | ||
| 211 | } | 205 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index 2a21222..1148216 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.strobel.assembler.metadata.FieldDefinition; | 14 | import com.strobel.assembler.metadata.FieldDefinition; |
| @@ -20,79 +21,79 @@ import cuchaz.enigma.mapping.*; | |||
| 20 | 21 | ||
| 21 | public class SourceIndexClassVisitor extends SourceIndexVisitor { | 22 | public class SourceIndexClassVisitor extends SourceIndexVisitor { |
| 22 | 23 | ||
| 23 | private ClassEntry classEntry; | 24 | private ClassEntry classEntry; |
| 24 | 25 | ||
| 25 | public SourceIndexClassVisitor(ClassEntry classEntry) { | 26 | public SourceIndexClassVisitor(ClassEntry classEntry) { |
| 26 | this.classEntry = classEntry; | 27 | this.classEntry = classEntry; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | @Override | 30 | @Override |
| 30 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { | 31 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { |
| 31 | // is this this class, or a subtype? | 32 | // is this this class, or a subtype? |
| 32 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); | 33 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); |
| 33 | ClassEntry classEntry = new ClassEntry(def.getInternalName()); | 34 | ClassEntry classEntry = new ClassEntry(def.getInternalName()); |
| 34 | if (!classEntry.equals(this.classEntry)) { | 35 | if (!classEntry.equals(this.classEntry)) { |
| 35 | // it's a sub-type, recurse | 36 | // it's a sub-type, recurse |
| 36 | index.addDeclaration(node.getNameToken(), classEntry); | 37 | index.addDeclaration(node.getNameToken(), classEntry); |
| 37 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); | 38 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | return recurse(node, index); | 41 | return recurse(node, index); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | @Override | 44 | @Override |
| 44 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | 45 | public Void visitSimpleType(SimpleType node, SourceIndex index) { |
| 45 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | 46 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); |
| 46 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | 47 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { |
| 47 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | 48 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); |
| 48 | index.addReference(node.getIdentifierToken(), classEntry, this.classEntry); | 49 | index.addReference(node.getIdentifierToken(), classEntry, this.classEntry); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | return recurse(node, index); | 52 | return recurse(node, index); |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | @Override | 55 | @Override |
| 55 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { | 56 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { |
| 56 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | 57 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); |
| 57 | BehaviorEntry behaviorEntry = ProcyonEntryFactory.getBehaviorEntry(def); | 58 | BehaviorEntry behaviorEntry = ProcyonEntryFactory.getBehaviorEntry(def); |
| 58 | AstNode tokenNode = node.getNameToken(); | 59 | AstNode tokenNode = node.getNameToken(); |
| 59 | if (behaviorEntry instanceof ConstructorEntry) { | 60 | if (behaviorEntry instanceof ConstructorEntry) { |
| 60 | ConstructorEntry constructorEntry = (ConstructorEntry) behaviorEntry; | 61 | ConstructorEntry constructorEntry = (ConstructorEntry) behaviorEntry; |
| 61 | if (constructorEntry.isStatic()) { | 62 | if (constructorEntry.isStatic()) { |
| 62 | // for static initializers, check elsewhere for the token node | 63 | // for static initializers, check elsewhere for the token node |
| 63 | tokenNode = node.getModifiers().firstOrNullObject(); | 64 | tokenNode = node.getModifiers().firstOrNullObject(); |
| 64 | } | 65 | } |
| 65 | } | 66 | } |
| 66 | index.addDeclaration(tokenNode, behaviorEntry); | 67 | index.addDeclaration(tokenNode, behaviorEntry); |
| 67 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index); | 68 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index); |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | @Override | 71 | @Override |
| 71 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { | 72 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { |
| 72 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | 73 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); |
| 73 | ConstructorEntry constructorEntry = ProcyonEntryFactory.getConstructorEntry(def); | 74 | ConstructorEntry constructorEntry = ProcyonEntryFactory.getConstructorEntry(def); |
| 74 | index.addDeclaration(node.getNameToken(), constructorEntry); | 75 | index.addDeclaration(node.getNameToken(), constructorEntry); |
| 75 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); | 76 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | @Override | 79 | @Override |
| 79 | public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { | 80 | public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { |
| 80 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); | 81 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); |
| 81 | FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); | 82 | FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); |
| 82 | assert (node.getVariables().size() == 1); | 83 | assert (node.getVariables().size() == 1); |
| 83 | VariableInitializer variable = node.getVariables().firstOrNullObject(); | 84 | VariableInitializer variable = node.getVariables().firstOrNullObject(); |
| 84 | index.addDeclaration(variable.getNameToken(), fieldEntry); | 85 | index.addDeclaration(variable.getNameToken(), fieldEntry); |
| 85 | 86 | ||
| 86 | return recurse(node, index); | 87 | return recurse(node, index); |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | @Override | 90 | @Override |
| 90 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { | 91 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { |
| 91 | // treat enum declarations as field declarations | 92 | // treat enum declarations as field declarations |
| 92 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); | 93 | FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); |
| 93 | FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); | 94 | FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); |
| 94 | index.addDeclaration(node.getNameToken(), fieldEntry); | 95 | index.addDeclaration(node.getNameToken(), fieldEntry); |
| 95 | 96 | ||
| 96 | return recurse(node, index); | 97 | return recurse(node, index); |
| 97 | } | 98 | } |
| 98 | } | 99 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java index 40381f4..a94a55b 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexVisitor.java | |||
| @@ -8,374 +8,374 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.strobel.assembler.metadata.TypeDefinition; | 14 | import com.strobel.assembler.metadata.TypeDefinition; |
| 14 | import com.strobel.decompiler.languages.java.ast.*; | 15 | import com.strobel.decompiler.languages.java.ast.*; |
| 15 | import com.strobel.decompiler.patterns.Pattern; | 16 | import com.strobel.decompiler.patterns.Pattern; |
| 16 | |||
| 17 | import cuchaz.enigma.mapping.ClassEntry; | 17 | import cuchaz.enigma.mapping.ClassEntry; |
| 18 | 18 | ||
| 19 | public class SourceIndexVisitor implements IAstVisitor<SourceIndex, Void> { | 19 | public class SourceIndexVisitor implements IAstVisitor<SourceIndex, Void> { |
| 20 | 20 | ||
| 21 | @Override | 21 | @Override |
| 22 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { | 22 | public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { |
| 23 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); | 23 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); |
| 24 | ClassEntry classEntry = new ClassEntry(def.getInternalName()); | 24 | ClassEntry classEntry = new ClassEntry(def.getInternalName()); |
| 25 | index.addDeclaration(node.getNameToken(), classEntry); | 25 | index.addDeclaration(node.getNameToken(), classEntry); |
| 26 | 26 | ||
| 27 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); | 27 | return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | protected Void recurse(AstNode node, SourceIndex index) { | 30 | protected Void recurse(AstNode node, SourceIndex index) { |
| 31 | for (final AstNode child : node.getChildren()) { | 31 | for (final AstNode child : node.getChildren()) { |
| 32 | child.acceptVisitor(this, index); | 32 | child.acceptVisitor(this, index); |
| 33 | } | 33 | } |
| 34 | return null; | 34 | return null; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | @Override | 37 | @Override |
| 38 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { | 38 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { |
| 39 | return recurse(node, index); | 39 | return recurse(node, index); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | @Override | 42 | @Override |
| 43 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { | 43 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { |
| 44 | return recurse(node, index); | 44 | return recurse(node, index); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | @Override | 47 | @Override |
| 48 | public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { | 48 | public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { |
| 49 | return recurse(node, index); | 49 | return recurse(node, index); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | @Override | 52 | @Override |
| 53 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { | 53 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { |
| 54 | return recurse(node, index); | 54 | return recurse(node, index); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | @Override | 57 | @Override |
| 58 | public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { | 58 | public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { |
| 59 | return recurse(node, index); | 59 | return recurse(node, index); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | @Override | 62 | @Override |
| 63 | public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { | 63 | public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { |
| 64 | return recurse(node, index); | 64 | return recurse(node, index); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | @Override | 67 | @Override |
| 68 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { | 68 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { |
| 69 | return recurse(node, index); | 69 | return recurse(node, index); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | @Override | 72 | @Override |
| 73 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | 73 | public Void visitSimpleType(SimpleType node, SourceIndex index) { |
| 74 | return recurse(node, index); | 74 | return recurse(node, index); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | @Override | 77 | @Override |
| 78 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { | 78 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { |
| 79 | return recurse(node, index); | 79 | return recurse(node, index); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | @Override | 82 | @Override |
| 83 | public Void visitComment(Comment node, SourceIndex index) { | 83 | public Void visitComment(Comment node, SourceIndex index) { |
| 84 | return recurse(node, index); | 84 | return recurse(node, index); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | @Override | 87 | @Override |
| 88 | public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) { | 88 | public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) { |
| 89 | return recurse(node, index); | 89 | return recurse(node, index); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | @Override | 92 | @Override |
| 93 | public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) { | 93 | public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) { |
| 94 | return recurse(node, index); | 94 | return recurse(node, index); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | @Override | 97 | @Override |
| 98 | public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) { | 98 | public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) { |
| 99 | return recurse(node, index); | 99 | return recurse(node, index); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | @Override | 102 | @Override |
| 103 | public Void visitIdentifier(Identifier node, SourceIndex index) { | 103 | public Void visitIdentifier(Identifier node, SourceIndex index) { |
| 104 | return recurse(node, index); | 104 | return recurse(node, index); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | @Override | 107 | @Override |
| 108 | public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) { | 108 | public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) { |
| 109 | return recurse(node, index); | 109 | return recurse(node, index); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | @Override | 112 | @Override |
| 113 | public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) { | 113 | public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) { |
| 114 | return recurse(node, index); | 114 | return recurse(node, index); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | @Override | 117 | @Override |
| 118 | public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) { | 118 | public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) { |
| 119 | return recurse(node, index); | 119 | return recurse(node, index); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | @Override | 122 | @Override |
| 123 | public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) { | 123 | public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) { |
| 124 | return recurse(node, index); | 124 | return recurse(node, index); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | @Override | 127 | @Override |
| 128 | public Void visitBlockStatement(BlockStatement node, SourceIndex index) { | 128 | public Void visitBlockStatement(BlockStatement node, SourceIndex index) { |
| 129 | return recurse(node, index); | 129 | return recurse(node, index); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | @Override | 132 | @Override |
| 133 | public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) { | 133 | public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) { |
| 134 | return recurse(node, index); | 134 | return recurse(node, index); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | @Override | 137 | @Override |
| 138 | public Void visitBreakStatement(BreakStatement node, SourceIndex index) { | 138 | public Void visitBreakStatement(BreakStatement node, SourceIndex index) { |
| 139 | return recurse(node, index); | 139 | return recurse(node, index); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | @Override | 142 | @Override |
| 143 | public Void visitContinueStatement(ContinueStatement node, SourceIndex index) { | 143 | public Void visitContinueStatement(ContinueStatement node, SourceIndex index) { |
| 144 | return recurse(node, index); | 144 | return recurse(node, index); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | @Override | 147 | @Override |
| 148 | public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) { | 148 | public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) { |
| 149 | return recurse(node, index); | 149 | return recurse(node, index); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | @Override | 152 | @Override |
| 153 | public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) { | 153 | public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) { |
| 154 | return recurse(node, index); | 154 | return recurse(node, index); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | @Override | 157 | @Override |
| 158 | public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) { | 158 | public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) { |
| 159 | return recurse(node, index); | 159 | return recurse(node, index); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | @Override | 162 | @Override |
| 163 | public Void visitLabelStatement(LabelStatement node, SourceIndex index) { | 163 | public Void visitLabelStatement(LabelStatement node, SourceIndex index) { |
| 164 | return recurse(node, index); | 164 | return recurse(node, index); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | @Override | 167 | @Override |
| 168 | public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) { | 168 | public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) { |
| 169 | return recurse(node, index); | 169 | return recurse(node, index); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | @Override | 172 | @Override |
| 173 | public Void visitReturnStatement(ReturnStatement node, SourceIndex index) { | 173 | public Void visitReturnStatement(ReturnStatement node, SourceIndex index) { |
| 174 | return recurse(node, index); | 174 | return recurse(node, index); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | @Override | 177 | @Override |
| 178 | public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) { | 178 | public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) { |
| 179 | return recurse(node, index); | 179 | return recurse(node, index); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | @Override | 182 | @Override |
| 183 | public Void visitSwitchSection(SwitchSection node, SourceIndex index) { | 183 | public Void visitSwitchSection(SwitchSection node, SourceIndex index) { |
| 184 | return recurse(node, index); | 184 | return recurse(node, index); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | @Override | 187 | @Override |
| 188 | public Void visitCaseLabel(CaseLabel node, SourceIndex index) { | 188 | public Void visitCaseLabel(CaseLabel node, SourceIndex index) { |
| 189 | return recurse(node, index); | 189 | return recurse(node, index); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | @Override | 192 | @Override |
| 193 | public Void visitThrowStatement(ThrowStatement node, SourceIndex index) { | 193 | public Void visitThrowStatement(ThrowStatement node, SourceIndex index) { |
| 194 | return recurse(node, index); | 194 | return recurse(node, index); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | @Override | 197 | @Override |
| 198 | public Void visitCatchClause(CatchClause node, SourceIndex index) { | 198 | public Void visitCatchClause(CatchClause node, SourceIndex index) { |
| 199 | return recurse(node, index); | 199 | return recurse(node, index); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | @Override | 202 | @Override |
| 203 | public Void visitAnnotation(Annotation node, SourceIndex index) { | 203 | public Void visitAnnotation(Annotation node, SourceIndex index) { |
| 204 | return recurse(node, index); | 204 | return recurse(node, index); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | @Override | 207 | @Override |
| 208 | public Void visitNewLine(NewLineNode node, SourceIndex index) { | 208 | public Void visitNewLine(NewLineNode node, SourceIndex index) { |
| 209 | return recurse(node, index); | 209 | return recurse(node, index); |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | @Override | 212 | @Override |
| 213 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { | 213 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { |
| 214 | return recurse(node, index); | 214 | return recurse(node, index); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | @Override | 217 | @Override |
| 218 | public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) { | 218 | public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) { |
| 219 | return recurse(node, index); | 219 | return recurse(node, index); |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | @Override | 222 | @Override |
| 223 | public Void visitText(TextNode node, SourceIndex index) { | 223 | public Void visitText(TextNode node, SourceIndex index) { |
| 224 | return recurse(node, index); | 224 | return recurse(node, index); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | @Override | 227 | @Override |
| 228 | public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) { | 228 | public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) { |
| 229 | return recurse(node, index); | 229 | return recurse(node, index); |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | @Override | 232 | @Override |
| 233 | public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) { | 233 | public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) { |
| 234 | return recurse(node, index); | 234 | return recurse(node, index); |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | @Override | 237 | @Override |
| 238 | public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) { | 238 | public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) { |
| 239 | return recurse(node, index); | 239 | return recurse(node, index); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | @Override | 242 | @Override |
| 243 | public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) { | 243 | public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) { |
| 244 | return recurse(node, index); | 244 | return recurse(node, index); |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | @Override | 247 | @Override |
| 248 | public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) { | 248 | public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) { |
| 249 | return recurse(node, index); | 249 | return recurse(node, index); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | @Override | 252 | @Override |
| 253 | public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) { | 253 | public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) { |
| 254 | return recurse(node, index); | 254 | return recurse(node, index); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | @Override | 257 | @Override |
| 258 | public Void visitComposedType(ComposedType node, SourceIndex index) { | 258 | public Void visitComposedType(ComposedType node, SourceIndex index) { |
| 259 | return recurse(node, index); | 259 | return recurse(node, index); |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | @Override | 262 | @Override |
| 263 | public Void visitWhileStatement(WhileStatement node, SourceIndex index) { | 263 | public Void visitWhileStatement(WhileStatement node, SourceIndex index) { |
| 264 | return recurse(node, index); | 264 | return recurse(node, index); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | @Override | 267 | @Override |
| 268 | public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) { | 268 | public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) { |
| 269 | return recurse(node, index); | 269 | return recurse(node, index); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | @Override | 272 | @Override |
| 273 | public Void visitCastExpression(CastExpression node, SourceIndex index) { | 273 | public Void visitCastExpression(CastExpression node, SourceIndex index) { |
| 274 | return recurse(node, index); | 274 | return recurse(node, index); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | @Override | 277 | @Override |
| 278 | public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) { | 278 | public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) { |
| 279 | return recurse(node, index); | 279 | return recurse(node, index); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | @Override | 282 | @Override |
| 283 | public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) { | 283 | public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) { |
| 284 | return recurse(node, index); | 284 | return recurse(node, index); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | @Override | 287 | @Override |
| 288 | public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) { | 288 | public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) { |
| 289 | return recurse(node, index); | 289 | return recurse(node, index); |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | @Override | 292 | @Override |
| 293 | public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) { | 293 | public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) { |
| 294 | return recurse(node, index); | 294 | return recurse(node, index); |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | @Override | 297 | @Override |
| 298 | public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) { | 298 | public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) { |
| 299 | return recurse(node, index); | 299 | return recurse(node, index); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | @Override | 302 | @Override |
| 303 | public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) { | 303 | public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) { |
| 304 | return recurse(node, index); | 304 | return recurse(node, index); |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | @Override | 307 | @Override |
| 308 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { | 308 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { |
| 309 | return recurse(node, index); | 309 | return recurse(node, index); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | @Override | 312 | @Override |
| 313 | public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) { | 313 | public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) { |
| 314 | return recurse(node, index); | 314 | return recurse(node, index); |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | @Override | 317 | @Override |
| 318 | public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) { | 318 | public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) { |
| 319 | return recurse(node, index); | 319 | return recurse(node, index); |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | @Override | 322 | @Override |
| 323 | public Void visitForStatement(ForStatement node, SourceIndex index) { | 323 | public Void visitForStatement(ForStatement node, SourceIndex index) { |
| 324 | return recurse(node, index); | 324 | return recurse(node, index); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | @Override | 327 | @Override |
| 328 | public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { | 328 | public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { |
| 329 | return recurse(node, index); | 329 | return recurse(node, index); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | @Override | 332 | @Override |
| 333 | public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) { | 333 | public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) { |
| 334 | return recurse(node, index); | 334 | return recurse(node, index); |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | @Override | 337 | @Override |
| 338 | public Void visitGotoStatement(GotoStatement node, SourceIndex index) { | 338 | public Void visitGotoStatement(GotoStatement node, SourceIndex index) { |
| 339 | return recurse(node, index); | 339 | return recurse(node, index); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | @Override | 342 | @Override |
| 343 | public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) { | 343 | public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) { |
| 344 | return recurse(node, index); | 344 | return recurse(node, index); |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | @Override | 347 | @Override |
| 348 | public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) { | 348 | public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) { |
| 349 | return recurse(node, index); | 349 | return recurse(node, index); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | @Override | 352 | @Override |
| 353 | public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) { | 353 | public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) { |
| 354 | return recurse(node, index); | 354 | return recurse(node, index); |
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | @Override | 357 | @Override |
| 358 | public Void visitWildcardType(WildcardType node, SourceIndex index) { | 358 | public Void visitWildcardType(WildcardType node, SourceIndex index) { |
| 359 | return recurse(node, index); | 359 | return recurse(node, index); |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | @Override | 362 | @Override |
| 363 | public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { | 363 | public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { |
| 364 | return recurse(node, index); | 364 | return recurse(node, index); |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | @Override | 367 | @Override |
| 368 | public Void visitAssertStatement(AssertStatement node, SourceIndex index) { | 368 | public Void visitAssertStatement(AssertStatement node, SourceIndex index) { |
| 369 | return recurse(node, index); | 369 | return recurse(node, index); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | @Override | 372 | @Override |
| 373 | public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) { | 373 | public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) { |
| 374 | return recurse(node, index); | 374 | return recurse(node, index); |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | @Override | 377 | @Override |
| 378 | public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) { | 378 | public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) { |
| 379 | return recurse(node, index); | 379 | return recurse(node, index); |
| 380 | } | 380 | } |
| 381 | } | 381 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java index 42f4660..266d202 100644 --- a/src/main/java/cuchaz/enigma/analysis/Token.java +++ b/src/main/java/cuchaz/enigma/analysis/Token.java | |||
| @@ -8,48 +8,48 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | public class Token implements Comparable<Token> { | 14 | public class Token implements Comparable<Token> { |
| 14 | 15 | ||
| 15 | public int start; | 16 | public int start; |
| 16 | public int end; | 17 | public int end; |
| 17 | public String text; | 18 | public String text; |
| 18 | 19 | ||
| 19 | public Token(int start, int end, String source) { | 20 | public Token(int start, int end, String source) { |
| 20 | this.start = start; | 21 | this.start = start; |
| 21 | this.end = end; | 22 | this.end = end; |
| 22 | if (source != null) { | 23 | if (source != null) { |
| 23 | this.text = source.substring(start, end); | 24 | this.text = source.substring(start, end); |
| 24 | } | 25 | } |
| 25 | } | 26 | } |
| 26 | 27 | ||
| 27 | public boolean contains(int pos) { | 28 | public boolean contains(int pos) { |
| 28 | return pos >= start && pos <= end; | 29 | return pos >= start && pos <= end; |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | @Override | 32 | @Override |
| 32 | public int compareTo(Token other) { | 33 | public int compareTo(Token other) { |
| 33 | return start - other.start; | 34 | return start - other.start; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | @Override | 37 | @Override |
| 37 | public boolean equals(Object other) { | 38 | public boolean equals(Object other) { |
| 38 | return other instanceof Token && equals((Token) other); | 39 | return other instanceof Token && equals((Token) other); |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | @Override | 42 | @Override |
| 42 | public int hashCode() | 43 | public int hashCode() { |
| 43 | { | 44 | return Integer.hashCode(start) + Integer.hashCode(end) + (text != null ? text.hashCode() : 0); |
| 44 | return Integer.hashCode(start) + Integer.hashCode(end) + (text != null ? text.hashCode() : 0); | 45 | } |
| 45 | } | 46 | |
| 46 | 47 | public boolean equals(Token other) { | |
| 47 | public boolean equals(Token other) { | 48 | return start == other.start && end == other.end; |
| 48 | return start == other.start && end == other.end; | 49 | } |
| 49 | } | 50 | |
| 50 | 51 | @Override | |
| 51 | @Override | 52 | public String toString() { |
| 52 | public String toString() { | 53 | return String.format("[%d,%d]", start, end); |
| 53 | return String.format("[%d,%d]", start, end); | 54 | } |
| 54 | } | ||
| 55 | } | 55 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java index d51131f..26be05b 100644 --- a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java | |||
| @@ -8,291 +8,288 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.HashMultimap; | 14 | import com.google.common.collect.HashMultimap; |
| 14 | import com.google.common.collect.Lists; | 15 | import com.google.common.collect.Lists; |
| 15 | import com.google.common.collect.Maps; | 16 | import com.google.common.collect.Maps; |
| 16 | import com.google.common.collect.Multimap; | 17 | import com.google.common.collect.Multimap; |
| 17 | |||
| 18 | import java.util.Collection; | ||
| 19 | import java.util.List; | ||
| 20 | import java.util.Map; | ||
| 21 | import java.util.Set; | ||
| 22 | |||
| 23 | import cuchaz.enigma.mapping.*; | 18 | import cuchaz.enigma.mapping.*; |
| 24 | import javassist.CtBehavior; | 19 | import javassist.CtBehavior; |
| 25 | import javassist.CtClass; | 20 | import javassist.CtClass; |
| 26 | import javassist.CtField; | 21 | import javassist.CtField; |
| 27 | import javassist.bytecode.Descriptor; | 22 | import javassist.bytecode.Descriptor; |
| 28 | 23 | ||
| 24 | import java.util.Collection; | ||
| 25 | import java.util.List; | ||
| 26 | import java.util.Map; | ||
| 27 | import java.util.Set; | ||
| 28 | |||
| 29 | public class TranslationIndex { | 29 | public class TranslationIndex { |
| 30 | 30 | ||
| 31 | private Map<ClassEntry, ClassEntry> superclasses; | 31 | private Map<ClassEntry, ClassEntry> superclasses; |
| 32 | private Multimap<ClassEntry, FieldEntry> fieldEntries; | 32 | private Multimap<ClassEntry, FieldEntry> fieldEntries; |
| 33 | private Multimap<ClassEntry, BehaviorEntry> behaviorEntries; | 33 | private Multimap<ClassEntry, BehaviorEntry> behaviorEntries; |
| 34 | private Multimap<ClassEntry, ClassEntry> interfaces; | 34 | private Multimap<ClassEntry, ClassEntry> interfaces; |
| 35 | 35 | ||
| 36 | public TranslationIndex() { | 36 | public TranslationIndex() { |
| 37 | this.superclasses = Maps.newHashMap(); | 37 | this.superclasses = Maps.newHashMap(); |
| 38 | this.fieldEntries = HashMultimap.create(); | 38 | this.fieldEntries = HashMultimap.create(); |
| 39 | this.behaviorEntries = HashMultimap.create(); | 39 | this.behaviorEntries = HashMultimap.create(); |
| 40 | this.interfaces = HashMultimap.create(); | 40 | this.interfaces = HashMultimap.create(); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | public TranslationIndex(TranslationIndex other, Translator translator) { | 43 | public TranslationIndex(TranslationIndex other, Translator translator) { |
| 44 | // translate the superclasses | 44 | // translate the superclasses |
| 45 | this.superclasses = Maps.newHashMap(); | 45 | this.superclasses = Maps.newHashMap(); |
| 46 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.superclasses.entrySet()) { | 46 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.superclasses.entrySet()) { |
| 47 | this.superclasses.put(translator.translateEntry(mapEntry.getKey()), translator.translateEntry(mapEntry.getValue())); | 47 | this.superclasses.put(translator.translateEntry(mapEntry.getKey()), translator.translateEntry(mapEntry.getValue())); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | // translate the interfaces | 50 | // translate the interfaces |
| 51 | this.interfaces = HashMultimap.create(); | 51 | this.interfaces = HashMultimap.create(); |
| 52 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.interfaces.entries()) { | 52 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.interfaces.entries()) { |
| 53 | this.interfaces.put( | 53 | this.interfaces.put( |
| 54 | translator.translateEntry(mapEntry.getKey()), | 54 | translator.translateEntry(mapEntry.getKey()), |
| 55 | translator.translateEntry(mapEntry.getValue()) | 55 | translator.translateEntry(mapEntry.getValue()) |
| 56 | ); | 56 | ); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | // translate the fields | 59 | // translate the fields |
| 60 | this.fieldEntries = HashMultimap.create(); | 60 | this.fieldEntries = HashMultimap.create(); |
| 61 | for (Map.Entry<ClassEntry, FieldEntry> mapEntry : other.fieldEntries.entries()) { | 61 | for (Map.Entry<ClassEntry, FieldEntry> mapEntry : other.fieldEntries.entries()) { |
| 62 | this.fieldEntries.put( | 62 | this.fieldEntries.put( |
| 63 | translator.translateEntry(mapEntry.getKey()), | 63 | translator.translateEntry(mapEntry.getKey()), |
| 64 | translator.translateEntry(mapEntry.getValue()) | 64 | translator.translateEntry(mapEntry.getValue()) |
| 65 | ); | 65 | ); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | this.behaviorEntries = HashMultimap.create(); | 68 | this.behaviorEntries = HashMultimap.create(); |
| 69 | for (Map.Entry<ClassEntry, BehaviorEntry> mapEntry : other.behaviorEntries.entries()) { | 69 | for (Map.Entry<ClassEntry, BehaviorEntry> mapEntry : other.behaviorEntries.entries()) { |
| 70 | this.behaviorEntries.put( | 70 | this.behaviorEntries.put( |
| 71 | translator.translateEntry(mapEntry.getKey()), | 71 | translator.translateEntry(mapEntry.getKey()), |
| 72 | translator.translateEntry(mapEntry.getValue()) | 72 | translator.translateEntry(mapEntry.getValue()) |
| 73 | ); | 73 | ); |
| 74 | } | 74 | } |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | public void indexClass(CtClass c) { | 77 | public void indexClass(CtClass c) { |
| 78 | indexClass(c, true); | 78 | indexClass(c, true); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | public void indexClass(CtClass c, boolean indexMembers) { | 81 | public void indexClass(CtClass c, boolean indexMembers) { |
| 82 | ClassEntry classEntry = EntryFactory.getClassEntry(c); | 82 | ClassEntry classEntry = EntryFactory.getClassEntry(c); |
| 83 | if (isJre(classEntry)) { | 83 | if (isJre(classEntry)) { |
| 84 | return; | 84 | return; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | // add the superclass | 87 | // add the superclass |
| 88 | ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); | 88 | ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); |
| 89 | if (superclassEntry != null) { | 89 | if (superclassEntry != null) { |
| 90 | this.superclasses.put(classEntry, superclassEntry); | 90 | this.superclasses.put(classEntry, superclassEntry); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | // add the interfaces | 93 | // add the interfaces |
| 94 | for (String interfaceClassName : c.getClassFile().getInterfaces()) { | 94 | for (String interfaceClassName : c.getClassFile().getInterfaces()) { |
| 95 | ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName)); | 95 | ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName)); |
| 96 | if (!isJre(interfaceClassEntry)) { | 96 | if (!isJre(interfaceClassEntry)) { |
| 97 | 97 | ||
| 98 | this.interfaces.put(classEntry, interfaceClassEntry); | 98 | this.interfaces.put(classEntry, interfaceClassEntry); |
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | if (indexMembers) { | 102 | if (indexMembers) { |
| 103 | // add fields | 103 | // add fields |
| 104 | for (CtField field : c.getDeclaredFields()) { | 104 | for (CtField field : c.getDeclaredFields()) { |
| 105 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); | 105 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 106 | this.fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); | 106 | this.fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // add behaviors | 109 | // add behaviors |
| 110 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 110 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 111 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); | 111 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 112 | this.behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); | 112 | this.behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); |
| 113 | } | 113 | } |
| 114 | } | 114 | } |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | public void renameClasses(Map<String, String> renames) { | 117 | public void renameClasses(Map<String, String> renames) { |
| 118 | EntryRenamer.renameClassesInMap(renames, this.superclasses); | 118 | EntryRenamer.renameClassesInMap(renames, this.superclasses); |
| 119 | EntryRenamer.renameClassesInMultimap(renames, this.fieldEntries); | 119 | EntryRenamer.renameClassesInMultimap(renames, this.fieldEntries); |
| 120 | EntryRenamer.renameClassesInMultimap(renames, this.behaviorEntries); | 120 | EntryRenamer.renameClassesInMultimap(renames, this.behaviorEntries); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | public ClassEntry getSuperclass(ClassEntry classEntry) { | 123 | public ClassEntry getSuperclass(ClassEntry classEntry) { |
| 124 | return this.superclasses.get(classEntry); | 124 | return this.superclasses.get(classEntry); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | public List<ClassEntry> getAncestry(ClassEntry classEntry) { | 127 | public List<ClassEntry> getAncestry(ClassEntry classEntry) { |
| 128 | List<ClassEntry> ancestors = Lists.newArrayList(); | 128 | List<ClassEntry> ancestors = Lists.newArrayList(); |
| 129 | while (classEntry != null) { | 129 | while (classEntry != null) { |
| 130 | classEntry = getSuperclass(classEntry); | 130 | classEntry = getSuperclass(classEntry); |
| 131 | if (classEntry != null) { | 131 | if (classEntry != null) { |
| 132 | ancestors.add(classEntry); | 132 | ancestors.add(classEntry); |
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| 135 | return ancestors; | 135 | return ancestors; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | public List<ClassEntry> getSubclass(ClassEntry classEntry) { | 138 | public List<ClassEntry> getSubclass(ClassEntry classEntry) { |
| 139 | // linear search is fast enough for now | 139 | // linear search is fast enough for now |
| 140 | List<ClassEntry> subclasses = Lists.newArrayList(); | 140 | List<ClassEntry> subclasses = Lists.newArrayList(); |
| 141 | for (Map.Entry<ClassEntry, ClassEntry> entry : this.superclasses.entrySet()) { | 141 | for (Map.Entry<ClassEntry, ClassEntry> entry : this.superclasses.entrySet()) { |
| 142 | ClassEntry subclass = entry.getKey(); | 142 | ClassEntry subclass = entry.getKey(); |
| 143 | ClassEntry superclass = entry.getValue(); | 143 | ClassEntry superclass = entry.getValue(); |
| 144 | if (classEntry.equals(superclass)) { | 144 | if (classEntry.equals(superclass)) { |
| 145 | subclasses.add(subclass); | 145 | subclasses.add(subclass); |
| 146 | } | 146 | } |
| 147 | } | 147 | } |
| 148 | return subclasses; | 148 | return subclasses; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | public void getSubclassesRecursively(Set<ClassEntry> out, ClassEntry classEntry) { | 151 | public void getSubclassesRecursively(Set<ClassEntry> out, ClassEntry classEntry) { |
| 152 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { | 152 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { |
| 153 | out.add(subclassEntry); | 153 | out.add(subclassEntry); |
| 154 | getSubclassesRecursively(out, subclassEntry); | 154 | getSubclassesRecursively(out, subclassEntry); |
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | public void getSubclassNamesRecursively(Set<String> out, ClassEntry classEntry) { | 158 | public void getSubclassNamesRecursively(Set<String> out, ClassEntry classEntry) { |
| 159 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { | 159 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { |
| 160 | out.add(subclassEntry.getName()); | 160 | out.add(subclassEntry.getName()); |
| 161 | getSubclassNamesRecursively(out, subclassEntry); | 161 | getSubclassNamesRecursively(out, subclassEntry); |
| 162 | } | 162 | } |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | public Collection<Map.Entry<ClassEntry, ClassEntry>> getClassInterfaces() { | 165 | public Collection<Map.Entry<ClassEntry, ClassEntry>> getClassInterfaces() { |
| 166 | return this.interfaces.entries(); | 166 | return this.interfaces.entries(); |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) { | 169 | public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) { |
| 170 | return this.interfaces.get(classEntry); | 170 | return this.interfaces.get(classEntry); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | public boolean isInterface(ClassEntry classEntry) { | 173 | public boolean isInterface(ClassEntry classEntry) { |
| 174 | return this.interfaces.containsValue(classEntry); | 174 | return this.interfaces.containsValue(classEntry); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | public boolean entryExists(Entry entry) { | 177 | public boolean entryExists(Entry entry) { |
| 178 | if (entry instanceof FieldEntry) { | 178 | if (entry instanceof FieldEntry) { |
| 179 | return fieldExists((FieldEntry) entry); | 179 | return fieldExists((FieldEntry) entry); |
| 180 | } else if (entry instanceof BehaviorEntry) { | 180 | } else if (entry instanceof BehaviorEntry) { |
| 181 | return behaviorExists((BehaviorEntry) entry); | 181 | return behaviorExists((BehaviorEntry) entry); |
| 182 | } else if (entry instanceof ArgumentEntry) { | 182 | } else if (entry instanceof ArgumentEntry) { |
| 183 | return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry()); | 183 | return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry()); |
| 184 | } else if (entry instanceof LocalVariableEntry) { | 184 | } else if (entry instanceof LocalVariableEntry) { |
| 185 | return behaviorExists(((LocalVariableEntry) entry).getBehaviorEntry()); | 185 | return behaviorExists(((LocalVariableEntry) entry).getBehaviorEntry()); |
| 186 | } | 186 | } |
| 187 | throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); | 187 | throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | public boolean fieldExists(FieldEntry fieldEntry) { | 190 | public boolean fieldExists(FieldEntry fieldEntry) { |
| 191 | return this.fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry); | 191 | return this.fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | public boolean behaviorExists(BehaviorEntry behaviorEntry) { | 194 | public boolean behaviorExists(BehaviorEntry behaviorEntry) { |
| 195 | return this.behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry); | 195 | return this.behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | public ClassEntry resolveEntryClass(Entry entry) { | 198 | public ClassEntry resolveEntryClass(Entry entry) { |
| 199 | return resolveEntryClass(entry, false); | 199 | return resolveEntryClass(entry, false); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | public ClassEntry resolveEntryClass(Entry entry, boolean checkSuperclassBeforeChild) { | 202 | public ClassEntry resolveEntryClass(Entry entry, boolean checkSuperclassBeforeChild) { |
| 203 | if (entry instanceof ClassEntry) { | 203 | if (entry instanceof ClassEntry) { |
| 204 | return (ClassEntry) entry; | 204 | return (ClassEntry) entry; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | ClassEntry superclassEntry = resolveSuperclass(entry, checkSuperclassBeforeChild); | 207 | ClassEntry superclassEntry = resolveSuperclass(entry, checkSuperclassBeforeChild); |
| 208 | if (superclassEntry != null) { | 208 | if (superclassEntry != null) { |
| 209 | return superclassEntry; | 209 | return superclassEntry; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | ClassEntry interfaceEntry = resolveInterface(entry); | 212 | ClassEntry interfaceEntry = resolveInterface(entry); |
| 213 | if (interfaceEntry != null) { | 213 | if (interfaceEntry != null) { |
| 214 | return interfaceEntry; | 214 | return interfaceEntry; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | return null; | 217 | return null; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | public ClassEntry resolveSuperclass(Entry entry, boolean checkSuperclassBeforeChild) { | 220 | public ClassEntry resolveSuperclass(Entry entry, boolean checkSuperclassBeforeChild) { |
| 221 | 221 | ||
| 222 | // Default case | 222 | // Default case |
| 223 | if (!checkSuperclassBeforeChild) | 223 | if (!checkSuperclassBeforeChild) |
| 224 | return resolveSuperclass(entry); | 224 | return resolveSuperclass(entry); |
| 225 | 225 | ||
| 226 | // Save the original entry | 226 | // Save the original entry |
| 227 | Entry originalEntry = entry; | 227 | Entry originalEntry = entry; |
| 228 | 228 | ||
| 229 | // Get all possible superclasses and reverse the list | 229 | // Get all possible superclasses and reverse the list |
| 230 | List<ClassEntry> superclasses = Lists.reverse(getAncestry(originalEntry.getClassEntry())); | 230 | List<ClassEntry> superclasses = Lists.reverse(getAncestry(originalEntry.getClassEntry())); |
| 231 | 231 | ||
| 232 | boolean existInEntry = false; | 232 | boolean existInEntry = false; |
| 233 | 233 | ||
| 234 | for (ClassEntry classEntry : superclasses) | 234 | for (ClassEntry classEntry : superclasses) { |
| 235 | { | 235 | entry = entry.cloneToNewClass(classEntry); |
| 236 | entry = entry.cloneToNewClass(classEntry); | 236 | existInEntry = entryExists(entry); |
| 237 | existInEntry = entryExists(entry); | 237 | |
| 238 | 238 | // Check for possible entry in interfaces of superclasses | |
| 239 | // Check for possible entry in interfaces of superclasses | 239 | ClassEntry interfaceEntry = resolveInterface(entry); |
| 240 | ClassEntry interfaceEntry = resolveInterface(entry); | 240 | if (interfaceEntry != null) |
| 241 | if (interfaceEntry != null) | 241 | return interfaceEntry; |
| 242 | return interfaceEntry; | 242 | if (existInEntry) |
| 243 | if (existInEntry) | 243 | break; |
| 244 | break; | 244 | } |
| 245 | } | 245 | |
| 246 | 246 | // Doesn't exists in superclasses? check the child or return null | |
| 247 | // Doesn't exists in superclasses? check the child or return null | 247 | if (!existInEntry) |
| 248 | if (!existInEntry) | 248 | return !entryExists(originalEntry) ? null : originalEntry.getClassEntry(); |
| 249 | return !entryExists(originalEntry) ? null : originalEntry.getClassEntry(); | 249 | |
| 250 | 250 | return entry.getClassEntry(); | |
| 251 | return entry.getClassEntry(); | 251 | } |
| 252 | } | 252 | |
| 253 | 253 | public ClassEntry resolveSuperclass(Entry entry) { | |
| 254 | public ClassEntry resolveSuperclass(Entry entry) | 254 | // this entry could refer to a method on a class where the method is not actually implemented |
| 255 | { | 255 | // travel up the inheritance tree to find the closest implementation |
| 256 | // this entry could refer to a method on a class where the method is not actually implemented | 256 | |
| 257 | // travel up the inheritance tree to find the closest implementation | 257 | while (!entryExists(entry)) { |
| 258 | 258 | // is there a parent class? | |
| 259 | while (!entryExists(entry)) { | 259 | ClassEntry superclassEntry = getSuperclass(entry.getClassEntry()); |
| 260 | // is there a parent class? | 260 | if (superclassEntry == null) { |
| 261 | ClassEntry superclassEntry = getSuperclass(entry.getClassEntry()); | 261 | // this is probably a method from a class in a library |
| 262 | if (superclassEntry == null) { | 262 | // we can't trace the implementation up any higher unless we index the library |
| 263 | // this is probably a method from a class in a library | 263 | return null; |
| 264 | // we can't trace the implementation up any higher unless we index the library | 264 | } |
| 265 | return null; | 265 | |
| 266 | } | 266 | // move up to the parent class |
| 267 | 267 | entry = entry.cloneToNewClass(superclassEntry); | |
| 268 | // move up to the parent class | 268 | } |
| 269 | entry = entry.cloneToNewClass(superclassEntry); | 269 | return entry.getClassEntry(); |
| 270 | } | 270 | } |
| 271 | return entry.getClassEntry(); | 271 | |
| 272 | } | 272 | public ClassEntry resolveInterface(Entry entry) { |
| 273 | 273 | // the interfaces for any class is a forest | |
| 274 | public ClassEntry resolveInterface(Entry entry) { | 274 | // so let's look at all the trees |
| 275 | // the interfaces for any class is a forest | 275 | |
| 276 | // so let's look at all the trees | 276 | for (ClassEntry interfaceEntry : this.interfaces.get(entry.getClassEntry())) { |
| 277 | 277 | Collection<ClassEntry> subInterface = this.interfaces.get(interfaceEntry); | |
| 278 | for (ClassEntry interfaceEntry : this.interfaces.get(entry.getClassEntry())) { | 278 | if (subInterface != null && !subInterface.isEmpty()) { |
| 279 | Collection<ClassEntry> subInterface = this.interfaces.get(interfaceEntry); | 279 | ClassEntry result = resolveInterface(entry.cloneToNewClass(interfaceEntry)); |
| 280 | if (subInterface != null && !subInterface.isEmpty()) | 280 | if (result != null) |
| 281 | { | 281 | return result; |
| 282 | ClassEntry result = resolveInterface(entry.cloneToNewClass(interfaceEntry)); | 282 | } |
| 283 | if (result != null) | 283 | ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry)); |
| 284 | return result; | 284 | if (resolvedClassEntry != null) { |
| 285 | } | 285 | return resolvedClassEntry; |
| 286 | ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry)); | 286 | } |
| 287 | if (resolvedClassEntry != null) { | 287 | } |
| 288 | return resolvedClassEntry; | 288 | return null; |
| 289 | } | 289 | } |
| 290 | } | 290 | |
| 291 | return null; | 291 | private boolean isJre(ClassEntry classEntry) { |
| 292 | } | 292 | String packageName = classEntry.getPackageName(); |
| 293 | 293 | return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); | |
| 294 | private boolean isJre(ClassEntry classEntry) { | 294 | } |
| 295 | String packageName = classEntry.getPackageName(); | ||
| 296 | return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); | ||
| 297 | } | ||
| 298 | } | 295 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java index cc025da..c98fb9e 100644 --- a/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/TreeDumpVisitor.java | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 12 | 13 | ||
| 13 | import com.strobel.componentmodel.Key; | 14 | import com.strobel.componentmodel.Key; |
| @@ -19,420 +20,420 @@ import java.nio.charset.Charset; | |||
| 19 | 20 | ||
| 20 | public class TreeDumpVisitor implements IAstVisitor<Void, Void> { | 21 | public class TreeDumpVisitor implements IAstVisitor<Void, Void> { |
| 21 | 22 | ||
| 22 | private File file; | 23 | private File file; |
| 23 | private Writer out; | 24 | private Writer out; |
| 24 | 25 | ||
| 25 | public TreeDumpVisitor(File file) { | 26 | public TreeDumpVisitor(File file) { |
| 26 | this.file = file; | 27 | this.file = file; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | @Override | 30 | @Override |
| 30 | public Void visitCompilationUnit(CompilationUnit node, Void ignored) { | 31 | public Void visitCompilationUnit(CompilationUnit node, Void ignored) { |
| 31 | try { | 32 | try { |
| 32 | out = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8")); | 33 | out = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8")); |
| 33 | recurse(node, ignored); | 34 | recurse(node, ignored); |
| 34 | out.close(); | 35 | out.close(); |
| 35 | return null; | 36 | return null; |
| 36 | } catch (IOException ex) { | 37 | } catch (IOException ex) { |
| 37 | throw new Error(ex); | 38 | throw new Error(ex); |
| 38 | } | 39 | } |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | private Void recurse(AstNode node, Void ignored) { | 42 | private Void recurse(AstNode node, Void ignored) { |
| 42 | // show the tree | 43 | // show the tree |
| 43 | try { | 44 | try { |
| 44 | out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n"); | 45 | out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n"); |
| 45 | } catch (IOException ex) { | 46 | } catch (IOException ex) { |
| 46 | throw new Error(ex); | 47 | throw new Error(ex); |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | // recurse | 50 | // recurse |
| 50 | for (final AstNode child : node.getChildren()) { | 51 | for (final AstNode child : node.getChildren()) { |
| 51 | child.acceptVisitor(this, ignored); | 52 | child.acceptVisitor(this, ignored); |
| 52 | } | 53 | } |
| 53 | return null; | 54 | return null; |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | private String getText(AstNode node) { | 57 | private String getText(AstNode node) { |
| 57 | if (node instanceof Identifier) { | 58 | if (node instanceof Identifier) { |
| 58 | return "\"" + ((Identifier) node).getName() + "\""; | 59 | return "\"" + ((Identifier) node).getName() + "\""; |
| 59 | } | 60 | } |
| 60 | return ""; | 61 | return ""; |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | private String dumpUserData(AstNode node) { | 64 | private String dumpUserData(AstNode node) { |
| 64 | StringBuilder buf = new StringBuilder(); | 65 | StringBuilder buf = new StringBuilder(); |
| 65 | for (Key<?> key : Keys.ALL_KEYS) { | 66 | for (Key<?> key : Keys.ALL_KEYS) { |
| 66 | Object val = node.getUserData(key); | 67 | Object val = node.getUserData(key); |
| 67 | if (val != null) { | 68 | if (val != null) { |
| 68 | buf.append(String.format(" [%s=%s]", key, val)); | 69 | buf.append(String.format(" [%s=%s]", key, val)); |
| 69 | } | 70 | } |
| 70 | } | 71 | } |
| 71 | return buf.toString(); | 72 | return buf.toString(); |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | private String getIndent(AstNode node) { | 75 | private String getIndent(AstNode node) { |
| 75 | StringBuilder buf = new StringBuilder(); | 76 | StringBuilder buf = new StringBuilder(); |
| 76 | int depth = getDepth(node); | 77 | int depth = getDepth(node); |
| 77 | for (int i = 0; i < depth; i++) { | 78 | for (int i = 0; i < depth; i++) { |
| 78 | buf.append("\t"); | 79 | buf.append("\t"); |
| 79 | } | 80 | } |
| 80 | return buf.toString(); | 81 | return buf.toString(); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | private int getDepth(AstNode node) { | 84 | private int getDepth(AstNode node) { |
| 84 | int depth = -1; | 85 | int depth = -1; |
| 85 | while (node != null) { | 86 | while (node != null) { |
| 86 | depth++; | 87 | depth++; |
| 87 | node = node.getParent(); | 88 | node = node.getParent(); |
| 88 | } | 89 | } |
| 89 | return depth; | 90 | return depth; |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | // OVERRIDES WE DON'T CARE ABOUT | 93 | // OVERRIDES WE DON'T CARE ABOUT |
| 93 | 94 | ||
| 94 | @Override | 95 | @Override |
| 95 | public Void visitInvocationExpression(InvocationExpression node, Void ignored) { | 96 | public Void visitInvocationExpression(InvocationExpression node, Void ignored) { |
| 96 | return recurse(node, ignored); | 97 | return recurse(node, ignored); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | @Override | 100 | @Override |
| 100 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) { | 101 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) { |
| 101 | return recurse(node, ignored); | 102 | return recurse(node, ignored); |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | @Override | 105 | @Override |
| 105 | public Void visitSimpleType(SimpleType node, Void ignored) { | 106 | public Void visitSimpleType(SimpleType node, Void ignored) { |
| 106 | return recurse(node, ignored); | 107 | return recurse(node, ignored); |
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | @Override | 110 | @Override |
| 110 | public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) { | 111 | public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) { |
| 111 | return recurse(node, ignored); | 112 | return recurse(node, ignored); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | @Override | 115 | @Override |
| 115 | public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) { | 116 | public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) { |
| 116 | return recurse(node, ignored); | 117 | return recurse(node, ignored); |
| 117 | } | 118 | } |
| 118 | 119 | ||
| 119 | @Override | 120 | @Override |
| 120 | public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) { | 121 | public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) { |
| 121 | return recurse(node, ignored); | 122 | return recurse(node, ignored); |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | @Override | 125 | @Override |
| 125 | public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) { | 126 | public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) { |
| 126 | return recurse(node, ignored); | 127 | return recurse(node, ignored); |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | @Override | 130 | @Override |
| 130 | public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) { | 131 | public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) { |
| 131 | return recurse(node, ignored); | 132 | return recurse(node, ignored); |
| 132 | } | 133 | } |
| 133 | 134 | ||
| 134 | @Override | 135 | @Override |
| 135 | public Void visitComment(Comment node, Void ignored) { | 136 | public Void visitComment(Comment node, Void ignored) { |
| 136 | return recurse(node, ignored); | 137 | return recurse(node, ignored); |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 139 | @Override | 140 | @Override |
| 140 | public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) { | 141 | public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) { |
| 141 | return recurse(node, ignored); | 142 | return recurse(node, ignored); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | @Override | 145 | @Override |
| 145 | public Void visitTypeReference(TypeReferenceExpression node, Void ignored) { | 146 | public Void visitTypeReference(TypeReferenceExpression node, Void ignored) { |
| 146 | return recurse(node, ignored); | 147 | return recurse(node, ignored); |
| 147 | } | 148 | } |
| 148 | 149 | ||
| 149 | @Override | 150 | @Override |
| 150 | public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) { | 151 | public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) { |
| 151 | return recurse(node, ignored); | 152 | return recurse(node, ignored); |
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | @Override | 155 | @Override |
| 155 | public Void visitIdentifier(Identifier node, Void ignored) { | 156 | public Void visitIdentifier(Identifier node, Void ignored) { |
| 156 | return recurse(node, ignored); | 157 | return recurse(node, ignored); |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 159 | @Override | 160 | @Override |
| 160 | public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) { | 161 | public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) { |
| 161 | return recurse(node, ignored); | 162 | return recurse(node, ignored); |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | @Override | 165 | @Override |
| 165 | public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) { | 166 | public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) { |
| 166 | return recurse(node, ignored); | 167 | return recurse(node, ignored); |
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | @Override | 170 | @Override |
| 170 | public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) { | 171 | public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) { |
| 171 | return recurse(node, ignored); | 172 | return recurse(node, ignored); |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 174 | @Override | 175 | @Override |
| 175 | public Void visitClassOfExpression(ClassOfExpression node, Void ignored) { | 176 | public Void visitClassOfExpression(ClassOfExpression node, Void ignored) { |
| 176 | return recurse(node, ignored); | 177 | return recurse(node, ignored); |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | @Override | 180 | @Override |
| 180 | public Void visitBlockStatement(BlockStatement node, Void ignored) { | 181 | public Void visitBlockStatement(BlockStatement node, Void ignored) { |
| 181 | return recurse(node, ignored); | 182 | return recurse(node, ignored); |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | @Override | 185 | @Override |
| 185 | public Void visitExpressionStatement(ExpressionStatement node, Void ignored) { | 186 | public Void visitExpressionStatement(ExpressionStatement node, Void ignored) { |
| 186 | return recurse(node, ignored); | 187 | return recurse(node, ignored); |
| 187 | } | 188 | } |
| 188 | 189 | ||
| 189 | @Override | 190 | @Override |
| 190 | public Void visitBreakStatement(BreakStatement node, Void ignored) { | 191 | public Void visitBreakStatement(BreakStatement node, Void ignored) { |
| 191 | return recurse(node, ignored); | 192 | return recurse(node, ignored); |
| 192 | } | 193 | } |
| 193 | 194 | ||
| 194 | @Override | 195 | @Override |
| 195 | public Void visitContinueStatement(ContinueStatement node, Void ignored) { | 196 | public Void visitContinueStatement(ContinueStatement node, Void ignored) { |
| 196 | return recurse(node, ignored); | 197 | return recurse(node, ignored); |
| 197 | } | 198 | } |
| 198 | 199 | ||
| 199 | @Override | 200 | @Override |
| 200 | public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) { | 201 | public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) { |
| 201 | return recurse(node, ignored); | 202 | return recurse(node, ignored); |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 204 | @Override | 205 | @Override |
| 205 | public Void visitEmptyStatement(EmptyStatement node, Void ignored) { | 206 | public Void visitEmptyStatement(EmptyStatement node, Void ignored) { |
| 206 | return recurse(node, ignored); | 207 | return recurse(node, ignored); |
| 207 | } | 208 | } |
| 208 | 209 | ||
| 209 | @Override | 210 | @Override |
| 210 | public Void visitIfElseStatement(IfElseStatement node, Void ignored) { | 211 | public Void visitIfElseStatement(IfElseStatement node, Void ignored) { |
| 211 | return recurse(node, ignored); | 212 | return recurse(node, ignored); |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 214 | @Override | 215 | @Override |
| 215 | public Void visitLabelStatement(LabelStatement node, Void ignored) { | 216 | public Void visitLabelStatement(LabelStatement node, Void ignored) { |
| 216 | return recurse(node, ignored); | 217 | return recurse(node, ignored); |
| 217 | } | 218 | } |
| 218 | 219 | ||
| 219 | @Override | 220 | @Override |
| 220 | public Void visitLabeledStatement(LabeledStatement node, Void ignored) { | 221 | public Void visitLabeledStatement(LabeledStatement node, Void ignored) { |
| 221 | return recurse(node, ignored); | 222 | return recurse(node, ignored); |
| 222 | } | 223 | } |
| 223 | 224 | ||
| 224 | @Override | 225 | @Override |
| 225 | public Void visitReturnStatement(ReturnStatement node, Void ignored) { | 226 | public Void visitReturnStatement(ReturnStatement node, Void ignored) { |
| 226 | return recurse(node, ignored); | 227 | return recurse(node, ignored); |
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | @Override | 230 | @Override |
| 230 | public Void visitSwitchStatement(SwitchStatement node, Void ignored) { | 231 | public Void visitSwitchStatement(SwitchStatement node, Void ignored) { |
| 231 | return recurse(node, ignored); | 232 | return recurse(node, ignored); |
| 232 | } | 233 | } |
| 233 | 234 | ||
| 234 | @Override | 235 | @Override |
| 235 | public Void visitSwitchSection(SwitchSection node, Void ignored) { | 236 | public Void visitSwitchSection(SwitchSection node, Void ignored) { |
| 236 | return recurse(node, ignored); | 237 | return recurse(node, ignored); |
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | @Override | 240 | @Override |
| 240 | public Void visitCaseLabel(CaseLabel node, Void ignored) { | 241 | public Void visitCaseLabel(CaseLabel node, Void ignored) { |
| 241 | return recurse(node, ignored); | 242 | return recurse(node, ignored); |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 244 | @Override | 245 | @Override |
| 245 | public Void visitThrowStatement(ThrowStatement node, Void ignored) { | 246 | public Void visitThrowStatement(ThrowStatement node, Void ignored) { |
| 246 | return recurse(node, ignored); | 247 | return recurse(node, ignored); |
| 247 | } | 248 | } |
| 248 | 249 | ||
| 249 | @Override | 250 | @Override |
| 250 | public Void visitCatchClause(CatchClause node, Void ignored) { | 251 | public Void visitCatchClause(CatchClause node, Void ignored) { |
| 251 | return recurse(node, ignored); | 252 | return recurse(node, ignored); |
| 252 | } | 253 | } |
| 253 | 254 | ||
| 254 | @Override | 255 | @Override |
| 255 | public Void visitAnnotation(Annotation node, Void ignored) { | 256 | public Void visitAnnotation(Annotation node, Void ignored) { |
| 256 | return recurse(node, ignored); | 257 | return recurse(node, ignored); |
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | @Override | 260 | @Override |
| 260 | public Void visitNewLine(NewLineNode node, Void ignored) { | 261 | public Void visitNewLine(NewLineNode node, Void ignored) { |
| 261 | return recurse(node, ignored); | 262 | return recurse(node, ignored); |
| 262 | } | 263 | } |
| 263 | 264 | ||
| 264 | @Override | 265 | @Override |
| 265 | public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) { | 266 | public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) { |
| 266 | return recurse(node, ignored); | 267 | return recurse(node, ignored); |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 269 | @Override | 270 | @Override |
| 270 | public Void visitVariableInitializer(VariableInitializer node, Void ignored) { | 271 | public Void visitVariableInitializer(VariableInitializer node, Void ignored) { |
| 271 | return recurse(node, ignored); | 272 | return recurse(node, ignored); |
| 272 | } | 273 | } |
| 273 | 274 | ||
| 274 | @Override | 275 | @Override |
| 275 | public Void visitText(TextNode node, Void ignored) { | 276 | public Void visitText(TextNode node, Void ignored) { |
| 276 | return recurse(node, ignored); | 277 | return recurse(node, ignored); |
| 277 | } | 278 | } |
| 278 | 279 | ||
| 279 | @Override | 280 | @Override |
| 280 | public Void visitImportDeclaration(ImportDeclaration node, Void ignored) { | 281 | public Void visitImportDeclaration(ImportDeclaration node, Void ignored) { |
| 281 | return recurse(node, ignored); | 282 | return recurse(node, ignored); |
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | @Override | 285 | @Override |
| 285 | public Void visitInitializerBlock(InstanceInitializer node, Void ignored) { | 286 | public Void visitInitializerBlock(InstanceInitializer node, Void ignored) { |
| 286 | return recurse(node, ignored); | 287 | return recurse(node, ignored); |
| 287 | } | 288 | } |
| 288 | 289 | ||
| 289 | @Override | 290 | @Override |
| 290 | public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) { | 291 | public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) { |
| 291 | return recurse(node, ignored); | 292 | return recurse(node, ignored); |
| 292 | } | 293 | } |
| 293 | 294 | ||
| 294 | @Override | 295 | @Override |
| 295 | public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) { | 296 | public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) { |
| 296 | return recurse(node, ignored); | 297 | return recurse(node, ignored); |
| 297 | } | 298 | } |
| 298 | 299 | ||
| 299 | @Override | 300 | @Override |
| 300 | public Void visitArraySpecifier(ArraySpecifier node, Void ignored) { | 301 | public Void visitArraySpecifier(ArraySpecifier node, Void ignored) { |
| 301 | return recurse(node, ignored); | 302 | return recurse(node, ignored); |
| 302 | } | 303 | } |
| 303 | 304 | ||
| 304 | @Override | 305 | @Override |
| 305 | public Void visitComposedType(ComposedType node, Void ignored) { | 306 | public Void visitComposedType(ComposedType node, Void ignored) { |
| 306 | return recurse(node, ignored); | 307 | return recurse(node, ignored); |
| 307 | } | 308 | } |
| 308 | 309 | ||
| 309 | @Override | 310 | @Override |
| 310 | public Void visitWhileStatement(WhileStatement node, Void ignored) { | 311 | public Void visitWhileStatement(WhileStatement node, Void ignored) { |
| 311 | return recurse(node, ignored); | 312 | return recurse(node, ignored); |
| 312 | } | 313 | } |
| 313 | 314 | ||
| 314 | @Override | 315 | @Override |
| 315 | public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) { | 316 | public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) { |
| 316 | return recurse(node, ignored); | 317 | return recurse(node, ignored); |
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | @Override | 320 | @Override |
| 320 | public Void visitCastExpression(CastExpression node, Void ignored) { | 321 | public Void visitCastExpression(CastExpression node, Void ignored) { |
| 321 | return recurse(node, ignored); | 322 | return recurse(node, ignored); |
| 322 | } | 323 | } |
| 323 | 324 | ||
| 324 | @Override | 325 | @Override |
| 325 | public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) { | 326 | public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) { |
| 326 | return recurse(node, ignored); | 327 | return recurse(node, ignored); |
| 327 | } | 328 | } |
| 328 | 329 | ||
| 329 | @Override | 330 | @Override |
| 330 | public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) { | 331 | public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) { |
| 331 | return recurse(node, ignored); | 332 | return recurse(node, ignored); |
| 332 | } | 333 | } |
| 333 | 334 | ||
| 334 | @Override | 335 | @Override |
| 335 | public Void visitIndexerExpression(IndexerExpression node, Void ignored) { | 336 | public Void visitIndexerExpression(IndexerExpression node, Void ignored) { |
| 336 | return recurse(node, ignored); | 337 | return recurse(node, ignored); |
| 337 | } | 338 | } |
| 338 | 339 | ||
| 339 | @Override | 340 | @Override |
| 340 | public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) { | 341 | public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) { |
| 341 | return recurse(node, ignored); | 342 | return recurse(node, ignored); |
| 342 | } | 343 | } |
| 343 | 344 | ||
| 344 | @Override | 345 | @Override |
| 345 | public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) { | 346 | public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) { |
| 346 | return recurse(node, ignored); | 347 | return recurse(node, ignored); |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 349 | @Override | 350 | @Override |
| 350 | public Void visitConditionalExpression(ConditionalExpression node, Void ignored) { | 351 | public Void visitConditionalExpression(ConditionalExpression node, Void ignored) { |
| 351 | return recurse(node, ignored); | 352 | return recurse(node, ignored); |
| 352 | } | 353 | } |
| 353 | 354 | ||
| 354 | @Override | 355 | @Override |
| 355 | public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) { | 356 | public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) { |
| 356 | return recurse(node, ignored); | 357 | return recurse(node, ignored); |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 359 | @Override | 360 | @Override |
| 360 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) { | 361 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) { |
| 361 | return recurse(node, ignored); | 362 | return recurse(node, ignored); |
| 362 | } | 363 | } |
| 363 | 364 | ||
| 364 | @Override | 365 | @Override |
| 365 | public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) { | 366 | public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) { |
| 366 | return recurse(node, ignored); | 367 | return recurse(node, ignored); |
| 367 | } | 368 | } |
| 368 | 369 | ||
| 369 | @Override | 370 | @Override |
| 370 | public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) { | 371 | public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) { |
| 371 | return recurse(node, ignored); | 372 | return recurse(node, ignored); |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | @Override | 375 | @Override |
| 375 | public Void visitForStatement(ForStatement node, Void ignored) { | 376 | public Void visitForStatement(ForStatement node, Void ignored) { |
| 376 | return recurse(node, ignored); | 377 | return recurse(node, ignored); |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | @Override | 380 | @Override |
| 380 | public Void visitForEachStatement(ForEachStatement node, Void ignored) { | 381 | public Void visitForEachStatement(ForEachStatement node, Void ignored) { |
| 381 | return recurse(node, ignored); | 382 | return recurse(node, ignored); |
| 382 | } | 383 | } |
| 383 | 384 | ||
| 384 | @Override | 385 | @Override |
| 385 | public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) { | 386 | public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) { |
| 386 | return recurse(node, ignored); | 387 | return recurse(node, ignored); |
| 387 | } | 388 | } |
| 388 | 389 | ||
| 389 | @Override | 390 | @Override |
| 390 | public Void visitGotoStatement(GotoStatement node, Void ignored) { | 391 | public Void visitGotoStatement(GotoStatement node, Void ignored) { |
| 391 | return recurse(node, ignored); | 392 | return recurse(node, ignored); |
| 392 | } | 393 | } |
| 393 | 394 | ||
| 394 | @Override | 395 | @Override |
| 395 | public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) { | 396 | public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) { |
| 396 | return recurse(node, ignored); | 397 | return recurse(node, ignored); |
| 397 | } | 398 | } |
| 398 | 399 | ||
| 399 | @Override | 400 | @Override |
| 400 | public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) { | 401 | public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) { |
| 401 | return recurse(node, ignored); | 402 | return recurse(node, ignored); |
| 402 | } | 403 | } |
| 403 | 404 | ||
| 404 | @Override | 405 | @Override |
| 405 | public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) { | 406 | public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) { |
| 406 | return recurse(node, ignored); | 407 | return recurse(node, ignored); |
| 407 | } | 408 | } |
| 408 | 409 | ||
| 409 | @Override | 410 | @Override |
| 410 | public Void visitWildcardType(WildcardType node, Void ignored) { | 411 | public Void visitWildcardType(WildcardType node, Void ignored) { |
| 411 | return recurse(node, ignored); | 412 | return recurse(node, ignored); |
| 412 | } | 413 | } |
| 413 | 414 | ||
| 414 | @Override | 415 | @Override |
| 415 | public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) { | 416 | public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) { |
| 416 | return recurse(node, ignored); | 417 | return recurse(node, ignored); |
| 417 | } | 418 | } |
| 418 | 419 | ||
| 419 | @Override | 420 | @Override |
| 420 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) { | 421 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) { |
| 421 | return recurse(node, ignored); | 422 | return recurse(node, ignored); |
| 422 | } | 423 | } |
| 423 | 424 | ||
| 424 | @Override | 425 | @Override |
| 425 | public Void visitAssertStatement(AssertStatement node, Void ignored) { | 426 | public Void visitAssertStatement(AssertStatement node, Void ignored) { |
| 426 | return recurse(node, ignored); | 427 | return recurse(node, ignored); |
| 427 | } | 428 | } |
| 428 | 429 | ||
| 429 | @Override | 430 | @Override |
| 430 | public Void visitLambdaExpression(LambdaExpression node, Void ignored) { | 431 | public Void visitLambdaExpression(LambdaExpression node, Void ignored) { |
| 431 | return recurse(node, ignored); | 432 | return recurse(node, ignored); |
| 432 | } | 433 | } |
| 433 | 434 | ||
| 434 | @Override | 435 | @Override |
| 435 | public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) { | 436 | public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) { |
| 436 | return recurse(node, ignored); | 437 | return recurse(node, ignored); |
| 437 | } | 438 | } |
| 438 | } | 439 | } |