• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 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;
22 
23 import proguard.classfile.attribute.Attribute;
24 import proguard.classfile.attribute.visitor.AttributeVisitor;
25 import proguard.classfile.constant.*;
26 import proguard.classfile.constant.visitor.ConstantVisitor;
27 import proguard.classfile.util.ClassSubHierarchyInitializer;
28 import proguard.classfile.visitor.*;
29 
30 /**
31  * This Clazz is a complete representation of the data in a Java class.
32  *
33  * @author Eric Lafortune
34  */
35 public class ProgramClass implements Clazz
36 {
37     public int             u4magic;
38     public int             u4version;
39     public int             u2constantPoolCount;
40     public Constant[]      constantPool;
41     public int             u2accessFlags;
42     public int             u2thisClass;
43     public int             u2superClass;
44     public int             u2interfacesCount;
45     public int[]           u2interfaces;
46     public int             u2fieldsCount;
47     public ProgramField[]  fields;
48     public int             u2methodsCount;
49     public ProgramMethod[] methods;
50     public int             u2attributesCount;
51     public Attribute[]     attributes;
52 
53     /**
54      * An extra field pointing to the subclasses of this class.
55      * This field is filled out by the {@link ClassSubHierarchyInitializer}.
56      */
57     public Clazz[] subClasses;
58 
59     /**
60      * An extra field in which visitors can store information.
61      */
62     public Object visitorInfo;
63 
64 
65     /**
66      * Creates an uninitialized ProgramClass.
67      */
ProgramClass()68     public ProgramClass() {}
69 
70 
71     /**
72      * Returns the Constant at the given index in the constant pool.
73      */
getConstant(int constantIndex)74     public Constant getConstant(int constantIndex)
75     {
76         return constantPool[constantIndex];
77     }
78 
79 
80     // Implementations for Clazz.
81 
getAccessFlags()82     public int getAccessFlags()
83     {
84         return u2accessFlags;
85     }
86 
getName()87     public String getName()
88     {
89         return getClassName(u2thisClass);
90     }
91 
getSuperName()92     public String getSuperName()
93     {
94         return u2superClass == 0 ? null : getClassName(u2superClass);
95     }
96 
getInterfaceCount()97     public int getInterfaceCount()
98     {
99         return u2interfacesCount;
100     }
101 
getInterfaceName(int index)102     public String getInterfaceName(int index)
103     {
104         return getClassName(u2interfaces[index]);
105     }
106 
getTag(int constantIndex)107     public int getTag(int constantIndex)
108     {
109         return constantPool[constantIndex].getTag();
110     }
111 
getString(int constantIndex)112     public String getString(int constantIndex)
113     {
114         try
115         {
116             return ((Utf8Constant)constantPool[constantIndex]).getString();
117         }
118         catch (ClassCastException ex)
119         {
120             throw ((IllegalStateException)new IllegalStateException("Expected Utf8Constant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
121         }
122     }
123 
getStringString(int constantIndex)124     public String getStringString(int constantIndex)
125     {
126         try
127         {
128             return ((StringConstant)constantPool[constantIndex]).getString(this);
129         }
130         catch (ClassCastException ex)
131         {
132             throw ((IllegalStateException)new IllegalStateException("Expected StringConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
133         }
134     }
135 
getClassName(int constantIndex)136     public String getClassName(int constantIndex)
137     {
138         try
139         {
140             return ((ClassConstant)constantPool[constantIndex]).getName(this);
141         }
142         catch (ClassCastException ex)
143         {
144             throw ((IllegalStateException)new IllegalStateException("Expected ClassConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
145         }
146     }
147 
getName(int constantIndex)148     public String getName(int constantIndex)
149     {
150         try
151         {
152             return ((NameAndTypeConstant)constantPool[constantIndex]).getName(this);
153         }
154         catch (ClassCastException ex)
155         {
156             throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
157         }
158     }
159 
getType(int constantIndex)160     public String getType(int constantIndex)
161     {
162         try
163         {
164             return ((NameAndTypeConstant)constantPool[constantIndex]).getType(this);
165         }
166         catch (ClassCastException ex)
167         {
168             throw ((IllegalStateException)new IllegalStateException("Expected NameAndTypeConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
169         }
170     }
171 
172 
getRefClassName(int constantIndex)173     public String getRefClassName(int constantIndex)
174     {
175         try
176         {
177             return ((RefConstant)constantPool[constantIndex]).getClassName(this);
178         }
179         catch (ClassCastException ex)
180         {
181             throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
182         }
183     }
184 
getRefName(int constantIndex)185     public String getRefName(int constantIndex)
186     {
187         try
188         {
189             return ((RefConstant)constantPool[constantIndex]).getName(this);
190         }
191         catch (ClassCastException ex)
192         {
193             throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
194         }
195     }
196 
getRefType(int constantIndex)197     public String getRefType(int constantIndex)
198     {
199         try
200         {
201             return ((RefConstant)constantPool[constantIndex]).getType(this);
202         }
203         catch (ClassCastException ex)
204         {
205             throw ((IllegalStateException)new IllegalStateException("Expected RefConstant at index ["+constantIndex+"] in class ["+getName()+"]").initCause(ex));
206         }
207     }
208 
209 
addSubClass(Clazz clazz)210     public void addSubClass(Clazz clazz)
211     {
212         if (subClasses == null)
213         {
214             subClasses = new Clazz[1];
215         }
216         else
217         {
218             // Copy the old elements into new larger array.
219             Clazz[] temp = new Clazz[subClasses.length+1];
220             System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
221             subClasses = temp;
222         }
223 
224         subClasses[subClasses.length-1] = clazz;
225     }
226 
227 
getSuperClass()228     public Clazz getSuperClass()
229     {
230         return u2superClass != 0 ?
231             ((ClassConstant)constantPool[u2superClass]).referencedClass :
232             null;
233     }
234 
235 
getInterface(int index)236     public Clazz getInterface(int index)
237     {
238         return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass;
239     }
240 
241 
extends_(Clazz clazz)242     public boolean extends_(Clazz clazz)
243     {
244         if (this.equals(clazz))
245         {
246             return true;
247         }
248 
249         Clazz superClass = getSuperClass();
250         return superClass != null &&
251                superClass.extends_(clazz);
252     }
253 
254 
extends_(String className)255     public boolean extends_(String className)
256     {
257         if (getName().equals(className))
258         {
259             return true;
260         }
261 
262         Clazz superClass = getSuperClass();
263         return superClass != null &&
264                superClass.extends_(className);
265     }
266 
267 
extendsOrImplements(Clazz clazz)268     public boolean extendsOrImplements(Clazz clazz)
269     {
270         if (this.equals(clazz))
271         {
272             return true;
273         }
274 
275         Clazz superClass = getSuperClass();
276         if (superClass != null &&
277             superClass.extendsOrImplements(clazz))
278         {
279             return true;
280         }
281 
282         for (int index = 0; index < u2interfacesCount; index++)
283         {
284             Clazz interfaceClass = getInterface(index);
285             if (interfaceClass != null &&
286                 interfaceClass.extendsOrImplements(clazz))
287             {
288                 return true;
289             }
290         }
291 
292         return false;
293     }
294 
295 
extendsOrImplements(String className)296     public boolean extendsOrImplements(String className)
297     {
298         if (getName().equals(className))
299         {
300             return true;
301         }
302 
303         Clazz superClass = getSuperClass();
304         if (superClass != null &&
305             superClass.extendsOrImplements(className))
306         {
307             return true;
308         }
309 
310         for (int index = 0; index < u2interfacesCount; index++)
311         {
312             Clazz interfaceClass = getInterface(index);
313             if (interfaceClass != null &&
314                 interfaceClass.extendsOrImplements(className))
315             {
316                 return true;
317             }
318         }
319 
320         return false;
321     }
322 
323 
findField(String name, String descriptor)324     public Field findField(String name, String descriptor)
325     {
326         for (int index = 0; index < u2fieldsCount; index++)
327         {
328             Field field = fields[index];
329             if ((name       == null || field.getName(this).equals(name)) &&
330                 (descriptor == null || field.getDescriptor(this).equals(descriptor)))
331             {
332                 return field;
333             }
334         }
335 
336         return null;
337     }
338 
339 
findMethod(String name, String descriptor)340     public Method findMethod(String name, String descriptor)
341     {
342         for (int index = 0; index < u2methodsCount; index++)
343         {
344             Method method = methods[index];
345             if ((name       == null || method.getName(this).equals(name)) &&
346                 (descriptor == null || method.getDescriptor(this).equals(descriptor)))
347             {
348                 return method;
349             }
350         }
351 
352         return null;
353     }
354 
355 
accept(ClassVisitor classVisitor)356     public void accept(ClassVisitor classVisitor)
357     {
358         classVisitor.visitProgramClass(this);
359     }
360 
361 
hierarchyAccept(boolean visitThisClass, boolean visitSuperClass, boolean visitInterfaces, boolean visitSubclasses, ClassVisitor classVisitor)362     public void hierarchyAccept(boolean      visitThisClass,
363                                 boolean      visitSuperClass,
364                                 boolean      visitInterfaces,
365                                 boolean      visitSubclasses,
366                                 ClassVisitor classVisitor)
367     {
368         // First visit the current classfile.
369         if (visitThisClass)
370         {
371             accept(classVisitor);
372         }
373 
374         // Then visit its superclass, recursively.
375         if (visitSuperClass)
376         {
377             Clazz superClass = getSuperClass();
378             if (superClass != null)
379             {
380                 superClass.hierarchyAccept(true,
381                                            true,
382                                            visitInterfaces,
383                                            false,
384                                            classVisitor);
385             }
386         }
387 
388         // Then visit its interfaces, recursively.
389         if (visitInterfaces)
390         {
391             // Visit the interfaces of the superclasses, if we haven't done so yet.
392             if (!visitSuperClass)
393             {
394                 Clazz superClass = getSuperClass();
395                 if (superClass != null)
396                 {
397                     superClass.hierarchyAccept(false,
398                                                false,
399                                                true,
400                                                false,
401                                                classVisitor);
402                 }
403             }
404 
405             // Visit the interfaces.
406             for (int index = 0; index < u2interfacesCount; index++)
407             {
408                 Clazz interfaceClass = getInterface(index);
409                 if (interfaceClass != null)
410                 {
411                     interfaceClass.hierarchyAccept(true,
412                                                    false,
413                                                    true,
414                                                    false,
415                                                    classVisitor);
416                 }
417             }
418         }
419 
420         // Then visit its subclasses, recursively.
421         if (visitSubclasses)
422         {
423             if (subClasses != null)
424             {
425                 for (int index = 0; index < subClasses.length; index++)
426                 {
427                     Clazz subClass = subClasses[index];
428                     subClass.hierarchyAccept(true,
429                                              false,
430                                              false,
431                                              true,
432                                              classVisitor);
433                 }
434             }
435         }
436     }
437 
438 
subclassesAccept(ClassVisitor classVisitor)439     public void subclassesAccept(ClassVisitor classVisitor)
440     {
441         if (subClasses != null)
442         {
443             for (int index = 0; index < subClasses.length; index++)
444             {
445                 subClasses[index].accept(classVisitor);
446             }
447         }
448     }
449 
450 
constantPoolEntriesAccept(ConstantVisitor constantVisitor)451     public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
452     {
453         for (int index = 1; index < u2constantPoolCount; index++)
454         {
455             if (constantPool[index] != null)
456             {
457                 constantPool[index].accept(this, constantVisitor);
458             }
459         }
460     }
461 
462 
constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)463     public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
464     {
465         constantPool[index].accept(this, constantVisitor);
466     }
467 
468 
thisClassConstantAccept(ConstantVisitor constantVisitor)469     public void thisClassConstantAccept(ConstantVisitor constantVisitor)
470     {
471         constantPool[u2thisClass].accept(this, constantVisitor);
472     }
473 
474 
superClassConstantAccept(ConstantVisitor constantVisitor)475     public void superClassConstantAccept(ConstantVisitor constantVisitor)
476     {
477         if (u2superClass != 0)
478         {
479             constantPool[u2superClass].accept(this, constantVisitor);
480         }
481     }
482 
483 
interfaceConstantsAccept(ConstantVisitor constantVisitor)484     public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
485     {
486         for (int index = 0; index < u2interfacesCount; index++)
487         {
488             constantPool[u2interfaces[index]].accept(this, constantVisitor);
489         }
490     }
491 
492 
fieldsAccept(MemberVisitor memberVisitor)493     public void fieldsAccept(MemberVisitor memberVisitor)
494     {
495         for (int index = 0; index < u2fieldsCount; index++)
496         {
497             fields[index].accept(this, memberVisitor);
498         }
499     }
500 
501 
fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)502     public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
503     {
504         Field field = findField(name, descriptor);
505         if (field != null)
506         {
507             field.accept(this, memberVisitor);
508         }
509     }
510 
511 
methodsAccept(MemberVisitor memberVisitor)512     public void methodsAccept(MemberVisitor memberVisitor)
513     {
514         for (int index = 0; index < u2methodsCount; index++)
515         {
516             methods[index].accept(this, memberVisitor);
517         }
518     }
519 
520 
methodAccept(String name, String descriptor, MemberVisitor memberVisitor)521     public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
522     {
523         Method method = findMethod(name, descriptor);
524         if (method != null)
525         {
526             method.accept(this, memberVisitor);
527         }
528     }
529 
530 
mayHaveImplementations(Method method)531     public boolean mayHaveImplementations(Method method)
532     {
533         return
534             (u2accessFlags & ClassConstants.ACC_FINAL) == 0 &&
535             (method == null ||
536              ((method.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
537                                           ClassConstants.ACC_STATIC  |
538                                           ClassConstants.ACC_FINAL)) == 0 &&
539               !method.getName(this).equals(ClassConstants.METHOD_NAME_INIT)));
540     }
541 
542 
attributesAccept(AttributeVisitor attributeVisitor)543     public void attributesAccept(AttributeVisitor attributeVisitor)
544     {
545         for (int index = 0; index < u2attributesCount; index++)
546         {
547             attributes[index].accept(this, attributeVisitor);
548         }
549     }
550 
551 
attributeAccept(String name, AttributeVisitor attributeVisitor)552     public void attributeAccept(String name, AttributeVisitor attributeVisitor)
553     {
554         for (int index = 0; index < u2attributesCount; index++)
555         {
556             Attribute attribute = attributes[index];
557             if (attribute.getAttributeName(this).equals(name))
558             {
559                 attribute.accept(this, attributeVisitor);
560             }
561         }
562     }
563 
564 
565     // Implementations for VisitorAccepter.
566 
getVisitorInfo()567     public Object getVisitorInfo()
568     {
569         return visitorInfo;
570     }
571 
setVisitorInfo(Object visitorInfo)572     public void setVisitorInfo(Object visitorInfo)
573     {
574         this.visitorInfo = visitorInfo;
575     }
576 
577 
578     // Implementations for Object.
579 
toString()580     public String toString()
581     {
582         return "ProgramClass("+getName()+")";
583     }
584 }
585