KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > ClassSpecificationVisitorFactory


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2003 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;
22
23 import proguard.classfile.attribute.annotation.visitor.*;
24 import proguard.classfile.attribute.annotation.visitor.AnnotatedClassVisitor;
25 import proguard.classfile.attribute.visitor.AllAttributeVisitor;
26 import proguard.classfile.visitor.*;
27
28 import java.util.*;
29
30 /**
31  * This factory creates visitors to efficiently travel to specified classes and
32  * class members.
33  *
34  * @author Eric Lafortune
35  */

36 public class ClassSpecificationVisitorFactory
37 {
38     /**
39      * Constructs a ClassPoolVisitor to efficiently travel to the specified
40      * classes and class members.
41      *
42      * @param keepSpecifications the list of KeepSpecification instances,
43      * defining of the classes and class members to
44      * visit.
45      * @param classVisitor the ClassVisitor to be applied to matching
46      * classes.
47      * @param memberVisitor the MemberVisitor to be applied to matching
48      * class members.
49      */

50     public static ClassPoolVisitor createClassPoolVisitor(List keepSpecifications,
51                                                           ClassVisitor classVisitor,
52                                                           MemberVisitor memberVisitor,
53                                                           boolean shrinking,
54                                                           boolean optimizing,
55                                                           boolean obfuscating)
56     {
57         MultiClassPoolVisitor multiClassPoolVisitor = new MultiClassPoolVisitor();
58
59         if (keepSpecifications != null)
60         {
61             for (int index = 0; index < keepSpecifications.size(); index++)
62             {
63                 KeepSpecification keepSpecification =
64                     (KeepSpecification)keepSpecifications.get(index);
65
66                 if ((shrinking && !keepSpecification.allowShrinking) ||
67                     (optimizing && !keepSpecification.allowOptimization) ||
68                     (obfuscating && !keepSpecification.allowObfuscation))
69                 {
70                     multiClassPoolVisitor.addClassPoolVisitor(
71                         createClassPoolVisitor(keepSpecification,
72                                                classVisitor,
73                                                memberVisitor));
74                 }
75             }
76         }
77
78         return multiClassPoolVisitor;
79     }
80
81
82     /**
83      * Constructs a ClassPoolVisitor to efficiently travel to the specified
84      * classes and class members.
85      *
86      * @param classSpecifications the list of ClassSpecification instances,
87      * defining of the classes and class members to
88      * visit.
89      * @param classVisitor the ClassVisitor to be applied to matching
90      * classes.
91      * @param memberVisitor the MemberVisitor to be applied to matching
92      * class members.
93      */

94     public static ClassPoolVisitor createClassPoolVisitor(List classSpecifications,
95                                                           ClassVisitor classVisitor,
96                                                           MemberVisitor memberVisitor)
97     {
98         MultiClassPoolVisitor multiClassPoolVisitor = new MultiClassPoolVisitor();
99
100         if (classSpecifications != null)
101         {
102             for (int index = 0; index < classSpecifications.size(); index++)
103             {
104                 ClassSpecification classSpecification =
105                     (ClassSpecification)classSpecifications.get(index);
106
107                 multiClassPoolVisitor.addClassPoolVisitor(
108                     createClassPoolVisitor(classSpecification,
109                                            classVisitor,
110                                            memberVisitor));
111             }
112         }
113
114         return multiClassPoolVisitor;
115     }
116
117
118     /**
119      * Constructs a ClassPoolVisitor to efficiently travel to the specified
120      * classes and class members.
121      *
122      * @param keepSpecification the specifications of the class(es) and class
123      * members to visit.
124      * @param classVisitor the ClassVisitor to be applied to matching
125      * classes.
126      * @param memberVisitor the MemberVisitor to be applied to matching
127      * class members.
128      */

129     private static ClassPoolVisitor createClassPoolVisitor(KeepSpecification keepSpecification,
130                                                            ClassVisitor classVisitor,
131                                                            MemberVisitor memberVisitor)
132     {
133         // Don't visit the classes if not specified.
134
if (!keepSpecification.markClasses &&
135             !keepSpecification.markConditionally)
136         {
137             classVisitor = null;
138         }
139
140         // If specified, let the marker visit the class and its class
141
// members conditionally.
142
if (keepSpecification.markConditionally)
143         {
144             // Combine both visitors.
145
ClassVisitor composedClassVisitor =
146                 createCombinedClassVisitor(keepSpecification,
147                                            classVisitor,
148                                            memberVisitor);
149
150             // Replace the class visitor.
151
classVisitor =
152                 createClassMemberTester(keepSpecification,
153                                         composedClassVisitor);
154
155             // Discard the member visitor, because it has already been included.
156
memberVisitor = null;
157         }
158
159         return createClassPoolVisitor((ClassSpecification)keepSpecification,
160                                       classVisitor,
161                                       memberVisitor);
162     }
163
164
165     /**
166      * Constructs a ClassPoolVisitor to efficiently travel to the specified
167      * classes and class members.
168      *
169      * @param classSpecification the specifications of the class(es) and class
170      * members to visit.
171      * @param classVisitor the ClassVisitor to be applied to matching
172      * classes.
173      * @param memberVisitor the MemberVisitor to be applied to matching
174      * class members.
175      */

176     private static ClassPoolVisitor createClassPoolVisitor(ClassSpecification classSpecification,
177                                                            ClassVisitor classVisitor,
178                                                            MemberVisitor memberVisitor)
179     {
180         // Combine both visitors.
181
ClassVisitor composedClassVisitor =
182             createCombinedClassVisitor(classSpecification,
183                                        classVisitor,
184                                        memberVisitor);
185
186         // By default, start visiting from the named class name, if specified.
187
String JavaDoc className = classSpecification.className;
188
189         // Although we may have to start from the extended class.
190
String JavaDoc extendsAnnotationType = classSpecification.extendsAnnotationType;
191         String JavaDoc extendsClassName = classSpecification.extendsClassName;
192
193         // If wildcarded, only visit classes with matching names.
194
if (className != null &&
195             (extendsAnnotationType != null ||
196              extendsClassName != null ||
197              containsWildCards(className)))
198         {
199             composedClassVisitor =
200                 new ClassNameFilter(className, composedClassVisitor);
201
202             // We'll have to visit all classes now.
203
className = null;
204         }
205
206         // If specified, only visit classes with the right annotation.
207
String JavaDoc annotationType = classSpecification.annotationType;
208
209         if (annotationType != null)
210         {
211             composedClassVisitor =
212                 new AllAttributeVisitor(
213                 new AllAnnotationVisitor(
214                 new AnnotationTypeFilter(annotationType,
215                 new AnnotatedClassVisitor(composedClassVisitor))));
216         }
217
218         // If specified, only visit classes with the right access flags.
219
if (classSpecification.requiredSetAccessFlags != 0 ||
220             classSpecification.requiredUnsetAccessFlags != 0)
221         {
222             composedClassVisitor =
223                 new ClassAccessFilter(classSpecification.requiredSetAccessFlags,
224                                       classSpecification.requiredUnsetAccessFlags,
225                                       composedClassVisitor);
226         }
227
228         // If it's specified, start visiting from the extended class.
229
if (extendsAnnotationType != null ||
230             extendsClassName != null)
231         {
232             // Start visiting from the extended class.
233
composedClassVisitor =
234                 new ClassHierarchyTraveler(false, false, false, true,
235                                            composedClassVisitor);
236
237             // If specified, only visit extended classes with the right annotation.
238
if (extendsAnnotationType != null)
239             {
240                 composedClassVisitor =
241                     new AllAttributeVisitor(
242                     new AllAnnotationVisitor(
243                     new AnnotationTypeFilter(extendsAnnotationType,
244                     new AnnotatedClassVisitor(composedClassVisitor))));
245             }
246
247             // If specified, only visit extended classes with matching names.
248
if (extendsClassName != null)
249             {
250                 // If wildcarded, only visit extended classes with matching names.
251
if (containsWildCards(extendsClassName))
252                 {
253                     composedClassVisitor =
254                         new ClassNameFilter(extendsClassName,
255                                             composedClassVisitor);
256                 }
257                 else
258                 {
259                     // Start visiting from the named extended class.
260
className = extendsClassName;
261                 }
262             }
263         }
264
265         // If specified, visit a single named class, otherwise visit all classes.
266
return className != null ?
267             (ClassPoolVisitor)new NamedClassVisitor(composedClassVisitor, className) :
268             (ClassPoolVisitor)new AllClassVisitor(composedClassVisitor);
269     }
270
271
272     /**
273      * Constructs a ClassVisitor to efficiently travel to the specified
274      * classes and class members.
275      *
276      * @param classSpecification the specifications of the class(es) and class
277      * members to visit.
278      * @param classVisitor the ClassVisitor to be applied to matching
279      * classes.
280      * @param memberVisitor the MemberVisitor to be applied to matching
281      * class members.
282      */

283     private static ClassVisitor createCombinedClassVisitor(ClassSpecification classSpecification,
284                                                            ClassVisitor classVisitor,
285                                                            MemberVisitor memberVisitor)
286     {
287         // Don't visit any members if there aren't any member specifications.
288
if (classSpecification.fieldSpecifications == null &&
289             classSpecification.methodSpecifications == null)
290         {
291             memberVisitor = null;
292         }
293
294         // The class visitor for classes and their members.
295
MultiClassVisitor multiClassVisitor = new MultiClassVisitor();
296
297         // If specified, let the class visitor visit the class itself.
298
if (classVisitor != null)
299         {
300             // This class visitor may be the only one.
301
if (memberVisitor == null)
302             {
303                 return classVisitor;
304             }
305
306             multiClassVisitor.addClassVisitor(classVisitor);
307         }
308
309         // If specified, let the member info visitor visit the class members.
310
if (memberVisitor != null)
311         {
312             ClassVisitor memberClassVisitor =
313                 createClassVisitor(classSpecification, memberVisitor);
314
315             // This class visitor may be the only one.
316
if (classVisitor == null)
317             {
318                 return memberClassVisitor;
319             }
320
321             multiClassVisitor.addClassVisitor(memberClassVisitor);
322         }
323
324         return multiClassVisitor;
325     }
326
327
328     /**
329      * Constructs a ClassVisitor to efficiently travel to the specified class
330      * members.
331      *
332      * @param classSpecification the specifications of the class members to visit.
333      * @param memberVisitor the MemberVisitor to be applied to matching
334      * class members.
335      */

336     private static ClassVisitor createClassVisitor(ClassSpecification classSpecification,
337                                                    MemberVisitor memberVisitor)
338     {
339         MultiClassVisitor multiClassVisitor = new MultiClassVisitor();
340
341         addMemberVisitors(classSpecification.fieldSpecifications, true, multiClassVisitor, memberVisitor);
342         addMemberVisitors(classSpecification.methodSpecifications, false, multiClassVisitor, memberVisitor);
343
344         // Mark the class member in this class and in super classes.
345
return new ClassHierarchyTraveler(true, true, false, false,
346                                           multiClassVisitor);
347     }
348
349
350     /**
351      * Adds elements to the given MultiClassVisitor, to apply the given
352      * MemberVisitor to all class members that match the given List
353      * of options (of the given type).
354      */

355     private static void addMemberVisitors(List memberSpecifications,
356                                           boolean isField,
357                                           MultiClassVisitor multiClassVisitor,
358                                           MemberVisitor memberVisitor)
359     {
360         if (memberSpecifications != null)
361         {
362             for (int index = 0; index < memberSpecifications.size(); index++)
363             {
364                 MemberSpecification memberSpecification =
365                     (MemberSpecification)memberSpecifications.get(index);
366
367                 multiClassVisitor.addClassVisitor(
368                     createClassVisitor(memberSpecification,
369                                        isField,
370                                        memberVisitor));
371             }
372         }
373     }
374
375
376     /**
377      * Constructs a ClassVisitor that conditionally applies the given
378      * ClassVisitor to all classes that contain the given class members.
379      */

380     private static ClassVisitor createClassMemberTester(ClassSpecification classSpecification,
381                                                         ClassVisitor classVisitor)
382     {
383         // Create a linked list of conditional visitors, for fields and for
384
// methods.
385
return createClassMemberTester(classSpecification.fieldSpecifications,
386                                        true,
387                createClassMemberTester(classSpecification.methodSpecifications,
388                                        false,
389                                        classVisitor));
390     }
391
392
393     /**
394      * Constructs a ClassVisitor that conditionally applies the given
395      * ClassVisitor to all classes that contain the given List of class
396      * members (of the given type).
397      */

398     private static ClassVisitor createClassMemberTester(List memberSpecifications,
399                                                         boolean isField,
400                                                         ClassVisitor classVisitor)
401     {
402         // Create a linked list of conditional visitors.
403
if (memberSpecifications != null)
404         {
405             for (int index = 0; index < memberSpecifications.size(); index++)
406             {
407                 MemberSpecification memberSpecification =
408                     (MemberSpecification)memberSpecifications.get(index);
409
410                 classVisitor =
411                     createClassVisitor(memberSpecification,
412                                        isField,
413                                        new MemberToClassVisitor(classVisitor));
414             }
415         }
416
417         return classVisitor;
418     }
419
420
421     /**
422      * Creates a new ClassVisitor to efficiently travel to the specified class
423      * members.
424      *
425      * @param memberSpecification the specification of the class member(s) to
426      * visit.
427      * @param memberVisitor the MemberVisitor to be applied to matching
428      * class member(s).
429      */

430     private static ClassVisitor createClassVisitor(MemberSpecification memberSpecification,
431                                                    boolean isField,
432                                                    MemberVisitor memberVisitor)
433     {
434         String JavaDoc name = memberSpecification.name;
435         String JavaDoc descriptor = memberSpecification.descriptor;
436
437         // If name or descriptor are not fully specified, only visit matching
438
// class members.
439
boolean fullySpecified =
440             name != null &&
441             descriptor != null &&
442             !containsWildCards(name) &&
443             !containsWildCards(descriptor);
444
445         if (!fullySpecified)
446         {
447             if (descriptor != null)
448             {
449                 memberVisitor =
450                     new MemberDescriptorFilter(descriptor, memberVisitor);
451             }
452
453             if (name != null)
454             {
455                 memberVisitor =
456                     new MemberNameFilter(name, memberVisitor);
457             }
458         }
459
460         // If specified, only visit class members with the right annotation.
461
if (memberSpecification.annotationType != null)
462         {
463             memberVisitor =
464                 new AllAttributeVisitor(
465                 new AllAnnotationVisitor(
466                 new AnnotationTypeFilter(memberSpecification.annotationType,
467                 new AnnotationToMemberVisitor(memberVisitor))));
468         }
469
470         // If any access flags are specified, only visit matching class members.
471
if (memberSpecification.requiredSetAccessFlags != 0 ||
472             memberSpecification.requiredUnsetAccessFlags != 0)
473         {
474             memberVisitor =
475                 new MemberAccessFilter(memberSpecification.requiredSetAccessFlags,
476                                        memberSpecification.requiredUnsetAccessFlags,
477                                        memberVisitor);
478         }
479
480         // Depending on what's specified, visit a single named class member,
481
// or all class members, filtering the matching ones.
482
return isField ?
483             fullySpecified ?
484                 (ClassVisitor)new NamedFieldVisitor(name, descriptor, memberVisitor) :
485                 (ClassVisitor)new AllFieldVisitor(memberVisitor) :
486             fullySpecified ?
487                 (ClassVisitor)new NamedMethodVisitor(name, descriptor, memberVisitor) :
488                 (ClassVisitor)new AllMethodVisitor(memberVisitor);
489     }
490
491
492     // Small utility methods.
493

494     private static boolean containsWildCards(String JavaDoc string)
495     {
496         return string != null &&
497             (string.indexOf('*') >= 0 ||
498              string.indexOf('?') >= 0 ||
499              string.indexOf('%') >= 0 ||
500              string.indexOf(',') >= 0);
501     }
502 }
503
Popular Tags