summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jeff2014-09-21 00:32:03 -0400
committerGravatar jeff2014-09-21 00:32:03 -0400
commit8409dea980fa03c06b180969c5e0696f7cb5474b (patch)
treeeb0cdfad4bc2cee6df8a311e62fc2f60d0360970
parentremoved workaround for procyon bug (diff)
downloadenigma-fork-8409dea980fa03c06b180969c5e0696f7cb5474b.tar.gz
enigma-fork-8409dea980fa03c06b180969c5e0696f7cb5474b.tar.xz
enigma-fork-8409dea980fa03c06b180969c5e0696f7cb5474b.zip
started unit testing for inner/anonymous class detection
-rw-r--r--build.gradle47
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java181
-rw-r--r--src/cuchaz/enigma/mapping/SignatureUpdater.java18
-rw-r--r--test/cuchaz/enigma/TestDeobfuscator.java2
-rw-r--r--test/cuchaz/enigma/TestInnerClasses.java64
-rw-r--r--test/cuchaz/enigma/TestJarIndexConstructorReferences.java10
-rw-r--r--test/cuchaz/enigma/TestJarIndexInheritanceTree.java14
-rw-r--r--test/cuchaz/enigma/TestJarIndexLoneClass.java14
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/Anonymous.java17
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java22
-rw-r--r--test/cuchaz/enigma/inputs/innerClasses/Simple.java9
11 files changed, 306 insertions, 92 deletions
diff --git a/build.gradle b/build.gradle
index 767b032..6b89d32 100644
--- a/build.gradle
+++ b/build.gradle
@@ -90,21 +90,46 @@ task jarConstructors( type: Jar ) {
90 archiveName( "testConstructors.jar" ) 90 archiveName( "testConstructors.jar" )
91} 91}
92 92
93task obfTestCases( type: proguard.gradle.ProGuardTask ) { 93task jarInnerClasses( type: Jar ) {
94 dependsOn jarLoneClass, jarInheritanceTree, jarConstructors 94 from( sourceSets.test.output ) {
95 95 include( "cuchaz/enigma/inputs/Keep.class" )
96 include( "cuchaz/enigma/inputs/innerClasses/**" )
97 }
98 archiveName( "testInnerClasses.jar" )
99}
100
101tasks.withType( proguard.gradle.ProGuardTask ) {
96 libraryjars( "${System.getProperty('java.home')}/lib/rt.jar" ) 102 libraryjars( "${System.getProperty('java.home')}/lib/rt.jar" )
97 overloadaggressively 103 overloadaggressively
98 repackageclasses 104 repackageclasses
99 allowaccessmodification 105 allowaccessmodification
100 dontoptimize 106 dontoptimize
101 dontshrink 107 dontshrink
102
103 keep( "class cuchaz.enigma.inputs.Keep" ) 108 keep( "class cuchaz.enigma.inputs.Keep" )
104 109}
105 def jarNames = [ "LoneClass", "InheritanceTree", "Constructors" ]; 110
106 jarNames.each() { 111task obfLoneClass( type: proguard.gradle.ProGuardTask, dependsOn: jarLoneClass ) {
107 injars( "build/libs/test${it}.jar" ) 112 def name = "LoneClass"
108 outjars( "build/libs/test${it}.obf.jar" ) 113 injars( "build/libs/test${name}.jar" )
109 } 114 outjars( "build/libs/test${name}.obf.jar" )
110} \ No newline at end of file 115}
116
117task obfInheritanceTree( type: proguard.gradle.ProGuardTask, dependsOn: jarInheritanceTree ) {
118 def name = "InheritanceTree"
119 injars( "build/libs/test${name}.jar" )
120 outjars( "build/libs/test${name}.obf.jar" )
121}
122
123task obfConstructors( type: proguard.gradle.ProGuardTask, dependsOn: jarConstructors ) {
124 def name = "Constructors"
125 injars( "build/libs/test${name}.jar" )
126 outjars( "build/libs/test${name}.obf.jar" )
127}
128
129task obfInnerClasses( type: proguard.gradle.ProGuardTask, dependsOn: jarInnerClasses ) {
130 def name = "InnerClasses"
131 injars( "build/libs/test${name}.jar" )
132 outjars( "build/libs/test${name}.obf.jar" )
133}
134
135task obfTestCases( dependsOn: tasks.withType( proguard.gradle.ProGuardTask ) )
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 6c955bc..43e2bf6 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -48,6 +48,7 @@ import cuchaz.enigma.mapping.ConstructorEntry;
48import cuchaz.enigma.mapping.Entry; 48import cuchaz.enigma.mapping.Entry;
49import cuchaz.enigma.mapping.FieldEntry; 49import cuchaz.enigma.mapping.FieldEntry;
50import cuchaz.enigma.mapping.MethodEntry; 50import cuchaz.enigma.mapping.MethodEntry;
51import cuchaz.enigma.mapping.SignatureUpdater;
51import cuchaz.enigma.mapping.Translator; 52import cuchaz.enigma.mapping.Translator;
52 53
53public class JarIndex 54public class JarIndex
@@ -56,6 +57,7 @@ public class JarIndex
56 private TranslationIndex m_translationIndex; 57 private TranslationIndex m_translationIndex;
57 private Multimap<String,String> m_interfaces; 58 private Multimap<String,String> m_interfaces;
58 private Map<Entry,Access> m_access; 59 private Map<Entry,Access> m_access;
60 private Map<FieldEntry,ClassEntry> m_fieldClasses;
59 private Multimap<String,MethodEntry> m_methodImplementations; 61 private Multimap<String,MethodEntry> m_methodImplementations;
60 private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; 62 private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences;
61 private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences; 63 private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences;
@@ -70,6 +72,7 @@ public class JarIndex
70 m_translationIndex = new TranslationIndex(); 72 m_translationIndex = new TranslationIndex();
71 m_interfaces = HashMultimap.create(); 73 m_interfaces = HashMultimap.create();
72 m_access = Maps.newHashMap(); 74 m_access = Maps.newHashMap();
75 m_fieldClasses = Maps.newHashMap();
73 m_methodImplementations = HashMultimap.create(); 76 m_methodImplementations = HashMultimap.create();
74 m_behaviorReferences = HashMultimap.create(); 77 m_behaviorReferences = HashMultimap.create();
75 m_fieldReferences = HashMultimap.create(); 78 m_fieldReferences = HashMultimap.create();
@@ -127,7 +130,7 @@ public class JarIndex
127 } 130 }
128 for( CtField field : c.getDeclaredFields() ) 131 for( CtField field : c.getDeclaredFields() )
129 { 132 {
130 m_translationIndex.addField( className, field.getName() ); 133 indexField( field );
131 } 134 }
132 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 135 for( CtBehavior behavior : c.getDeclaredBehaviors() )
133 { 136 {
@@ -193,6 +196,22 @@ public class JarIndex
193 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); 196 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences );
194 } 197 }
195 198
199 private void indexField( CtField field )
200 {
201 // get the field entry
202 String className = Descriptor.toJvmName( field.getDeclaringClass().getName() );
203 FieldEntry fieldEntry = new FieldEntry( new ClassEntry( className ), field.getName() );
204
205 m_translationIndex.addField( className, field.getName() );
206
207 // is the field a class type?
208 if( field.getSignature().startsWith( "L" ) )
209 {
210 ClassEntry fieldTypeEntry = new ClassEntry( field.getSignature().substring( 1, field.getSignature().length() - 1 ) );
211 m_fieldClasses.put( fieldEntry, fieldTypeEntry );
212 }
213 }
214
196 private void indexBehavior( CtBehavior behavior ) 215 private void indexBehavior( CtBehavior behavior )
197 { 216 {
198 // get the behavior entry 217 // get the behavior entry
@@ -412,7 +431,8 @@ public class JarIndex
412 // use the synthetic fields to find the synthetic constructors 431 // use the synthetic fields to find the synthetic constructors
413 for( CtConstructor constructor : c.getDeclaredConstructors() ) 432 for( CtConstructor constructor : c.getDeclaredConstructors() )
414 { 433 {
415 if( !isIllegalConstructor( constructor ) ) 434 Set<String> syntheticFieldTypes = Sets.newHashSet();
435 if( !isIllegalConstructor( syntheticFieldTypes, constructor ) )
416 { 436 {
417 continue; 437 continue;
418 } 438 }
@@ -420,27 +440,57 @@ public class JarIndex
420 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 440 ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) );
421 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() ); 441 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, constructor.getMethodInfo().getDescriptor() );
422 442
443 // look at the synthetic types to get candidates for the outer class
444 Set<ClassEntry> candidateOuterClasses = Sets.newHashSet();
445 for( String type : syntheticFieldTypes )
446 {
447 if( type.startsWith( "L" ) )
448 {
449 candidateOuterClasses.add( new ClassEntry( type.substring( 1, type.length() - 1 ) ) );
450 }
451 }
452
453 // do we have an answer yet?
454 if( candidateOuterClasses.isEmpty() )
455 {
456 continue;
457 }
458 else if( candidateOuterClasses.size() == 1 )
459 {
460 ClassEntry outerClassEntry = candidateOuterClasses.iterator().next();
461
462 // does this class make sense as an outer class?
463 if( !outerClassEntry.equals( classEntry ) )
464 {
465 return outerClassEntry.getName();
466 }
467 }
468
423 // who calls this constructor? 469 // who calls this constructor?
424 Set<ClassEntry> callerClasses = Sets.newHashSet(); 470 Set<ClassEntry> callerClasses = Sets.newHashSet();
425 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) ) 471 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) )
426 { 472 {
427 callerClasses.add( reference.context.getClassEntry() ); 473 // is that one of our candidates?
474 if( candidateOuterClasses.contains( reference.context.getClassEntry() ) )
475 {
476 callerClasses.add( reference.context.getClassEntry() );
477 }
428 } 478 }
429 479
430 // is this called by exactly one class? 480 // do we have an answer yet?
431 if( callerClasses.size() == 1 ) 481 if( callerClasses.size() == 1 )
432 { 482 {
433 ClassEntry callerClassEntry = callerClasses.iterator().next(); 483 ClassEntry outerClassEntry = callerClasses.iterator().next();
434 484
435 // does this class make sense as an outer class? 485 // does this class make sense as an outer class?
436 if( !callerClassEntry.equals( classEntry ) ) 486 if( !outerClassEntry.equals( classEntry ) )
437 { 487 {
438 return callerClassEntry.getName(); 488 return outerClassEntry.getName();
439 } 489 }
440 } 490 }
441 else if( callerClasses.size() > 1 ) 491 else
442 { 492 {
443 System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses ); 493 System.out.println( "WARNING: Unable to choose outer class among options: " + candidateOuterClasses );
444 } 494 }
445 } 495 }
446 496
@@ -448,7 +498,7 @@ public class JarIndex
448 } 498 }
449 499
450 @SuppressWarnings( "unchecked" ) 500 @SuppressWarnings( "unchecked" )
451 private boolean isIllegalConstructor( CtConstructor constructor ) 501 private boolean isIllegalConstructor( Set<String> syntheticFieldTypes, CtConstructor constructor )
452 { 502 {
453 // illegal constructors only set synthetic member fields, then call super() 503 // illegal constructors only set synthetic member fields, then call super()
454 String className = constructor.getDeclaringClass().getName(); 504 String className = constructor.getDeclaringClass().getName();
@@ -456,7 +506,6 @@ public class JarIndex
456 // collect all the field accesses, constructor calls, and method calls 506 // collect all the field accesses, constructor calls, and method calls
457 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList(); 507 final List<FieldAccess> illegalFieldWrites = Lists.newArrayList();
458 final List<ConstructorCall> constructorCalls = Lists.newArrayList(); 508 final List<ConstructorCall> constructorCalls = Lists.newArrayList();
459 final List<MethodCall> methodCalls = Lists.newArrayList();
460 try 509 try
461 { 510 {
462 constructor.instrument( new ExprEditor( ) 511 constructor.instrument( new ExprEditor( )
@@ -475,12 +524,6 @@ public class JarIndex
475 { 524 {
476 constructorCalls.add( constructorCall ); 525 constructorCalls.add( constructorCall );
477 } 526 }
478
479 @Override
480 public void edit( MethodCall methodCall )
481 {
482 methodCalls.add( methodCall );
483 }
484 } ); 527 } );
485 } 528 }
486 catch( CannotCompileException ex ) 529 catch( CannotCompileException ex )
@@ -489,25 +532,6 @@ public class JarIndex
489 throw new Error( ex ); 532 throw new Error( ex );
490 } 533 }
491 534
492 // method calls are not allowed
493 if( !methodCalls.isEmpty() )
494 {
495 return false;
496 }
497
498 // is there only one constructor call?
499 if( constructorCalls.size() != 1 )
500 {
501 return false;
502 }
503
504 // is the call to super?
505 ConstructorCall constructorCall = constructorCalls.get( 0 );
506 if( !constructorCall.getMethodName().equals( "super" ) )
507 {
508 return false;
509 }
510
511 // are there any illegal field writes? 535 // are there any illegal field writes?
512 if( illegalFieldWrites.isEmpty() ) 536 if( illegalFieldWrites.isEmpty() )
513 { 537 {
@@ -528,7 +552,7 @@ public class JarIndex
528 FieldInfo fieldInfo = null; 552 FieldInfo fieldInfo = null;
529 for( FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields() ) 553 for( FieldInfo info : (List<FieldInfo>)constructor.getDeclaringClass().getClassFile().getFields() )
530 { 554 {
531 if( info.getName().equals( fieldWrite.getFieldName() ) ) 555 if( info.getName().equals( fieldWrite.getFieldName() ) && info.getDescriptor().equals( fieldWrite.getSignature() ) )
532 { 556 {
533 fieldInfo = info; 557 fieldInfo = info;
534 break; 558 break;
@@ -542,9 +566,13 @@ public class JarIndex
542 566
543 // is this field synthetic? 567 // is this field synthetic?
544 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; 568 boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0;
545 if( !isSynthetic ) 569 if( isSynthetic )
570 {
571 syntheticFieldTypes.add( fieldInfo.getDescriptor() );
572 }
573 else
546 { 574 {
547 System.err.println( String.format( "WARNING: illegal write to non synthetic field %s.%s", className, fieldInfo.getName() ) ); 575 System.err.println( String.format( "WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName() ) );
548 return false; 576 return false;
549 } 577 }
550 } 578 }
@@ -555,15 +583,15 @@ public class JarIndex
555 583
556 private boolean isAnonymousClass( CtClass c, String outerClassName ) 584 private boolean isAnonymousClass( CtClass c, String outerClassName )
557 { 585 {
558 String innerClassName = Descriptor.toJvmName( c.getName() ); 586 ClassEntry innerClassEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) );
559 587
560 // anonymous classes: 588 // anonymous classes:
561 // can't be abstract 589 // can't be abstract
562 // have only one constructor 590 // have only one constructor
563 // it's called exactly once by the outer class 591 // it's called exactly once by the outer class
564 // type of inner class not referenced anywhere in outer class 592 // the type the instance is assigned to can't be this type
565 593
566 // is absract? 594 // is abstract?
567 if( Modifier.isAbstract( c.getModifiers() ) ) 595 if( Modifier.isAbstract( c.getModifiers() ) )
568 { 596 {
569 return false; 597 return false;
@@ -577,22 +605,40 @@ public class JarIndex
577 CtConstructor constructor = c.getDeclaredConstructors()[0]; 605 CtConstructor constructor = c.getDeclaredConstructors()[0];
578 606
579 // is this constructor called exactly once? 607 // is this constructor called exactly once?
580 ConstructorEntry constructorEntry = new ConstructorEntry( 608 ConstructorEntry constructorEntry = new ConstructorEntry( innerClassEntry, constructor.getMethodInfo().getDescriptor() );
581 new ClassEntry( innerClassName ), 609 Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences( constructorEntry );
582 constructor.getMethodInfo().getDescriptor() 610 if( references.size() != 1 )
583 );
584 if( getBehaviorReferences( constructorEntry ).size() != 1 )
585 { 611 {
586 return false; 612 return false;
587 } 613 }
588 614
589 // TODO: check outer class doesn't reference type 615 // does the caller use this type?
590 // except this is hard because we can't just load the outer class now 616 BehaviorEntry caller = references.iterator().next().context;
591 // we'd have to pre-index those references in the JarIndex 617 for( FieldEntry fieldEntry : getReferencedFields( caller ) )
618 {
619 ClassEntry fieldClass = getFieldClass( fieldEntry );
620 if( fieldClass != null && fieldClass.equals( innerClassEntry ) )
621 {
622 // caller references this type, so it can't be anonymous
623 return false;
624 }
625 }
626 for( BehaviorEntry behaviorEntry : getReferencedBehaviors( caller ) )
627 {
628 // get the class types from the signature
629 for( String className : SignatureUpdater.getClasses( behaviorEntry.getSignature() ) )
630 {
631 if( className.equals( innerClassEntry.getName() ) )
632 {
633 // caller references this type, so it can't be anonymous
634 return false;
635 }
636 }
637 }
592 638
593 return true; 639 return true;
594 } 640 }
595 641
596 public Set<ClassEntry> getObfClassEntries( ) 642 public Set<ClassEntry> getObfClassEntries( )
597 { 643 {
598 return m_obfClassEntries; 644 return m_obfClassEntries;
@@ -608,6 +654,11 @@ public class JarIndex
608 return m_access.get( entry ); 654 return m_access.get( entry );
609 } 655 }
610 656
657 public ClassEntry getFieldClass( FieldEntry fieldEntry )
658 {
659 return m_fieldClasses.get( fieldEntry );
660 }
661
611 public boolean isMethodImplemented( MethodEntry methodEntry ) 662 public boolean isMethodImplemented( MethodEntry methodEntry )
612 { 663 {
613 Collection<MethodEntry> implementations = m_methodImplementations.get( methodEntry.getClassName() ); 664 Collection<MethodEntry> implementations = m_methodImplementations.get( methodEntry.getClassName() );
@@ -772,11 +823,39 @@ public class JarIndex
772 return m_fieldReferences.get( fieldEntry ); 823 return m_fieldReferences.get( fieldEntry );
773 } 824 }
774 825
826 public Collection<FieldEntry> getReferencedFields( BehaviorEntry behaviorEntry )
827 {
828 // linear search is fast enough for now
829 Set<FieldEntry> fieldEntries = Sets.newHashSet();
830 for( EntryReference<FieldEntry,BehaviorEntry> reference : m_fieldReferences.values() )
831 {
832 if( reference.context == behaviorEntry )
833 {
834 fieldEntries.add( reference.entry );
835 }
836 }
837 return fieldEntries;
838 }
839
775 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry ) 840 public Collection<EntryReference<BehaviorEntry,BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry )
776 { 841 {
777 return m_behaviorReferences.get( behaviorEntry ); 842 return m_behaviorReferences.get( behaviorEntry );
778 } 843 }
779 844
845 public Collection<BehaviorEntry> getReferencedBehaviors( BehaviorEntry behaviorEntry )
846 {
847 // linear search is fast enough for now
848 Set<BehaviorEntry> behaviorEntries = Sets.newHashSet();
849 for( EntryReference<BehaviorEntry,BehaviorEntry> reference : m_behaviorReferences.values() )
850 {
851 if( reference.context == behaviorEntry )
852 {
853 behaviorEntries.add( reference.entry );
854 }
855 }
856 return behaviorEntries;
857 }
858
780 public Collection<String> getInnerClasses( String obfOuterClassName ) 859 public Collection<String> getInnerClasses( String obfOuterClassName )
781 { 860 {
782 return m_innerClasses.get( obfOuterClassName ); 861 return m_innerClasses.get( obfOuterClassName );
diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java
index 4c0dbac..528a743 100644
--- a/src/cuchaz/enigma/mapping/SignatureUpdater.java
+++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java
@@ -12,6 +12,9 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.IOException; 13import java.io.IOException;
14import java.io.StringReader; 14import java.io.StringReader;
15import java.util.List;
16
17import com.beust.jcommander.internal.Lists;
15 18
16public class SignatureUpdater 19public class SignatureUpdater
17{ 20{
@@ -84,4 +87,19 @@ public class SignatureUpdater
84 87
85 return null; 88 return null;
86 } 89 }
90
91 public static List<String> getClasses( String signature )
92 {
93 final List<String> classNames = Lists.newArrayList();
94 update( signature, new ClassNameUpdater( )
95 {
96 @Override
97 public String update( String className )
98 {
99 classNames.add( className );
100 return className;
101 }
102 } );
103 return classNames;
104 }
87} 105}
diff --git a/test/cuchaz/enigma/TestDeobfuscator.java b/test/cuchaz/enigma/TestDeobfuscator.java
index 3bb0c48..71de24a 100644
--- a/test/cuchaz/enigma/TestDeobfuscator.java
+++ b/test/cuchaz/enigma/TestDeobfuscator.java
@@ -11,7 +11,7 @@
11 ******************************************************************************/ 11 ******************************************************************************/
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static org.junit.Assert.assertEquals; 14import static org.junit.Assert.*;
15 15
16import java.io.File; 16import java.io.File;
17import java.io.IOException; 17import java.io.IOException;
diff --git a/test/cuchaz/enigma/TestInnerClasses.java b/test/cuchaz/enigma/TestInnerClasses.java
new file mode 100644
index 0000000..c6b1b5f
--- /dev/null
+++ b/test/cuchaz/enigma/TestInnerClasses.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the GNU Public License v3.0
6 * which accompanies this distribution, and is available at
7 * http://www.gnu.org/licenses/gpl.html
8 *
9 * Contributors:
10 * Jeff Martin - initial API and implementation
11 ******************************************************************************/
12package cuchaz.enigma;
13
14import static org.hamcrest.MatcherAssert.*;
15import static org.hamcrest.Matchers.*;
16
17import java.util.jar.JarFile;
18
19import org.junit.Test;
20
21import cuchaz.enigma.analysis.JarIndex;
22
23public class TestInnerClasses
24{
25 private JarIndex m_index;
26
27 private static final String AnonymousOuter = "none/a";
28 private static final String AnonymousInner = "none/b";
29 private static final String SimpleOuter = "none/e";
30 private static final String SimpleInner = "none/f";
31 private static final String ConstructorArgsOuter = "none/c";
32 private static final String ConstructorArgsInner = "none/d";
33
34 public TestInnerClasses( )
35 throws Exception
36 {
37 m_index = new JarIndex();
38 m_index.indexJar( new JarFile( "build/libs/testInnerClasses.obf.jar" ), true );
39 }
40
41 @Test
42 public void simple( )
43 {
44 assertThat( m_index.getOuterClass( SimpleInner ), is( SimpleOuter ) );
45 assertThat( m_index.getInnerClasses( SimpleOuter ), containsInAnyOrder( SimpleInner ) );
46 assertThat( m_index.isAnonymousClass( SimpleInner ), is( false ) );
47 }
48
49 @Test
50 public void anonymous( )
51 {
52 assertThat( m_index.getOuterClass( AnonymousInner ), is( AnonymousOuter ) );
53 assertThat( m_index.getInnerClasses( AnonymousOuter ), containsInAnyOrder( AnonymousInner ) );
54 assertThat( m_index.isAnonymousClass( AnonymousInner ), is( true ) );
55 }
56
57 @Test
58 public void constructorArgs( )
59 {
60 assertThat( m_index.getOuterClass( ConstructorArgsInner ), is( ConstructorArgsOuter ) );
61 assertThat( m_index.getInnerClasses( ConstructorArgsOuter ), containsInAnyOrder( ConstructorArgsInner ) );
62 assertThat( m_index.isAnonymousClass( ConstructorArgsInner ), is( false ) );
63 }
64}
diff --git a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
index c069188..0238171 100644
--- a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
+++ b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java
@@ -10,13 +10,9 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByConstructor; 13import static cuchaz.enigma.EntryFactory.*;
14import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByMethod; 14import static org.hamcrest.MatcherAssert.*;
15import static cuchaz.enigma.EntryFactory.newClass; 15import static org.hamcrest.Matchers.*;
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.hamcrest.Matchers.containsInAnyOrder;
18import static org.hamcrest.Matchers.empty;
19import static org.hamcrest.Matchers.is;
20 16
21import java.io.File; 17import java.io.File;
22import java.util.Collection; 18import java.util.Collection;
diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
index 3d488ee..317a6bc 100644
--- a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -10,17 +10,9 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByConstructor; 13import static cuchaz.enigma.EntryFactory.*;
14import static cuchaz.enigma.EntryFactory.newBehaviorReferenceByMethod; 14import static org.hamcrest.MatcherAssert.*;
15import static cuchaz.enigma.EntryFactory.newClass; 15import static org.hamcrest.Matchers.*;
16import static cuchaz.enigma.EntryFactory.newFieldReferenceByConstructor;
17import static cuchaz.enigma.EntryFactory.newFieldReferenceByMethod;
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.contains;
20import static org.hamcrest.Matchers.containsInAnyOrder;
21import static org.hamcrest.Matchers.empty;
22import static org.hamcrest.Matchers.is;
23import static org.hamcrest.Matchers.nullValue;
24 16
25import java.util.Collection; 17import java.util.Collection;
26import java.util.Set; 18import java.util.Set;
diff --git a/test/cuchaz/enigma/TestJarIndexLoneClass.java b/test/cuchaz/enigma/TestJarIndexLoneClass.java
index 9236d0c..4c32b70 100644
--- a/test/cuchaz/enigma/TestJarIndexLoneClass.java
+++ b/test/cuchaz/enigma/TestJarIndexLoneClass.java
@@ -11,17 +11,9 @@
11 ******************************************************************************/ 11 ******************************************************************************/
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.EntryFactory.newClass; 14import static cuchaz.enigma.EntryFactory.*;
15import static cuchaz.enigma.EntryFactory.newField; 15import static org.hamcrest.MatcherAssert.*;
16import static cuchaz.enigma.EntryFactory.newFieldReferenceByConstructor; 16import static org.hamcrest.Matchers.*;
17import static cuchaz.enigma.EntryFactory.newFieldReferenceByMethod;
18import static cuchaz.enigma.EntryFactory.newMethod;
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.containsInAnyOrder;
21import static org.hamcrest.Matchers.empty;
22import static org.hamcrest.Matchers.is;
23import static org.hamcrest.Matchers.not;
24import static org.hamcrest.Matchers.nullValue;
25 17
26import java.util.Collection; 18import java.util.Collection;
27import java.util.Set; 19import java.util.Set;
diff --git a/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java b/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java
new file mode 100644
index 0000000..dbff523
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/innerClasses/Anonymous.java
@@ -0,0 +1,17 @@
1package cuchaz.enigma.inputs.innerClasses;
2
3public class Anonymous // a
4{
5 public void foo( )
6 {
7 Runnable runnable = new Runnable( ) // b
8 {
9 @Override
10 public void run( )
11 {
12 // don't care
13 }
14 };
15 runnable.run();
16 }
17}
diff --git a/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java b/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java
new file mode 100644
index 0000000..d12d9cf
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/innerClasses/ConstructorArgs.java
@@ -0,0 +1,22 @@
1package cuchaz.enigma.inputs.innerClasses;
2
3@SuppressWarnings( "unused" )
4public class ConstructorArgs // c
5{
6 class Inner // d
7 {
8 private int a;
9
10 public Inner( int a )
11 {
12 this.a = a;
13 }
14 }
15
16 Inner i;
17
18 public void foo( )
19 {
20 i = new Inner( 5 );
21 }
22}
diff --git a/test/cuchaz/enigma/inputs/innerClasses/Simple.java b/test/cuchaz/enigma/inputs/innerClasses/Simple.java
new file mode 100644
index 0000000..f2c08a7
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/innerClasses/Simple.java
@@ -0,0 +1,9 @@
1package cuchaz.enigma.inputs.innerClasses;
2
3public class Simple // e
4{
5 class Inner // f
6 {
7 // nothing to do
8 }
9}