KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > util > ClassReferenceInitializer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.classfile.util;
22
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.*;
26 import proguard.classfile.attribute.annotation.*;
27 import proguard.classfile.attribute.annotation.visitor.*;
28 import proguard.classfile.constant.*;
29 import proguard.classfile.constant.visitor.ConstantVisitor;
30 import proguard.classfile.visitor.*;
31
32
33 /**
34  * This ClassVisitor initializes the references of all classes that
35  * it visits.
36  * <p>
37  * All class constant pool entries get direct references to the corresponding
38  * classes. These references make it more convenient to travel up and across
39  * the class hierarchy.
40  * <p>
41  * All field and method reference constant pool entries get direct references
42  * to the corresponding classes, fields, and methods.
43  * <p>
44  * All name and type constant pool entries get a list of direct references to
45  * the classes listed in the type.
46  * <p>
47  * This visitor optionally prints warnings if some items can't be found.
48  * <p>
49  * The class hierarchy must be initialized before using this visitor.
50  *
51  * @author Eric Lafortune
52  */

53 public class ClassReferenceInitializer
54 extends SimplifiedVisitor
55 implements ClassVisitor,
56              MemberVisitor,
57              ConstantVisitor,
58              AttributeVisitor,
59              LocalVariableInfoVisitor,
60              LocalVariableTypeInfoVisitor,
61              AnnotationVisitor,
62              ElementValueVisitor
63 {
64     private ClassPool programClassPool;
65     private ClassPool libraryClassPool;
66     private WarningPrinter warningPrinter;
67
68     private MemberFinder memberFinder = new MemberFinder();
69
70
71     /**
72      * Creates a new ClassReferenceInitializer that initializes the references
73      * of all visited class files, optionally printing warnings if some classes
74      * can't be found.
75      */

76     public ClassReferenceInitializer(ClassPool programClassPool,
77                                      ClassPool libraryClassPool,
78                                      WarningPrinter warningPrinter)
79     {
80         this.programClassPool = programClassPool;
81         this.libraryClassPool = libraryClassPool;
82         this.warningPrinter = warningPrinter;
83     }
84
85
86     // Implementations for ClassVisitor.
87

88     public void visitProgramClass(ProgramClass programClass)
89     {
90         // Initialize the constant pool entries.
91
programClass.constantPoolEntriesAccept(this);
92
93         // Initialize all fields and methods.
94
programClass.fieldsAccept(this);
95         programClass.methodsAccept(this);
96
97         // Initialize the attributes.
98
programClass.attributesAccept(this);
99     }
100
101
102     public void visitLibraryClass(LibraryClass libraryClass)
103     {
104         // Initialize all fields and methods.
105
libraryClass.fieldsAccept(this);
106         libraryClass.methodsAccept(this);
107     }
108
109
110     // Implementations for MemberVisitor.
111

112     public void visitProgramField(ProgramClass programClass, ProgramField programField)
113     {
114         programField.referencedClass =
115             findReferencedClass(programField.getDescriptor(programClass));
116
117         // Initialize the attributes.
118
programField.attributesAccept(programClass, this);
119     }
120
121
122     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
123     {
124         programMethod.referencedClasses =
125             findReferencedClasses(programMethod.getDescriptor(programClass));
126
127         // Initialize the attributes.
128
programMethod.attributesAccept(programClass, this);
129     }
130
131
132     public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
133     {
134         libraryField.referencedClass =
135             findReferencedClass(libraryField.getDescriptor(libraryClass));
136     }
137
138
139     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
140     {
141         libraryMethod.referencedClasses =
142             findReferencedClasses(libraryMethod.getDescriptor(libraryClass));
143     }
144
145
146     // Implementations for ConstantVisitor.
147

148     public void visitAnyConstant(Clazz clazz, Constant constant) {}
149
150
151     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
152     {
153         String JavaDoc className = refConstant.getClassName(clazz);
154
155         // See if we can find the referenced class.
156
// Unresolved references are assumed to refer to library classes
157
// that will not change anyway.
158
Clazz referencedClass = findClass(className);
159
160         if (referencedClass != null &&
161             !ClassUtil.isInternalArrayType(className))
162         {
163             String JavaDoc name = refConstant.getName(clazz);
164             String JavaDoc type = refConstant.getType(clazz);
165
166             boolean isFieldRef = refConstant.getTag() == ClassConstants.CONSTANT_Fieldref;
167
168             // See if we can find the referenced class member somewhere in the
169
// hierarchy.
170
refConstant.referencedMember = memberFinder.findMember(clazz,
171                                                                    referencedClass,
172                                                                    name,
173                                                                    type,
174                                                                    isFieldRef);
175             refConstant.referencedClass = memberFinder.correspondingClass();
176
177             if (refConstant.referencedMember == null &&
178                 warningPrinter != null)
179             {
180                 // We've haven't found the class member anywhere in the hierarchy.
181
warningPrinter.print("Warning: " +
182                                      ClassUtil.externalClassName(clazz.getName()) +
183                                      ": can't find referenced " +
184                                      (isFieldRef ?
185                                          "field '" + ClassUtil.externalFullFieldDescription(0, name, type) :
186                                          "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) +
187                                      "' in class " +
188                                      ClassUtil.externalClassName(className));
189             }
190         }
191     }
192
193
194     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
195     {
196         classConstant.referencedClass =
197             findClass(classConstant.getName(clazz));
198     }
199
200
201     // Implementations for AttributeVisitor.
202

203     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
204
205
206     public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
207     {
208         String JavaDoc className = enclosingMethodAttribute.getClassName(clazz);
209
210         // See if we can find the referenced class.
211
Clazz referencedClass = findClass(className);
212
213         if (referencedClass == null)
214         {
215             // We couldn't find the enclosing class.
216
if (warningPrinter != null)
217             {
218                 warningPrinter.print("Warning: " +
219                                      ClassUtil.externalClassName(clazz.getName()) +
220                                      ": can't find enclosing class " +
221                                      ClassUtil.externalClassName(className));
222             }
223
224             return;
225         }
226
227         // Make sure there is actually an enclosed method.
228
if (enclosingMethodAttribute.u2nameAndTypeIndex == 0)
229         {
230             return;
231         }
232
233         String JavaDoc name = enclosingMethodAttribute.getName(clazz);
234         String JavaDoc type = enclosingMethodAttribute.getType(clazz);
235
236         // See if we can find the method in the referenced class.
237
Method referencedMethod = referencedClass.findMethod(name, type);
238
239         if (referencedMethod == null)
240         {
241             // We couldn't find the enclosing method.
242
if (warningPrinter != null)
243             {
244                 warningPrinter.print("Warning: " +
245                                      ClassUtil.externalClassName(clazz.getName()) +
246                                      ": can't find enclosing method '" +
247                                      ClassUtil.externalFullMethodDescription(className, 0, name, type) +
248                                      "' in class " +
249                                      ClassUtil.externalClassName(className));
250             }
251
252             return;
253         }
254
255         // Save the references.
256
enclosingMethodAttribute.referencedClass = referencedClass;
257         enclosingMethodAttribute.referencedMethod = referencedMethod;
258     }
259
260
261     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
262     {
263         // Initialize the nested attributes.
264
codeAttribute.attributesAccept(clazz, method, this);
265     }
266
267
268     public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
269     {
270         // Initialize the local variables.
271
localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
272     }
273
274
275     public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
276     {
277         // Initialize the local variable types.
278
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
279     }
280
281
282     public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
283     {
284         signatureAttribute.referencedClasses =
285             findReferencedClasses(clazz.getString(signatureAttribute.u2signatureIndex));
286     }
287
288
289     public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
290     {
291         // Initialize the annotations.
292
annotationsAttribute.annotationsAccept(clazz, this);
293     }
294
295
296     public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
297     {
298         // Initialize the annotations.
299
parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
300     }
301
302
303     public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
304     {
305         // Initialize the annotation.
306
annotationDefaultAttribute.defaultValueAccept(clazz, this);
307     }
308
309
310     // Implementations for LocalVariableInfoVisitor.
311

312     public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
313     {
314         localVariableInfo.referencedClass =
315             findReferencedClass(clazz.getString(localVariableInfo.u2descriptorIndex));
316     }
317
318
319     // Implementations for LocalVariableTypeInfoVisitor.
320

321     public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
322     {
323         localVariableTypeInfo.referencedClasses =
324             findReferencedClasses(clazz.getString(localVariableTypeInfo.u2signatureIndex));
325     }
326
327
328     // Implementations for AnnotationVisitor.
329

330     public void visitAnnotation(Clazz clazz, Annotation annotation)
331     {
332         annotation.referencedClasses =
333             findReferencedClasses(clazz.getString(annotation.u2typeIndex));
334
335         // Initialize the element values.
336
annotation.elementValuesAccept(clazz, this);
337     }
338
339
340     // Implementations for ElementValueVisitor.
341

342     public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
343     {
344         initializeElementValue(clazz, annotation, constantElementValue);
345     }
346
347
348     public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
349     {
350         initializeElementValue(clazz, annotation, enumConstantElementValue);
351
352         enumConstantElementValue.referencedClasses =
353             findReferencedClasses(clazz.getString(enumConstantElementValue.u2typeNameIndex));
354     }
355
356
357     public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
358     {
359         initializeElementValue(clazz, annotation, classElementValue);
360
361         classElementValue.referencedClasses =
362             findReferencedClasses(clazz.getString(classElementValue.u2classInfoIndex));
363     }
364
365
366     public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
367     {
368         initializeElementValue(clazz, annotation, annotationElementValue);
369
370         // Initialize the annotation.
371
annotationElementValue.annotationAccept(clazz, this);
372     }
373
374
375     public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
376     {
377         initializeElementValue(clazz, annotation, arrayElementValue);
378
379         // Initialize the element values.
380
arrayElementValue.elementValuesAccept(clazz, annotation, this);
381     }
382
383
384     /**
385      * Initializes the referenced method of an element value, if any.
386      */

387     private void initializeElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue)
388     {
389         // See if we have a referenced class.
390
if (annotation != null &&
391             annotation.referencedClasses != null &&
392             elementValue.u2elementNameIndex != 0)
393         {
394             // See if we can find the method in the referenced class
395
// (ignoring the descriptor).
396
String JavaDoc name = clazz.getString(elementValue.u2elementNameIndex);
397
398             Clazz referencedClass = annotation.referencedClasses[0];
399             elementValue.referencedClass = referencedClass;
400             elementValue.referencedMethod = referencedClass.findMethod(name, null);
401         }
402     }
403
404
405     // Small utility methods.
406

407     /**
408      * Returns the single class referenced by the given descriptor, or
409      * <code>null</code> if there isn't any useful reference.
410      */

411     private Clazz findReferencedClass(String JavaDoc descriptor)
412     {
413         DescriptorClassEnumeration enumeration =
414             new DescriptorClassEnumeration(descriptor);
415
416         if (enumeration.hasMoreClassNames())
417         {
418             return findClass(enumeration.nextClassName());
419         }
420
421         return null;
422     }
423
424
425     /**
426      * Returns an array of classes referenced by the given descriptor, or
427      * <code>null</code> if there aren't any useful references.
428      */

429     private Clazz[] findReferencedClasses(String JavaDoc descriptor)
430     {
431         DescriptorClassEnumeration enumeration =
432             new DescriptorClassEnumeration(descriptor);
433
434         int classCount = enumeration.classCount();
435         if (classCount > 0)
436         {
437             Clazz[] referencedClasses = new Clazz[classCount];
438
439             boolean foundReferencedClasses = false;
440
441             for (int index = 0; index < classCount; index++)
442             {
443                 String JavaDoc name = enumeration.nextClassName();
444
445                 Clazz referencedClass = findClass(name);
446
447                 if (referencedClass != null)
448                 {
449                     referencedClasses[index] = referencedClass;
450                     foundReferencedClasses = true;
451                 }
452             }
453
454             if (foundReferencedClasses)
455             {
456                 return referencedClasses;
457             }
458         }
459
460         return null;
461     }
462
463
464     /**
465      * Returns the class with the given name, either for the program class pool
466      * or from the library class pool, or <code>null</code> if it can't be found.
467      */

468     private Clazz findClass(String JavaDoc name)
469     {
470         // First look for the class in the program class pool.
471
Clazz clazz = programClassPool.getClass(name);
472
473         // Otherwise look for the class in the library class pool.
474
if (clazz == null)
475         {
476             clazz = libraryClassPool.getClass(name);
477         }
478
479         return clazz;
480     }
481 }
482
Popular Tags