summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java120
-rw-r--r--test/cuchaz/enigma/TestJarIndexInheritanceTree.java3
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java5
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java3
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java11
-rw-r--r--test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java6
6 files changed, 107 insertions, 41 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index b4096e9..f484316 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -127,7 +127,7 @@ public class JarIndex
127 } 127 }
128 for( CtField field : c.getDeclaredFields() ) 128 for( CtField field : c.getDeclaredFields() )
129 { 129 {
130 indexField( field ); 130 m_translationIndex.addField( className, field.getName() );
131 } 131 }
132 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 132 for( CtBehavior behavior : c.getDeclaredBehaviors() )
133 { 133 {
@@ -135,9 +135,19 @@ public class JarIndex
135 } 135 }
136 } 136 }
137 137
138 // step 4: index field, method, constructor references
139 for( CtClass c : JarClassIterator.classes( jar ) )
140 {
141 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage );
142 for( CtBehavior behavior : c.getDeclaredBehaviors() )
143 {
144 indexBehaviorReferences( behavior );
145 }
146 }
147
138 if( buildInnerClasses ) 148 if( buildInnerClasses )
139 { 149 {
140 // step 4: index inner classes and anonymous classes 150 // step 5: index inner classes and anonymous classes
141 for( CtClass c : JarClassIterator.classes( jar ) ) 151 for( CtClass c : JarClassIterator.classes( jar ) )
142 { 152 {
143 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 153 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage );
@@ -163,7 +173,7 @@ public class JarIndex
163 } 173 }
164 } 174 }
165 175
166 // step 5: update other indices with inner class info 176 // step 6: update other indices with inner class info
167 Map<String,String> renames = Maps.newHashMap(); 177 Map<String,String> renames = Maps.newHashMap();
168 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() ) 178 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() )
169 { 179 {
@@ -183,25 +193,14 @@ public class JarIndex
183 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences ); 193 EntryRenamer.renameMethodsInMultimap( m_bridgeMethods, m_fieldReferences );
184 } 194 }
185 195
186 private void indexField( CtField field )
187 {
188 String className = Descriptor.toJvmName( field.getDeclaringClass().getName() );
189 m_translationIndex.addField( className, field.getName() );
190 }
191
192 private void indexBehavior( CtBehavior behavior ) 196 private void indexBehavior( CtBehavior behavior )
193 { 197 {
194 // get the method entry 198 // get the behavior entry
195 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); 199 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() );
196 final BehaviorEntry thisEntry; 200 final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior );
197 if( behavior instanceof CtMethod ) 201 if( behaviorEntry instanceof MethodEntry )
198 { 202 {
199 MethodEntry methodEntry = new MethodEntry( 203 MethodEntry methodEntry = (MethodEntry)behaviorEntry;
200 new ClassEntry( className ),
201 behavior.getName(),
202 behavior.getSignature()
203 );
204 thisEntry = methodEntry;
205 204
206 // index implementation 205 // index implementation
207 m_methodImplementations.put( className, methodEntry ); 206 m_methodImplementations.put( className, methodEntry );
@@ -218,24 +217,13 @@ public class JarIndex
218 m_bridgeMethods.put( bridgedMethodEntry, methodEntry ); 217 m_bridgeMethods.put( bridgedMethodEntry, methodEntry );
219 } 218 }
220 } 219 }
221 else if( behavior instanceof CtConstructor ) 220 // looks like we don't care about constructors here
222 { 221 }
223 boolean isStatic = behavior.getName().equals( "<clinit>" ); 222
224 if( isStatic ) 223 private void indexBehaviorReferences( CtBehavior behavior )
225 { 224 {
226 thisEntry = new ConstructorEntry( new ClassEntry( className ) );
227 }
228 else
229 {
230 thisEntry = new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() );
231 }
232 }
233 else
234 {
235 throw new IllegalArgumentException( "behavior must be a method or a constructor!" );
236 }
237
238 // index method calls 225 // index method calls
226 final BehaviorEntry behaviorEntry = getBehaviorEntry( behavior );
239 try 227 try
240 { 228 {
241 behavior.instrument( new ExprEditor( ) 229 behavior.instrument( new ExprEditor( )
@@ -249,9 +237,10 @@ public class JarIndex
249 call.getMethodName(), 237 call.getMethodName(),
250 call.getSignature() 238 call.getSignature()
251 ); 239 );
240 calledMethodEntry = resolveMethodClass( calledMethodEntry );
252 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 241 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
253 calledMethodEntry, 242 calledMethodEntry,
254 thisEntry 243 behaviorEntry
255 ); 244 );
256 m_behaviorReferences.put( calledMethodEntry, reference ); 245 m_behaviorReferences.put( calledMethodEntry, reference );
257 } 246 }
@@ -266,7 +255,7 @@ public class JarIndex
266 ); 255 );
267 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>( 256 EntryReference<FieldEntry,BehaviorEntry> reference = new EntryReference<FieldEntry,BehaviorEntry>(
268 calledFieldEntry, 257 calledFieldEntry,
269 thisEntry 258 behaviorEntry
270 ); 259 );
271 m_fieldReferences.put( calledFieldEntry, reference ); 260 m_fieldReferences.put( calledFieldEntry, reference );
272 } 261 }
@@ -284,7 +273,7 @@ public class JarIndex
284 ); 273 );
285 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 274 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
286 calledConstructorEntry, 275 calledConstructorEntry,
287 thisEntry 276 behaviorEntry
288 ); 277 );
289 m_behaviorReferences.put( calledConstructorEntry, reference ); 278 m_behaviorReferences.put( calledConstructorEntry, reference );
290 } 279 }
@@ -299,7 +288,7 @@ public class JarIndex
299 ); 288 );
300 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( 289 EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>(
301 calledConstructorEntry, 290 calledConstructorEntry,
302 thisEntry 291 behaviorEntry
303 ); 292 );
304 m_behaviorReferences.put( calledConstructorEntry, reference ); 293 m_behaviorReferences.put( calledConstructorEntry, reference );
305 } 294 }
@@ -311,6 +300,59 @@ public class JarIndex
311 } 300 }
312 } 301 }
313 302
303 private BehaviorEntry getBehaviorEntry( CtBehavior behavior )
304 {
305 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() );
306 if( behavior instanceof CtMethod )
307 {
308 return new MethodEntry(
309 new ClassEntry( className ),
310 behavior.getName(),
311 behavior.getSignature()
312 );
313 }
314 else if( behavior instanceof CtConstructor )
315 {
316 boolean isStatic = behavior.getName().equals( "<clinit>" );
317 if( isStatic )
318 {
319 return new ConstructorEntry( new ClassEntry( className ) );
320 }
321 else
322 {
323 return new ConstructorEntry( new ClassEntry( className ), behavior.getSignature() );
324 }
325 }
326 else
327 {
328 throw new IllegalArgumentException( "behavior must be a method or a constructor!" );
329 }
330 }
331
332 private MethodEntry resolveMethodClass( MethodEntry methodEntry )
333 {
334 // this entry could refer to a method on a class where the method is not actually implemented
335 // travel up the inheritance tree to find the closest implementation
336 while( !isMethodImplemented( methodEntry ) )
337 {
338 // is there a parent class?
339 String superclassName = m_translationIndex.getSuperclassName( methodEntry.getClassName() );
340 if( superclassName == null )
341 {
342 // this is probably a method from a class in a library
343 // we can't trace the implementation up any higher unless we index the library
344 return methodEntry;
345 }
346
347 // move up to the parent class
348 methodEntry = new MethodEntry(
349 new ClassEntry( superclassName ),
350 methodEntry.getName(),
351 methodEntry.getSignature()
352 );
353 }
354 return methodEntry;
355 }
314 356
315 private CtMethod getBridgedMethod( CtMethod method ) 357 private CtMethod getBridgedMethod( CtMethod method )
316 { 358 {
diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
index 5ded5df..3d488ee 100644
--- a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -220,7 +220,8 @@ public class TestJarIndexInheritanceTree
220 source = new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" ); 220 source = new MethodEntry( m_baseClass, "a", "()Ljava/lang/String;" );
221 references = m_index.getBehaviorReferences( source ); 221 references = m_index.getBehaviorReferences( source );
222 assertThat( references, containsInAnyOrder( 222 assertThat( references, containsInAnyOrder(
223 newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()Ljava/lang/String;" ) 223 newBehaviorReferenceByMethod( source, m_subClassAA.getName(), "a", "()Ljava/lang/String;" ),
224 newBehaviorReferenceByMethod( source, m_subClassB.getName(), "a", "()V" )
224 ) ); 225 ) );
225 226
226 // subclassAA.getName() 227 // subclassAA.getName()
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
index a6b3845..8402dde 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
@@ -1,18 +1,23 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/a
3public abstract class BaseClass 4public abstract class BaseClass
4{ 5{
6 // a
5 private String m_name; 7 private String m_name;
6 8
9 // <init>(Ljava/lang/String;)V
7 protected BaseClass( String name ) 10 protected BaseClass( String name )
8 { 11 {
9 m_name = name; 12 m_name = name;
10 } 13 }
11 14
15 // a()Ljava/lang/String;
12 public String getName( ) 16 public String getName( )
13 { 17 {
14 return m_name; 18 return m_name;
15 } 19 }
16 20
21 // a()V
17 public abstract void doBaseThings( ); 22 public abstract void doBaseThings( );
18} 23}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
index f4780a2..ed50709 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
@@ -1,9 +1,12 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/b extends none/a
3public abstract class SubclassA extends BaseClass 4public abstract class SubclassA extends BaseClass
4{ 5{
6 // <init>(Ljava/lang/String;)V
5 protected SubclassA( String name ) 7 protected SubclassA( String name )
6 { 8 {
9 // call to none/a.<init>(Ljava/lang/String)V
7 super( name ); 10 super( name );
8 } 11 }
9} 12}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
index 4001e7a..fc4c8ee 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
@@ -1,24 +1,33 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/c extends none/a
3public class SubclassB extends BaseClass 4public class SubclassB extends BaseClass
4{ 5{
6 // a
5 private int m_numThings; 7 private int m_numThings;
6 8
9 // <init>()V
7 protected SubclassB( ) 10 protected SubclassB( )
8 { 11 {
12 // none/a.<init>(Ljava/lang/String;)V
9 super( "B" ); 13 super( "B" );
10 14
15 // access to a
11 m_numThings = 4; 16 m_numThings = 4;
12 } 17 }
13 18
14 @Override 19 @Override
20 // a()V
15 public void doBaseThings( ) 21 public void doBaseThings( )
16 { 22 {
17 System.out.println( "Base things by B!" ); 23 // call to none/a.a()Ljava/lang/String;
24 System.out.println( "Base things by B! " + getName() );
18 } 25 }
19 26
27 // b()V
20 public void doBThings( ) 28 public void doBThings( )
21 { 29 {
30 // access to a
22 System.out.println( "" + m_numThings + " B things!" ); 31 System.out.println( "" + m_numThings + " B things!" );
23 } 32 }
24} 33}
diff --git a/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
index 11196d1..b3b8342 100644
--- a/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
+++ b/test/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
@@ -1,21 +1,27 @@
1package cuchaz.enigma.inputs.inheritanceTree; 1package cuchaz.enigma.inputs.inheritanceTree;
2 2
3// none/d extends none/b
3public class SubsubclassAA extends SubclassA 4public class SubsubclassAA extends SubclassA
4{ 5{
5 protected SubsubclassAA( ) 6 protected SubsubclassAA( )
6 { 7 {
8 // call to none/b.<init>(Ljava/lang/String;)V
7 super( "AA" ); 9 super( "AA" );
8 } 10 }
9 11
10 @Override 12 @Override
13 // a()Ljava/lang/String;
11 public String getName( ) 14 public String getName( )
12 { 15 {
16 // call to none/b.a()Ljava/lang/String;
13 return "subsub" + super.getName(); 17 return "subsub" + super.getName();
14 } 18 }
15 19
16 @Override 20 @Override
21 // a()V
17 public void doBaseThings( ) 22 public void doBaseThings( )
18 { 23 {
24 // call to none/d.a()Ljava/lang/String;
19 System.out.println( "Base things by " + getName() ); 25 System.out.println( "Base things by " + getName() );
20 } 26 }
21} 27}