summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/analysis
diff options
context:
space:
mode:
authorGravatar jeff2015-01-13 23:25:04 -0500
committerGravatar jeff2015-01-13 23:25:04 -0500
commit959cb5fd4f9586ec3bd265b452fe25fe1db82e3f (patch)
treebdd8a2c52c2fe053ba3460614bde8542e5378dbe /src/cuchaz/enigma/analysis
parentgot rid of gradle in favor of ivy+ssjb (diff)
downloadenigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.gz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.tar.xz
enigma-fork-959cb5fd4f9586ec3bd265b452fe25fe1db82e3f.zip
source format change
don't hate me too much if you were planning a big merge. =P
Diffstat (limited to 'src/cuchaz/enigma/analysis')
-rw-r--r--src/cuchaz/enigma/analysis/Access.java30
-rw-r--r--src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java56
-rw-r--r--src/cuchaz/enigma/analysis/BridgeFixer.java51
-rw-r--r--src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java48
-rw-r--r--src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java58
-rw-r--r--src/cuchaz/enigma/analysis/EntryReference.java94
-rw-r--r--src/cuchaz/enigma/analysis/EntryRenamer.java173
-rw-r--r--src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java65
-rw-r--r--src/cuchaz/enigma/analysis/JarClassIterator.java107
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java820
-rw-r--r--src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java66
-rw-r--r--src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java80
-rw-r--r--src/cuchaz/enigma/analysis/ReferenceTreeNode.java3
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java144
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java159
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java97
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexVisitor.java370
-rw-r--r--src/cuchaz/enigma/analysis/Token.java41
-rw-r--r--src/cuchaz/enigma/analysis/TranslationIndex.java93
-rw-r--r--src/cuchaz/enigma/analysis/TreeDumpVisitor.java424
20 files changed, 1186 insertions, 1793 deletions
diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java
index e35bb21..8d3409a 100644
--- a/src/cuchaz/enigma/analysis/Access.java
+++ b/src/cuchaz/enigma/analysis/Access.java
@@ -15,37 +15,29 @@ import java.lang.reflect.Modifier;
15import javassist.CtBehavior; 15import javassist.CtBehavior;
16import javassist.CtField; 16import javassist.CtField;
17 17
18public enum Access 18public enum Access {
19{ 19
20 Public, 20 Public,
21 Protected, 21 Protected,
22 Private; 22 Private;
23 23
24 public static Access get( CtBehavior behavior ) 24 public static Access get(CtBehavior behavior) {
25 { 25 return get(behavior.getModifiers());
26 return get( behavior.getModifiers() );
27 } 26 }
28 27
29 public static Access get( CtField field ) 28 public static Access get(CtField field) {
30 { 29 return get(field.getModifiers());
31 return get( field.getModifiers() );
32 } 30 }
33 31
34 public static Access get( int modifiers ) 32 public static Access get(int modifiers) {
35 { 33 if (Modifier.isPublic(modifiers)) {
36 if( Modifier.isPublic( modifiers ) )
37 {
38 return Public; 34 return Public;
39 } 35 } else if (Modifier.isProtected(modifiers)) {
40 else if( Modifier.isProtected( modifiers ) )
41 {
42 return Protected; 36 return Protected;
43 } 37 } else if (Modifier.isPrivate(modifiers)) {
44 else if( Modifier.isPrivate( modifiers ) )
45 {
46 return Private; 38 return Private;
47 } 39 }
48 // assume public by default 40 // assume public by default
49 return Public; 41 return Public;
50 } 42 }
51} \ No newline at end of file 43}
diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
index 20f1d47..9adac5e 100644
--- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java
@@ -21,8 +21,8 @@ import cuchaz.enigma.mapping.BehaviorEntry;
21import cuchaz.enigma.mapping.Entry; 21import cuchaz.enigma.mapping.Entry;
22import cuchaz.enigma.mapping.Translator; 22import cuchaz.enigma.mapping.Translator;
23 23
24public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<BehaviorEntry,BehaviorEntry> 24public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<BehaviorEntry,BehaviorEntry> {
25{ 25
26 private static final long serialVersionUID = -3658163700783307520L; 26 private static final long serialVersionUID = -3658163700783307520L;
27 27
28 private Translator m_deobfuscatingTranslator; 28 private Translator m_deobfuscatingTranslator;
@@ -30,15 +30,13 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements
30 private EntryReference<BehaviorEntry,BehaviorEntry> m_reference; 30 private EntryReference<BehaviorEntry,BehaviorEntry> m_reference;
31 private Access m_access; 31 private Access m_access;
32 32
33 public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) 33 public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) {
34 {
35 m_deobfuscatingTranslator = deobfuscatingTranslator; 34 m_deobfuscatingTranslator = deobfuscatingTranslator;
36 m_entry = entry; 35 m_entry = entry;
37 m_reference = null; 36 m_reference = null;
38 } 37 }
39 38
40 public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference<BehaviorEntry,BehaviorEntry> reference, Access access ) 39 public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<BehaviorEntry,BehaviorEntry> reference, Access access) {
41 {
42 m_deobfuscatingTranslator = deobfuscatingTranslator; 40 m_deobfuscatingTranslator = deobfuscatingTranslator;
43 m_entry = reference.entry; 41 m_entry = reference.entry;
44 m_reference = reference; 42 m_reference = reference;
@@ -46,60 +44,48 @@ public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements
46 } 44 }
47 45
48 @Override 46 @Override
49 public BehaviorEntry getEntry( ) 47 public BehaviorEntry getEntry() {
50 {
51 return m_entry; 48 return m_entry;
52 } 49 }
53 50
54 @Override 51 @Override
55 public EntryReference<BehaviorEntry,BehaviorEntry> getReference( ) 52 public EntryReference<BehaviorEntry,BehaviorEntry> getReference() {
56 {
57 return m_reference; 53 return m_reference;
58 } 54 }
59 55
60 @Override 56 @Override
61 public String toString( ) 57 public String toString() {
62 { 58 if (m_reference != null) {
63 if( m_reference != null ) 59 return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access);
64 {
65 return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access );
66 } 60 }
67 return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); 61 return m_deobfuscatingTranslator.translateEntry(m_entry).toString();
68 } 62 }
69 63
70 public void load( JarIndex index, boolean recurse ) 64 public void load(JarIndex index, boolean recurse) {
71 {
72 // get all the child nodes 65 // get all the child nodes
73 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( m_entry ) ) 66 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(m_entry)) {
74 { 67 add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry)));
75 add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) );
76 } 68 }
77 69
78 if( recurse && children != null ) 70 if (recurse && children != null) {
79 { 71 for (Object child : children) {
80 for( Object child : children ) 72 if (child instanceof BehaviorReferenceTreeNode) {
81 {
82 if( child instanceof BehaviorReferenceTreeNode )
83 {
84 BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; 73 BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child;
85 74
86 // don't recurse into ancestor 75 // don't recurse into ancestor
87 Set<Entry> ancestors = Sets.newHashSet(); 76 Set<Entry> ancestors = Sets.newHashSet();
88 TreeNode n = (TreeNode)node; 77 TreeNode n = (TreeNode)node;
89 while( n.getParent() != null ) 78 while (n.getParent() != null) {
90 {
91 n = n.getParent(); 79 n = n.getParent();
92 if( n instanceof BehaviorReferenceTreeNode ) 80 if (n instanceof BehaviorReferenceTreeNode) {
93 { 81 ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry());
94 ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry() );
95 } 82 }
96 } 83 }
97 if( ancestors.contains( node.getEntry() ) ) 84 if (ancestors.contains(node.getEntry())) {
98 {
99 continue; 85 continue;
100 } 86 }
101 87
102 node.load( index, true ); 88 node.load(index, true);
103 } 89 }
104 } 90 }
105 } 91 }
diff --git a/src/cuchaz/enigma/analysis/BridgeFixer.java b/src/cuchaz/enigma/analysis/BridgeFixer.java
index 112b864..ad23b00 100644
--- a/src/cuchaz/enigma/analysis/BridgeFixer.java
+++ b/src/cuchaz/enigma/analysis/BridgeFixer.java
@@ -20,61 +20,48 @@ import cuchaz.enigma.mapping.BehaviorEntryFactory;
20import cuchaz.enigma.mapping.ClassEntry; 20import cuchaz.enigma.mapping.ClassEntry;
21import cuchaz.enigma.mapping.MethodEntry; 21import cuchaz.enigma.mapping.MethodEntry;
22 22
23public class BridgeFixer 23public class BridgeFixer {
24{ 24
25 private JarIndex m_index; 25 private JarIndex m_index;
26 26
27 public BridgeFixer( JarIndex index ) 27 public BridgeFixer(JarIndex index) {
28 {
29 m_index = index; 28 m_index = index;
30 } 29 }
31 30
32 public void fixBridges( CtClass c ) 31 public void fixBridges(CtClass c) {
33 {
34 // rename declared methods 32 // rename declared methods
35 for( CtMethod method : c.getDeclaredMethods() ) 33 for (CtMethod method : c.getDeclaredMethods()) {
36 {
37 // get the method entry 34 // get the method entry
38 MethodEntry methodEntry = new MethodEntry( 35 MethodEntry methodEntry = new MethodEntry(
39 new ClassEntry( Descriptor.toJvmName( c.getName() ) ), 36 new ClassEntry(Descriptor.toJvmName(c.getName())),
40 method.getName(), 37 method.getName(),
41 method.getSignature() 38 method.getSignature()
42 ); 39 );
43 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); 40 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry);
44 if( bridgeMethodEntry != null ) 41 if (bridgeMethodEntry != null) {
45 {
46 // fix this bridged method 42 // fix this bridged method
47 method.setName( bridgeMethodEntry.getName() ); 43 method.setName(bridgeMethodEntry.getName());
48 } 44 }
49 } 45 }
50 46
51 // rename method references 47 // rename method references
52 // translate all the field and method references in the code by editing the constant pool 48 // translate all the field and method references in the code by editing the constant pool
53 ConstPool constants = c.getClassFile().getConstPool(); 49 ConstPool constants = c.getClassFile().getConstPool();
54 ConstPoolEditor editor = new ConstPoolEditor( constants ); 50 ConstPoolEditor editor = new ConstPoolEditor(constants);
55 for( int i=1; i<constants.getSize(); i++ ) 51 for (int i = 1; i < constants.getSize(); i++) {
56 { 52 switch (constants.getTag(i)) {
57 switch( constants.getTag( i ) )
58 {
59 case ConstPool.CONST_Methodref: 53 case ConstPool.CONST_Methodref:
60 case ConstPool.CONST_InterfaceMethodref: 54 case ConstPool.CONST_InterfaceMethodref: {
61 { 55 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(Descriptor.toJvmName(editor.getMemberrefClassname(i)), editor.getMemberrefName(i), editor.getMemberrefType(i));
62 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(
63 Descriptor.toJvmName( editor.getMemberrefClassname( i ) ),
64 editor.getMemberrefName( i ),
65 editor.getMemberrefType( i )
66 );
67 56
68 if( behaviorEntry instanceof MethodEntry ) 57 if (behaviorEntry instanceof MethodEntry) {
69 {
70 MethodEntry methodEntry = (MethodEntry)behaviorEntry; 58 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
71 59
72 // translate the name and type 60 // translate the name and type
73 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod( methodEntry ); 61 MethodEntry bridgeMethodEntry = m_index.getBridgeMethod(methodEntry);
74 if( bridgeMethodEntry != null ) 62 if (bridgeMethodEntry != null) {
75 {
76 // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT 63 // FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT FIXIT
77 editor.changeMemberrefNameAndType( i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature() ); 64 editor.changeMemberrefNameAndType(i, bridgeMethodEntry.getName(), bridgeMethodEntry.getSignature());
78 } 65 }
79 } 66 }
80 } 67 }
diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
index 4e9dd52..49aac5f 100644
--- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
@@ -20,70 +20,58 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class ClassImplementationsTreeNode extends DefaultMutableTreeNode 23public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 3112703459157851912L; 25 private static final long serialVersionUID = 3112703459157851912L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private ClassEntry m_entry; 28 private ClassEntry m_entry;
29 29
30 public ClassImplementationsTreeNode( Translator deobfuscatingTranslator, ClassEntry entry ) 30 public ClassImplementationsTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) {
31 {
32 m_deobfuscatingTranslator = deobfuscatingTranslator; 31 m_deobfuscatingTranslator = deobfuscatingTranslator;
33 m_entry = entry; 32 m_entry = entry;
34 } 33 }
35 34
36 public ClassEntry getClassEntry( ) 35 public ClassEntry getClassEntry() {
37 {
38 return m_entry; 36 return m_entry;
39 } 37 }
40 38
41 public String getDeobfClassName( ) 39 public String getDeobfClassName() {
42 { 40 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
43 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
44 } 41 }
45 42
46 @Override 43 @Override
47 public String toString( ) 44 public String toString() {
48 {
49 String className = getDeobfClassName(); 45 String className = getDeobfClassName();
50 if( className == null ) 46 if (className == null) {
51 {
52 className = m_entry.getClassName(); 47 className = m_entry.getClassName();
53 } 48 }
54 return className; 49 return className;
55 } 50 }
56 51
57 public void load( JarIndex index ) 52 public void load(JarIndex index) {
58 {
59 // get all method implementations 53 // get all method implementations
60 List<ClassImplementationsTreeNode> nodes = Lists.newArrayList(); 54 List<ClassImplementationsTreeNode> nodes = Lists.newArrayList();
61 for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) 55 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) {
62 { 56 nodes.add(new ClassImplementationsTreeNode(m_deobfuscatingTranslator, new ClassEntry(implementingClassName)));
63 nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) );
64 } 57 }
65 58
66 // add them to this node 59 // add them to this node
67 for( ClassImplementationsTreeNode node : nodes ) 60 for (ClassImplementationsTreeNode node : nodes) {
68 { 61 this.add(node);
69 this.add( node );
70 } 62 }
71 } 63 }
72 64
73 public static ClassImplementationsTreeNode findNode( ClassImplementationsTreeNode node, MethodEntry entry ) 65 public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) {
74 {
75 // is this the node? 66 // is this the node?
76 if( node.m_entry.equals( entry ) ) 67 if (node.m_entry.equals(entry)) {
77 {
78 return node; 68 return node;
79 } 69 }
80 70
81 // recurse 71 // recurse
82 for( int i=0; i<node.getChildCount(); i++ ) 72 for (int i = 0; i < node.getChildCount(); i++) {
83 { 73 ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode)node.getChildAt(i), entry);
84 ClassImplementationsTreeNode foundNode = findNode( (ClassImplementationsTreeNode)node.getChildAt( i ), entry ); 74 if (foundNode != null) {
85 if( foundNode != null )
86 {
87 return foundNode; 75 return foundNode;
88 } 76 }
89 } 77 }
diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
index d3fc9dc..b132305 100644
--- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
@@ -19,78 +19,64 @@ import com.google.common.collect.Lists;
19import cuchaz.enigma.mapping.ClassEntry; 19import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.Translator; 20import cuchaz.enigma.mapping.Translator;
21 21
22public class ClassInheritanceTreeNode extends DefaultMutableTreeNode 22public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
23{ 23
24 private static final long serialVersionUID = 4432367405826178490L; 24 private static final long serialVersionUID = 4432367405826178490L;
25 25
26 private Translator m_deobfuscatingTranslator; 26 private Translator m_deobfuscatingTranslator;
27 private String m_obfClassName; 27 private String m_obfClassName;
28 28
29 public ClassInheritanceTreeNode( Translator deobfuscatingTranslator, String obfClassName ) 29 public ClassInheritanceTreeNode(Translator deobfuscatingTranslator, String obfClassName) {
30 {
31 m_deobfuscatingTranslator = deobfuscatingTranslator; 30 m_deobfuscatingTranslator = deobfuscatingTranslator;
32 m_obfClassName = obfClassName; 31 m_obfClassName = obfClassName;
33 } 32 }
34 33
35 public String getObfClassName( ) 34 public String getObfClassName() {
36 {
37 return m_obfClassName; 35 return m_obfClassName;
38 } 36 }
39 37
40 public String getDeobfClassName( ) 38 public String getDeobfClassName() {
41 { 39 return m_deobfuscatingTranslator.translateClass(m_obfClassName);
42 return m_deobfuscatingTranslator.translateClass( m_obfClassName );
43 } 40 }
44 41
45 @Override 42 @Override
46 public String toString( ) 43 public String toString() {
47 {
48 String deobfClassName = getDeobfClassName(); 44 String deobfClassName = getDeobfClassName();
49 if( deobfClassName != null ) 45 if (deobfClassName != null) {
50 {
51 return deobfClassName; 46 return deobfClassName;
52 } 47 }
53 return m_obfClassName; 48 return m_obfClassName;
54 } 49 }
55 50
56 public void load( TranslationIndex ancestries, boolean recurse ) 51 public void load(TranslationIndex ancestries, boolean recurse) {
57 {
58 // get all the child nodes 52 // get all the child nodes
59 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); 53 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList();
60 for( String subclassName : ancestries.getSubclassNames( m_obfClassName ) ) 54 for (String subclassName : ancestries.getSubclassNames(m_obfClassName)) {
61 { 55 nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassName));
62 nodes.add( new ClassInheritanceTreeNode( m_deobfuscatingTranslator, subclassName ) );
63 } 56 }
64 57
65 // add them to this node 58 // add them to this node
66 for( ClassInheritanceTreeNode node : nodes ) 59 for (ClassInheritanceTreeNode node : nodes) {
67 { 60 this.add(node);
68 this.add( node );
69 } 61 }
70 62
71 if( recurse ) 63 if (recurse) {
72 { 64 for (ClassInheritanceTreeNode node : nodes) {
73 for( ClassInheritanceTreeNode node : nodes ) 65 node.load(ancestries, true);
74 {
75 node.load( ancestries, true );
76 } 66 }
77 } 67 }
78 } 68 }
79 69
80 public static ClassInheritanceTreeNode findNode( ClassInheritanceTreeNode node, ClassEntry entry ) 70 public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) {
81 {
82 // is this the node? 71 // is this the node?
83 if( node.getObfClassName().equals( entry.getName() ) ) 72 if (node.getObfClassName().equals(entry.getName())) {
84 {
85 return node; 73 return node;
86 } 74 }
87 75
88 // recurse 76 // recurse
89 for( int i=0; i<node.getChildCount(); i++ ) 77 for (int i = 0; i < node.getChildCount(); i++) {
90 { 78 ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode)node.getChildAt(i), entry);
91 ClassInheritanceTreeNode foundNode = findNode( (ClassInheritanceTreeNode)node.getChildAt( i ), entry ); 79 if (foundNode != null) {
92 if( foundNode != null )
93 {
94 return foundNode; 80 return foundNode;
95 } 81 }
96 } 82 }
diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java
index 0cde875..bb611df 100644
--- a/src/cuchaz/enigma/analysis/EntryReference.java
+++ b/src/cuchaz/enigma/analysis/EntryReference.java
@@ -18,74 +18,61 @@ import cuchaz.enigma.mapping.ClassEntry;
18import cuchaz.enigma.mapping.ConstructorEntry; 18import cuchaz.enigma.mapping.ConstructorEntry;
19import cuchaz.enigma.mapping.Entry; 19import cuchaz.enigma.mapping.Entry;
20 20
21public class EntryReference<E extends Entry, C extends Entry> 21public class EntryReference<E extends Entry,C extends Entry> {
22{ 22
23 private static final List<String> ConstructorNonNames = Arrays.asList( "this", "super", "static" ); 23 private static final List<String> ConstructorNonNames = Arrays.asList("this", "super", "static");
24 public E entry; 24 public E entry;
25 public C context; 25 public C context;
26 26
27 private boolean m_isNamed; 27 private boolean m_isNamed;
28 28
29 public EntryReference( E entry, String sourceName ) 29 public EntryReference(E entry, String sourceName) {
30 { 30 this(entry, sourceName, null);
31 this( entry, sourceName, null );
32 } 31 }
33 32
34 public EntryReference( E entry, String sourceName, C context ) 33 public EntryReference(E entry, String sourceName, C context) {
35 { 34 if (entry == null) {
36 if( entry == null ) 35 throw new IllegalArgumentException("Entry cannot be null!");
37 {
38 throw new IllegalArgumentException( "Entry cannot be null!" );
39 } 36 }
40 37
41 this.entry = entry; 38 this.entry = entry;
42 this.context = context; 39 this.context = context;
43 40
44 m_isNamed = sourceName != null && sourceName.length() > 0; 41 m_isNamed = sourceName != null && sourceName.length() > 0;
45 if( entry instanceof ConstructorEntry && ConstructorNonNames.contains( sourceName ) ) 42 if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) {
46 {
47 m_isNamed = false; 43 m_isNamed = false;
48 } 44 }
49 } 45 }
50 46
51 public EntryReference( E entry, C context, EntryReference<E,C> other ) 47 public EntryReference(E entry, C context, EntryReference<E,C> other) {
52 {
53 this.entry = entry; 48 this.entry = entry;
54 this.context = context; 49 this.context = context;
55 m_isNamed = other.m_isNamed; 50 m_isNamed = other.m_isNamed;
56 } 51 }
57 52
58 public ClassEntry getLocationClassEntry( ) 53 public ClassEntry getLocationClassEntry() {
59 { 54 if (context != null) {
60 if( context != null )
61 {
62 return context.getClassEntry(); 55 return context.getClassEntry();
63 } 56 }
64 return entry.getClassEntry(); 57 return entry.getClassEntry();
65 } 58 }
66 59
67 public boolean isNamed( ) 60 public boolean isNamed() {
68 {
69 return m_isNamed; 61 return m_isNamed;
70 } 62 }
71 63
72 public Entry getNameableEntry( ) 64 public Entry getNameableEntry() {
73 { 65 if (entry instanceof ConstructorEntry) {
74 if( entry instanceof ConstructorEntry )
75 {
76 // renaming a constructor really means renaming the class 66 // renaming a constructor really means renaming the class
77 return entry.getClassEntry(); 67 return entry.getClassEntry();
78 } 68 }
79 return entry; 69 return entry;
80 } 70 }
81 71
82 public String getNamableName( ) 72 public String getNamableName() {
83 { 73 if (getNameableEntry() instanceof ClassEntry) {
84 if( getNameableEntry() instanceof ClassEntry )
85 {
86 ClassEntry classEntry = (ClassEntry)getNameableEntry(); 74 ClassEntry classEntry = (ClassEntry)getNameableEntry();
87 if( classEntry.isInnerClass() ) 75 if (classEntry.isInnerClass()) {
88 {
89 // make sure we only rename the inner class name 76 // make sure we only rename the inner class name
90 return classEntry.getInnerClassName(); 77 return classEntry.getInnerClassName();
91 } 78 }
@@ -95,55 +82,44 @@ public class EntryReference<E extends Entry, C extends Entry>
95 } 82 }
96 83
97 @Override 84 @Override
98 public int hashCode( ) 85 public int hashCode() {
99 { 86 if (context != null) {
100 if( context != null ) 87 return Util.combineHashesOrdered(entry.hashCode(), context.hashCode());
101 {
102 return Util.combineHashesOrdered( entry.hashCode(), context.hashCode() );
103 } 88 }
104 return entry.hashCode(); 89 return entry.hashCode();
105 } 90 }
106 91
107 @Override 92 @Override
108 public boolean equals( Object other ) 93 public boolean equals(Object other) {
109 { 94 if (other instanceof EntryReference) {
110 if( other instanceof EntryReference ) 95 return equals((EntryReference<?,?>)other);
111 {
112 return equals( (EntryReference<?,?>)other );
113 } 96 }
114 return false; 97 return false;
115 } 98 }
116 99
117 public boolean equals( EntryReference<?,?> other ) 100 public boolean equals(EntryReference<?,?> other) {
118 {
119 // check entry first 101 // check entry first
120 boolean isEntrySame = entry.equals( other.entry ); 102 boolean isEntrySame = entry.equals(other.entry);
121 if( !isEntrySame ) 103 if (!isEntrySame) {
122 {
123 return false; 104 return false;
124 } 105 }
125 106
126 // check caller 107 // check caller
127 if( context == null && other.context == null ) 108 if (context == null && other.context == null) {
128 {
129 return true; 109 return true;
130 } 110 } else if (context != null && other.context != null) {
131 else if( context != null && other.context != null ) 111 return context.equals(other.context);
132 {
133 return context.equals( other.context );
134 } 112 }
135 return false; 113 return false;
136 } 114 }
137 115
138 @Override 116 @Override
139 public String toString( ) 117 public String toString() {
140 {
141 StringBuilder buf = new StringBuilder(); 118 StringBuilder buf = new StringBuilder();
142 buf.append( entry ); 119 buf.append(entry);
143 if( context != null ) 120 if (context != null) {
144 { 121 buf.append(" called from ");
145 buf.append( " called from " ); 122 buf.append(context);
146 buf.append( context );
147 } 123 }
148 return buf.toString(); 124 return buf.toString();
149 } 125 }
diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java
index 2d59fe9..b54489c 100644
--- a/src/cuchaz/enigma/analysis/EntryRenamer.java
+++ b/src/cuchaz/enigma/analysis/EntryRenamer.java
@@ -26,100 +26,83 @@ import cuchaz.enigma.mapping.Entry;
26import cuchaz.enigma.mapping.FieldEntry; 26import cuchaz.enigma.mapping.FieldEntry;
27import cuchaz.enigma.mapping.MethodEntry; 27import cuchaz.enigma.mapping.MethodEntry;
28 28
29public class EntryRenamer 29public class EntryRenamer {
30{ 30
31 public static <T> void renameClassesInSet( Map<String,String> renames, Set<T> set ) 31 public static <T> void renameClassesInSet(Map<String,String> renames, Set<T> set) {
32 {
33 List<T> entries = Lists.newArrayList(); 32 List<T> entries = Lists.newArrayList();
34 for( T val : set ) 33 for (T val : set) {
35 { 34 entries.add(renameClassesInThing(renames, val));
36 entries.add( renameClassesInThing( renames, val ) );
37 } 35 }
38 set.clear(); 36 set.clear();
39 set.addAll( entries ); 37 set.addAll(entries);
40 } 38 }
41 39
42 public static <Key,Val> void renameClassesInMap( Map<String,String> renames, Map<Key,Val> map ) 40 public static <Key,Val> void renameClassesInMap(Map<String,String> renames, Map<Key,Val> map) {
43 {
44 // for each key/value pair... 41 // for each key/value pair...
45 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 42 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
46 for( Map.Entry<Key,Val> entry : map.entrySet() ) 43 for (Map.Entry<Key,Val> entry : map.entrySet()) {
47 { 44 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
48 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 45 renameClassesInThing(renames, entry.getKey()),
49 renameClassesInThing( renames, entry.getKey() ), 46 renameClassesInThing(renames, entry.getValue())
50 renameClassesInThing( renames, entry.getValue() ) 47 ));
51 ) );
52 } 48 }
53 map.clear(); 49 map.clear();
54 for( Map.Entry<Key,Val> entry : entriesToAdd ) 50 for (Map.Entry<Key,Val> entry : entriesToAdd) {
55 { 51 map.put(entry.getKey(), entry.getValue());
56 map.put( entry.getKey(), entry.getValue() );
57 } 52 }
58 } 53 }
59 54
60 public static <Key,Val> void renameClassesInMultimap( Map<String,String> renames, Multimap<Key,Val> map ) 55 public static <Key,Val> void renameClassesInMultimap(Map<String,String> renames, Multimap<Key,Val> map) {
61 {
62 // for each key/value pair... 56 // for each key/value pair...
63 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 57 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
64 for( Map.Entry<Key,Val> entry : map.entries() ) 58 for (Map.Entry<Key,Val> entry : map.entries()) {
65 { 59 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
66 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 60 renameClassesInThing(renames, entry.getKey()),
67 renameClassesInThing( renames, entry.getKey() ), 61 renameClassesInThing(renames, entry.getValue())
68 renameClassesInThing( renames, entry.getValue() ) 62 ));
69 ) );
70 } 63 }
71 map.clear(); 64 map.clear();
72 for( Map.Entry<Key,Val> entry : entriesToAdd ) 65 for (Map.Entry<Key,Val> entry : entriesToAdd) {
73 { 66 map.put(entry.getKey(), entry.getValue());
74 map.put( entry.getKey(), entry.getValue() );
75 } 67 }
76 } 68 }
77 69
78 public static <Key,Val> void renameMethodsInMultimap( Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map ) 70 public static <Key,Val> void renameMethodsInMultimap(Map<MethodEntry,MethodEntry> renames, Multimap<Key,Val> map) {
79 {
80 // for each key/value pair... 71 // for each key/value pair...
81 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 72 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
82 for( Map.Entry<Key,Val> entry : map.entries() ) 73 for (Map.Entry<Key,Val> entry : map.entries()) {
83 { 74 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
84 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 75 renameMethodsInThing(renames, entry.getKey()),
85 renameMethodsInThing( renames, entry.getKey() ), 76 renameMethodsInThing(renames, entry.getValue())
86 renameMethodsInThing( renames, entry.getValue() ) 77 ));
87 ) );
88 } 78 }
89 map.clear(); 79 map.clear();
90 for( Map.Entry<Key,Val> entry : entriesToAdd ) 80 for (Map.Entry<Key,Val> entry : entriesToAdd) {
91 { 81 map.put(entry.getKey(), entry.getValue());
92 map.put( entry.getKey(), entry.getValue() );
93 } 82 }
94 } 83 }
95 84
96 public static <Key,Val> void renameMethodsInMap( Map<MethodEntry,MethodEntry> renames, Map<Key,Val> map ) 85 public static <Key,Val> void renameMethodsInMap(Map<MethodEntry,MethodEntry> renames, Map<Key,Val> map) {
97 {
98 // for each key/value pair... 86 // for each key/value pair...
99 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 87 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
100 for( Map.Entry<Key,Val> entry : map.entrySet() ) 88 for (Map.Entry<Key,Val> entry : map.entrySet()) {
101 { 89 entriesToAdd.add(new AbstractMap.SimpleEntry<Key,Val>(
102 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 90 renameMethodsInThing(renames, entry.getKey()),
103 renameMethodsInThing( renames, entry.getKey() ), 91 renameMethodsInThing(renames, entry.getValue())
104 renameMethodsInThing( renames, entry.getValue() ) 92 ));
105 ) );
106 } 93 }
107 map.clear(); 94 map.clear();
108 for( Map.Entry<Key,Val> entry : entriesToAdd ) 95 for (Map.Entry<Key,Val> entry : entriesToAdd) {
109 { 96 map.put(entry.getKey(), entry.getValue());
110 map.put( entry.getKey(), entry.getValue() );
111 } 97 }
112 } 98 }
113 99
114 @SuppressWarnings( "unchecked" ) 100 @SuppressWarnings("unchecked")
115 public static <T> T renameMethodsInThing( Map<MethodEntry,MethodEntry> renames, T thing ) 101 public static <T> T renameMethodsInThing(Map<MethodEntry,MethodEntry> renames, T thing) {
116 { 102 if (thing instanceof MethodEntry) {
117 if( thing instanceof MethodEntry )
118 {
119 MethodEntry methodEntry = (MethodEntry)thing; 103 MethodEntry methodEntry = (MethodEntry)thing;
120 MethodEntry newMethodEntry = renames.get( methodEntry ); 104 MethodEntry newMethodEntry = renames.get(methodEntry);
121 if( newMethodEntry != null ) 105 if (newMethodEntry != null) {
122 {
123 return (T)new MethodEntry( 106 return (T)new MethodEntry(
124 methodEntry.getClassEntry(), 107 methodEntry.getClassEntry(),
125 newMethodEntry.getName(), 108 newMethodEntry.getName(),
@@ -127,81 +110,59 @@ public class EntryRenamer
127 ); 110 );
128 } 111 }
129 return thing; 112 return thing;
130 } 113 } else if (thing instanceof ArgumentEntry) {
131 else if( thing instanceof ArgumentEntry )
132 {
133 ArgumentEntry argumentEntry = (ArgumentEntry)thing; 114 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
134 return (T)new ArgumentEntry( 115 return (T)new ArgumentEntry(
135 renameMethodsInThing( renames, argumentEntry.getBehaviorEntry() ), 116 renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()),
136 argumentEntry.getIndex(), 117 argumentEntry.getIndex(),
137 argumentEntry.getName() 118 argumentEntry.getName()
138 ); 119 );
139 } 120 } else if (thing instanceof EntryReference) {
140 else if( thing instanceof EntryReference )
141 {
142 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; 121 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
143 reference.entry = renameMethodsInThing( renames, reference.entry ); 122 reference.entry = renameMethodsInThing(renames, reference.entry);
144 reference.context = renameMethodsInThing( renames, reference.context ); 123 reference.context = renameMethodsInThing(renames, reference.context);
145 return thing; 124 return thing;
146 } 125 }
147 return thing; 126 return thing;
148 } 127 }
149 128
150 @SuppressWarnings( "unchecked" ) 129 @SuppressWarnings("unchecked")
151 public static <T> T renameClassesInThing( Map<String,String> renames, T thing ) 130 public static <T> T renameClassesInThing(Map<String,String> renames, T thing) {
152 { 131 if (thing instanceof String) {
153 if( thing instanceof String )
154 {
155 String stringEntry = (String)thing; 132 String stringEntry = (String)thing;
156 if( renames.containsKey( stringEntry ) ) 133 if (renames.containsKey(stringEntry)) {
157 { 134 return (T)renames.get(stringEntry);
158 return (T)renames.get( stringEntry );
159 } 135 }
160 } 136 } else if (thing instanceof ClassEntry) {
161 else if( thing instanceof ClassEntry )
162 {
163 ClassEntry classEntry = (ClassEntry)thing; 137 ClassEntry classEntry = (ClassEntry)thing;
164 return (T)new ClassEntry( renameClassesInThing( renames, classEntry.getClassName() ) ); 138 return (T)new ClassEntry(renameClassesInThing(renames, classEntry.getClassName()));
165 } 139 } else if (thing instanceof FieldEntry) {
166 else if( thing instanceof FieldEntry )
167 {
168 FieldEntry fieldEntry = (FieldEntry)thing; 140 FieldEntry fieldEntry = (FieldEntry)thing;
169 return (T)new FieldEntry( 141 return (T)new FieldEntry(renameClassesInThing(renames, fieldEntry.getClassEntry()), fieldEntry.getName());
170 renameClassesInThing( renames, fieldEntry.getClassEntry() ), 142 } else if (thing instanceof ConstructorEntry) {
171 fieldEntry.getName()
172 );
173 }
174 else if( thing instanceof ConstructorEntry )
175 {
176 ConstructorEntry constructorEntry = (ConstructorEntry)thing; 143 ConstructorEntry constructorEntry = (ConstructorEntry)thing;
177 return (T)new ConstructorEntry( 144 return (T)new ConstructorEntry(
178 renameClassesInThing( renames, constructorEntry.getClassEntry() ), 145 renameClassesInThing(renames, constructorEntry.getClassEntry()),
179 constructorEntry.getSignature() 146 constructorEntry.getSignature()
180 ); 147 );
181 } 148 } else if (thing instanceof MethodEntry) {
182 else if( thing instanceof MethodEntry )
183 {
184 MethodEntry methodEntry = (MethodEntry)thing; 149 MethodEntry methodEntry = (MethodEntry)thing;
185 return (T)new MethodEntry( 150 return (T)new MethodEntry(
186 renameClassesInThing( renames, methodEntry.getClassEntry() ), 151 renameClassesInThing(renames, methodEntry.getClassEntry()),
187 methodEntry.getName(), 152 methodEntry.getName(),
188 methodEntry.getSignature() 153 methodEntry.getSignature()
189 ); 154 );
190 } 155 } else if (thing instanceof ArgumentEntry) {
191 else if( thing instanceof ArgumentEntry )
192 {
193 ArgumentEntry argumentEntry = (ArgumentEntry)thing; 156 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
194 return (T)new ArgumentEntry( 157 return (T)new ArgumentEntry(
195 renameClassesInThing( renames, argumentEntry.getBehaviorEntry() ), 158 renameClassesInThing(renames, argumentEntry.getBehaviorEntry()),
196 argumentEntry.getIndex(), 159 argumentEntry.getIndex(),
197 argumentEntry.getName() 160 argumentEntry.getName()
198 ); 161 );
199 } 162 } else if (thing instanceof EntryReference) {
200 else if( thing instanceof EntryReference )
201 {
202 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing; 163 EntryReference<Entry,Entry> reference = (EntryReference<Entry,Entry>)thing;
203 reference.entry = renameClassesInThing( renames, reference.entry ); 164 reference.entry = renameClassesInThing(renames, reference.entry);
204 reference.context = renameClassesInThing( renames, reference.context ); 165 reference.context = renameClassesInThing(renames, reference.context);
205 return thing; 166 return thing;
206 } 167 }
207 168
diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
index 2652f64..2173eea 100644
--- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
@@ -16,24 +16,22 @@ import cuchaz.enigma.mapping.BehaviorEntry;
16import cuchaz.enigma.mapping.FieldEntry; 16import cuchaz.enigma.mapping.FieldEntry;
17import cuchaz.enigma.mapping.Translator; 17import cuchaz.enigma.mapping.Translator;
18 18
19public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry,BehaviorEntry> 19public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry,BehaviorEntry> {
20{ 20
21 private static final long serialVersionUID = -7934108091928699835L; 21 private static final long serialVersionUID = -7934108091928699835L;
22 22
23 private Translator m_deobfuscatingTranslator; 23 private Translator m_deobfuscatingTranslator;
24 private FieldEntry m_entry; 24 private FieldEntry m_entry;
25 private EntryReference<FieldEntry,BehaviorEntry> m_reference; 25 private EntryReference<FieldEntry,BehaviorEntry> m_reference;
26 private Access m_access; 26 private Access m_access;
27 27
28 public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) 28 public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) {
29 {
30 m_deobfuscatingTranslator = deobfuscatingTranslator; 29 m_deobfuscatingTranslator = deobfuscatingTranslator;
31 m_entry = entry; 30 m_entry = entry;
32 m_reference = null; 31 m_reference = null;
33 } 32 }
34 33
35 private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference<FieldEntry,BehaviorEntry> reference, Access access ) 34 private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference<FieldEntry,BehaviorEntry> reference, Access access) {
36 {
37 m_deobfuscatingTranslator = deobfuscatingTranslator; 35 m_deobfuscatingTranslator = deobfuscatingTranslator;
38 m_entry = reference.entry; 36 m_entry = reference.entry;
39 m_reference = reference; 37 m_reference = reference;
@@ -41,56 +39,41 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re
41 } 39 }
42 40
43 @Override 41 @Override
44 public FieldEntry getEntry( ) 42 public FieldEntry getEntry() {
45 {
46 return m_entry; 43 return m_entry;
47 } 44 }
48 45
49 @Override 46 @Override
50 public EntryReference<FieldEntry,BehaviorEntry> getReference( ) 47 public EntryReference<FieldEntry,BehaviorEntry> getReference() {
51 {
52 return m_reference; 48 return m_reference;
53 } 49 }
54 50
55 @Override 51 @Override
56 public String toString( ) 52 public String toString() {
57 { 53 if (m_reference != null) {
58 if( m_reference != null ) 54 return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access);
59 {
60 return String.format( "%s (%s)", m_deobfuscatingTranslator.translateEntry( m_reference.context ), m_access );
61 } 55 }
62 return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); 56 return m_deobfuscatingTranslator.translateEntry(m_entry).toString();
63 } 57 }
64 58
65 public void load( JarIndex index, boolean recurse ) 59 public void load(JarIndex index, boolean recurse) {
66 {
67 // get all the child nodes 60 // get all the child nodes
68 if( m_reference == null ) 61 if (m_reference == null) {
69 { 62 for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(m_entry)) {
70 for( EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences( m_entry ) ) 63 add(new FieldReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry)));
71 {
72 add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_entry ) ) );
73 } 64 }
74 } 65 } else {
75 else 66 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(m_reference.context)) {
76 { 67 add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_reference.context)));
77 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences( m_reference.context ) )
78 {
79 add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference, index.getAccess( m_reference.context ) ) );
80 } 68 }
81 } 69 }
82 70
83 if( recurse && children != null ) 71 if (recurse && children != null) {
84 { 72 for (Object node : children) {
85 for( Object node : children ) 73 if (node instanceof BehaviorReferenceTreeNode) {
86 { 74 ((BehaviorReferenceTreeNode)node).load(index, true);
87 if( node instanceof BehaviorReferenceTreeNode ) 75 } else if (node instanceof FieldReferenceTreeNode) {
88 { 76 ((FieldReferenceTreeNode)node).load(index, true);
89 ((BehaviorReferenceTreeNode)node).load( index, true );
90 }
91 else if( node instanceof FieldReferenceTreeNode )
92 {
93 ((FieldReferenceTreeNode)node).load( index, true );
94 } 77 }
95 } 78 }
96 } 79 }
diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java
index f65b8e7..8d9947c 100644
--- a/src/cuchaz/enigma/analysis/JarClassIterator.java
+++ b/src/cuchaz/enigma/analysis/JarClassIterator.java
@@ -30,132 +30,107 @@ import com.google.common.collect.Lists;
30import cuchaz.enigma.Constants; 30import cuchaz.enigma.Constants;
31import cuchaz.enigma.mapping.ClassEntry; 31import cuchaz.enigma.mapping.ClassEntry;
32 32
33public class JarClassIterator implements Iterator<CtClass> 33public class JarClassIterator implements Iterator<CtClass> {
34{ 34
35 private JarFile m_jar; 35 private JarFile m_jar;
36 private Iterator<JarEntry> m_iter; 36 private Iterator<JarEntry> m_iter;
37 37
38 public JarClassIterator( JarFile jar ) 38 public JarClassIterator(JarFile jar) {
39 {
40 m_jar = jar; 39 m_jar = jar;
41 40
42 // get the jar entries that correspond to classes 41 // get the jar entries that correspond to classes
43 List<JarEntry> classEntries = Lists.newArrayList(); 42 List<JarEntry> classEntries = Lists.newArrayList();
44 Enumeration<JarEntry> entries = m_jar.entries(); 43 Enumeration<JarEntry> entries = m_jar.entries();
45 while( entries.hasMoreElements() ) 44 while (entries.hasMoreElements()) {
46 {
47 JarEntry entry = entries.nextElement(); 45 JarEntry entry = entries.nextElement();
48 46
49 // is this a class file? 47 // is this a class file?
50 if( entry.getName().endsWith( ".class" ) ) 48 if (entry.getName().endsWith(".class")) {
51 { 49 classEntries.add(entry);
52 classEntries.add( entry );
53 } 50 }
54 } 51 }
55 m_iter = classEntries.iterator(); 52 m_iter = classEntries.iterator();
56 } 53 }
57 54
58 @Override 55 @Override
59 public boolean hasNext( ) 56 public boolean hasNext() {
60 {
61 return m_iter.hasNext(); 57 return m_iter.hasNext();
62 } 58 }
63 59
64 @Override 60 @Override
65 public CtClass next( ) 61 public CtClass next() {
66 {
67 JarEntry entry = m_iter.next(); 62 JarEntry entry = m_iter.next();
68 try 63 try {
69 { 64 return getClass(m_jar, entry);
70 return getClass( m_jar, entry ); 65 } catch (IOException | NotFoundException ex) {
71 } 66 throw new Error("Unable to load class: " + entry.getName());
72 catch( IOException | NotFoundException ex )
73 {
74 throw new Error( "Unable to load class: " + entry.getName() );
75 } 67 }
76 } 68 }
77 69
78 @Override 70 @Override
79 public void remove( ) 71 public void remove() {
80 {
81 throw new UnsupportedOperationException(); 72 throw new UnsupportedOperationException();
82 } 73 }
83 74
84 public static List<ClassEntry> getClassEntries( JarFile jar ) 75 public static List<ClassEntry> getClassEntries(JarFile jar) {
85 {
86 List<ClassEntry> classEntries = Lists.newArrayList(); 76 List<ClassEntry> classEntries = Lists.newArrayList();
87 Enumeration<JarEntry> entries = jar.entries(); 77 Enumeration<JarEntry> entries = jar.entries();
88 while( entries.hasMoreElements() ) 78 while (entries.hasMoreElements()) {
89 {
90 JarEntry entry = entries.nextElement(); 79 JarEntry entry = entries.nextElement();
91 80
92 // is this a class file? 81 // is this a class file?
93 if( !entry.isDirectory() && entry.getName().endsWith( ".class" ) ) 82 if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
94 { 83 classEntries.add(getClassEntry(entry));
95 classEntries.add( getClassEntry( entry ) );
96 } 84 }
97 } 85 }
98 return classEntries; 86 return classEntries;
99 } 87 }
100 88
101 public static Iterable<CtClass> classes( final JarFile jar ) 89 public static Iterable<CtClass> classes(final JarFile jar) {
102 { 90 return new Iterable<CtClass>() {
103 return new Iterable<CtClass>( )
104 {
105 @Override 91 @Override
106 public Iterator<CtClass> iterator( ) 92 public Iterator<CtClass> iterator() {
107 { 93 return new JarClassIterator(jar);
108 return new JarClassIterator( jar );
109 } 94 }
110 }; 95 };
111 } 96 }
112 97
113 public static CtClass getClass( JarFile jar, ClassEntry classEntry ) 98 public static CtClass getClass(JarFile jar, ClassEntry classEntry) {
114 { 99 try {
115 try 100 return getClass(jar, new JarEntry(classEntry.getName() + ".class"));
116 { 101 } catch (IOException | NotFoundException ex) {
117 return getClass( jar, new JarEntry( classEntry.getName() + ".class" ) ); 102 throw new Error("Unable to load class: " + classEntry.getName());
118 }
119 catch( IOException | NotFoundException ex )
120 {
121 throw new Error( "Unable to load class: " + classEntry.getName() );
122 } 103 }
123 } 104 }
124 105
125 private static CtClass getClass( JarFile jar, JarEntry entry ) 106 private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException {
126 throws IOException, NotFoundException
127 {
128 // read the class into a buffer 107 // read the class into a buffer
129 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 108 ByteArrayOutputStream bos = new ByteArrayOutputStream();
130 byte[] buf = new byte[Constants.KiB]; 109 byte[] buf = new byte[Constants.KiB];
131 int totalNumBytesRead = 0; 110 int totalNumBytesRead = 0;
132 InputStream in = jar.getInputStream( entry ); 111 InputStream in = jar.getInputStream(entry);
133 while( in.available() > 0 ) 112 while (in.available() > 0) {
134 { 113 int numBytesRead = in.read(buf);
135 int numBytesRead = in.read( buf ); 114 if (numBytesRead < 0) {
136 if( numBytesRead < 0 )
137 {
138 break; 115 break;
139 } 116 }
140 bos.write( buf, 0, numBytesRead ); 117 bos.write(buf, 0, numBytesRead);
141 118
142 // sanity checking 119 // sanity checking
143 totalNumBytesRead += numBytesRead; 120 totalNumBytesRead += numBytesRead;
144 if( totalNumBytesRead > Constants.MiB ) 121 if (totalNumBytesRead > Constants.MiB) {
145 { 122 throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!");
146 throw new Error( "Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!" );
147 } 123 }
148 } 124 }
149 125
150 // get a javassist handle for the class 126 // get a javassist handle for the class
151 String className = Descriptor.toJavaName( getClassEntry( entry ).getName() ); 127 String className = Descriptor.toJavaName(getClassEntry(entry).getName());
152 ClassPool classPool = new ClassPool(); 128 ClassPool classPool = new ClassPool();
153 classPool.insertClassPath( new ByteArrayClassPath( className, bos.toByteArray() ) ); 129 classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray()));
154 return classPool.get( className ); 130 return classPool.get(className);
155 } 131 }
156 132
157 private static ClassEntry getClassEntry( JarEntry entry ) 133 private static ClassEntry getClassEntry(JarEntry entry) {
158 { 134 return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length()));
159 return new ClassEntry( entry.getName().substring( 0, entry.getName().length() - ".class".length() ) );
160 } 135 }
161} 136}
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 0954564..4b03a33 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -53,8 +53,8 @@ import cuchaz.enigma.mapping.MethodEntry;
53import cuchaz.enigma.mapping.SignatureUpdater; 53import cuchaz.enigma.mapping.SignatureUpdater;
54import cuchaz.enigma.mapping.Translator; 54import cuchaz.enigma.mapping.Translator;
55 55
56public class JarIndex 56public class JarIndex {
57{ 57
58 private Set<ClassEntry> m_obfClassEntries; 58 private Set<ClassEntry> m_obfClassEntries;
59 private TranslationIndex m_translationIndex; 59 private TranslationIndex m_translationIndex;
60 private Multimap<String,String> m_interfaces; 60 private Multimap<String,String> m_interfaces;
@@ -68,8 +68,7 @@ public class JarIndex
68 private Map<String,BehaviorEntry> m_anonymousClasses; 68 private Map<String,BehaviorEntry> m_anonymousClasses;
69 private Map<MethodEntry,MethodEntry> m_bridgeMethods; 69 private Map<MethodEntry,MethodEntry> m_bridgeMethods;
70 70
71 public JarIndex( ) 71 public JarIndex() {
72 {
73 m_obfClassEntries = Sets.newHashSet(); 72 m_obfClassEntries = Sets.newHashSet();
74 m_translationIndex = new TranslationIndex(); 73 m_translationIndex = new TranslationIndex();
75 m_interfaces = HashMultimap.create(); 74 m_interfaces = HashMultimap.create();
@@ -84,192 +83,161 @@ public class JarIndex
84 m_bridgeMethods = Maps.newHashMap(); 83 m_bridgeMethods = Maps.newHashMap();
85 } 84 }
86 85
87 public void indexJar( JarFile jar, boolean buildInnerClasses ) 86 public void indexJar(JarFile jar, boolean buildInnerClasses) {
88 {
89 // step 1: read the class names 87 // step 1: read the class names
90 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) 88 for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) {
91 { 89 if (classEntry.isInDefaultPackage()) {
92 if( classEntry.isInDefaultPackage() )
93 {
94 // move out of default package 90 // move out of default package
95 classEntry = new ClassEntry( Constants.NonePackage + "/" + classEntry.getName() ); 91 classEntry = new ClassEntry(Constants.NonePackage + "/" + classEntry.getName());
96 } 92 }
97 m_obfClassEntries.add( classEntry ); 93 m_obfClassEntries.add(classEntry);
98 } 94 }
99 95
100 // step 2: index field/method/constructor access 96 // step 2: index field/method/constructor access
101 for( CtClass c : JarClassIterator.classes( jar ) ) 97 for (CtClass c : JarClassIterator.classes(jar)) {
102 { 98 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
103 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 99 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
104 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 100 for (CtField field : c.getDeclaredFields()) {
105 for( CtField field : c.getDeclaredFields() ) 101 FieldEntry fieldEntry = new FieldEntry(classEntry, field.getName());
106 { 102 m_access.put(fieldEntry, Access.get(field));
107 FieldEntry fieldEntry = new FieldEntry( classEntry, field.getName() );
108 m_access.put( fieldEntry, Access.get( field ) );
109 } 103 }
110 for( CtMethod method : c.getDeclaredMethods() ) 104 for (CtMethod method : c.getDeclaredMethods()) {
111 { 105 MethodEntry methodEntry = new MethodEntry(classEntry, method.getName(), method.getSignature());
112 MethodEntry methodEntry = new MethodEntry( classEntry, method.getName(), method.getSignature() ); 106 m_access.put(methodEntry, Access.get(method));
113 m_access.put( methodEntry, Access.get( method ) );
114 } 107 }
115 for( CtConstructor constructor : c.getDeclaredConstructors() ) 108 for (CtConstructor constructor : c.getDeclaredConstructors()) {
116 { 109 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, constructor.getSignature());
117 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getSignature() ); 110 m_access.put(constructorEntry, Access.get(constructor));
118 m_access.put( constructorEntry, Access.get( constructor ) );
119 } 111 }
120 } 112 }
121 113
122 // step 3: index extends, implements, fields, and methods 114 // step 3: index extends, implements, fields, and methods
123 for( CtClass c : JarClassIterator.classes( jar ) ) 115 for (CtClass c : JarClassIterator.classes(jar)) {
124 { 116 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
125 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 117 String className = Descriptor.toJvmName(c.getName());
126 String className = Descriptor.toJvmName( c.getName() ); 118 m_translationIndex.addSuperclass(className, Descriptor.toJvmName(c.getClassFile().getSuperclass()));
127 m_translationIndex.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) ); 119 for (String interfaceName : c.getClassFile().getInterfaces()) {
128 for( String interfaceName : c.getClassFile().getInterfaces() ) 120 className = Descriptor.toJvmName(className);
129 { 121 interfaceName = Descriptor.toJvmName(interfaceName);
130 className = Descriptor.toJvmName( className ); 122 if (className.equals(interfaceName)) {
131 interfaceName = Descriptor.toJvmName( interfaceName ); 123 throw new IllegalArgumentException("Class cannot be its own interface! " + className);
132 if( className.equals( interfaceName ) )
133 {
134 throw new IllegalArgumentException( "Class cannot be its own interface! " + className );
135 } 124 }
136 m_interfaces.put( className, interfaceName ); 125 m_interfaces.put(className, interfaceName);
137 } 126 }
138 for( CtField field : c.getDeclaredFields() ) 127 for (CtField field : c.getDeclaredFields()) {
139 { 128 indexField(field);
140 indexField( field );
141 } 129 }
142 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 130 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
143 { 131 indexBehavior(behavior);
144 indexBehavior( behavior );
145 } 132 }
146 } 133 }
147 134
148 // step 4: index field, method, constructor references 135 // step 4: index field, method, constructor references
149 for( CtClass c : JarClassIterator.classes( jar ) ) 136 for (CtClass c : JarClassIterator.classes(jar)) {
150 { 137 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
151 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 138 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
152 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 139 indexBehaviorReferences(behavior);
153 {
154 indexBehaviorReferences( behavior );
155 } 140 }
156 } 141 }
157 142
158 if( buildInnerClasses ) 143 if (buildInnerClasses) {
159 {
160 // step 5: index inner classes and anonymous classes 144 // step 5: index inner classes and anonymous classes
161 for( CtClass c : JarClassIterator.classes( jar ) ) 145 for (CtClass c : JarClassIterator.classes(jar)) {
162 { 146 ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage);
163 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 147 String outerClassName = findOuterClass(c);
164 String outerClassName = findOuterClass( c ); 148 if (outerClassName != null) {
165 if( outerClassName != null )
166 {
167 String innerClassName = c.getSimpleName(); 149 String innerClassName = c.getSimpleName();
168 m_innerClasses.put( outerClassName, innerClassName ); 150 m_innerClasses.put(outerClassName, innerClassName);
169 boolean innerWasAdded = m_outerClasses.put( innerClassName, outerClassName ) == null; 151 boolean innerWasAdded = m_outerClasses.put(innerClassName, outerClassName) == null;
170 assert( innerWasAdded ); 152 assert (innerWasAdded);
171 153
172 BehaviorEntry enclosingBehavior = isAnonymousClass( c, outerClassName ); 154 BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassName);
173 if( enclosingBehavior != null ) 155 if (enclosingBehavior != null) {
174 { 156 m_anonymousClasses.put(innerClassName, enclosingBehavior);
175 m_anonymousClasses.put( innerClassName, enclosingBehavior );
176 157
177 // DEBUG 158 // DEBUG
178 //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); 159 // System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName );
179 } 160 } else {
180 else
181 {
182 // DEBUG 161 // DEBUG
183 //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); 162 // System.out.println( "INNER: " + outerClassName + "$" + innerClassName );
184 } 163 }
185 } 164 }
186 } 165 }
187 166
188 // step 6: update other indices with inner class info 167 // step 6: update other indices with inner class info
189 Map<String,String> renames = Maps.newHashMap(); 168 Map<String,String> renames = Maps.newHashMap();
190 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() ) 169 for (Map.Entry<String,String> entry : m_outerClasses.entrySet()) {
191 { 170 renames.put(Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey());
192 renames.put( Constants.NonePackage + "/" + entry.getKey(), entry.getValue() + "$" + entry.getKey() );
193 } 171 }
194 EntryRenamer.renameClassesInSet( renames, m_obfClassEntries ); 172 EntryRenamer.renameClassesInSet(renames, m_obfClassEntries);
195 m_translationIndex.renameClasses( renames ); 173 m_translationIndex.renameClasses(renames);
196 EntryRenamer.renameClassesInMultimap( renames, m_interfaces ); 174 EntryRenamer.renameClassesInMultimap(renames, m_interfaces);
197 EntryRenamer.renameClassesInMultimap( renames, m_methodImplementations ); 175 EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations);
198 EntryRenamer.renameClassesInMultimap( renames, m_behaviorReferences ); 176 EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences);
199 EntryRenamer.renameClassesInMultimap( renames, m_fieldReferences ); 177 EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences);
200 EntryRenamer.renameClassesInMap( renames, m_bridgeMethods ); 178 EntryRenamer.renameClassesInMap(renames, m_bridgeMethods);
201 EntryRenamer.renameClassesInMap( renames, m_access ); 179 EntryRenamer.renameClassesInMap(renames, m_access);
202 } 180 }
203 181
204 // step 6: update other indices with bridge method info 182 // step 6: update other indices with bridge method info
205 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_methodImplementations ); 183 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_methodImplementations);
206 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_behaviorReferences ); 184 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_behaviorReferences);
207 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); 185 EntryRenamer.renameMethodsInMultimap(m_bridgeMethods, m_fieldReferences);
208 EntryRenamer.renameMethodsInMap( m_bridgeMethods, m_access ); 186 EntryRenamer.renameMethodsInMap(m_bridgeMethods, m_access);
209 } 187 }
210 188
211 private void indexField( CtField field ) 189 private void indexField(CtField field) {
212 {
213 // get the field entry 190 // get the field entry
214 String className = Descriptor.toJvmName( field.getDeclaringClass().getName() ); 191 String className = Descriptor.toJvmName(field.getDeclaringClass().getName());
215 FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() ); 192 FieldEntry fieldEntry = new FieldEntry(new ClassEntry(className), field.getName());
216 193
217 m_translationIndex.addField( className, field.getName() ); 194 m_translationIndex.addField(className, field.getName());
218 195
219 // is the field a class type? 196 // is the field a class type?
220 if( field.getSignature().startsWith( "L" ) ) 197 if (field.getSignature().startsWith("L")) {
221 { 198 ClassEntry fieldTypeEntry = new ClassEntry(field.getSignature().substring(1, field.getSignature().length() - 1));
222 ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) ); 199 m_fieldClasses.put(fieldEntry, fieldTypeEntry);
223 m_fieldClasses.put( fieldEntry, fieldTypeEntry );
224 } 200 }
225 } 201 }
226 202
227 private void indexBehavior( CtBehavior behavior ) 203 private void indexBehavior(CtBehavior behavior) {
228 {
229 // get the behavior entry 204 // get the behavior entry
230 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); 205 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior);
231 if( behaviorEntry instanceof MethodEntry ) 206 if (behaviorEntry instanceof MethodEntry) {
232 {
233 MethodEntry methodEntry = (MethodEntry)behaviorEntry; 207 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
234 208
235 // index implementation 209 // index implementation
236 m_methodImplementations.put( behaviorEntry.getClassName(), methodEntry ); 210 m_methodImplementations.put(behaviorEntry.getClassName(), methodEntry);
237 211
238 // look for bridge methods 212 // look for bridge methods
239 CtMethod bridgedMethod = getBridgedMethod( (CtMethod)behavior ); 213 CtMethod bridgedMethod = getBridgedMethod((CtMethod)behavior);
240 if( bridgedMethod != null ) 214 if (bridgedMethod != null) {
241 {
242 MethodEntry bridgedMethodEntry = new MethodEntry( 215 MethodEntry bridgedMethodEntry = new MethodEntry(
243 behaviorEntry.getClassEntry(), 216 behaviorEntry.getClassEntry(),
244 bridgedMethod.getName(), 217 bridgedMethod.getName(),
245 bridgedMethod.getSignature() 218 bridgedMethod.getSignature()
246 ); 219 );
247 m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); 220 m_bridgeMethods.put(bridgedMethodEntry, methodEntry);
248 } 221 }
249 } 222 }
250 // looks like we don't care about constructors here 223 // looks like we don't care about constructors here
251 } 224 }
252 225
253 private void indexBehaviorReferences( CtBehavior behavior ) 226 private void indexBehaviorReferences(CtBehavior behavior) {
254 {
255 // index method calls 227 // index method calls
256 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( behavior ); 228 final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior);
257 try 229 try {
258 { 230 behavior.instrument(new ExprEditor() {
259 behavior.instrument( new ExprEditor( )
260 {
261 @Override 231 @Override
262 public void edit( MethodCall call ) 232 public void edit(MethodCall call) {
263 { 233 String className = Descriptor.toJvmName(call.getClassName());
264 String className = Descriptor.toJvmName( call.getClassName() );
265 MethodEntry calledMethodEntry = new MethodEntry( 234 MethodEntry calledMethodEntry = new MethodEntry(
266 new ClassEntry( className ), 235 new ClassEntry(className),
267 call.getMethodName(), 236 call.getMethodName(),
268 call.getSignature() 237 call.getSignature()
269 ); 238 );
270 ClassEntry resolvedClassEntry = resolveEntryClass( calledMethodEntry ); 239 ClassEntry resolvedClassEntry = resolveEntryClass(calledMethodEntry);
271 if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledMethodEntry.getClassEntry() ) ) 240 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) {
272 {
273 calledMethodEntry = new MethodEntry( 241 calledMethodEntry = new MethodEntry(
274 resolvedClassEntry, 242 resolvedClassEntry,
275 call.getMethodName(), 243 call.getMethodName(),
@@ -281,39 +249,33 @@ public class JarIndex
281 call.getMethodName(), 249 call.getMethodName(),
282 behaviorEntry 250 behaviorEntry
283 ); 251 );
284 m_behaviorReferences.put( calledMethodEntry, reference ); 252 m_behaviorReferences.put(calledMethodEntry, reference);
285 } 253 }
286 254
287 @Override 255 @Override
288 public void edit( FieldAccess call ) 256 public void edit(FieldAccess call) {
289 { 257 String className = Descriptor.toJvmName(call.getClassName());
290 String className = Descriptor.toJvmName( call.getClassName() );
291 FieldEntry calledFieldEntry = new FieldEntry( 258 FieldEntry calledFieldEntry = new FieldEntry(
292 new ClassEntry( className ), 259 new ClassEntry(className),
293 call.getFieldName() 260 call.getFieldName()
294 ); 261 );
295 ClassEntry resolvedClassEntry = resolveEntryClass( calledFieldEntry ); 262 ClassEntry resolvedClassEntry = resolveEntryClass(calledFieldEntry);
296 if( resolvedClassEntry != null && !resolvedClassEntry.equals( calledFieldEntry.getClassEntry() ) ) 263 if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) {
297 { 264 calledFieldEntry = new FieldEntry(resolvedClassEntry, call.getFieldName());
298 calledFieldEntry = new FieldEntry(
299 resolvedClassEntry,
300 call.getFieldName()
301 );
302 } 265 }
303 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>( 266 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>(
304 calledFieldEntry, 267 calledFieldEntry,
305 call.getFieldName(), 268 call.getFieldName(),
306 behaviorEntry 269 behaviorEntry
307 ); 270 );
308 m_fieldReferences.put( calledFieldEntry, reference ); 271 m_fieldReferences.put(calledFieldEntry, reference);
309 } 272 }
310 273
311 @Override 274 @Override
312 public void edit( ConstructorCall call ) 275 public void edit(ConstructorCall call) {
313 { 276 String className = Descriptor.toJvmName(call.getClassName());
314 String className = Descriptor.toJvmName( call.getClassName() );
315 ConstructorEntry calledConstructorEntry = new ConstructorEntry( 277 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
316 new ClassEntry( className ), 278 new ClassEntry(className),
317 call.getSignature() 279 call.getSignature()
318 ); 280 );
319 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 281 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
@@ -321,15 +283,14 @@ public class JarIndex
321 call.getMethodName(), 283 call.getMethodName(),
322 behaviorEntry 284 behaviorEntry
323 ); 285 );
324 m_behaviorReferences.put( calledConstructorEntry, reference ); 286 m_behaviorReferences.put(calledConstructorEntry, reference);
325 } 287 }
326 288
327 @Override 289 @Override
328 public void edit( NewExpr call ) 290 public void edit(NewExpr call) {
329 { 291 String className = Descriptor.toJvmName(call.getClassName());
330 String className = Descriptor.toJvmName( call.getClassName() );
331 ConstructorEntry calledConstructorEntry = new ConstructorEntry( 292 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
332 new ClassEntry( className ), 293 new ClassEntry(className),
333 call.getSignature() 294 call.getSignature()
334 ); 295 );
335 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 296 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
@@ -337,173 +298,141 @@ public class JarIndex
337 call.getClassName(), 298 call.getClassName(),
338 behaviorEntry 299 behaviorEntry
339 ); 300 );
340 m_behaviorReferences.put( calledConstructorEntry, reference ); 301 m_behaviorReferences.put(calledConstructorEntry, reference);
341 } 302 }
342 } ); 303 });
343 } 304 } catch (CannotCompileException ex) {
344 catch( CannotCompileException ex ) 305 throw new Error(ex);
345 {
346 throw new Error( ex );
347 } 306 }
348 } 307 }
349 308
350 public ClassEntry resolveEntryClass( Entry obfEntry ) 309 public ClassEntry resolveEntryClass(Entry obfEntry) {
351 { 310
352 // this entry could refer to a method on a class where the method is not actually implemented 311 // this entry could refer to a method on a class where the method is not actually implemented
353 // travel up the inheritance tree to find the closest implementation 312 // travel up the inheritance tree to find the closest implementation
354 while( !containsObfEntry( obfEntry ) ) 313 while (!containsObfEntry(obfEntry)) {
355 {
356 // is there a parent class? 314 // is there a parent class?
357 String superclassName = m_translationIndex.getSuperclassName( obfEntry.getClassName() ); 315 String superclassName = m_translationIndex.getSuperclassName(obfEntry.getClassName());
358 if( superclassName == null ) 316 if (superclassName == null) {
359 {
360 // this is probably a method from a class in a library 317 // this is probably a method from a class in a library
361 // we can't trace the implementation up any higher unless we index the library 318 // we can't trace the implementation up any higher unless we index the library
362 return null; 319 return null;
363 } 320 }
364 321
365 // move up to the parent class 322 // move up to the parent class
366 obfEntry = obfEntry.cloneToNewClass( new ClassEntry( superclassName ) ); 323 obfEntry = obfEntry.cloneToNewClass(new ClassEntry(superclassName));
367 } 324 }
368 return obfEntry.getClassEntry(); 325 return obfEntry.getClassEntry();
369 } 326 }
370 327
371 private CtMethod getBridgedMethod( CtMethod method ) 328 private CtMethod getBridgedMethod(CtMethod method) {
372 { 329
373 // bridge methods just call another method, cast it to the return type, and return the result 330 // bridge methods just call another method, cast it to the return type, and return the result
374 // let's see if we can detect this scenario 331 // let's see if we can detect this scenario
375 332
376 // skip non-synthetic methods 333 // skip non-synthetic methods
377 if( ( method.getModifiers() & AccessFlag.SYNTHETIC ) == 0 ) 334 if ( (method.getModifiers() & AccessFlag.SYNTHETIC) == 0) {
378 {
379 return null; 335 return null;
380 } 336 }
381 337
382 // get all the called methods 338 // get all the called methods
383 final List<MethodCall> methodCalls = Lists.newArrayList(); 339 final List<MethodCall> methodCalls = Lists.newArrayList();
384 try 340 try {
385 { 341 method.instrument(new ExprEditor() {
386 method.instrument( new ExprEditor( )
387 {
388 @Override 342 @Override
389 public void edit( MethodCall call ) 343 public void edit(MethodCall call) {
390 { 344 methodCalls.add(call);
391 methodCalls.add( call );
392 } 345 }
393 } ); 346 });
394 } 347 } catch (CannotCompileException ex) {
395 catch( CannotCompileException ex )
396 {
397 // this is stupid... we're not even compiling anything 348 // this is stupid... we're not even compiling anything
398 throw new Error( ex ); 349 throw new Error(ex);
399 } 350 }
400 351
401 // is there just one? 352 // is there just one?
402 if( methodCalls.size() != 1 ) 353 if (methodCalls.size() != 1) {
403 {
404 return null; 354 return null;
405 } 355 }
406 MethodCall call = methodCalls.get( 0 ); 356 MethodCall call = methodCalls.get(0);
407 357
408 try 358 try {
409 {
410 // we have a bridge method! 359 // we have a bridge method!
411 return call.getMethod(); 360 return call.getMethod();
412 } 361 } catch (NotFoundException ex) {
413 catch( NotFoundException ex )
414 {
415 // can't find the type? not a bridge method 362 // can't find the type? not a bridge method
416 return null; 363 return null;
417 } 364 }
418 } 365 }
419 366
420 private String findOuterClass( CtClass c ) 367 private String findOuterClass(CtClass c) {
421 { 368
422 // inner classes: 369 // inner classes:
423 // have constructors that can (illegally) set synthetic fields 370 // have constructors that can (illegally) set synthetic fields
424 // the outer class is the only class that calls constructors 371 // the outer class is the only class that calls constructors
425 372
426 // use the synthetic fields to find the synthetic constructors 373 // use the synthetic fields to find the synthetic constructors
427 for( CtConstructor constructor : c.getDeclaredConstructors() ) 374 for (CtConstructor constructor : c.getDeclaredConstructors()) {
428 {
429 Set<String> syntheticFieldTypes = Sets.newHashSet(); 375 Set<String> syntheticFieldTypes = Sets.newHashSet();
430 if( !isIllegalConstructor( syntheticFieldTypes, constructor ) ) 376 if (!isIllegalConstructor(syntheticFieldTypes, constructor)) {
431 {
432 continue; 377 continue;
433 } 378 }
434 379
435 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 380 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
436 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); 381 ConstructorEntry constructorEntry = new ConstructorEntry(
382 classEntry,
383 constructor.getMethodInfo().getDescriptor()
384 );
437 385
438 // gather the classes from the illegally-set synthetic fields 386 // gather the classes from the illegally-set synthetic fields
439 Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); 387 Set<ClassEntry> illegallySetClasses = Sets.newHashSet();
440 for( String type : syntheticFieldTypes ) 388 for (String type : syntheticFieldTypes) {
441 { 389 if (type.startsWith("L")) {
442 if( type.startsWith( "L" ) ) 390 ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1));
443 { 391 if (isSaneOuterClass(outerClassEntry, classEntry)) {
444 ClassEntry outerClassEntry = new ClassEntry( type.substring( 1, type.length() - 1 ) ); 392 illegallySetClasses.add(outerClassEntry);
445 if( isSaneOuterClass( outerClassEntry, classEntry ) )
446 {
447 illegallySetClasses.add( outerClassEntry );
448 } 393 }
449 } 394 }
450 } 395 }
451 396
452 // who calls this constructor? 397 // who calls this constructor?
453 Set<ClassEntry> callerClasses = Sets.newHashSet(); 398 Set<ClassEntry> callerClasses = Sets.newHashSet();
454 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) ) 399 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences(constructorEntry)) {
455 { 400
456 // make sure it's not a call to super 401 // make sure it's not a call to super
457 if( reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry ) 402 if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) {
458 { 403
459 // is the entry a superclass of the context? 404 // is the entry a superclass of the context?
460 String calledClassName = reference.entry.getClassName(); 405 String calledClassName = reference.entry.getClassName();
461 String callerSuperclassName = m_translationIndex.getSuperclassName( reference.context.getClassName() ); 406 String callerSuperclassName = m_translationIndex.getSuperclassName(reference.context.getClassName());
462 if( callerSuperclassName != null && callerSuperclassName.equals( calledClassName ) ) 407 if (callerSuperclassName != null && callerSuperclassName.equals(calledClassName)) {
463 {
464 // it's a super call, skip 408 // it's a super call, skip
465 continue; 409 continue;
466 } 410 }
467 } 411 }
468 412
469 if( isSaneOuterClass( reference.context.getClassEntry(), classEntry ) ) 413 if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) {
470 { 414 callerClasses.add(reference.context.getClassEntry());
471 callerClasses.add( reference.context.getClassEntry() );
472 } 415 }
473 } 416 }
474 417
475 // do we have an answer yet? 418 // do we have an answer yet?
476 if( callerClasses.isEmpty() ) 419 if (callerClasses.isEmpty()) {
477 { 420 if (illegallySetClasses.size() == 1) {
478 if( illegallySetClasses.size() == 1 )
479 {
480 return illegallySetClasses.iterator().next().getName(); 421 return illegallySetClasses.iterator().next().getName();
422 } else {
423 System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry));
481 } 424 }
482 else 425 } else {
483 { 426 if (callerClasses.size() == 1) {
484 System.out.println( String.format( "WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry ) );
485 }
486 }
487 else
488 {
489 if( callerClasses.size() == 1 )
490 {
491 return callerClasses.iterator().next().getName(); 427 return callerClasses.iterator().next().getName();
492 } 428 } else {
493 else
494 {
495 // multiple callers, do the illegally set classes narrow it down? 429 // multiple callers, do the illegally set classes narrow it down?
496 Set<ClassEntry> intersection = Sets.newHashSet( callerClasses ); 430 Set<ClassEntry> intersection = Sets.newHashSet(callerClasses);
497 intersection.retainAll( illegallySetClasses ); 431 intersection.retainAll(illegallySetClasses);
498 if( intersection.size() == 1 ) 432 if (intersection.size() == 1) {
499 {
500 return intersection.iterator().next().getName(); 433 return intersection.iterator().next().getName();
501 } 434 } else {
502 else 435 System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses));
503 {
504 System.out.println( String.format( "WARNING: Unable to choose outer class for %s among options: %s",
505 classEntry, callerClasses
506 ) );
507 } 436 }
508 } 437 }
509 } 438 }
@@ -512,99 +441,82 @@ public class JarIndex
512 return null; 441 return null;
513 } 442 }
514 443
515 private boolean isSaneOuterClass( ClassEntry outerClassEntry, ClassEntry innerClassEntry ) 444 private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) {
516 { 445
517 // clearly this would be silly 446 // clearly this would be silly
518 if( outerClassEntry.equals( innerClassEntry ) ) 447 if (outerClassEntry.equals(innerClassEntry)) {
519 {
520 return false; 448 return false;
521 } 449 }
522 450
523 // is the outer class in the jar? 451 // is the outer class in the jar?
524 if( !m_obfClassEntries.contains( outerClassEntry ) ) 452 if (!m_obfClassEntries.contains(outerClassEntry)) {
525 {
526 return false; 453 return false;
527 } 454 }
528 455
529 return true; 456 return true;
530 } 457 }
531 458
532 @SuppressWarnings( "unchecked" ) 459 @SuppressWarnings("unchecked")
533 private boolean isIllegalConstructor( Set<String> syntheticFieldTypes, CtConstructor constructor ) 460 private boolean isIllegalConstructor(Set<String> syntheticFieldTypes, CtConstructor constructor) {
534 { 461
535 // illegal constructors only set synthetic member fields, then call super() 462 // illegal constructors only set synthetic member fields, then call super()
536 String className = constructor.getDeclaringClass().getName(); 463 String className = constructor.getDeclaringClass().getName();
537 464
538 // collect all the field accesses, constructor calls, and method calls 465 // collect all the field accesses, constructor calls, and method calls
539 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList(); 466 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList();
540 final List<ConstructorCall> constructorCalls = Lists.newArrayList(); 467 final List<ConstructorCall> constructorCalls = Lists.newArrayList();
541 try 468 try {
542 { 469 constructor.instrument(new ExprEditor() {
543 constructor.instrument( new ExprEditor( )
544 {
545 @Override 470 @Override
546 public void edit( FieldAccess fieldAccess ) 471 public void edit(FieldAccess fieldAccess) {
547 { 472 if (fieldAccess.isWriter() && constructorCalls.isEmpty()) {
548 if( fieldAccess.isWriter() && constructorCalls.isEmpty() ) 473 illegalFieldWrites.add(fieldAccess);
549 {
550 illegalFieldWrites.add( fieldAccess );
551 } 474 }
552 } 475 }
553 476
554 @Override 477 @Override
555 public void edit( ConstructorCall constructorCall ) 478 public void edit(ConstructorCall constructorCall) {
556 { 479 constructorCalls.add(constructorCall);
557 constructorCalls.add( constructorCall );
558 } 480 }
559 } ); 481 });
560 } 482 } catch (CannotCompileException ex) {
561 catch( CannotCompileException ex )
562 {
563 // we're not compiling anything... this is stupid 483 // we're not compiling anything... this is stupid
564 throw new Error( ex ); 484 throw new Error(ex);
565 } 485 }
566 486
567 // are there any illegal field writes? 487 // are there any illegal field writes?
568 if( illegalFieldWrites.isEmpty() ) 488 if (illegalFieldWrites.isEmpty()) {
569 {
570 return false; 489 return false;
571 } 490 }
572 491
573 // are all the writes to synthetic fields? 492 // are all the writes to synthetic fields?
574 for( FieldAccess fieldWrite : illegalFieldWrites ) 493 for (FieldAccess fieldWrite : illegalFieldWrites) {
575 { 494
576 // all illegal writes have to be to the local class 495 // all illegal writes have to be to the local class
577 if( !fieldWrite.getClassName().equals( className ) ) 496 if (!fieldWrite.getClassName().equals(className)) {
578 { 497 System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName()));
579 System.err.println( String.format( "WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName() ) );
580 return false; 498 return false;
581 } 499 }
582 500
583 // find the field 501 // find the field
584 FieldInfo fieldInfo = null; 502 FieldInfo fieldInfo = null;
585 for( FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields() ) 503 for (FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields()) {
586 { 504 if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) {
587 if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) )
588 {
589 fieldInfo = info; 505 fieldInfo = info;
590 break; 506 break;
591 } 507 }
592 } 508 }
593 if( fieldInfo == null ) 509 if (fieldInfo == null) {
594 {
595 // field is in a superclass or something, can't be a local synthetic member 510 // field is in a superclass or something, can't be a local synthetic member
596 return false; 511 return false;
597 } 512 }
598 513
599 // is this field synthetic? 514 // is this field synthetic?
600 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; 515 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0;
601 if( isSynthetic ) 516 if (isSynthetic) {
602 { 517 syntheticFieldTypes.add(fieldInfo.getDescriptor());
603 syntheticFieldTypes.add( fieldInfo.getDescriptor() ); 518 } else {
604 } 519 System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName()));
605 else
606 {
607 System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) );
608 return false; 520 return false;
609 } 521 }
610 } 522 }
@@ -612,56 +524,51 @@ public class JarIndex
612 // we passed all the tests! 524 // we passed all the tests!
613 return true; 525 return true;
614 } 526 }
615 527
616 private BehaviorEntry isAnonymousClass( CtClass c, String outerClassName ) 528 private BehaviorEntry isAnonymousClass(CtClass c, String outerClassName) {
617 { 529
618 ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 530 ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
619 531
620 // anonymous classes: 532 // anonymous classes:
621 // can't be abstract 533 // can't be abstract
622 // have only one constructor 534 // have only one constructor
623 // it's called exactly once by the outer class 535 // it's called exactly once by the outer class
624 // the type the instance is assigned to can't be this type 536 // the type the instance is assigned to can't be this type
625 537
626 // is abstract? 538 // is abstract?
627 if( Modifier.isAbstract( c.getModifiers() ) ) 539 if (Modifier.isAbstract(c.getModifiers())) {
628 {
629 return null; 540 return null;
630 } 541 }
631 542
632 // is there exactly one constructor? 543 // is there exactly one constructor?
633 if( c.getDeclaredConstructors().length != 1 ) 544 if (c.getDeclaredConstructors().length != 1) {
634 {
635 return null; 545 return null;
636 } 546 }
637 CtConstructor constructor = c.getDeclaredConstructors()[0]; 547 CtConstructor constructor = c.getDeclaredConstructors()[0];
638 548
639 // is this constructor called exactly once? 549 // is this constructor called exactly once?
640 ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() ); 550 ConstructorEntry constructorEntry = new ConstructorEntry(
641 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences( constructorEntry ); 551 innerClassEntry,
642 if( references.size() != 1 ) 552 constructor.getMethodInfo().getDescriptor()
643 { 553 );
554 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry);
555 if (references.size() != 1) {
644 return null; 556 return null;
645 } 557 }
646 558
647 // does the caller use this type? 559 // does the caller use this type?
648 BehaviorEntry caller = references.iterator().next().context; 560 BehaviorEntry caller = references.iterator().next().context;
649 for( FieldEntry fieldEntry : getReferencedFields( caller ) ) 561 for (FieldEntry fieldEntry : getReferencedFields(caller)) {
650 { 562 ClassEntry fieldClass = getFieldClass(fieldEntry);
651 ClassEntry fieldClass = getFieldClass( fieldEntry ); 563 if (fieldClass != null && fieldClass.equals(innerClassEntry)) {
652 if( fieldClass != null && fieldClass.equals( innerClassEntry ) )
653 {
654 // caller references this type, so it can't be anonymous 564 // caller references this type, so it can't be anonymous
655 return null; 565 return null;
656 } 566 }
657 } 567 }
658 for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) ) 568 for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) {
659 {
660 // get the class types from the signature 569 // get the class types from the signature
661 for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) ) 570 for (String className : SignatureUpdater.getClasses(behaviorEntry.getSignature())) {
662 { 571 if (className.equals(innerClassEntry.getName())) {
663 if( className.equals( innerClassEntry.getName() ) )
664 {
665 // caller references this type, so it can't be anonymous 572 // caller references this type, so it can't be anonymous
666 return null; 573 return null;
667 } 574 }
@@ -670,330 +577,275 @@ public class JarIndex
670 577
671 return caller; 578 return caller;
672 } 579 }
673 580
674 public Set<ClassEntry> getObfClassEntries( ) 581 public Set<ClassEntry> getObfClassEntries() {
675 {
676 return m_obfClassEntries; 582 return m_obfClassEntries;
677 } 583 }
678 584
679 public TranslationIndex getTranslationIndex( ) 585 public TranslationIndex getTranslationIndex() {
680 {
681 return m_translationIndex; 586 return m_translationIndex;
682 } 587 }
683 588
684 public Access getAccess( Entry entry ) 589 public Access getAccess(Entry entry) {
685 { 590 return m_access.get(entry);
686 return m_access.get( entry );
687 } 591 }
688 592
689 public ClassEntry getFieldClass( FieldEntry fieldEntry ) 593 public ClassEntry getFieldClass(FieldEntry fieldEntry) {
690 { 594 return m_fieldClasses.get(fieldEntry);
691 return m_fieldClasses.get( fieldEntry );
692 } 595 }
693 596
694 public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) 597 public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) {
695 { 598
696 // get the root node 599 // get the root node
697 List<String> ancestry = Lists.newArrayList(); 600 List<String> ancestry = Lists.newArrayList();
698 ancestry.add( obfClassEntry.getName() ); 601 ancestry.add(obfClassEntry.getName());
699 ancestry.addAll( m_translationIndex.getAncestry( obfClassEntry.getName() ) ); 602 ancestry.addAll(m_translationIndex.getAncestry(obfClassEntry.getName()));
700 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); 603 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode(
604 deobfuscatingTranslator,
605 ancestry.get(ancestry.size() - 1)
606 );
701 607
702 // expand all children recursively 608 // expand all children recursively
703 rootNode.load( m_translationIndex, true ); 609 rootNode.load(m_translationIndex, true);
704 610
705 return rootNode; 611 return rootNode;
706 } 612 }
707 613
708 public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) 614 public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) {
709 { 615
710 // is this even an interface? 616 // is this even an interface?
711 if( isInterface( obfClassEntry.getClassName() ) ) 617 if (isInterface(obfClassEntry.getClassName())) {
712 { 618 ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry);
713 ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry ); 619 node.load(this);
714 node.load( this );
715 return node; 620 return node;
716 } 621 }
717 return null; 622 return null;
718 } 623 }
719 624
720 public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) 625 public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) {
721 { 626
722 // travel to the ancestor implementation 627 // travel to the ancestor implementation
723 String baseImplementationClassName = obfMethodEntry.getClassName(); 628 String baseImplementationClassName = obfMethodEntry.getClassName();
724 for( String ancestorClassName : m_translationIndex.getAncestry( obfMethodEntry.getClassName() ) ) 629 for (String ancestorClassName : m_translationIndex.getAncestry(obfMethodEntry.getClassName())) {
725 {
726 MethodEntry ancestorMethodEntry = new MethodEntry( 630 MethodEntry ancestorMethodEntry = new MethodEntry(
727 new ClassEntry( ancestorClassName ), 631 new ClassEntry(ancestorClassName),
728 obfMethodEntry.getName(), 632 obfMethodEntry.getName(),
729 obfMethodEntry.getSignature() 633 obfMethodEntry.getSignature()
730 ); 634 );
731 if( containsObfBehavior( ancestorMethodEntry ) ) 635 if (containsObfBehavior(ancestorMethodEntry)) {
732 {
733 baseImplementationClassName = ancestorClassName; 636 baseImplementationClassName = ancestorClassName;
734 } 637 }
735 } 638 }
736 639
737 // make a root node at the base 640 // make a root node at the base
738 MethodEntry methodEntry = new MethodEntry( 641 MethodEntry methodEntry = new MethodEntry(
739 new ClassEntry( baseImplementationClassName ), 642 new ClassEntry(baseImplementationClassName),
740 obfMethodEntry.getName(), 643 obfMethodEntry.getName(),
741 obfMethodEntry.getSignature() 644 obfMethodEntry.getSignature()
742 ); 645 );
743 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( 646 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(
744 deobfuscatingTranslator, 647 deobfuscatingTranslator,
745 methodEntry, 648 methodEntry,
746 containsObfBehavior( methodEntry ) 649 containsObfBehavior(methodEntry)
747 ); 650 );
748 651
749 // expand the full tree 652 // expand the full tree
750 rootNode.load( this, true ); 653 rootNode.load(this, true);
751 654
752 return rootNode; 655 return rootNode;
753 } 656 }
754 657
755 public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) 658 public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) {
756 { 659
757 MethodEntry interfaceMethodEntry; 660 MethodEntry interfaceMethodEntry;
758 661
759 // is this method on an interface? 662 // is this method on an interface?
760 if( isInterface( obfMethodEntry.getClassName() ) ) 663 if (isInterface(obfMethodEntry.getClassName())) {
761 {
762 interfaceMethodEntry = obfMethodEntry; 664 interfaceMethodEntry = obfMethodEntry;
763 } 665 } else {
764 else
765 {
766 // get the interface class 666 // get the interface class
767 List<MethodEntry> methodInterfaces = Lists.newArrayList(); 667 List<MethodEntry> methodInterfaces = Lists.newArrayList();
768 for( String interfaceName : getInterfaces( obfMethodEntry.getClassName() ) ) 668 for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) {
769 {
770 // is this method defined in this interface? 669 // is this method defined in this interface?
771 MethodEntry methodInterface = new MethodEntry( 670 MethodEntry methodInterface = new MethodEntry(
772 new ClassEntry( interfaceName ), 671 new ClassEntry(interfaceName),
773 obfMethodEntry.getName(), 672 obfMethodEntry.getName(),
774 obfMethodEntry.getSignature() 673 obfMethodEntry.getSignature()
775 ); 674 );
776 if( containsObfBehavior( methodInterface ) ) 675 if (containsObfBehavior(methodInterface)) {
777 { 676 methodInterfaces.add(methodInterface);
778 methodInterfaces.add( methodInterface );
779 } 677 }
780 } 678 }
781 if( methodInterfaces.isEmpty() ) 679 if (methodInterfaces.isEmpty()) {
782 {
783 return null; 680 return null;
784 } 681 }
785 if( methodInterfaces.size() > 1 ) 682 if (methodInterfaces.size() > 1) {
786 { 683 throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!");
787 throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" );
788 } 684 }
789 interfaceMethodEntry = methodInterfaces.get( 0 ); 685 interfaceMethodEntry = methodInterfaces.get(0);
790 } 686 }
791 687
792 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry ); 688 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry);
793 rootNode.load( this ); 689 rootNode.load(this);
794 return rootNode; 690 return rootNode;
795 } 691 }
796 692
797 public Set<MethodEntry> getRelatedMethodImplementations( MethodEntry obfMethodEntry ) 693 public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) {
798 {
799 Set<MethodEntry> methodEntries = Sets.newHashSet(); 694 Set<MethodEntry> methodEntries = Sets.newHashSet();
800 getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) ); 695 getRelatedMethodImplementations(methodEntries, getMethodInheritance(null, obfMethodEntry));
801 return methodEntries; 696 return methodEntries;
802 } 697 }
803 698
804 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node ) 699 private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) {
805 {
806 MethodEntry methodEntry = node.getMethodEntry(); 700 MethodEntry methodEntry = node.getMethodEntry();
807 if( containsObfBehavior( methodEntry ) ) 701 if (containsObfBehavior(methodEntry)) {
808 {
809 // collect the entry 702 // collect the entry
810 methodEntries.add( methodEntry ); 703 methodEntries.add(methodEntry);
811 } 704 }
812 705
813 // look at interface methods too 706 // look at interface methods too
814 MethodImplementationsTreeNode implementations = getMethodImplementations( null, methodEntry ); 707 MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry);
815 if( implementations != null ) 708 if (implementations != null) {
816 { 709 getRelatedMethodImplementations(methodEntries, implementations);
817 getRelatedMethodImplementations( methodEntries, implementations );
818 } 710 }
819 711
820 // recurse 712 // recurse
821 for( int i=0; i<node.getChildCount(); i++ ) 713 for (int i = 0; i < node.getChildCount(); i++) {
822 { 714 getRelatedMethodImplementations(methodEntries, (MethodInheritanceTreeNode)node.getChildAt(i));
823 getRelatedMethodImplementations( methodEntries, (MethodInheritanceTreeNode)node.getChildAt( i ) );
824 } 715 }
825 } 716 }
826 717
827 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node ) 718 private void getRelatedMethodImplementations(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) {
828 {
829 MethodEntry methodEntry = node.getMethodEntry(); 719 MethodEntry methodEntry = node.getMethodEntry();
830 if( containsObfBehavior( methodEntry ) ) 720 if (containsObfBehavior(methodEntry)) {
831 {
832 // collect the entry 721 // collect the entry
833 methodEntries.add( methodEntry ); 722 methodEntries.add(methodEntry);
834 } 723 }
835 724
836 // recurse 725 // recurse
837 for( int i=0; i<node.getChildCount(); i++ ) 726 for (int i = 0; i < node.getChildCount(); i++) {
838 { 727 getRelatedMethodImplementations(methodEntries, (MethodImplementationsTreeNode)node.getChildAt(i));
839 getRelatedMethodImplementations( methodEntries, (MethodImplementationsTreeNode)node.getChildAt( i ) );
840 } 728 }
841 } 729 }
842 730
843 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences( FieldEntry fieldEntry ) 731 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences(FieldEntry fieldEntry) {
844 { 732 return m_fieldReferences.get(fieldEntry);
845 return m_fieldReferences.get( fieldEntry );
846 } 733 }
847 734
848 public Collection<FieldEntry> getReferencedFields( BehaviorEntry behaviorEntry ) 735 public Collection<FieldEntry> getReferencedFields(BehaviorEntry behaviorEntry) {
849 {
850 // linear search is fast enough for now 736 // linear search is fast enough for now
851 Set<FieldEntry> fieldEntries = Sets.newHashSet(); 737 Set<FieldEntry> fieldEntries = Sets.newHashSet();
852 for( EntryReference<FieldEntry,BehaviorEntry> reference : m_fieldReferences.values() ) 738 for (EntryReference<FieldEntry,BehaviorEntry> reference : m_fieldReferences.values()) {
853 { 739 if (reference.context == behaviorEntry) {
854 if( reference.context == behaviorEntry ) 740 fieldEntries.add(reference.entry);
855 {
856 fieldEntries.add( reference.entry );
857 } 741 }
858 } 742 }
859 return fieldEntries; 743 return fieldEntries;
860 } 744 }
861 745
862 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry ) 746 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences(BehaviorEntry behaviorEntry) {
863 { 747 return m_behaviorReferences.get(behaviorEntry);
864 return m_behaviorReferences.get( behaviorEntry );
865 } 748 }
866 749
867 public Collection<BehaviorEntry> getReferencedBehaviors( BehaviorEntry behaviorEntry ) 750 public Collection<BehaviorEntry> getReferencedBehaviors(BehaviorEntry behaviorEntry) {
868 {
869 // linear search is fast enough for now 751 // linear search is fast enough for now
870 Set<BehaviorEntry> behaviorEntries = Sets.newHashSet(); 752 Set<BehaviorEntry> behaviorEntries = Sets.newHashSet();
871 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : m_behaviorReferences.values() ) 753 for (EntryReference<BehaviorEntry,BehaviorEntry> reference : m_behaviorReferences.values()) {
872 { 754 if (reference.context == behaviorEntry) {
873 if( reference.context == behaviorEntry ) 755 behaviorEntries.add(reference.entry);
874 {
875 behaviorEntries.add( reference.entry );
876 } 756 }
877 } 757 }
878 return behaviorEntries; 758 return behaviorEntries;
879 } 759 }
880 760
881 public Collection<String> getInnerClasses( String obfOuterClassName ) 761 public Collection<String> getInnerClasses(String obfOuterClassName) {
882 { 762 return m_innerClasses.get(obfOuterClassName);
883 return m_innerClasses.get( obfOuterClassName );
884 } 763 }
885 764
886 public String getOuterClass( String obfInnerClassName ) 765 public String getOuterClass(String obfInnerClassName) {
887 {
888 // make sure we use the right name 766 // make sure we use the right name
889 if( new ClassEntry( obfInnerClassName ).getPackageName() != null ) 767 if (new ClassEntry(obfInnerClassName).getPackageName() != null) {
890 { 768 throw new IllegalArgumentException("Don't reference obfuscated inner classes using packages: " + obfInnerClassName);
891 throw new IllegalArgumentException( "Don't reference obfuscated inner classes using packages: " + obfInnerClassName );
892 } 769 }
893 return m_outerClasses.get( obfInnerClassName ); 770 return m_outerClasses.get(obfInnerClassName);
894 } 771 }
895 772
896 public boolean isAnonymousClass( String obfInnerClassName ) 773 public boolean isAnonymousClass(String obfInnerClassName) {
897 { 774 return m_anonymousClasses.containsKey(obfInnerClassName);
898 return m_anonymousClasses.containsKey( obfInnerClassName );
899 } 775 }
900 776
901 public BehaviorEntry getAnonymousClassCaller( String obfInnerClassName ) 777 public BehaviorEntry getAnonymousClassCaller(String obfInnerClassName) {
902 { 778 return m_anonymousClasses.get(obfInnerClassName);
903 return m_anonymousClasses.get( obfInnerClassName );
904 } 779 }
905 780
906 public Set<String> getInterfaces( String className ) 781 public Set<String> getInterfaces(String className) {
907 {
908 Set<String> interfaceNames = new HashSet<String>(); 782 Set<String> interfaceNames = new HashSet<String>();
909 interfaceNames.addAll( m_interfaces.get( className ) ); 783 interfaceNames.addAll(m_interfaces.get(className));
910 for( String ancestor : m_translationIndex.getAncestry( className ) ) 784 for (String ancestor : m_translationIndex.getAncestry(className)) {
911 { 785 interfaceNames.addAll(m_interfaces.get(ancestor));
912 interfaceNames.addAll( m_interfaces.get( ancestor ) );
913 } 786 }
914 return interfaceNames; 787 return interfaceNames;
915 } 788 }
916 789
917 public Set<String> getImplementingClasses( String targetInterfaceName ) 790 public Set<String> getImplementingClasses(String targetInterfaceName) {
918 {
919 // linear search is fast enough for now 791 // linear search is fast enough for now
920 Set<String> classNames = Sets.newHashSet(); 792 Set<String> classNames = Sets.newHashSet();
921 for( Map.Entry<String,String> entry : m_interfaces.entries() ) 793 for (Map.Entry<String,String> entry : m_interfaces.entries()) {
922 {
923 String className = entry.getKey(); 794 String className = entry.getKey();
924 String interfaceName = entry.getValue(); 795 String interfaceName = entry.getValue();
925 if( interfaceName.equals( targetInterfaceName ) ) 796 if (interfaceName.equals(targetInterfaceName)) {
926 { 797 classNames.add(className);
927 classNames.add( className ); 798 m_translationIndex.getSubclassNamesRecursively(classNames, className);
928 m_translationIndex.getSubclassNamesRecursively( classNames, className );
929 } 799 }
930 } 800 }
931 return classNames; 801 return classNames;
932 } 802 }
933 803
934 public boolean isInterface( String className ) 804 public boolean isInterface(String className) {
935 { 805 return m_interfaces.containsValue(className);
936 return m_interfaces.containsValue( className );
937 } 806 }
938 807
939 public MethodEntry getBridgeMethod( MethodEntry methodEntry ) 808 public MethodEntry getBridgeMethod(MethodEntry methodEntry) {
940 { 809 return m_bridgeMethods.get(methodEntry);
941 return m_bridgeMethods.get( methodEntry );
942 } 810 }
943 811
944 public boolean containsObfClass( ClassEntry obfClassEntry ) 812 public boolean containsObfClass(ClassEntry obfClassEntry) {
945 { 813 return m_obfClassEntries.contains(obfClassEntry);
946 return m_obfClassEntries.contains( obfClassEntry );
947 } 814 }
948 815
949 public boolean containsObfField( FieldEntry obfFieldEntry ) 816 public boolean containsObfField(FieldEntry obfFieldEntry) {
950 { 817 return m_access.containsKey(obfFieldEntry);
951 return m_access.containsKey( obfFieldEntry );
952 } 818 }
953 819
954 public boolean containsObfBehavior( BehaviorEntry obfBehaviorEntry ) 820 public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) {
955 { 821 return m_access.containsKey(obfBehaviorEntry);
956 return m_access.containsKey( obfBehaviorEntry );
957 } 822 }
958 823
959 public boolean containsObfArgument( ArgumentEntry obfArgumentEntry ) 824 public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) {
960 {
961 // check the behavior 825 // check the behavior
962 if( !containsObfBehavior( obfArgumentEntry.getBehaviorEntry() ) ) 826 if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) {
963 {
964 return false; 827 return false;
965 } 828 }
966 829
967 // check the argument 830 // check the argument
968 if( obfArgumentEntry.getIndex() >= Descriptor.numOfParameters( obfArgumentEntry.getBehaviorEntry().getSignature() ) ) 831 if (obfArgumentEntry.getIndex() >= Descriptor.numOfParameters(obfArgumentEntry.getBehaviorEntry().getSignature())) {
969 {
970 return false; 832 return false;
971 } 833 }
972 834
973 return true; 835 return true;
974 } 836 }
975 837
976 public boolean containsObfEntry( Entry obfEntry ) 838 public boolean containsObfEntry(Entry obfEntry) {
977 { 839 if (obfEntry instanceof ClassEntry) {
978 if( obfEntry instanceof ClassEntry ) 840 return containsObfClass((ClassEntry)obfEntry);
979 { 841 } else if (obfEntry instanceof FieldEntry) {
980 return containsObfClass( (ClassEntry)obfEntry ); 842 return containsObfField((FieldEntry)obfEntry);
981 } 843 } else if (obfEntry instanceof BehaviorEntry) {
982 else if( obfEntry instanceof FieldEntry ) 844 return containsObfBehavior((BehaviorEntry)obfEntry);
983 { 845 } else if (obfEntry instanceof ArgumentEntry) {
984 return containsObfField( (FieldEntry)obfEntry ); 846 return containsObfArgument((ArgumentEntry)obfEntry);
985 } 847 } else {
986 else if( obfEntry instanceof BehaviorEntry ) 848 throw new Error("Entry type not supported: " + obfEntry.getClass().getName());
987 {
988 return containsObfBehavior( (BehaviorEntry)obfEntry );
989 }
990 else if( obfEntry instanceof ArgumentEntry )
991 {
992 return containsObfArgument( (ArgumentEntry)obfEntry );
993 }
994 else
995 {
996 throw new Error( "Entry type not supported: " + obfEntry.getClass().getName() );
997 } 849 }
998 } 850 }
999} 851}
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
index a050282..1009226 100644
--- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
@@ -20,94 +20,78 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class MethodImplementationsTreeNode extends DefaultMutableTreeNode 23public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 3781080657461899915L; 25 private static final long serialVersionUID = 3781080657461899915L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private MethodEntry m_entry; 28 private MethodEntry m_entry;
29 29
30 public MethodImplementationsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) 30 public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) {
31 { 31 if (entry == null) {
32 if( entry == null ) 32 throw new IllegalArgumentException("entry cannot be null!");
33 {
34 throw new IllegalArgumentException( "entry cannot be null!" );
35 } 33 }
36 34
37 m_deobfuscatingTranslator = deobfuscatingTranslator; 35 m_deobfuscatingTranslator = deobfuscatingTranslator;
38 m_entry = entry; 36 m_entry = entry;
39 } 37 }
40 38
41 public MethodEntry getMethodEntry( ) 39 public MethodEntry getMethodEntry() {
42 {
43 return m_entry; 40 return m_entry;
44 } 41 }
45 42
46 public String getDeobfClassName( ) 43 public String getDeobfClassName() {
47 { 44 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
48 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
49 } 45 }
50 46
51 public String getDeobfMethodName( ) 47 public String getDeobfMethodName() {
52 { 48 return m_deobfuscatingTranslator.translate(m_entry);
53 return m_deobfuscatingTranslator.translate( m_entry );
54 } 49 }
55 50
56 @Override 51 @Override
57 public String toString( ) 52 public String toString() {
58 {
59 String className = getDeobfClassName(); 53 String className = getDeobfClassName();
60 if( className == null ) 54 if (className == null) {
61 {
62 className = m_entry.getClassName(); 55 className = m_entry.getClassName();
63 } 56 }
64 57
65 String methodName = getDeobfMethodName(); 58 String methodName = getDeobfMethodName();
66 if( methodName == null ) 59 if (methodName == null) {
67 {
68 methodName = m_entry.getName(); 60 methodName = m_entry.getName();
69 } 61 }
70 return className + "." + methodName + "()"; 62 return className + "." + methodName + "()";
71 } 63 }
72 64
73 public void load( JarIndex index ) 65 public void load(JarIndex index) {
74 {
75 // get all method implementations 66 // get all method implementations
76 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); 67 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
77 for( String implementingClassName : index.getImplementingClasses( m_entry.getClassName() ) ) 68 for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) {
78 {
79 MethodEntry methodEntry = new MethodEntry( 69 MethodEntry methodEntry = new MethodEntry(
80 new ClassEntry( implementingClassName ), 70 new ClassEntry(implementingClassName),
81 m_entry.getName(), 71 m_entry.getName(),
82 m_entry.getSignature() 72 m_entry.getSignature()
83 ); 73 );
84 if( index.containsObfBehavior( methodEntry ) ) 74 if (index.containsObfBehavior(methodEntry)) {
85 { 75 nodes.add(new MethodImplementationsTreeNode(m_deobfuscatingTranslator, methodEntry));
86 nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) );
87 } 76 }
88 } 77 }
89 78
90 // add them to this node 79 // add them to this node
91 for( MethodImplementationsTreeNode node : nodes ) 80 for (MethodImplementationsTreeNode node : nodes) {
92 { 81 this.add(node);
93 this.add( node );
94 } 82 }
95 } 83 }
96 84
97 public static MethodImplementationsTreeNode findNode( MethodImplementationsTreeNode node, MethodEntry entry ) 85 public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) {
98 {
99 // is this the node? 86 // is this the node?
100 if( node.getMethodEntry().equals( entry ) ) 87 if (node.getMethodEntry().equals(entry)) {
101 {
102 return node; 88 return node;
103 } 89 }
104 90
105 // recurse 91 // recurse
106 for( int i=0; i<node.getChildCount(); i++ ) 92 for (int i = 0; i < node.getChildCount(); i++) {
107 { 93 MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode)node.getChildAt(i), entry);
108 MethodImplementationsTreeNode foundNode = findNode( (MethodImplementationsTreeNode)node.getChildAt( i ), entry ); 94 if (foundNode != null) {
109 if( foundNode != null )
110 {
111 return foundNode; 95 return foundNode;
112 } 96 }
113 } 97 }
diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
index bd91951..eba8d87 100644
--- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
@@ -20,112 +20,92 @@ import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry; 20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator; 21import cuchaz.enigma.mapping.Translator;
22 22
23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode 23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
24{ 24
25 private static final long serialVersionUID = 1096677030991810007L; 25 private static final long serialVersionUID = 1096677030991810007L;
26 26
27 private Translator m_deobfuscatingTranslator; 27 private Translator m_deobfuscatingTranslator;
28 private MethodEntry m_entry; 28 private MethodEntry m_entry;
29 private boolean m_isImplemented; 29 private boolean m_isImplemented;
30 30
31 public MethodInheritanceTreeNode( Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented ) 31 public MethodInheritanceTreeNode(Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented) {
32 {
33 m_deobfuscatingTranslator = deobfuscatingTranslator; 32 m_deobfuscatingTranslator = deobfuscatingTranslator;
34 m_entry = entry; 33 m_entry = entry;
35 m_isImplemented = isImplemented; 34 m_isImplemented = isImplemented;
36 } 35 }
37 36
38 public MethodEntry getMethodEntry( ) 37 public MethodEntry getMethodEntry() {
39 {
40 return m_entry; 38 return m_entry;
41 } 39 }
42 40
43 public String getDeobfClassName( ) 41 public String getDeobfClassName() {
44 { 42 return m_deobfuscatingTranslator.translateClass(m_entry.getClassName());
45 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
46 } 43 }
47 44
48 public String getDeobfMethodName( ) 45 public String getDeobfMethodName() {
49 { 46 return m_deobfuscatingTranslator.translate(m_entry);
50 return m_deobfuscatingTranslator.translate( m_entry );
51 } 47 }
52 48
53 public boolean isImplemented( ) 49 public boolean isImplemented() {
54 {
55 return m_isImplemented; 50 return m_isImplemented;
56 } 51 }
57 52
58 @Override 53 @Override
59 public String toString( ) 54 public String toString() {
60 {
61 String className = getDeobfClassName(); 55 String className = getDeobfClassName();
62 if( className == null ) 56 if (className == null) {
63 {
64 className = m_entry.getClassName(); 57 className = m_entry.getClassName();
65 } 58 }
66 59
67 if( !m_isImplemented ) 60 if (!m_isImplemented) {
68 {
69 return className; 61 return className;
70 } 62 } else {
71 else
72 {
73 String methodName = getDeobfMethodName(); 63 String methodName = getDeobfMethodName();
74 if( methodName == null ) 64 if (methodName == null) {
75 {
76 methodName = m_entry.getName(); 65 methodName = m_entry.getName();
77 } 66 }
78 return className + "." + methodName + "()"; 67 return className + "." + methodName + "()";
79 } 68 }
80 } 69 }
81 70
82 public void load( JarIndex index, boolean recurse ) 71 public void load(JarIndex index, boolean recurse) {
83 {
84 // get all the child nodes 72 // get all the child nodes
85 List<MethodInheritanceTreeNode> nodes = Lists.newArrayList(); 73 List<MethodInheritanceTreeNode> nodes = Lists.newArrayList();
86 for( String subclassName : index.getTranslationIndex().getSubclassNames( m_entry.getClassName() ) ) 74 for (String subclassName : index.getTranslationIndex().getSubclassNames(m_entry.getClassName())) {
87 {
88 MethodEntry methodEntry = new MethodEntry( 75 MethodEntry methodEntry = new MethodEntry(
89 new ClassEntry( subclassName ), 76 new ClassEntry(subclassName),
90 m_entry.getName(), 77 m_entry.getName(),
91 m_entry.getSignature() 78 m_entry.getSignature()
92 ); 79 );
93 nodes.add( new MethodInheritanceTreeNode( 80 nodes.add(new MethodInheritanceTreeNode(
94 m_deobfuscatingTranslator, 81 m_deobfuscatingTranslator,
95 methodEntry, 82 methodEntry,
96 index.containsObfBehavior( methodEntry ) 83 index.containsObfBehavior(methodEntry)
97 ) ); 84 ));
98 } 85 }
99 86
100 // add them to this node 87 // add them to this node
101 for( MethodInheritanceTreeNode node : nodes ) 88 for (MethodInheritanceTreeNode node : nodes) {
102 { 89 this.add(node);
103 this.add( node );
104 } 90 }
105 91
106 if( recurse ) 92 if (recurse) {
107 { 93 for (MethodInheritanceTreeNode node : nodes) {
108 for( MethodInheritanceTreeNode node : nodes ) 94 node.load(index, true);
109 {
110 node.load( index, true );
111 } 95 }
112 } 96 }
113 } 97 }
114 98
115 public static MethodInheritanceTreeNode findNode( MethodInheritanceTreeNode node, MethodEntry entry ) 99 public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) {
116 {
117 // is this the node? 100 // is this the node?
118 if( node.getMethodEntry().equals( entry ) ) 101 if (node.getMethodEntry().equals(entry)) {
119 {
120 return node; 102 return node;
121 } 103 }
122 104
123 // recurse 105 // recurse
124 for( int i=0; i<node.getChildCount(); i++ ) 106 for (int i = 0; i < node.getChildCount(); i++) {
125 { 107 MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode)node.getChildAt(i), entry);
126 MethodInheritanceTreeNode foundNode = findNode( (MethodInheritanceTreeNode)node.getChildAt( i ), entry ); 108 if (foundNode != null) {
127 if( foundNode != null )
128 {
129 return foundNode; 109 return foundNode;
130 } 110 }
131 } 111 }
diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
index e0a0a74..2b08616 100644
--- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
+++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java
@@ -12,8 +12,7 @@ package cuchaz.enigma.analysis;
12 12
13import cuchaz.enigma.mapping.Entry; 13import cuchaz.enigma.mapping.Entry;
14 14
15public interface ReferenceTreeNode<E extends Entry, C extends Entry> 15public interface ReferenceTreeNode<E extends Entry,C extends Entry> {
16{
17 E getEntry(); 16 E getEntry();
18 EntryReference<E,C> getReference(); 17 EntryReference<E,C> getReference();
19} 18}
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java
index 0e33de0..b43ab61 100644
--- a/src/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/cuchaz/enigma/analysis/SourceIndex.java
@@ -25,16 +25,15 @@ import com.strobel.decompiler.languages.java.ast.Identifier;
25 25
26import cuchaz.enigma.mapping.Entry; 26import cuchaz.enigma.mapping.Entry;
27 27
28public class SourceIndex 28public class SourceIndex {
29{ 29
30 private String m_source; 30 private String m_source;
31 private TreeMap<Token,EntryReference<Entry,Entry>> m_tokenToReference; 31 private TreeMap<Token,EntryReference<Entry,Entry>> m_tokenToReference;
32 private Multimap<EntryReference<Entry,Entry>,Token> m_referenceToTokens; 32 private Multimap<EntryReference<Entry,Entry>,Token> m_referenceToTokens;
33 private Map<Entry,Token> m_declarationToToken; 33 private Map<Entry,Token> m_declarationToToken;
34 private List<Integer> m_lineOffsets; 34 private List<Integer> m_lineOffsets;
35 35
36 public SourceIndex( String source ) 36 public SourceIndex(String source) {
37 {
38 m_source = source; 37 m_source = source;
39 m_tokenToReference = Maps.newTreeMap(); 38 m_tokenToReference = Maps.newTreeMap();
40 m_referenceToTokens = HashMultimap.create(); 39 m_referenceToTokens = HashMultimap.create();
@@ -42,142 +41,119 @@ public class SourceIndex
42 m_lineOffsets = Lists.newArrayList(); 41 m_lineOffsets = Lists.newArrayList();
43 42
44 // count the lines 43 // count the lines
45 m_lineOffsets.add( 0 ); 44 m_lineOffsets.add(0);
46 for( int i=0; i<source.length(); i++ ) 45 for (int i = 0; i < source.length(); i++) {
47 { 46 if (source.charAt(i) == '\n') {
48 if( source.charAt( i ) == '\n' ) 47 m_lineOffsets.add(i + 1);
49 {
50 m_lineOffsets.add( i + 1 );
51 } 48 }
52 } 49 }
53 } 50 }
54 51
55 public String getSource( ) 52 public String getSource() {
56 {
57 return m_source; 53 return m_source;
58 } 54 }
59 55
60 public Token getToken( AstNode node ) 56 public Token getToken(AstNode node) {
61 { 57
62 // get the text of the node 58 // get the text of the node
63 String name = ""; 59 String name = "";
64 if( node instanceof Identifier ) 60 if (node instanceof Identifier) {
65 {
66 name = ((Identifier)node).getName(); 61 name = ((Identifier)node).getName();
67 } 62 }
68 63
69 // get a token for this node's region 64 // get a token for this node's region
70 Region region = node.getRegion(); 65 Region region = node.getRegion();
71 if( region.getBeginLine() == 0 || region.getEndLine() == 0 ) 66 if (region.getBeginLine() == 0 || region.getEndLine() == 0) {
72 {
73 // DEBUG 67 // DEBUG
74 System.err.println( String.format( "WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region ) ); 68 System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region));
75 return null; 69 return null;
76 } 70 }
77 Token token = new Token( 71 Token token = new Token(
78 toPos( region.getBeginLine(), region.getBeginColumn() ), 72 toPos(region.getBeginLine(), region.getBeginColumn()),
79 toPos( region.getEndLine(), region.getEndColumn() ), 73 toPos(region.getEndLine(), region.getEndColumn()),
80 m_source 74 m_source
81 ); 75 );
82 if( token.start == 0 ) 76 if (token.start == 0) {
83 {
84 // DEBUG 77 // DEBUG
85 System.err.println( String.format( "WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region ) ); 78 System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region));
86 return null; 79 return null;
87 } 80 }
88 81
89 // DEBUG 82 // DEBUG
90 //System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); 83 // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) );
91 84
92 // for tokens representing inner classes, make sure we only get the simple name 85 // for tokens representing inner classes, make sure we only get the simple name
93 int pos = name.lastIndexOf( '$' ); 86 int pos = name.lastIndexOf('$');
94 if( pos >= 0 ) 87 if (pos >= 0) {
95 {
96 token.end -= pos + 1; 88 token.end -= pos + 1;
97 } 89 }
98 90
99 return token; 91 return token;
100 } 92 }
101 93
102 public void addReference( AstNode node, Entry deobfEntry, Entry deobfContext ) 94 public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) {
103 { 95 Token token = getToken(node);
104 Token token = getToken( node ); 96 if (token != null) {
105 if( token != null ) 97 EntryReference<Entry,Entry> deobfReference = new EntryReference<Entry,Entry>(deobfEntry, token.text, deobfContext);
106 { 98 m_tokenToReference.put(token, deobfReference);
107 EntryReference<Entry,Entry> deobfReference = new EntryReference<Entry,Entry>( deobfEntry, token.text, deobfContext ); 99 m_referenceToTokens.put(deobfReference, token);
108 m_tokenToReference.put( token, deobfReference );
109 m_referenceToTokens.put( deobfReference, token );
110 } 100 }
111 } 101 }
112 102
113 public void addDeclaration( AstNode node, Entry deobfEntry ) 103 public void addDeclaration(AstNode node, Entry deobfEntry) {
114 { 104 Token token = getToken(node);
115 Token token = getToken( node ); 105 if (token != null) {
116 if( token != null ) 106 EntryReference<Entry,Entry> reference = new EntryReference<Entry,Entry>(deobfEntry, token.text);
117 { 107 m_tokenToReference.put(token, reference);
118 EntryReference<Entry,Entry> reference = new EntryReference<Entry,Entry>( deobfEntry, token.text ); 108 m_referenceToTokens.put(reference, token);
119 m_tokenToReference.put( token, reference ); 109 m_declarationToToken.put(deobfEntry, token);
120 m_referenceToTokens.put( reference, token );
121 m_declarationToToken.put( deobfEntry, token );
122 } 110 }
123 } 111 }
124 112
125 public Token getReferenceToken( int pos ) 113 public Token getReferenceToken(int pos) {
126 { 114 Token token = m_tokenToReference.floorKey(new Token(pos, pos, null));
127 Token token = m_tokenToReference.floorKey( new Token( pos, pos, null ) ); 115 if (token != null && token.contains(pos)) {
128 if( token != null && token.contains( pos ) )
129 {
130 return token; 116 return token;
131 } 117 }
132 return null; 118 return null;
133 } 119 }
134 120
135 public Collection<Token> getReferenceTokens( EntryReference<Entry,Entry> deobfReference ) 121 public Collection<Token> getReferenceTokens(EntryReference<Entry,Entry> deobfReference) {
136 { 122 return m_referenceToTokens.get(deobfReference);
137 return m_referenceToTokens.get( deobfReference );
138 } 123 }
139 124
140 public EntryReference<Entry,Entry> getDeobfReference( Token token ) 125 public EntryReference<Entry,Entry> getDeobfReference(Token token) {
141 { 126 if (token == null) {
142 if( token == null )
143 {
144 return null; 127 return null;
145 } 128 }
146 return m_tokenToReference.get( token ); 129 return m_tokenToReference.get(token);
147 } 130 }
148 131
149 public void replaceDeobfReference( Token token, EntryReference<Entry,Entry> newDeobfReference ) 132 public void replaceDeobfReference(Token token, EntryReference<Entry,Entry> newDeobfReference) {
150 { 133 EntryReference<Entry,Entry> oldDeobfReference = m_tokenToReference.get(token);
151 EntryReference<Entry,Entry> oldDeobfReference = m_tokenToReference.get( token ); 134 m_tokenToReference.put(token, newDeobfReference);
152 m_tokenToReference.put( token, newDeobfReference ); 135 Collection<Token> tokens = m_referenceToTokens.get(oldDeobfReference);
153 Collection<Token> tokens = m_referenceToTokens.get( oldDeobfReference ); 136 m_referenceToTokens.removeAll(oldDeobfReference);
154 m_referenceToTokens.removeAll( oldDeobfReference ); 137 m_referenceToTokens.putAll(newDeobfReference, tokens);
155 m_referenceToTokens.putAll( newDeobfReference, tokens );
156 } 138 }
157 139
158 public Iterable<Token> referenceTokens( ) 140 public Iterable<Token> referenceTokens() {
159 {
160 return m_tokenToReference.keySet(); 141 return m_tokenToReference.keySet();
161 } 142 }
162 143
163 public Iterable<Token> declarationTokens( ) 144 public Iterable<Token> declarationTokens() {
164 {
165 return m_declarationToToken.values(); 145 return m_declarationToToken.values();
166 } 146 }
167 147
168 public Token getDeclarationToken( Entry deobfEntry ) 148 public Token getDeclarationToken(Entry deobfEntry) {
169 { 149 return m_declarationToToken.get(deobfEntry);
170 return m_declarationToToken.get( deobfEntry );
171 } 150 }
172 151
173 public int getLineNumber( int pos ) 152 public int getLineNumber(int pos) {
174 {
175 // line number is 1-based 153 // line number is 1-based
176 int line = 0; 154 int line = 0;
177 for( Integer offset : m_lineOffsets ) 155 for (Integer offset : m_lineOffsets) {
178 { 156 if (offset > pos) {
179 if( offset > pos )
180 {
181 break; 157 break;
182 } 158 }
183 line++; 159 line++;
@@ -185,15 +161,13 @@ public class SourceIndex
185 return line; 161 return line;
186 } 162 }
187 163
188 public int getColumnNumber( int pos ) 164 public int getColumnNumber(int pos) {
189 {
190 // column number is 1-based 165 // column number is 1-based
191 return pos - m_lineOffsets.get( getLineNumber( pos ) - 1 ) + 1; 166 return pos - m_lineOffsets.get(getLineNumber(pos) - 1) + 1;
192 } 167 }
193 168
194 private int toPos( int line, int col ) 169 private int toPos(int line, int col) {
195 {
196 // line and col are 1-based 170 // line and col are 1-based
197 return m_lineOffsets.get( line - 1 ) + col - 1; 171 return m_lineOffsets.get(line - 1) + col - 1;
198 } 172 }
199} 173}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
index 7ffd170..43c1749 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java
@@ -36,159 +36,128 @@ import cuchaz.enigma.mapping.ConstructorEntry;
36import cuchaz.enigma.mapping.FieldEntry; 36import cuchaz.enigma.mapping.FieldEntry;
37import cuchaz.enigma.mapping.MethodEntry; 37import cuchaz.enigma.mapping.MethodEntry;
38 38
39public class SourceIndexBehaviorVisitor extends SourceIndexVisitor 39public class SourceIndexBehaviorVisitor extends SourceIndexVisitor {
40{ 40
41 private BehaviorEntry m_behaviorEntry; 41 private BehaviorEntry m_behaviorEntry;
42 42
43 public SourceIndexBehaviorVisitor( BehaviorEntry behaviorEntry ) 43 public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) {
44 {
45 m_behaviorEntry = behaviorEntry; 44 m_behaviorEntry = behaviorEntry;
46 } 45 }
47 46
48 @Override 47 @Override
49 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 48 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
50 { 49 return recurse(node, index);
51 return recurse( node, index );
52 } 50 }
53 51
54 @Override 52 @Override
55 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 53 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
56 { 54 return recurse(node, index);
57 return recurse( node, index );
58 } 55 }
59 56
60 @Override 57 @Override
61 public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) 58 public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) {
62 { 59 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
63 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE );
64 60
65 // get the behavior entry 61 // get the behavior entry
66 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 62 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
67 BehaviorEntry behaviorEntry = null; 63 BehaviorEntry behaviorEntry = null;
68 if( ref instanceof MethodReference ) 64 if (ref instanceof MethodReference) {
69 {
70 MethodReference methodRef = (MethodReference)ref; 65 MethodReference methodRef = (MethodReference)ref;
71 if( methodRef.isConstructor() ) 66 if (methodRef.isConstructor()) {
72 { 67 behaviorEntry = new ConstructorEntry(classEntry, ref.getSignature());
73 behaviorEntry = new ConstructorEntry( classEntry, ref.getSignature() ); 68 } else if (methodRef.isTypeInitializer()) {
74 } 69 behaviorEntry = new ConstructorEntry(classEntry);
75 else if( methodRef.isTypeInitializer() ) 70 } else {
76 { 71 behaviorEntry = new MethodEntry(classEntry, ref.getName(), ref.getSignature());
77 behaviorEntry = new ConstructorEntry( classEntry );
78 }
79 else
80 {
81 behaviorEntry = new MethodEntry( classEntry, ref.getName(), ref.getSignature() );
82 } 72 }
83 } 73 }
84 if( behaviorEntry != null ) 74 if (behaviorEntry != null) {
85 {
86 // get the node for the token 75 // get the node for the token
87 AstNode tokenNode = null; 76 AstNode tokenNode = null;
88 if( node.getTarget() instanceof MemberReferenceExpression ) 77 if (node.getTarget() instanceof MemberReferenceExpression) {
89 {
90 tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(); 78 tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken();
91 } 79 } else if (node.getTarget() instanceof SuperReferenceExpression) {
92 else if( node.getTarget() instanceof SuperReferenceExpression )
93 {
94 tokenNode = node.getTarget(); 80 tokenNode = node.getTarget();
95 } 81 } else if (node.getTarget() instanceof ThisReferenceExpression) {
96 else if( node.getTarget() instanceof ThisReferenceExpression )
97 {
98 tokenNode = node.getTarget(); 82 tokenNode = node.getTarget();
99 } 83 }
100 if( tokenNode != null ) 84 if (tokenNode != null) {
101 { 85 index.addReference(tokenNode, behaviorEntry, m_behaviorEntry);
102 index.addReference( tokenNode, behaviorEntry, m_behaviorEntry );
103 } 86 }
104 } 87 }
105 88
106 return recurse( node, index ); 89 return recurse(node, index);
107 } 90 }
108 91
109 @Override 92 @Override
110 public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) 93 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) {
111 { 94 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
112 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 95 if (ref != null) {
113 if( ref != null )
114 {
115 // make sure this is actually a field 96 // make sure this is actually a field
116 if( ref.getSignature().indexOf( '(' ) >= 0 ) 97 if (ref.getSignature().indexOf('(') >= 0) {
117 { 98 throw new Error("Expected a field here! got " + ref);
118 throw new Error( "Expected a field here! got " + ref );
119 } 99 }
120 100
121 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 101 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
122 FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); 102 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName());
123 index.addReference( node.getMemberNameToken(), fieldEntry, m_behaviorEntry ); 103 index.addReference(node.getMemberNameToken(), fieldEntry, m_behaviorEntry);
124 } 104 }
125 105
126 return recurse( node, index ); 106 return recurse(node, index);
127 } 107 }
128 108
129 @Override 109 @Override
130 public Void visitSimpleType( SimpleType node, SourceIndex index ) 110 public Void visitSimpleType(SimpleType node, SourceIndex index) {
131 { 111 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
132 TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); 112 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
133 if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) 113 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
134 { 114 index.addReference(node.getIdentifierToken(), classEntry, m_behaviorEntry);
135 ClassEntry classEntry = new ClassEntry( ref.getInternalName() );
136 index.addReference( node.getIdentifierToken(), classEntry, m_behaviorEntry );
137 } 115 }
138 116
139 return recurse( node, index ); 117 return recurse(node, index);
140 } 118 }
141 119
142 @Override 120 @Override
143 public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) 121 public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) {
144 { 122 ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION);
145 ParameterDefinition def = node.getUserData( Keys.PARAMETER_DEFINITION ); 123 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
146 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
147 MethodDefinition methodDef = (MethodDefinition)def.getMethod(); 124 MethodDefinition methodDef = (MethodDefinition)def.getMethod();
148 BehaviorEntry behaviorEntry; 125 BehaviorEntry behaviorEntry;
149 if( methodDef.isConstructor() ) 126 if (methodDef.isConstructor()) {
150 { 127 behaviorEntry = new ConstructorEntry(classEntry, methodDef.getSignature());
151 behaviorEntry = new ConstructorEntry( classEntry, methodDef.getSignature() ); 128 } else {
152 } 129 behaviorEntry = new MethodEntry(classEntry, methodDef.getName(), methodDef.getSignature());
153 else
154 {
155 behaviorEntry = new MethodEntry( classEntry, methodDef.getName(), methodDef.getSignature() );
156 } 130 }
157 ArgumentEntry argumentEntry = new ArgumentEntry( behaviorEntry, def.getPosition(), node.getName() ); 131 ArgumentEntry argumentEntry = new ArgumentEntry(behaviorEntry, def.getPosition(), node.getName());
158 index.addDeclaration( node.getNameToken(), argumentEntry ); 132 index.addDeclaration(node.getNameToken(), argumentEntry);
159 133
160 return recurse( node, index ); 134 return recurse(node, index);
161 } 135 }
162 136
163 @Override 137 @Override
164 public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) 138 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) {
165 { 139 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
166 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 140 if (ref != null) {
167 if( ref != null ) 141 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
168 { 142 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName());
169 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 143 index.addReference(node.getIdentifierToken(), fieldEntry, m_behaviorEntry);
170 FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() );
171 index.addReference( node.getIdentifierToken(), fieldEntry, m_behaviorEntry );
172 } 144 }
173 145
174 return recurse( node, index ); 146 return recurse(node, index);
175 } 147 }
176 148
177 @Override 149 @Override
178 public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) 150 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) {
179 { 151 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
180 MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); 152 if (ref != null) {
181 if( ref != null ) 153 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
182 { 154 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, ref.getSignature());
183 ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); 155 if (node.getType() instanceof SimpleType) {
184 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, ref.getSignature() );
185 if( node.getType() instanceof SimpleType )
186 {
187 SimpleType simpleTypeNode = (SimpleType)node.getType(); 156 SimpleType simpleTypeNode = (SimpleType)node.getType();
188 index.addReference( simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry ); 157 index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry);
189 } 158 }
190 } 159 }
191 160
192 return recurse( node, index ); 161 return recurse(node, index);
193 } 162 }
194} 163}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
index 24c4822..7b902a9 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java
@@ -31,95 +31,84 @@ import cuchaz.enigma.mapping.ClassEntry;
31import cuchaz.enigma.mapping.ConstructorEntry; 31import cuchaz.enigma.mapping.ConstructorEntry;
32import cuchaz.enigma.mapping.FieldEntry; 32import cuchaz.enigma.mapping.FieldEntry;
33 33
34public class SourceIndexClassVisitor extends SourceIndexVisitor 34public class SourceIndexClassVisitor extends SourceIndexVisitor {
35{ 35
36 private ClassEntry m_classEntry; 36 private ClassEntry m_classEntry;
37 37
38 public SourceIndexClassVisitor( ClassEntry classEntry ) 38 public SourceIndexClassVisitor(ClassEntry classEntry) {
39 {
40 m_classEntry = classEntry; 39 m_classEntry = classEntry;
41 } 40 }
42 41
43 @Override 42 @Override
44 public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) 43 public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) {
45 {
46 // is this this class, or a subtype? 44 // is this this class, or a subtype?
47 TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); 45 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION);
48 ClassEntry classEntry = new ClassEntry( def.getInternalName() ); 46 ClassEntry classEntry = new ClassEntry(def.getInternalName());
49 if( !classEntry.equals( m_classEntry ) ) 47 if (!classEntry.equals(m_classEntry)) {
50 {
51 // it's a sub-type, recurse 48 // it's a sub-type, recurse
52 index.addDeclaration( node.getNameToken(), classEntry ); 49 index.addDeclaration(node.getNameToken(), classEntry);
53 return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); 50 return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index);
54 } 51 }
55 52
56 return recurse( node, index ); 53 return recurse(node, index);
57 } 54 }
58 55
59 @Override 56 @Override
60 public Void visitSimpleType( SimpleType node, SourceIndex index ) 57 public Void visitSimpleType(SimpleType node, SourceIndex index) {
61 { 58 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
62 TypeReference ref = node.getUserData( Keys.TYPE_REFERENCE ); 59 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
63 if( node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY ) 60 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
64 { 61 index.addReference(node.getIdentifierToken(), classEntry, m_classEntry);
65 ClassEntry classEntry = new ClassEntry( ref.getInternalName() );
66 index.addReference( node.getIdentifierToken(), classEntry, m_classEntry );
67 } 62 }
68 63
69 return recurse( node, index ); 64 return recurse(node, index);
70 } 65 }
71 66
72 @Override 67 @Override
73 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 68 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
74 { 69 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
75 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); 70 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
76 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 71 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature());
77 BehaviorEntry behaviorEntry = BehaviorEntryFactory.create( classEntry, def.getName(), def.getSignature() );
78 AstNode tokenNode = node.getNameToken(); 72 AstNode tokenNode = node.getNameToken();
79 if( behaviorEntry instanceof ConstructorEntry ) 73 if (behaviorEntry instanceof ConstructorEntry) {
80 {
81 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; 74 ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry;
82 if( constructorEntry.isStatic() ) 75 if (constructorEntry.isStatic()) {
83 {
84 tokenNode = node.getModifiers().firstOrNullObject(); 76 tokenNode = node.getModifiers().firstOrNullObject();
85 } 77 }
86 } 78 }
87 index.addDeclaration( tokenNode, behaviorEntry ); 79 index.addDeclaration(tokenNode, behaviorEntry);
88 return node.acceptVisitor( new SourceIndexBehaviorVisitor( behaviorEntry ), index ); 80 return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index);
89 } 81 }
90 82
91 @Override 83 @Override
92 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 84 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
93 { 85 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
94 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); 86 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
95 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 87 ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, def.getSignature());
96 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() ); 88 index.addDeclaration(node.getNameToken(), constructorEntry);
97 index.addDeclaration( node.getNameToken(), constructorEntry ); 89 return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index);
98 return node.acceptVisitor( new SourceIndexBehaviorVisitor( constructorEntry ), index );
99 } 90 }
100 91
101 @Override 92 @Override
102 public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) 93 public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) {
103 { 94 FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION);
104 FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); 95 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
105 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 96 FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName());
106 FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); 97 assert (node.getVariables().size() == 1);
107 assert( node.getVariables().size() == 1 );
108 VariableInitializer variable = node.getVariables().firstOrNullObject(); 98 VariableInitializer variable = node.getVariables().firstOrNullObject();
109 index.addDeclaration( variable.getNameToken(), fieldEntry ); 99 index.addDeclaration(variable.getNameToken(), fieldEntry);
110 100
111 return recurse( node, index ); 101 return recurse(node, index);
112 } 102 }
113 103
114 @Override 104 @Override
115 public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) 105 public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) {
116 {
117 // treat enum declarations as field declarations 106 // treat enum declarations as field declarations
118 FieldDefinition def = node.getUserData( Keys.FIELD_DEFINITION ); 107 FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION);
119 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() ); 108 ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName());
120 FieldEntry fieldEntry = new FieldEntry( classEntry, def.getName() ); 109 FieldEntry fieldEntry = new FieldEntry(classEntry, def.getName());
121 index.addDeclaration( node.getNameToken(), fieldEntry ); 110 index.addDeclaration(node.getNameToken(), fieldEntry);
122 111
123 return recurse( node, index ); 112 return recurse(node, index);
124 } 113 }
125} 114}
diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
index 4e98989..0d5bdc0 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
@@ -87,438 +87,366 @@ import com.strobel.decompiler.patterns.Pattern;
87 87
88import cuchaz.enigma.mapping.ClassEntry; 88import cuchaz.enigma.mapping.ClassEntry;
89 89
90public class SourceIndexVisitor implements IAstVisitor<SourceIndex,Void> 90public class SourceIndexVisitor implements IAstVisitor<SourceIndex,Void> {
91{ 91
92 @Override 92 @Override
93 public Void visitTypeDeclaration( TypeDeclaration node, SourceIndex index ) 93 public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) {
94 { 94 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION);
95 TypeDefinition def = node.getUserData( Keys.TYPE_DEFINITION ); 95 ClassEntry classEntry = new ClassEntry(def.getInternalName());
96 ClassEntry classEntry = new ClassEntry( def.getInternalName() ); 96 index.addDeclaration(node.getNameToken(), classEntry);
97 index.addDeclaration( node.getNameToken(), classEntry );
98 97
99 return node.acceptVisitor( new SourceIndexClassVisitor( classEntry ), index ); 98 return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index);
100 } 99 }
101 100
102 protected Void recurse( AstNode node, SourceIndex index ) 101 protected Void recurse(AstNode node, SourceIndex index) {
103 { 102 for (final AstNode child : node.getChildren()) {
104 for( final AstNode child : node.getChildren() ) 103 child.acceptVisitor(this, index);
105 {
106 child.acceptVisitor( this, index );
107 } 104 }
108 return null; 105 return null;
109 } 106 }
110 107
111 @Override 108 @Override
112 public Void visitMethodDeclaration( MethodDeclaration node, SourceIndex index ) 109 public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) {
113 { 110 return recurse(node, index);
114 return recurse( node, index );
115 } 111 }
116 112
117 @Override 113 @Override
118 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 114 public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) {
119 { 115 return recurse(node, index);
120 return recurse( node, index );
121 } 116 }
122 117
123 @Override 118 @Override
124 public Void visitFieldDeclaration( FieldDeclaration node, SourceIndex index ) 119 public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) {
125 { 120 return recurse(node, index);
126 return recurse( node, index );
127 } 121 }
128 122
129 @Override 123 @Override
130 public Void visitEnumValueDeclaration( EnumValueDeclaration node, SourceIndex index ) 124 public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) {
131 { 125 return recurse(node, index);
132 return recurse( node, index );
133 } 126 }
134 127
135 @Override 128 @Override
136 public Void visitParameterDeclaration( ParameterDeclaration node, SourceIndex index ) 129 public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) {
137 { 130 return recurse(node, index);
138 return recurse( node, index );
139 } 131 }
140 132
141 @Override 133 @Override
142 public Void visitInvocationExpression( InvocationExpression node, SourceIndex index ) 134 public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) {
143 { 135 return recurse(node, index);
144 return recurse( node, index );
145 } 136 }
146 137
147 @Override 138 @Override
148 public Void visitMemberReferenceExpression( MemberReferenceExpression node, SourceIndex index ) 139 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) {
149 { 140 return recurse(node, index);
150 return recurse( node, index );
151 } 141 }
152 142
153 @Override 143 @Override
154 public Void visitSimpleType( SimpleType node, SourceIndex index ) 144 public Void visitSimpleType(SimpleType node, SourceIndex index) {
155 { 145 return recurse(node, index);
156 return recurse( node, index );
157 } 146 }
158 147
159 @Override 148 @Override
160 public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) 149 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) {
161 { 150 return recurse(node, index);
162 return recurse( node, index );
163 } 151 }
164 152
165 @Override 153 @Override
166 public Void visitComment( Comment node, SourceIndex index ) 154 public Void visitComment(Comment node, SourceIndex index) {
167 { 155 return recurse(node, index);
168 return recurse( node, index );
169 } 156 }
170 157
171 @Override 158 @Override
172 public Void visitPatternPlaceholder( AstNode node, Pattern pattern, SourceIndex index ) 159 public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) {
173 { 160 return recurse(node, index);
174 return recurse( node, index );
175 } 161 }
176 162
177 @Override 163 @Override
178 public Void visitTypeReference( TypeReferenceExpression node, SourceIndex index ) 164 public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) {
179 { 165 return recurse(node, index);
180 return recurse( node, index );
181 } 166 }
182 167
183 @Override 168 @Override
184 public Void visitJavaTokenNode( JavaTokenNode node, SourceIndex index ) 169 public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) {
185 { 170 return recurse(node, index);
186 return recurse( node, index );
187 } 171 }
188 172
189 @Override 173 @Override
190 public Void visitIdentifier( Identifier node, SourceIndex index ) 174 public Void visitIdentifier(Identifier node, SourceIndex index) {
191 { 175 return recurse(node, index);
192 return recurse( node, index );
193 } 176 }
194 177
195 @Override 178 @Override
196 public Void visitNullReferenceExpression( NullReferenceExpression node, SourceIndex index ) 179 public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) {
197 { 180 return recurse(node, index);
198 return recurse( node, index );
199 } 181 }
200 182
201 @Override 183 @Override
202 public Void visitThisReferenceExpression( ThisReferenceExpression node, SourceIndex index ) 184 public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) {
203 { 185 return recurse(node, index);
204 return recurse( node, index );
205 } 186 }
206 187
207 @Override 188 @Override
208 public Void visitSuperReferenceExpression( SuperReferenceExpression node, SourceIndex index ) 189 public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) {
209 { 190 return recurse(node, index);
210 return recurse( node, index );
211 } 191 }
212 192
213 @Override 193 @Override
214 public Void visitClassOfExpression( ClassOfExpression node, SourceIndex index ) 194 public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) {
215 { 195 return recurse(node, index);
216 return recurse( node, index );
217 } 196 }
218 197
219 @Override 198 @Override
220 public Void visitBlockStatement( BlockStatement node, SourceIndex index ) 199 public Void visitBlockStatement(BlockStatement node, SourceIndex index) {
221 { 200 return recurse(node, index);
222 return recurse( node, index );
223 } 201 }
224 202
225 @Override 203 @Override
226 public Void visitExpressionStatement( ExpressionStatement node, SourceIndex index ) 204 public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) {
227 { 205 return recurse(node, index);
228 return recurse( node, index );
229 } 206 }
230 207
231 @Override 208 @Override
232 public Void visitBreakStatement( BreakStatement node, SourceIndex index ) 209 public Void visitBreakStatement(BreakStatement node, SourceIndex index) {
233 { 210 return recurse(node, index);
234 return recurse( node, index );
235 } 211 }
236 212
237 @Override 213 @Override
238 public Void visitContinueStatement( ContinueStatement node, SourceIndex index ) 214 public Void visitContinueStatement(ContinueStatement node, SourceIndex index) {
239 { 215 return recurse(node, index);
240 return recurse( node, index );
241 } 216 }
242 217
243 @Override 218 @Override
244 public Void visitDoWhileStatement( DoWhileStatement node, SourceIndex index ) 219 public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) {
245 { 220 return recurse(node, index);
246 return recurse( node, index );
247 } 221 }
248 222
249 @Override 223 @Override
250 public Void visitEmptyStatement( EmptyStatement node, SourceIndex index ) 224 public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) {
251 { 225 return recurse(node, index);
252 return recurse( node, index );
253 } 226 }
254 227
255 @Override 228 @Override
256 public Void visitIfElseStatement( IfElseStatement node, SourceIndex index ) 229 public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) {
257 { 230 return recurse(node, index);
258 return recurse( node, index );
259 } 231 }
260 232
261 @Override 233 @Override
262 public Void visitLabelStatement( LabelStatement node, SourceIndex index ) 234 public Void visitLabelStatement(LabelStatement node, SourceIndex index) {
263 { 235 return recurse(node, index);
264 return recurse( node, index );
265 } 236 }
266 237
267 @Override 238 @Override
268 public Void visitLabeledStatement( LabeledStatement node, SourceIndex index ) 239 public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) {
269 { 240 return recurse(node, index);
270 return recurse( node, index );
271 } 241 }
272 242
273 @Override 243 @Override
274 public Void visitReturnStatement( ReturnStatement node, SourceIndex index ) 244 public Void visitReturnStatement(ReturnStatement node, SourceIndex index) {
275 { 245 return recurse(node, index);
276 return recurse( node, index );
277 } 246 }
278 247
279 @Override 248 @Override
280 public Void visitSwitchStatement( SwitchStatement node, SourceIndex index ) 249 public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) {
281 { 250 return recurse(node, index);
282 return recurse( node, index );
283 } 251 }
284 252
285 @Override 253 @Override
286 public Void visitSwitchSection( SwitchSection node, SourceIndex index ) 254 public Void visitSwitchSection(SwitchSection node, SourceIndex index) {
287 { 255 return recurse(node, index);
288 return recurse( node, index );
289 } 256 }
290 257
291 @Override 258 @Override
292 public Void visitCaseLabel( CaseLabel node, SourceIndex index ) 259 public Void visitCaseLabel(CaseLabel node, SourceIndex index) {
293 { 260 return recurse(node, index);
294 return recurse( node, index );
295 } 261 }
296 262
297 @Override 263 @Override
298 public Void visitThrowStatement( ThrowStatement node, SourceIndex index ) 264 public Void visitThrowStatement(ThrowStatement node, SourceIndex index) {
299 { 265 return recurse(node, index);
300 return recurse( node, index );
301 } 266 }
302 267
303 @Override 268 @Override
304 public Void visitCatchClause( CatchClause node, SourceIndex index ) 269 public Void visitCatchClause(CatchClause node, SourceIndex index) {
305 { 270 return recurse(node, index);
306 return recurse( node, index );
307 } 271 }
308 272
309 @Override 273 @Override
310 public Void visitAnnotation( Annotation node, SourceIndex index ) 274 public Void visitAnnotation(Annotation node, SourceIndex index) {
311 { 275 return recurse(node, index);
312 return recurse( node, index );
313 } 276 }
314 277
315 @Override 278 @Override
316 public Void visitNewLine( NewLineNode node, SourceIndex index ) 279 public Void visitNewLine(NewLineNode node, SourceIndex index) {
317 { 280 return recurse(node, index);
318 return recurse( node, index );
319 } 281 }
320 282
321 @Override 283 @Override
322 public Void visitVariableDeclaration( VariableDeclarationStatement node, SourceIndex index ) 284 public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) {
323 { 285 return recurse(node, index);
324 return recurse( node, index );
325 } 286 }
326 287
327 @Override 288 @Override
328 public Void visitVariableInitializer( VariableInitializer node, SourceIndex index ) 289 public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) {
329 { 290 return recurse(node, index);
330 return recurse( node, index );
331 } 291 }
332 292
333 @Override 293 @Override
334 public Void visitText( TextNode node, SourceIndex index ) 294 public Void visitText(TextNode node, SourceIndex index) {
335 { 295 return recurse(node, index);
336 return recurse( node, index );
337 } 296 }
338 297
339 @Override 298 @Override
340 public Void visitImportDeclaration( ImportDeclaration node, SourceIndex index ) 299 public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) {
341 { 300 return recurse(node, index);
342 return recurse( node, index );
343 } 301 }
344 302
345 @Override 303 @Override
346 public Void visitInitializerBlock( InstanceInitializer node, SourceIndex index ) 304 public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) {
347 { 305 return recurse(node, index);
348 return recurse( node, index );
349 } 306 }
350 307
351 @Override 308 @Override
352 public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, SourceIndex index ) 309 public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) {
353 { 310 return recurse(node, index);
354 return recurse( node, index );
355 } 311 }
356 312
357 @Override 313 @Override
358 public Void visitCompilationUnit( CompilationUnit node, SourceIndex index ) 314 public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) {
359 { 315 return recurse(node, index);
360 return recurse( node, index );
361 } 316 }
362 317
363 @Override 318 @Override
364 public Void visitPackageDeclaration( PackageDeclaration node, SourceIndex index ) 319 public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) {
365 { 320 return recurse(node, index);
366 return recurse( node, index );
367 } 321 }
368 322
369 @Override 323 @Override
370 public Void visitArraySpecifier( ArraySpecifier node, SourceIndex index ) 324 public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) {
371 { 325 return recurse(node, index);
372 return recurse( node, index );
373 } 326 }
374 327
375 @Override 328 @Override
376 public Void visitComposedType( ComposedType node, SourceIndex index ) 329 public Void visitComposedType(ComposedType node, SourceIndex index) {
377 { 330 return recurse(node, index);
378 return recurse( node, index );
379 } 331 }
380 332
381 @Override 333 @Override
382 public Void visitWhileStatement( WhileStatement node, SourceIndex index ) 334 public Void visitWhileStatement(WhileStatement node, SourceIndex index) {
383 { 335 return recurse(node, index);
384 return recurse( node, index );
385 } 336 }
386 337
387 @Override 338 @Override
388 public Void visitPrimitiveExpression( PrimitiveExpression node, SourceIndex index ) 339 public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) {
389 { 340 return recurse(node, index);
390 return recurse( node, index );
391 } 341 }
392 342
393 @Override 343 @Override
394 public Void visitCastExpression( CastExpression node, SourceIndex index ) 344 public Void visitCastExpression(CastExpression node, SourceIndex index) {
395 { 345 return recurse(node, index);
396 return recurse( node, index );
397 } 346 }
398 347
399 @Override 348 @Override
400 public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, SourceIndex index ) 349 public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) {
401 { 350 return recurse(node, index);
402 return recurse( node, index );
403 } 351 }
404 352
405 @Override 353 @Override
406 public Void visitInstanceOfExpression( InstanceOfExpression node, SourceIndex index ) 354 public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) {
407 { 355 return recurse(node, index);
408 return recurse( node, index );
409 } 356 }
410 357
411 @Override 358 @Override
412 public Void visitIndexerExpression( IndexerExpression node, SourceIndex index ) 359 public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) {
413 { 360 return recurse(node, index);
414 return recurse( node, index );
415 } 361 }
416 362
417 @Override 363 @Override
418 public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) 364 public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) {
419 { 365 return recurse(node, index);
420 return recurse( node, index );
421 } 366 }
422 367
423 @Override 368 @Override
424 public Void visitConditionalExpression( ConditionalExpression node, SourceIndex index ) 369 public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) {
425 { 370 return recurse(node, index);
426 return recurse( node, index );
427 } 371 }
428 372
429 @Override 373 @Override
430 public Void visitArrayInitializerExpression( ArrayInitializerExpression node, SourceIndex index ) 374 public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) {
431 { 375 return recurse(node, index);
432 return recurse( node, index );
433 } 376 }
434 377
435 @Override 378 @Override
436 public Void visitObjectCreationExpression( ObjectCreationExpression node, SourceIndex index ) 379 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) {
437 { 380 return recurse(node, index);
438 return recurse( node, index );
439 } 381 }
440 382
441 @Override 383 @Override
442 public Void visitArrayCreationExpression( ArrayCreationExpression node, SourceIndex index ) 384 public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) {
443 { 385 return recurse(node, index);
444 return recurse( node, index );
445 } 386 }
446 387
447 @Override 388 @Override
448 public Void visitAssignmentExpression( AssignmentExpression node, SourceIndex index ) 389 public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) {
449 { 390 return recurse(node, index);
450 return recurse( node, index );
451 } 391 }
452 392
453 @Override 393 @Override
454 public Void visitForStatement( ForStatement node, SourceIndex index ) 394 public Void visitForStatement(ForStatement node, SourceIndex index) {
455 { 395 return recurse(node, index);
456 return recurse( node, index );
457 } 396 }
458 397
459 @Override 398 @Override
460 public Void visitForEachStatement( ForEachStatement node, SourceIndex index ) 399 public Void visitForEachStatement(ForEachStatement node, SourceIndex index) {
461 { 400 return recurse(node, index);
462 return recurse( node, index );
463 } 401 }
464 402
465 @Override 403 @Override
466 public Void visitTryCatchStatement( TryCatchStatement node, SourceIndex index ) 404 public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) {
467 { 405 return recurse(node, index);
468 return recurse( node, index );
469 } 406 }
470 407
471 @Override 408 @Override
472 public Void visitGotoStatement( GotoStatement node, SourceIndex index ) 409 public Void visitGotoStatement(GotoStatement node, SourceIndex index) {
473 { 410 return recurse(node, index);
474 return recurse( node, index );
475 } 411 }
476 412
477 @Override 413 @Override
478 public Void visitParenthesizedExpression( ParenthesizedExpression node, SourceIndex index ) 414 public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) {
479 { 415 return recurse(node, index);
480 return recurse( node, index );
481 } 416 }
482 417
483 @Override 418 @Override
484 public Void visitSynchronizedStatement( SynchronizedStatement node, SourceIndex index ) 419 public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) {
485 { 420 return recurse(node, index);
486 return recurse( node, index );
487 } 421 }
488 422
489 @Override 423 @Override
490 public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, SourceIndex index ) 424 public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) {
491 { 425 return recurse(node, index);
492 return recurse( node, index );
493 } 426 }
494 427
495 @Override 428 @Override
496 public Void visitWildcardType( WildcardType node, SourceIndex index ) 429 public Void visitWildcardType(WildcardType node, SourceIndex index) {
497 { 430 return recurse(node, index);
498 return recurse( node, index );
499 } 431 }
500 432
501 @Override 433 @Override
502 public Void visitMethodGroupExpression( MethodGroupExpression node, SourceIndex index ) 434 public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) {
503 { 435 return recurse(node, index);
504 return recurse( node, index );
505 } 436 }
506 437
507 @Override 438 @Override
508 public Void visitAssertStatement( AssertStatement node, SourceIndex index ) 439 public Void visitAssertStatement(AssertStatement node, SourceIndex index) {
509 { 440 return recurse(node, index);
510 return recurse( node, index );
511 } 441 }
512 442
513 @Override 443 @Override
514 public Void visitLambdaExpression( LambdaExpression node, SourceIndex index ) 444 public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) {
515 { 445 return recurse(node, index);
516 return recurse( node, index );
517 } 446 }
518 447
519 @Override 448 @Override
520 public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, SourceIndex index ) 449 public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) {
521 { 450 return recurse(node, index);
522 return recurse( node, index );
523 } 451 }
524} 452}
diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java
index 5e70db7..481d2f4 100644
--- a/src/cuchaz/enigma/analysis/Token.java
+++ b/src/cuchaz/enigma/analysis/Token.java
@@ -10,56 +10,47 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13public class Token implements Comparable<Token> 13public class Token implements Comparable<Token> {
14{ 14
15 public int start; 15 public int start;
16 public int end; 16 public int end;
17 public String text; 17 public String text;
18 18
19 public Token( int start, int end ) 19 public Token(int start, int end) {
20 { 20 this(start, end, null);
21 this( start, end, null );
22 } 21 }
23 22
24 public Token( int start, int end, String source ) 23 public Token(int start, int end, String source) {
25 {
26 this.start = start; 24 this.start = start;
27 this.end = end; 25 this.end = end;
28 if( source != null ) 26 if (source != null) {
29 { 27 this.text = source.substring(start, end);
30 this.text = source.substring( start, end );
31 } 28 }
32 } 29 }
33 30
34 public boolean contains( int pos ) 31 public boolean contains(int pos) {
35 {
36 return pos >= start && pos <= end; 32 return pos >= start && pos <= end;
37 } 33 }
38 34
39 @Override 35 @Override
40 public int compareTo( Token other ) 36 public int compareTo(Token other) {
41 {
42 return start - other.start; 37 return start - other.start;
43 } 38 }
44 39
45 @Override 40 @Override
46 public boolean equals( Object other ) 41 public boolean equals(Object other) {
47 { 42 if (other instanceof Token) {
48 if( other instanceof Token ) 43 return equals((Token)other);
49 {
50 return equals( (Token)other );
51 } 44 }
52 return false; 45 return false;
53 } 46 }
54 47
55 public boolean equals( Token other ) 48 public boolean equals(Token other) {
56 {
57 return start == other.start && end == other.end; 49 return start == other.start && end == other.end;
58 } 50 }
59 51
60 @Override 52 @Override
61 public String toString( ) 53 public String toString() {
62 { 54 return String.format("[%d,%d]", start, end);
63 return String.format( "[%d,%d]", start, end );
64 } 55 }
65} 56}
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java
index 5311ec7..c14fd59 100644
--- a/src/cuchaz/enigma/analysis/TranslationIndex.java
+++ b/src/cuchaz/enigma/analysis/TranslationIndex.java
@@ -23,104 +23,85 @@ import com.google.common.collect.Lists;
23import com.google.common.collect.Maps; 23import com.google.common.collect.Maps;
24import com.google.common.collect.Multimap; 24import com.google.common.collect.Multimap;
25 25
26public class TranslationIndex implements Serializable 26public class TranslationIndex implements Serializable {
27{ 27
28 private static final long serialVersionUID = 738687982126844179L; 28 private static final long serialVersionUID = 738687982126844179L;
29 29
30 private Map<String,String> m_superclasses; 30 private Map<String,String> m_superclasses;
31 private Multimap<String,String> m_fields; 31 private Multimap<String,String> m_fields;
32 32
33 public TranslationIndex( ) 33 public TranslationIndex() {
34 {
35 m_superclasses = Maps.newHashMap(); 34 m_superclasses = Maps.newHashMap();
36 m_fields = HashMultimap.create(); 35 m_fields = HashMultimap.create();
37 } 36 }
38 37
39 public TranslationIndex( TranslationIndex other ) 38 public TranslationIndex(TranslationIndex other) {
40 { 39 m_superclasses = Maps.newHashMap(other.m_superclasses);
41 m_superclasses = Maps.newHashMap( other.m_superclasses ); 40 m_fields = HashMultimap.create(other.m_fields);
42 m_fields = HashMultimap.create( other.m_fields );
43 } 41 }
44 42
45 public void addSuperclass( String className, String superclassName ) 43 public void addSuperclass(String className, String superclassName) {
46 { 44 className = Descriptor.toJvmName(className);
47 className = Descriptor.toJvmName( className ); 45 superclassName = Descriptor.toJvmName(superclassName);
48 superclassName = Descriptor.toJvmName( superclassName );
49 46
50 if( className.equals( superclassName ) ) 47 if (className.equals(superclassName)) {
51 { 48 throw new IllegalArgumentException("Class cannot be its own superclass! " + className);
52 throw new IllegalArgumentException( "Class cannot be its own superclass! " + className );
53 } 49 }
54 50
55 if( !isJre( className ) && !isJre( superclassName ) ) 51 if (!isJre(className) && !isJre(superclassName)) {
56 { 52 m_superclasses.put(className, superclassName);
57 m_superclasses.put( className, superclassName );
58 } 53 }
59 } 54 }
60 55
61 public void addField( String className, String fieldName ) 56 public void addField(String className, String fieldName) {
62 { 57 m_fields.put(className, fieldName);
63 m_fields.put( className, fieldName );
64 } 58 }
65 59
66 public void renameClasses( Map<String,String> renames ) 60 public void renameClasses(Map<String,String> renames) {
67 { 61 EntryRenamer.renameClassesInMap(renames, m_superclasses);
68 EntryRenamer.renameClassesInMap( renames, m_superclasses ); 62 EntryRenamer.renameClassesInMultimap(renames, m_fields);
69 EntryRenamer.renameClassesInMultimap( renames, m_fields );
70 } 63 }
71 64
72 public String getSuperclassName( String className ) 65 public String getSuperclassName(String className) {
73 { 66 return m_superclasses.get(className);
74 return m_superclasses.get( className );
75 } 67 }
76 68
77 public List<String> getAncestry( String className ) 69 public List<String> getAncestry(String className) {
78 {
79 List<String> ancestors = new ArrayList<String>(); 70 List<String> ancestors = new ArrayList<String>();
80 while( className != null ) 71 while (className != null) {
81 { 72 className = getSuperclassName(className);
82 className = getSuperclassName( className ); 73 if (className != null) {
83 if( className != null ) 74 ancestors.add(className);
84 {
85 ancestors.add( className );
86 } 75 }
87 } 76 }
88 return ancestors; 77 return ancestors;
89 } 78 }
90 79
91 public List<String> getSubclassNames( String className ) 80 public List<String> getSubclassNames(String className) {
92 {
93 // linear search is fast enough for now 81 // linear search is fast enough for now
94 List<String> subclasses = Lists.newArrayList(); 82 List<String> subclasses = Lists.newArrayList();
95 for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) 83 for (Map.Entry<String,String> entry : m_superclasses.entrySet()) {
96 {
97 String subclass = entry.getKey(); 84 String subclass = entry.getKey();
98 String superclass = entry.getValue(); 85 String superclass = entry.getValue();
99 if( className.equals( superclass ) ) 86 if (className.equals(superclass)) {
100 { 87 subclasses.add(subclass);
101 subclasses.add( subclass );
102 } 88 }
103 } 89 }
104 return subclasses; 90 return subclasses;
105 } 91 }
106 92
107 public void getSubclassNamesRecursively( Set<String> out, String className ) 93 public void getSubclassNamesRecursively(Set<String> out, String className) {
108 { 94 for (String subclassName : getSubclassNames(className)) {
109 for( String subclassName : getSubclassNames( className ) ) 95 out.add(subclassName);
110 { 96 getSubclassNamesRecursively(out, subclassName);
111 out.add( subclassName );
112 getSubclassNamesRecursively( out, subclassName );
113 } 97 }
114 } 98 }
115 99
116 public boolean containsField( String className, String fieldName ) 100 public boolean containsField(String className, String fieldName) {
117 { 101 return m_fields.containsEntry(className, fieldName);
118 return m_fields.containsEntry( className, fieldName );
119 } 102 }
120 103
121 private boolean isJre( String className ) 104 private boolean isJre(String className) {
122 { 105 return className.startsWith("java/") || className.startsWith("javax/");
123 return className.startsWith( "java/" )
124 || className.startsWith( "javax/" );
125 } 106 }
126} 107}
diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
index e6ecb10..23f8089 100644
--- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
+++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java
@@ -90,92 +90,73 @@ import com.strobel.decompiler.languages.java.ast.WhileStatement;
90import com.strobel.decompiler.languages.java.ast.WildcardType; 90import com.strobel.decompiler.languages.java.ast.WildcardType;
91import com.strobel.decompiler.patterns.Pattern; 91import com.strobel.decompiler.patterns.Pattern;
92 92
93public class TreeDumpVisitor implements IAstVisitor<Void, Void> 93public class TreeDumpVisitor implements IAstVisitor<Void,Void> {
94{ 94
95 private File m_file; 95 private File m_file;
96 private Writer m_out; 96 private Writer m_out;
97 97
98 public TreeDumpVisitor( File file ) 98 public TreeDumpVisitor(File file) {
99 {
100 m_file = file; 99 m_file = file;
101 m_out = null; 100 m_out = null;
102 } 101 }
103 102
104 @Override 103 @Override
105 public Void visitCompilationUnit( CompilationUnit node, Void ignored ) 104 public Void visitCompilationUnit(CompilationUnit node, Void ignored) {
106 { 105 try {
107 try 106 m_out = new FileWriter(m_file);
108 { 107 recurse(node, ignored);
109 m_out = new FileWriter( m_file );
110 recurse( node, ignored );
111 m_out.close(); 108 m_out.close();
112 return null; 109 return null;
113 } 110 } catch (IOException ex) {
114 catch( IOException ex ) 111 throw new Error(ex);
115 {
116 throw new Error( ex );
117 } 112 }
118 } 113 }
119 114
120 private Void recurse( AstNode node, Void ignored ) 115 private Void recurse(AstNode node, Void ignored) {
121 {
122 // show the tree 116 // show the tree
123 try 117 try {
124 { 118 m_out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n");
125 m_out.write( getIndent( node ) + node.getClass().getSimpleName() + " " + getText( node ) + " " + dumpUserData( node ) + " " + node.getRegion() + "\n" ); 119 } catch (IOException ex) {
126 } 120 throw new Error(ex);
127 catch( IOException ex )
128 {
129 throw new Error( ex );
130 } 121 }
131 122
132 // recurse 123 // recurse
133 for( final AstNode child : node.getChildren() ) 124 for (final AstNode child : node.getChildren()) {
134 { 125 child.acceptVisitor(this, ignored);
135 child.acceptVisitor( this, ignored );
136 } 126 }
137 return null; 127 return null;
138 } 128 }
139 129
140 private String getText( AstNode node ) 130 private String getText(AstNode node) {
141 { 131 if (node instanceof Identifier) {
142 if( node instanceof Identifier )
143 {
144 return "\"" + ((Identifier)node).getName() + "\""; 132 return "\"" + ((Identifier)node).getName() + "\"";
145 } 133 }
146 return ""; 134 return "";
147 } 135 }
148 136
149 private String dumpUserData( AstNode node ) 137 private String dumpUserData(AstNode node) {
150 {
151 StringBuilder buf = new StringBuilder(); 138 StringBuilder buf = new StringBuilder();
152 for( Key<?> key : Keys.ALL_KEYS ) 139 for (Key<?> key : Keys.ALL_KEYS) {
153 { 140 Object val = node.getUserData(key);
154 Object val = node.getUserData( key ); 141 if (val != null) {
155 if( val != null ) 142 buf.append(String.format(" [%s=%s]", key, val));
156 {
157 buf.append( String.format( " [%s=%s]", key, val ) );
158 } 143 }
159 } 144 }
160 return buf.toString(); 145 return buf.toString();
161 } 146 }
162 147
163 private String getIndent( AstNode node ) 148 private String getIndent(AstNode node) {
164 {
165 StringBuilder buf = new StringBuilder(); 149 StringBuilder buf = new StringBuilder();
166 int depth = getDepth( node ); 150 int depth = getDepth(node);
167 for( int i = 0; i < depth; i++ ) 151 for (int i = 0; i < depth; i++) {
168 { 152 buf.append("\t");
169 buf.append( "\t" );
170 } 153 }
171 return buf.toString(); 154 return buf.toString();
172 } 155 }
173 156
174 private int getDepth( AstNode node ) 157 private int getDepth(AstNode node) {
175 {
176 int depth = -1; 158 int depth = -1;
177 while( node != null ) 159 while (node != null) {
178 {
179 depth++; 160 depth++;
180 node = node.getParent(); 161 node = node.getParent();
181 } 162 }
@@ -185,416 +166,347 @@ public class TreeDumpVisitor implements IAstVisitor<Void, Void>
185 // OVERRIDES WE DON'T CARE ABOUT 166 // OVERRIDES WE DON'T CARE ABOUT
186 167
187 @Override 168 @Override
188 public Void visitInvocationExpression( InvocationExpression node, Void ignored ) 169 public Void visitInvocationExpression(InvocationExpression node, Void ignored) {
189 { 170 return recurse(node, ignored);
190 return recurse( node, ignored );
191 } 171 }
192 172
193 @Override 173 @Override
194 public Void visitMemberReferenceExpression( MemberReferenceExpression node, Void ignored ) 174 public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) {
195 { 175 return recurse(node, ignored);
196 return recurse( node, ignored );
197 } 176 }
198 177
199 @Override 178 @Override
200 public Void visitSimpleType( SimpleType node, Void ignored ) 179 public Void visitSimpleType(SimpleType node, Void ignored) {
201 { 180 return recurse(node, ignored);
202 return recurse( node, ignored );
203 } 181 }
204 182
205 @Override 183 @Override
206 public Void visitMethodDeclaration( MethodDeclaration node, Void ignored ) 184 public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) {
207 { 185 return recurse(node, ignored);
208 return recurse( node, ignored );
209 } 186 }
210 187
211 @Override 188 @Override
212 public Void visitConstructorDeclaration( ConstructorDeclaration node, Void ignored ) 189 public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) {
213 { 190 return recurse(node, ignored);
214 return recurse( node, ignored );
215 } 191 }
216 192
217 @Override 193 @Override
218 public Void visitParameterDeclaration( ParameterDeclaration node, Void ignored ) 194 public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) {
219 { 195 return recurse(node, ignored);
220 return recurse( node, ignored );
221 } 196 }
222 197
223 @Override 198 @Override
224 public Void visitFieldDeclaration( FieldDeclaration node, Void ignored ) 199 public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) {
225 { 200 return recurse(node, ignored);
226 return recurse( node, ignored );
227 } 201 }
228 202
229 @Override 203 @Override
230 public Void visitTypeDeclaration( TypeDeclaration node, Void ignored ) 204 public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) {
231 { 205 return recurse(node, ignored);
232 return recurse( node, ignored );
233 } 206 }
234 207
235 @Override 208 @Override
236 public Void visitComment( Comment node, Void ignored ) 209 public Void visitComment(Comment node, Void ignored) {
237 { 210 return recurse(node, ignored);
238 return recurse( node, ignored );
239 } 211 }
240 212
241 @Override 213 @Override
242 public Void visitPatternPlaceholder( AstNode node, Pattern pattern, Void ignored ) 214 public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) {
243 { 215 return recurse(node, ignored);
244 return recurse( node, ignored );
245 } 216 }
246 217
247 @Override 218 @Override
248 public Void visitTypeReference( TypeReferenceExpression node, Void ignored ) 219 public Void visitTypeReference(TypeReferenceExpression node, Void ignored) {
249 { 220 return recurse(node, ignored);
250 return recurse( node, ignored );
251 } 221 }
252 222
253 @Override 223 @Override
254 public Void visitJavaTokenNode( JavaTokenNode node, Void ignored ) 224 public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) {
255 { 225 return recurse(node, ignored);
256 return recurse( node, ignored );
257 } 226 }
258 227
259 @Override 228 @Override
260 public Void visitIdentifier( Identifier node, Void ignored ) 229 public Void visitIdentifier(Identifier node, Void ignored) {
261 { 230 return recurse(node, ignored);
262 return recurse( node, ignored );
263 } 231 }
264 232
265 @Override 233 @Override
266 public Void visitNullReferenceExpression( NullReferenceExpression node, Void ignored ) 234 public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) {
267 { 235 return recurse(node, ignored);
268 return recurse( node, ignored );
269 } 236 }
270 237
271 @Override 238 @Override
272 public Void visitThisReferenceExpression( ThisReferenceExpression node, Void ignored ) 239 public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) {
273 { 240 return recurse(node, ignored);
274 return recurse( node, ignored );
275 } 241 }
276 242
277 @Override 243 @Override
278 public Void visitSuperReferenceExpression( SuperReferenceExpression node, Void ignored ) 244 public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) {
279 { 245 return recurse(node, ignored);
280 return recurse( node, ignored );
281 } 246 }
282 247
283 @Override 248 @Override
284 public Void visitClassOfExpression( ClassOfExpression node, Void ignored ) 249 public Void visitClassOfExpression(ClassOfExpression node, Void ignored) {
285 { 250 return recurse(node, ignored);
286 return recurse( node, ignored );
287 } 251 }
288 252
289 @Override 253 @Override
290 public Void visitBlockStatement( BlockStatement node, Void ignored ) 254 public Void visitBlockStatement(BlockStatement node, Void ignored) {
291 { 255 return recurse(node, ignored);
292 return recurse( node, ignored );
293 } 256 }
294 257
295 @Override 258 @Override
296 public Void visitExpressionStatement( ExpressionStatement node, Void ignored ) 259 public Void visitExpressionStatement(ExpressionStatement node, Void ignored) {
297 { 260 return recurse(node, ignored);
298 return recurse( node, ignored );
299 } 261 }
300 262
301 @Override 263 @Override
302 public Void visitBreakStatement( BreakStatement node, Void ignored ) 264 public Void visitBreakStatement(BreakStatement node, Void ignored) {
303 { 265 return recurse(node, ignored);
304 return recurse( node, ignored );
305 } 266 }
306 267
307 @Override 268 @Override
308 public Void visitContinueStatement( ContinueStatement node, Void ignored ) 269 public Void visitContinueStatement(ContinueStatement node, Void ignored) {
309 { 270 return recurse(node, ignored);
310 return recurse( node, ignored );
311 } 271 }
312 272
313 @Override 273 @Override
314 public Void visitDoWhileStatement( DoWhileStatement node, Void ignored ) 274 public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) {
315 { 275 return recurse(node, ignored);
316 return recurse( node, ignored );
317 } 276 }
318 277
319 @Override 278 @Override
320 public Void visitEmptyStatement( EmptyStatement node, Void ignored ) 279 public Void visitEmptyStatement(EmptyStatement node, Void ignored) {
321 { 280 return recurse(node, ignored);
322 return recurse( node, ignored );
323 } 281 }
324 282
325 @Override 283 @Override
326 public Void visitIfElseStatement( IfElseStatement node, Void ignored ) 284 public Void visitIfElseStatement(IfElseStatement node, Void ignored) {
327 { 285 return recurse(node, ignored);
328 return recurse( node, ignored );
329 } 286 }
330 287
331 @Override 288 @Override
332 public Void visitLabelStatement( LabelStatement node, Void ignored ) 289 public Void visitLabelStatement(LabelStatement node, Void ignored) {
333 { 290 return recurse(node, ignored);
334 return recurse( node, ignored );
335 } 291 }
336 292
337 @Override 293 @Override
338 public Void visitLabeledStatement( LabeledStatement node, Void ignored ) 294 public Void visitLabeledStatement(LabeledStatement node, Void ignored) {
339 { 295 return recurse(node, ignored);
340 return recurse( node, ignored );
341 } 296 }
342 297
343 @Override 298 @Override
344 public Void visitReturnStatement( ReturnStatement node, Void ignored ) 299 public Void visitReturnStatement(ReturnStatement node, Void ignored) {
345 { 300 return recurse(node, ignored);
346 return recurse( node, ignored );
347 } 301 }
348 302
349 @Override 303 @Override
350 public Void visitSwitchStatement( SwitchStatement node, Void ignored ) 304 public Void visitSwitchStatement(SwitchStatement node, Void ignored) {
351 { 305 return recurse(node, ignored);
352 return recurse( node, ignored );
353 } 306 }
354 307
355 @Override 308 @Override
356 public Void visitSwitchSection( SwitchSection node, Void ignored ) 309 public Void visitSwitchSection(SwitchSection node, Void ignored) {
357 { 310 return recurse(node, ignored);
358 return recurse( node, ignored );
359 } 311 }
360 312
361 @Override 313 @Override
362 public Void visitCaseLabel( CaseLabel node, Void ignored ) 314 public Void visitCaseLabel(CaseLabel node, Void ignored) {
363 { 315 return recurse(node, ignored);
364 return recurse( node, ignored );
365 } 316 }
366 317
367 @Override 318 @Override
368 public Void visitThrowStatement( ThrowStatement node, Void ignored ) 319 public Void visitThrowStatement(ThrowStatement node, Void ignored) {
369 { 320 return recurse(node, ignored);
370 return recurse( node, ignored );
371 } 321 }
372 322
373 @Override 323 @Override
374 public Void visitCatchClause( CatchClause node, Void ignored ) 324 public Void visitCatchClause(CatchClause node, Void ignored) {
375 { 325 return recurse(node, ignored);
376 return recurse( node, ignored );
377 } 326 }
378 327
379 @Override 328 @Override
380 public Void visitAnnotation( Annotation node, Void ignored ) 329 public Void visitAnnotation(Annotation node, Void ignored) {
381 { 330 return recurse(node, ignored);
382 return recurse( node, ignored );
383 } 331 }
384 332
385 @Override 333 @Override
386 public Void visitNewLine( NewLineNode node, Void ignored ) 334 public Void visitNewLine(NewLineNode node, Void ignored) {
387 { 335 return recurse(node, ignored);
388 return recurse( node, ignored );
389 } 336 }
390 337
391 @Override 338 @Override
392 public Void visitVariableDeclaration( VariableDeclarationStatement node, Void ignored ) 339 public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) {
393 { 340 return recurse(node, ignored);
394 return recurse( node, ignored );
395 } 341 }
396 342
397 @Override 343 @Override
398 public Void visitVariableInitializer( VariableInitializer node, Void ignored ) 344 public Void visitVariableInitializer(VariableInitializer node, Void ignored) {
399 { 345 return recurse(node, ignored);
400 return recurse( node, ignored );
401 } 346 }
402 347
403 @Override 348 @Override
404 public Void visitText( TextNode node, Void ignored ) 349 public Void visitText(TextNode node, Void ignored) {
405 { 350 return recurse(node, ignored);
406 return recurse( node, ignored );
407 } 351 }
408 352
409 @Override 353 @Override
410 public Void visitImportDeclaration( ImportDeclaration node, Void ignored ) 354 public Void visitImportDeclaration(ImportDeclaration node, Void ignored) {
411 { 355 return recurse(node, ignored);
412 return recurse( node, ignored );
413 } 356 }
414 357
415 @Override 358 @Override
416 public Void visitInitializerBlock( InstanceInitializer node, Void ignored ) 359 public Void visitInitializerBlock(InstanceInitializer node, Void ignored) {
417 { 360 return recurse(node, ignored);
418 return recurse( node, ignored );
419 } 361 }
420 362
421 @Override 363 @Override
422 public Void visitTypeParameterDeclaration( TypeParameterDeclaration node, Void ignored ) 364 public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) {
423 { 365 return recurse(node, ignored);
424 return recurse( node, ignored );
425 } 366 }
426 367
427 @Override 368 @Override
428 public Void visitPackageDeclaration( PackageDeclaration node, Void ignored ) 369 public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) {
429 { 370 return recurse(node, ignored);
430 return recurse( node, ignored );
431 } 371 }
432 372
433 @Override 373 @Override
434 public Void visitArraySpecifier( ArraySpecifier node, Void ignored ) 374 public Void visitArraySpecifier(ArraySpecifier node, Void ignored) {
435 { 375 return recurse(node, ignored);
436 return recurse( node, ignored );
437 } 376 }
438 377
439 @Override 378 @Override
440 public Void visitComposedType( ComposedType node, Void ignored ) 379 public Void visitComposedType(ComposedType node, Void ignored) {
441 { 380 return recurse(node, ignored);
442 return recurse( node, ignored );
443 } 381 }
444 382
445 @Override 383 @Override
446 public Void visitWhileStatement( WhileStatement node, Void ignored ) 384 public Void visitWhileStatement(WhileStatement node, Void ignored) {
447 { 385 return recurse(node, ignored);
448 return recurse( node, ignored );
449 } 386 }
450 387
451 @Override 388 @Override
452 public Void visitPrimitiveExpression( PrimitiveExpression node, Void ignored ) 389 public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) {
453 { 390 return recurse(node, ignored);
454 return recurse( node, ignored );
455 } 391 }
456 392
457 @Override 393 @Override
458 public Void visitCastExpression( CastExpression node, Void ignored ) 394 public Void visitCastExpression(CastExpression node, Void ignored) {
459 { 395 return recurse(node, ignored);
460 return recurse( node, ignored );
461 } 396 }
462 397
463 @Override 398 @Override
464 public Void visitBinaryOperatorExpression( BinaryOperatorExpression node, Void ignored ) 399 public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) {
465 { 400 return recurse(node, ignored);
466 return recurse( node, ignored );
467 } 401 }
468 402
469 @Override 403 @Override
470 public Void visitInstanceOfExpression( InstanceOfExpression node, Void ignored ) 404 public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) {
471 { 405 return recurse(node, ignored);
472 return recurse( node, ignored );
473 } 406 }
474 407
475 @Override 408 @Override
476 public Void visitIndexerExpression( IndexerExpression node, Void ignored ) 409 public Void visitIndexerExpression(IndexerExpression node, Void ignored) {
477 { 410 return recurse(node, ignored);
478 return recurse( node, ignored );
479 } 411 }
480 412
481 @Override 413 @Override
482 public Void visitIdentifierExpression( IdentifierExpression node, Void ignored ) 414 public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) {
483 { 415 return recurse(node, ignored);
484 return recurse( node, ignored );
485 } 416 }
486 417
487 @Override 418 @Override
488 public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, Void ignored ) 419 public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) {
489 { 420 return recurse(node, ignored);
490 return recurse( node, ignored );
491 } 421 }
492 422
493 @Override 423 @Override
494 public Void visitConditionalExpression( ConditionalExpression node, Void ignored ) 424 public Void visitConditionalExpression(ConditionalExpression node, Void ignored) {
495 { 425 return recurse(node, ignored);
496 return recurse( node, ignored );
497 } 426 }
498 427
499 @Override 428 @Override
500 public Void visitArrayInitializerExpression( ArrayInitializerExpression node, Void ignored ) 429 public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) {
501 { 430 return recurse(node, ignored);
502 return recurse( node, ignored );
503 } 431 }
504 432
505 @Override 433 @Override
506 public Void visitObjectCreationExpression( ObjectCreationExpression node, Void ignored ) 434 public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) {
507 { 435 return recurse(node, ignored);
508 return recurse( node, ignored );
509 } 436 }
510 437
511 @Override 438 @Override
512 public Void visitArrayCreationExpression( ArrayCreationExpression node, Void ignored ) 439 public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) {
513 { 440 return recurse(node, ignored);
514 return recurse( node, ignored );
515 } 441 }
516 442
517 @Override 443 @Override
518 public Void visitAssignmentExpression( AssignmentExpression node, Void ignored ) 444 public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) {
519 { 445 return recurse(node, ignored);
520 return recurse( node, ignored );
521 } 446 }
522 447
523 @Override 448 @Override
524 public Void visitForStatement( ForStatement node, Void ignored ) 449 public Void visitForStatement(ForStatement node, Void ignored) {
525 { 450 return recurse(node, ignored);
526 return recurse( node, ignored );
527 } 451 }
528 452
529 @Override 453 @Override
530 public Void visitForEachStatement( ForEachStatement node, Void ignored ) 454 public Void visitForEachStatement(ForEachStatement node, Void ignored) {
531 { 455 return recurse(node, ignored);
532 return recurse( node, ignored );
533 } 456 }
534 457
535 @Override 458 @Override
536 public Void visitTryCatchStatement( TryCatchStatement node, Void ignored ) 459 public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) {
537 { 460 return recurse(node, ignored);
538 return recurse( node, ignored );
539 } 461 }
540 462
541 @Override 463 @Override
542 public Void visitGotoStatement( GotoStatement node, Void ignored ) 464 public Void visitGotoStatement(GotoStatement node, Void ignored) {
543 { 465 return recurse(node, ignored);
544 return recurse( node, ignored );
545 } 466 }
546 467
547 @Override 468 @Override
548 public Void visitParenthesizedExpression( ParenthesizedExpression node, Void ignored ) 469 public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) {
549 { 470 return recurse(node, ignored);
550 return recurse( node, ignored );
551 } 471 }
552 472
553 @Override 473 @Override
554 public Void visitSynchronizedStatement( SynchronizedStatement node, Void ignored ) 474 public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) {
555 { 475 return recurse(node, ignored);
556 return recurse( node, ignored );
557 } 476 }
558 477
559 @Override 478 @Override
560 public Void visitAnonymousObjectCreationExpression( AnonymousObjectCreationExpression node, Void ignored ) 479 public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) {
561 { 480 return recurse(node, ignored);
562 return recurse( node, ignored );
563 } 481 }
564 482
565 @Override 483 @Override
566 public Void visitWildcardType( WildcardType node, Void ignored ) 484 public Void visitWildcardType(WildcardType node, Void ignored) {
567 { 485 return recurse(node, ignored);
568 return recurse( node, ignored );
569 } 486 }
570 487
571 @Override 488 @Override
572 public Void visitMethodGroupExpression( MethodGroupExpression node, Void ignored ) 489 public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) {
573 { 490 return recurse(node, ignored);
574 return recurse( node, ignored );
575 } 491 }
576 492
577 @Override 493 @Override
578 public Void visitEnumValueDeclaration( EnumValueDeclaration node, Void ignored ) 494 public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) {
579 { 495 return recurse(node, ignored);
580 return recurse( node, ignored );
581 } 496 }
582 497
583 @Override 498 @Override
584 public Void visitAssertStatement( AssertStatement node, Void ignored ) 499 public Void visitAssertStatement(AssertStatement node, Void ignored) {
585 { 500 return recurse(node, ignored);
586 return recurse( node, ignored );
587 } 501 }
588 502
589 @Override 503 @Override
590 public Void visitLambdaExpression( LambdaExpression node, Void ignored ) 504 public Void visitLambdaExpression(LambdaExpression node, Void ignored) {
591 { 505 return recurse(node, ignored);
592 return recurse( node, ignored );
593 } 506 }
594 507
595 @Override 508 @Override
596 public Void visitLocalTypeDeclarationStatement( LocalTypeDeclarationStatement node, Void ignored ) 509 public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) {
597 { 510 return recurse(node, ignored);
598 return recurse( node, ignored );
599 } 511 }
600} 512}