summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/analysis/JarIndex.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarIndex.java')
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java141
1 files changed, 93 insertions, 48 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 7d68c35..f1c29c5 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -35,12 +35,15 @@ import javassist.expr.MethodCall;
35import javassist.expr.NewExpr; 35import javassist.expr.NewExpr;
36 36
37import com.google.common.collect.HashMultimap; 37import com.google.common.collect.HashMultimap;
38import com.google.common.collect.HashMultiset;
38import com.google.common.collect.Lists; 39import com.google.common.collect.Lists;
39import com.google.common.collect.Maps; 40import com.google.common.collect.Maps;
40import com.google.common.collect.Multimap; 41import com.google.common.collect.Multimap;
42import com.google.common.collect.Multiset;
41import com.google.common.collect.Sets; 43import com.google.common.collect.Sets;
42 44
43import cuchaz.enigma.mapping.ArgumentEntry; 45import cuchaz.enigma.mapping.ArgumentEntry;
46import cuchaz.enigma.mapping.BehaviorEntry;
44import cuchaz.enigma.mapping.ClassEntry; 47import cuchaz.enigma.mapping.ClassEntry;
45import cuchaz.enigma.mapping.ConstructorEntry; 48import cuchaz.enigma.mapping.ConstructorEntry;
46import cuchaz.enigma.mapping.Entry; 49import cuchaz.enigma.mapping.Entry;
@@ -53,8 +56,8 @@ public class JarIndex
53 private Set<String> m_obfClassNames; 56 private Set<String> m_obfClassNames;
54 private Ancestries m_ancestries; 57 private Ancestries m_ancestries;
55 private Multimap<String,MethodEntry> m_methodImplementations; 58 private Multimap<String,MethodEntry> m_methodImplementations;
56 private Multimap<Entry,Entry> m_methodCalls; 59 private Multimap<BehaviorEntry,EntryReference<? extends Entry>> m_behaviorReferences;
57 private Multimap<FieldEntry,Entry> m_fieldCalls; 60 private Multimap<FieldEntry,EntryReference<? extends Entry>> m_fieldReferences;
58 private Multimap<String,String> m_innerClasses; 61 private Multimap<String,String> m_innerClasses;
59 private Map<String,String> m_outerClasses; 62 private Map<String,String> m_outerClasses;
60 private Set<String> m_anonymousClasses; 63 private Set<String> m_anonymousClasses;
@@ -64,8 +67,8 @@ public class JarIndex
64 m_obfClassNames = Sets.newHashSet(); 67 m_obfClassNames = Sets.newHashSet();
65 m_ancestries = new Ancestries(); 68 m_ancestries = new Ancestries();
66 m_methodImplementations = HashMultimap.create(); 69 m_methodImplementations = HashMultimap.create();
67 m_methodCalls = HashMultimap.create(); 70 m_behaviorReferences = HashMultimap.create();
68 m_fieldCalls = HashMultimap.create(); 71 m_fieldReferences = HashMultimap.create();
69 m_innerClasses = HashMultimap.create(); 72 m_innerClasses = HashMultimap.create();
70 m_outerClasses = Maps.newHashMap(); 73 m_outerClasses = Maps.newHashMap();
71 m_anonymousClasses = Sets.newHashSet(); 74 m_anonymousClasses = Sets.newHashSet();
@@ -128,7 +131,7 @@ public class JarIndex
128 { 131 {
129 // get the method entry 132 // get the method entry
130 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); 133 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() );
131 final Entry thisEntry; 134 final BehaviorEntry thisEntry;
132 if( behavior instanceof CtMethod ) 135 if( behavior instanceof CtMethod )
133 { 136 {
134 MethodEntry methodEntry = new MethodEntry( 137 MethodEntry methodEntry = new MethodEntry(
@@ -156,6 +159,7 @@ public class JarIndex
156 // index method calls 159 // index method calls
157 try 160 try
158 { 161 {
162 final Multiset<Entry> callNumbers = HashMultiset.create();
159 behavior.instrument( new ExprEditor( ) 163 behavior.instrument( new ExprEditor( )
160 { 164 {
161 @Override 165 @Override
@@ -167,7 +171,13 @@ public class JarIndex
167 call.getMethodName(), 171 call.getMethodName(),
168 call.getSignature() 172 call.getSignature()
169 ); 173 );
170 m_methodCalls.put( calledMethodEntry, thisEntry ); 174 callNumbers.add( calledMethodEntry );
175 EntryReference<MethodEntry> reference = new EntryReference<MethodEntry>(
176 calledMethodEntry,
177 thisEntry,
178 callNumbers.count( calledMethodEntry ) - 1
179 );
180 m_behaviorReferences.put( calledMethodEntry, reference );
171 } 181 }
172 182
173 @Override 183 @Override
@@ -178,22 +188,33 @@ public class JarIndex
178 new ClassEntry( className ), 188 new ClassEntry( className ),
179 call.getFieldName() 189 call.getFieldName()
180 ); 190 );
181 m_fieldCalls.put( calledFieldEntry, thisEntry ); 191 callNumbers.add( calledFieldEntry );
192 EntryReference<FieldEntry> reference = new EntryReference<FieldEntry>(
193 calledFieldEntry,
194 thisEntry,
195 callNumbers.count( calledFieldEntry ) - 1
196 );
197 m_fieldReferences.put( calledFieldEntry, reference );
182 } 198 }
183 199
184 @Override 200 @Override
185 public void edit( ConstructorCall call ) 201 public void edit( ConstructorCall call )
186 { 202 {
203 // TODO: save isSuper in the reference somehow
187 boolean isSuper = call.getMethodName().equals( "super" ); 204 boolean isSuper = call.getMethodName().equals( "super" );
188 // TODO: make method reference class, update method calls tree to use Invocation instances
189 // this might end up being a big refactor... =(
190 205
191 String className = Descriptor.toJvmName( call.getClassName() ); 206 String className = Descriptor.toJvmName( call.getClassName() );
192 ConstructorEntry calledConstructorEntry = new ConstructorEntry( 207 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
193 new ClassEntry( className ), 208 new ClassEntry( className ),
194 call.getSignature() 209 call.getSignature()
195 ); 210 );
196 m_methodCalls.put( calledConstructorEntry, thisEntry ); 211 callNumbers.add( calledConstructorEntry );
212 EntryReference<ConstructorEntry> reference = new EntryReference<ConstructorEntry>(
213 calledConstructorEntry,
214 thisEntry,
215 callNumbers.count( calledConstructorEntry ) - 1
216 );
217 m_behaviorReferences.put( calledConstructorEntry, reference );
197 } 218 }
198 219
199 @Override 220 @Override
@@ -204,7 +225,13 @@ public class JarIndex
204 new ClassEntry( className ), 225 new ClassEntry( className ),
205 call.getSignature() 226 call.getSignature()
206 ); 227 );
207 m_methodCalls.put( calledConstructorEntry, thisEntry ); 228 callNumbers.add( calledConstructorEntry );
229 EntryReference<ConstructorEntry> reference = new EntryReference<ConstructorEntry>(
230 calledConstructorEntry,
231 thisEntry,
232 callNumbers.count( calledConstructorEntry ) - 1
233 );
234 m_behaviorReferences.put( calledConstructorEntry, reference );
208 } 235 }
209 } ); 236 } );
210 } 237 }
@@ -234,9 +261,9 @@ public class JarIndex
234 new ClassEntry( Descriptor.toJvmName( c.getName() ) ), 261 new ClassEntry( Descriptor.toJvmName( c.getName() ) ),
235 constructor.getMethodInfo().getDescriptor() 262 constructor.getMethodInfo().getDescriptor()
236 ); 263 );
237 for( Entry callerEntry : getMethodCallers( constructorEntry ) ) 264 for( EntryReference<BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) )
238 { 265 {
239 callerClasses.add( callerEntry.getClassEntry() ); 266 callerClasses.add( reference.caller.getClassEntry() );
240 } 267 }
241 268
242 // is this called by exactly one class? 269 // is this called by exactly one class?
@@ -388,7 +415,7 @@ public class JarIndex
388 new ClassEntry( innerClassName ), 415 new ClassEntry( innerClassName ),
389 constructor.getMethodInfo().getDescriptor() 416 constructor.getMethodInfo().getDescriptor()
390 ); 417 );
391 if( getMethodCallers( constructorEntry ).size() != 1 ) 418 if( getBehaviorReferences( constructorEntry ).size() != 1 )
392 { 419 {
393 return false; 420 return false;
394 } 421 }
@@ -469,14 +496,26 @@ public class JarIndex
469 return rootNode; 496 return rootNode;
470 } 497 }
471 498
472 public Collection<Entry> getFieldCallers( FieldEntry fieldEntry ) 499 @SuppressWarnings( "unchecked" )
500 public Collection<EntryReference<FieldEntry>> getFieldReferences( FieldEntry fieldEntry )
473 { 501 {
474 return m_fieldCalls.get( fieldEntry ); 502 List<EntryReference<FieldEntry>> references = Lists.newArrayList();
503 for( EntryReference<? extends Entry> reference : m_fieldReferences.get( fieldEntry ) )
504 {
505 references.add( (EntryReference<FieldEntry>)reference );
506 }
507 return references;
475 } 508 }
476 509
477 public Collection<Entry> getMethodCallers( Entry entry ) 510 @SuppressWarnings( "unchecked" )
511 public Collection<EntryReference<BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry )
478 { 512 {
479 return m_methodCalls.get( entry ); 513 List<EntryReference<BehaviorEntry>> references = Lists.newArrayList();
514 for( EntryReference<? extends Entry> reference : m_behaviorReferences.get( behaviorEntry ) )
515 {
516 references.add( (EntryReference<BehaviorEntry>)reference );
517 }
518 return references;
480 } 519 }
481 520
482 public Collection<String> getInnerClasses( String obfOuterClassName ) 521 public Collection<String> getInnerClasses( String obfOuterClassName )
@@ -498,85 +537,91 @@ public class JarIndex
498 { 537 {
499 m_ancestries.renameClasses( renames ); 538 m_ancestries.renameClasses( renames );
500 renameMultimap( renames, m_methodImplementations ); 539 renameMultimap( renames, m_methodImplementations );
501 renameMultimap( renames, m_methodCalls ); 540 renameMultimap( renames, m_behaviorReferences );
502 renameMultimap( renames, m_fieldCalls ); 541 renameMultimap( renames, m_fieldReferences );
503 } 542 }
504 543
505 private <T,U> void renameMultimap( Map<String,String> renames, Multimap<T,U> map ) 544 private <Key,Val> void renameMultimap( Map<String,String> renames, Multimap<Key,Val> map )
506 { 545 {
507 // for each key/value pair... 546 // for each key/value pair...
508 Set<Map.Entry<T,U>> entriesToAdd = Sets.newHashSet(); 547 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
509 Iterator<Map.Entry<T,U>> iter = map.entries().iterator(); 548 Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator();
510 while( iter.hasNext() ) 549 while( iter.hasNext() )
511 { 550 {
512 Map.Entry<T,U> entry = iter.next(); 551 Map.Entry<Key,Val> entry = iter.next();
513 iter.remove(); 552 iter.remove();
514 entriesToAdd.add( new AbstractMap.SimpleEntry<T,U>( 553 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>(
515 renameEntry( renames, entry.getKey() ), 554 renameThing( renames, entry.getKey() ),
516 renameEntry( renames, entry.getValue() ) 555 renameThing( renames, entry.getValue() )
517 ) ); 556 ) );
518 } 557 }
519 for( Map.Entry<T,U> entry : entriesToAdd ) 558 for( Map.Entry<Key,Val> entry : entriesToAdd )
520 { 559 {
521 map.put( entry.getKey(), entry.getValue() ); 560 map.put( entry.getKey(), entry.getValue() );
522 } 561 }
523 } 562 }
524 563
525 @SuppressWarnings( "unchecked" ) 564 @SuppressWarnings( "unchecked" )
526 private <T> T renameEntry( Map<String,String> renames, T entry ) 565 private <T> T renameThing( Map<String,String> renames, T thing )
527 { 566 {
528 if( entry instanceof String ) 567 if( thing instanceof String )
529 { 568 {
530 String stringEntry = (String)entry; 569 String stringEntry = (String)thing;
531 if( renames.containsKey( stringEntry ) ) 570 if( renames.containsKey( stringEntry ) )
532 { 571 {
533 return (T)renames.get( stringEntry ); 572 return (T)renames.get( stringEntry );
534 } 573 }
535 } 574 }
536 else if( entry instanceof ClassEntry ) 575 else if( thing instanceof ClassEntry )
537 { 576 {
538 ClassEntry classEntry = (ClassEntry)entry; 577 ClassEntry classEntry = (ClassEntry)thing;
539 return (T)new ClassEntry( renameEntry( renames, classEntry.getClassName() ) ); 578 return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) );
540 } 579 }
541 else if( entry instanceof FieldEntry ) 580 else if( thing instanceof FieldEntry )
542 { 581 {
543 FieldEntry fieldEntry = (FieldEntry)entry; 582 FieldEntry fieldEntry = (FieldEntry)thing;
544 return (T)new FieldEntry( 583 return (T)new FieldEntry(
545 renameEntry( renames, fieldEntry.getClassEntry() ), 584 renameThing( renames, fieldEntry.getClassEntry() ),
546 fieldEntry.getName() 585 fieldEntry.getName()
547 ); 586 );
548 } 587 }
549 else if( entry instanceof ConstructorEntry ) 588 else if( thing instanceof ConstructorEntry )
550 { 589 {
551 ConstructorEntry constructorEntry = (ConstructorEntry)entry; 590 ConstructorEntry constructorEntry = (ConstructorEntry)thing;
552 return (T)new ConstructorEntry( 591 return (T)new ConstructorEntry(
553 renameEntry( renames, constructorEntry.getClassEntry() ), 592 renameThing( renames, constructorEntry.getClassEntry() ),
554 constructorEntry.getSignature() 593 constructorEntry.getSignature()
555 ); 594 );
556 } 595 }
557 else if( entry instanceof MethodEntry ) 596 else if( thing instanceof MethodEntry )
558 { 597 {
559 MethodEntry methodEntry = (MethodEntry)entry; 598 MethodEntry methodEntry = (MethodEntry)thing;
560 return (T)new MethodEntry( 599 return (T)new MethodEntry(
561 renameEntry( renames, methodEntry.getClassEntry() ), 600 renameThing( renames, methodEntry.getClassEntry() ),
562 methodEntry.getName(), 601 methodEntry.getName(),
563 methodEntry.getSignature() 602 methodEntry.getSignature()
564 ); 603 );
565 } 604 }
566 else if( entry instanceof ArgumentEntry ) 605 else if( thing instanceof ArgumentEntry )
567 { 606 {
568 ArgumentEntry argumentEntry = (ArgumentEntry)entry; 607 ArgumentEntry argumentEntry = (ArgumentEntry)thing;
569 return (T)new ArgumentEntry( 608 return (T)new ArgumentEntry(
570 renameEntry( renames, argumentEntry.getMethodEntry() ), 609 renameThing( renames, argumentEntry.getMethodEntry() ),
571 argumentEntry.getIndex(), 610 argumentEntry.getIndex(),
572 argumentEntry.getName() 611 argumentEntry.getName()
573 ); 612 );
574 } 613 }
614 else if( thing instanceof EntryReference )
615 {
616 EntryReference<Entry> reference = (EntryReference<Entry>)thing;
617 reference.entry = renameThing( renames, reference.entry );
618 return thing;
619 }
575 else 620 else
576 { 621 {
577 throw new Error( "Not an entry: " + entry ); 622 throw new Error( "Not an entry: " + thing );
578 } 623 }
579 624
580 return entry; 625 return thing;
581 } 626 }
582} 627}