KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > editor > MemberReferenceFixer


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.editor;
22
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.annotation.*;
26 import proguard.classfile.attribute.annotation.visitor.*;
27 import proguard.classfile.attribute.visitor.AttributeVisitor;
28 import proguard.classfile.constant.*;
29 import proguard.classfile.constant.visitor.ConstantVisitor;
30 import proguard.classfile.util.*;
31 import proguard.classfile.visitor.*;
32
33 /**
34  * This ClassVisitor fixes constant pool field and method references to
35  * fields and methods whose names or descriptors have changed.
36  *
37  * @author Eric Lafortune
38  */

39 public class MemberReferenceFixer
40 extends SimplifiedVisitor
41 implements ClassVisitor,
42              ConstantVisitor,
43              MemberVisitor,
44              AttributeVisitor,
45              AnnotationVisitor,
46              ElementValueVisitor
47 {
48     private static final boolean DEBUG = false;
49
50
51     private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
52     private StackSizeUpdater stackSizeUpdater = new StackSizeUpdater();
53
54     // Parameter for the visitor methods.
55
private int constantIndex;
56
57     // Return values for the visitor methods.
58
private boolean isInterfaceMethod;
59     private boolean stackSizesMayHaveChanged;
60
61
62     // Implementations for ClassVisitor.
63

64     public void visitProgramClass(ProgramClass programClass)
65     {
66         stackSizesMayHaveChanged = false;
67
68         // Fix the constant pool entries.
69
for (int index = 1; index < programClass.u2constantPoolCount; index++)
70         {
71             Constant constant = programClass.constantPool[index];
72             if (constant != null)
73             {
74                 // Fix the entry, replacing it entirely if needed.
75
this.constantIndex = index;
76
77                 constant.accept(programClass, this);
78             }
79         }
80
81         // Fix class members.
82
programClass.fieldsAccept(this);
83         programClass.methodsAccept(this);
84
85         // Fix the attributes.
86
programClass.attributesAccept(this);
87     }
88
89
90     // Implementations for ConstantVisitor.
91

92     public void visitAnyConstant(Clazz clazz, Constant constant) {}
93
94
95     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
96     {
97         // Does the string refer to a class member, due to a
98
// Class.get[Declared]{Field,Method} construct?
99
Member referencedMember = stringConstant.referencedMember;
100         if (referencedMember != null)
101         {
102             Clazz referencedClass = stringConstant.referencedClass;
103
104             // Does it have a new name?
105
String JavaDoc newName = referencedMember.getName(referencedClass);
106
107             if (!stringConstant.getString(clazz).equals(newName))
108             {
109                 if (DEBUG)
110                 {
111                     debug(clazz, stringConstant, referencedClass, referencedMember);
112                 }
113
114                 // Update the name.
115
stringConstant.u2stringIndex =
116                     constantPoolEditor.addUtf8Constant((ProgramClass)clazz,
117                                                        newName);
118             }
119         }
120     }
121
122
123     public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
124     {
125         // Do we know the referenced field?
126
Member referencedMember = fieldrefConstant.referencedMember;
127         if (referencedMember != null)
128         {
129             Clazz referencedClass = fieldrefConstant.referencedClass;
130
131             // Does it have a new name or type?
132
String JavaDoc newName = referencedMember.getName(referencedClass);
133             String JavaDoc newType = referencedMember.getDescriptor(referencedClass);
134
135             if (!fieldrefConstant.getName(clazz).equals(newName) ||
136                 !fieldrefConstant.getType(clazz).equals(newType))
137             {
138                 if (DEBUG)
139                 {
140                     debug(clazz, fieldrefConstant, referencedClass, referencedMember);
141                 }
142
143                 // Update the name and type index.
144
fieldrefConstant.u2nameAndTypeIndex =
145                     constantPoolEditor.addNameAndTypeConstant((ProgramClass)clazz,
146                                                               newName,
147                                                               newType);
148             }
149         }
150     }
151
152
153     public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
154     {
155         // Do we know the referenced interface method?
156
Member referencedMember = interfaceMethodrefConstant.referencedMember;
157         if (referencedMember != null)
158         {
159             Clazz referencedClass = interfaceMethodrefConstant.referencedClass;
160
161             // Does it have a new name or type?
162
String JavaDoc newName = referencedMember.getName(referencedClass);
163             String JavaDoc newType = referencedMember.getDescriptor(referencedClass);
164
165             if (!interfaceMethodrefConstant.getName(clazz).equals(newName) ||
166                 !interfaceMethodrefConstant.getType(clazz).equals(newType))
167             {
168                 if (DEBUG)
169                 {
170                     debug(clazz, interfaceMethodrefConstant, referencedClass, referencedMember);
171                 }
172
173                 // Update the name and type index.
174
interfaceMethodrefConstant.u2nameAndTypeIndex =
175                     constantPoolEditor.addNameAndTypeConstant((ProgramClass)clazz,
176                                                               newName,
177                                                               newType);
178
179                 // Remember that the stack sizes of the methods in this class
180
// may have changed.
181
stackSizesMayHaveChanged = true;
182             }
183
184             // Check if this is an interface method.
185
isInterfaceMethod = true;
186             clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this);
187
188             // Has the method become a non-interface method?
189
if (!isInterfaceMethod)
190             {
191                 if (DEBUG)
192                 {
193                     System.out.println("MemberReferenceFixer:");
194                     System.out.println(" Class file = "+clazz.getName());
195                     System.out.println(" Ref class = "+referencedClass.getName());
196                     System.out.println(" Ref method = "+interfaceMethodrefConstant.getName(clazz)+interfaceMethodrefConstant.getType(clazz));
197                     System.out.println(" -> ordinary method");
198                 }
199
200                 // Replace the interface method reference by a method reference.
201
((ProgramClass)clazz).constantPool[this.constantIndex] =
202                     new MethodrefConstant(interfaceMethodrefConstant.u2classIndex,
203                                           interfaceMethodrefConstant.u2nameAndTypeIndex,
204                                           referencedClass,
205                                           referencedMember);
206             }
207         }
208     }
209
210
211     public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
212     {
213         // Do we know the referenced method?
214
Member referencedMember = methodrefConstant.referencedMember;
215         if (referencedMember != null)
216         {
217             Clazz referencedClass = methodrefConstant.referencedClass;
218
219             // Does it have a new name or type?
220
String JavaDoc newName = referencedMember.getName(referencedClass);
221             String JavaDoc newType = referencedMember.getDescriptor(referencedClass);
222
223             if (!methodrefConstant.getName(clazz).equals(newName) ||
224                 !methodrefConstant.getType(clazz).equals(newType))
225             {
226                 if (DEBUG)
227                 {
228                     debug(clazz, methodrefConstant, referencedClass, referencedMember);
229                 }
230
231                 // Update the name and type index.
232
methodrefConstant.u2nameAndTypeIndex =
233                     constantPoolEditor.addNameAndTypeConstant((ProgramClass)clazz,
234                                                               newName,
235                                                               newType);
236
237                 // Remember that the stack sizes of the methods in this class
238
// may have changed.
239
stackSizesMayHaveChanged = true;
240             }
241
242             // Check if this is an interface method.
243
isInterfaceMethod = false;
244             clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this);
245
246             // Has the method become an interface method?
247
if (isInterfaceMethod)
248             {
249                 if (DEBUG)
250                 {
251                     System.out.println("MemberReferenceFixer:");
252                     System.out.println(" Class file = "+clazz.getName());
253                     System.out.println(" Ref class = "+referencedClass.getName());
254                     System.out.println(" Ref method = "+methodrefConstant.getName(clazz)+methodrefConstant.getType(clazz));
255                     System.out.println(" -> interface method");
256                 }
257
258                 // Replace the method reference by an interface method reference.
259
((ProgramClass)clazz).constantPool[this.constantIndex] =
260                     new InterfaceMethodrefConstant(methodrefConstant.u2classIndex,
261                                                    methodrefConstant.u2nameAndTypeIndex,
262                                                    referencedClass,
263                                                    referencedMember);
264             }
265         }
266     }
267
268
269     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
270     {
271         // Check if this class entry is an array type.
272
if (ClassUtil.isInternalArrayType(classConstant.getName(clazz)))
273         {
274             isInterfaceMethod = false;
275         }
276         else
277         {
278             // Check if this class entry refers to an interface class.
279
Clazz referencedClass = classConstant.referencedClass;
280             if (referencedClass != null)
281             {
282                 isInterfaceMethod = (referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0;
283             }
284         }
285     }
286
287
288     // Implementations for MemberVisitor.
289

290     public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
291     {
292         // Fix the attributes.
293
programMember.attributesAccept(programClass, this);
294     }
295
296
297     // Implementations for AttributeVisitor.
298

299     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
300
301
302     public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
303     {
304         Member referencedMember = enclosingMethodAttribute.referencedMethod;
305         if (referencedMember != null)
306         {
307             Clazz referencedClass = enclosingMethodAttribute.referencedClass;
308
309             // Does it have a new class?
310
if (!enclosingMethodAttribute.getClassName(clazz).equals(referencedClass.getName()))
311             {
312                 // Update the class index.
313
enclosingMethodAttribute.u2classIndex =
314                     constantPoolEditor.addClassConstant((ProgramClass)clazz,
315                                                         referencedClass);
316             }
317
318             // Does it have a new name or type?
319
if (!enclosingMethodAttribute.getName(clazz).equals(referencedMember.getName(referencedClass)) ||
320                 !enclosingMethodAttribute.getType(clazz).equals(referencedMember.getDescriptor(referencedClass)))
321             {
322                 // Update the name and type index.
323
enclosingMethodAttribute.u2nameAndTypeIndex =
324                     constantPoolEditor.addNameAndTypeConstant((ProgramClass)clazz,
325                                                               referencedMember.getName(referencedClass),
326                                                               referencedMember.getDescriptor(referencedClass));
327             }
328         }
329     }
330
331
332     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
333     {
334         // Recompute the maximum stack size if necessary.
335
if (stackSizesMayHaveChanged)
336         {
337             stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
338         }
339
340         // Fix the nested attributes.
341
codeAttribute.attributesAccept(clazz, method, this);
342     }
343
344
345     public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
346     {
347         // Fix the annotations.
348
annotationsAttribute.annotationsAccept(clazz, this);
349     }
350
351
352     public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
353     {
354         // Fix the annotations.
355
parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
356     }
357
358
359     public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
360     {
361         // Fix the annotation.
362
annotationDefaultAttribute.defaultValueAccept(clazz, this);
363     }
364
365
366     // Implementations for AnnotationVisitor.
367

368     public void visitAnnotation(Clazz clazz, Annotation annotation)
369     {
370         // Fix the element values.
371
annotation.elementValuesAccept(clazz, this);
372     }
373
374
375     // Implementations for ElementValueVisitor.
376

377     public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
378     {
379         fixElementValue(clazz, annotation, constantElementValue);
380     }
381
382
383     public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
384     {
385         fixElementValue(clazz, annotation, enumConstantElementValue);
386     }
387
388
389     public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
390     {
391         fixElementValue(clazz, annotation, classElementValue);
392     }
393
394
395     public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
396     {
397         fixElementValue(clazz, annotation, annotationElementValue);
398
399         // Fix the annotation.
400
annotationElementValue.annotationAccept(clazz, this);
401     }
402
403
404     public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
405     {
406         fixElementValue(clazz, annotation, arrayElementValue);
407
408         // Fix the element values.
409
arrayElementValue.elementValuesAccept(clazz, annotation, this);
410     }
411
412
413     // Small utility methods.
414

415     /**
416      * Fixes the method reference of the element value, if any.
417      */

418     private void fixElementValue(Clazz clazz,
419                                  Annotation annotation,
420                                  ElementValue elementValue)
421     {
422         // Do we know the referenced method?
423
Member referencedMember = elementValue.referencedMethod;
424         if (referencedMember != null)
425         {
426             // Does it have a new name or type?
427
String JavaDoc methodName = elementValue.getMethodName(clazz);
428             String JavaDoc newMethodName = referencedMember.getName(elementValue.referencedClass);
429
430             if (!methodName.equals(newMethodName))
431             {
432                 // Update the element name index.
433
elementValue.u2elementNameIndex =
434                     constantPoolEditor.addUtf8Constant((ProgramClass)clazz,
435                                                        newMethodName);
436             }
437         }
438     }
439
440
441     private void debug(Clazz clazz,
442                        StringConstant stringConstant,
443                        Clazz referencedClass,
444                        Member referencedMember)
445     {
446         System.out.println("MemberReferenceFixer:");
447         System.out.println(" Class file = "+clazz.getName());
448         System.out.println(" Ref class = "+referencedClass.getName());
449         System.out.println(" Ref member name = "+stringConstant.getString(clazz));
450         System.out.println(" -> "+referencedMember.getName(referencedClass));
451     }
452
453
454     private void debug(Clazz clazz,
455                        RefConstant refConstant,
456                        Clazz referencedClass,
457                        Member referencedMember)
458     {
459         System.out.println("MemberReferenceFixer:");
460         System.out.println(" Class file = "+clazz.getName());
461         System.out.println(" Ref class = "+referencedClass.getName());
462         System.out.println(" Ref member name = "+refConstant.getName(clazz));
463         System.out.println(" -> "+referencedMember.getName(referencedClass));
464         System.out.println(" Ref descriptor = "+refConstant.getType(clazz));
465         System.out.println(" -> "+referencedMember.getDescriptor(referencedClass));
466     }
467 }
468
Popular Tags