Home | History | Annotate | Download | only in classfile
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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.visitor.AttributeVisitor;
     24 import proguard.classfile.constant.visitor.ConstantVisitor;
     25 import proguard.classfile.util.*;
     26 import proguard.classfile.visitor.*;
     27 
     28 /**
     29  * This Clazz is a compact representation of the essential data in a Java class.
     30  *
     31  * @author Eric Lafortune
     32  */
     33 public class LibraryClass implements Clazz
     34 {
     35     public int             u2accessFlags;
     36     public String          thisClassName;
     37     public String          superClassName;
     38     public String[]        interfaceNames;
     39     public LibraryField[]  fields;
     40     public LibraryMethod[] methods;
     41 
     42     /**
     43      * An extra field pointing to the superclass of this class.
     44      * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
     45      */
     46     public Clazz   superClass;
     47 
     48     /**
     49      * An extra field pointing to the interfaces of this class.
     50      * This field is filled out by the {@link ClassSuperHierarchyInitializer}.
     51      */
     52     public Clazz[] interfaceClasses;
     53 
     54     /**
     55      * An extra field pointing to the subclasses of this class.
     56      * This field is filled out by the {@link ClassSubHierarchyInitializer}.
     57      */
     58     public Clazz[] subClasses;
     59 
     60     /**
     61      * An extra field in which visitors can store information.
     62      */
     63     public Object visitorInfo;
     64 
     65 
     66     /**
     67      * Creates an empty LibraryClass.
     68      */
     69     public LibraryClass() {}
     70 
     71 
     72     /**
     73      * Returns whether this library class is visible to the outside world.
     74      */
     75     boolean isVisible()
     76     {
     77         return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0;
     78     }
     79 
     80 
     81     // Implementations for Clazz.
     82 
     83     public int getAccessFlags()
     84     {
     85         return u2accessFlags;
     86     }
     87 
     88     public String getName()
     89     {
     90         return thisClassName;
     91     }
     92 
     93     public String getSuperName()
     94     {
     95         // This may be java/lang/Object, in which case there is no super.
     96         return superClassName;
     97     }
     98 
     99     public int getInterfaceCount()
    100     {
    101         return interfaceClasses.length;
    102     }
    103 
    104     public String getInterfaceName(int index)
    105     {
    106         return interfaceNames[index];
    107     }
    108 
    109     public int getTag(int constantIndex)
    110     {
    111         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    112     }
    113 
    114     public String getString(int constantIndex)
    115     {
    116         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    117     }
    118 
    119     public String getStringString(int constantIndex)
    120     {
    121         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    122     }
    123 
    124     public String getClassName(int constantIndex)
    125     {
    126         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    127     }
    128 
    129     public String getName(int constantIndex)
    130     {
    131         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    132     }
    133 
    134     public String getType(int constantIndex)
    135     {
    136         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    137     }
    138 
    139 
    140     public void addSubClass(Clazz clazz)
    141     {
    142         if (subClasses == null)
    143         {
    144             subClasses = new Clazz[1];
    145         }
    146         else
    147         {
    148             // Copy the old elements into new larger array.
    149             Clazz[] temp     = new Clazz[subClasses.length+1];
    150             System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
    151             subClasses = temp;
    152         }
    153 
    154         subClasses[subClasses.length-1] = clazz;
    155     }
    156 
    157 
    158     public Clazz getSuperClass()
    159     {
    160         return superClass;
    161     }
    162 
    163 
    164     public Clazz getInterface(int index)
    165     {
    166         return interfaceClasses[index];
    167     }
    168 
    169 
    170     public boolean extends_(Clazz clazz)
    171     {
    172         if (this.equals(clazz))
    173         {
    174             return true;
    175         }
    176 
    177         return superClass != null &&
    178                superClass.extends_(clazz);
    179     }
    180 
    181 
    182     public boolean extendsOrImplements(Clazz clazz)
    183     {
    184         if (this.equals(clazz))
    185         {
    186             return true;
    187         }
    188 
    189         if (superClass != null &&
    190             superClass.extendsOrImplements(clazz))
    191         {
    192             return true;
    193         }
    194 
    195         if (interfaceClasses != null)
    196         {
    197             for (int index = 0; index < interfaceClasses.length; index++)
    198             {
    199                 Clazz interfaceClass = interfaceClasses[index];
    200                 if (interfaceClass != null &&
    201                     interfaceClass.extendsOrImplements(clazz))
    202                 {
    203                     return true;
    204                 }
    205             }
    206         }
    207 
    208         return false;
    209     }
    210 
    211 
    212     public Field findField(String name, String descriptor)
    213     {
    214         for (int index = 0; index < fields.length; index++)
    215         {
    216             Field field = fields[index];
    217             if (field != null &&
    218                 (name       == null || field.getName(this).equals(name)) &&
    219                 (descriptor == null || field.getDescriptor(this).equals(descriptor)))
    220             {
    221                 return field;
    222             }
    223         }
    224 
    225         return null;
    226     }
    227 
    228 
    229     public Method findMethod(String name, String descriptor)
    230     {
    231         for (int index = 0; index < methods.length; index++)
    232         {
    233             Method method = methods[index];
    234             if (method != null &&
    235                 (name       == null || method.getName(this).equals(name)) &&
    236                 (descriptor == null || method.getDescriptor(this).equals(descriptor)))
    237             {
    238                 return method;
    239             }
    240         }
    241 
    242         return null;
    243     }
    244 
    245 
    246     public void accept(ClassVisitor classVisitor)
    247     {
    248         classVisitor.visitLibraryClass(this);
    249     }
    250 
    251 
    252     public void hierarchyAccept(boolean      visitThisClass,
    253                                 boolean      visitSuperClass,
    254                                 boolean      visitInterfaces,
    255                                 boolean      visitSubclasses,
    256                                 ClassVisitor classVisitor)
    257     {
    258         // First visit the current classfile.
    259         if (visitThisClass)
    260         {
    261             accept(classVisitor);
    262         }
    263 
    264         // Then visit its superclass, recursively.
    265         if (visitSuperClass)
    266         {
    267             if (superClass != null)
    268             {
    269                 superClass.hierarchyAccept(true,
    270                                            true,
    271                                            visitInterfaces,
    272                                            false,
    273                                            classVisitor);
    274             }
    275         }
    276 
    277         // Then visit its interfaces, recursively.
    278         if (visitInterfaces)
    279         {
    280             // Visit the interfaces of the superclasses, if we haven't done so yet.
    281             if (!visitSuperClass)
    282             {
    283                 if (superClass != null)
    284                 {
    285                     superClass.hierarchyAccept(false,
    286                                                false,
    287                                                true,
    288                                                false,
    289                                                classVisitor);
    290                 }
    291             }
    292 
    293             // Visit the interfaces.
    294             if (interfaceClasses != null)
    295             {
    296                 for (int index = 0; index < interfaceClasses.length; index++)
    297                 {
    298                     Clazz interfaceClass = interfaceClasses[index];
    299                     if (interfaceClass != null)
    300                     {
    301                         interfaceClass.hierarchyAccept(true,
    302                                                        false,
    303                                                        true,
    304                                                        false,
    305                                                        classVisitor);
    306                     }
    307                 }
    308             }
    309         }
    310 
    311         // Then visit its subclasses, recursively.
    312         if (visitSubclasses)
    313         {
    314             if (subClasses != null)
    315             {
    316                 for (int index = 0; index < subClasses.length; index++)
    317                 {
    318                     subClasses[index].hierarchyAccept(true,
    319                                                       false,
    320                                                       false,
    321                                                       true,
    322                                                       classVisitor);
    323                 }
    324             }
    325         }
    326     }
    327 
    328 
    329     /**
    330      * Lets the given class visitor visit the superclass, if it is known.
    331      * @param classVisitor the <code>ClassVisitor</code> that will visit the
    332      *                     superclass.
    333      */
    334     public void superClassAccept(ClassVisitor classVisitor)
    335     {
    336         if (superClass != null)
    337         {
    338             superClass.accept(classVisitor);
    339         }
    340     }
    341 
    342 
    343     /**
    344      * Lets the given class visitor visit all known direct interfaces.
    345      * @param classVisitor the <code>ClassVisitor</code> that will visit the
    346      *                     interfaces.
    347      */
    348     public void interfacesAccept(ClassVisitor classVisitor)
    349     {
    350         if (interfaceClasses != null)
    351         {
    352             for (int index = 0; index < interfaceClasses.length; index++)
    353             {
    354                 Clazz interfaceClass = interfaceClasses[index];
    355                 if (interfaceClass != null)
    356                 {
    357                     interfaceClass.accept(classVisitor);
    358                 }
    359             }
    360         }
    361     }
    362 
    363 
    364     public void subclassesAccept(ClassVisitor classVisitor)
    365     {
    366         if (subClasses != null)
    367         {
    368             for (int index = 0; index < subClasses.length; index++)
    369             {
    370                 subClasses[index].accept(classVisitor);
    371             }
    372         }
    373     }
    374 
    375 
    376     public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
    377     {
    378         // This class doesn't keep references to its constant pool entries.
    379     }
    380 
    381 
    382     public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
    383     {
    384         // This class doesn't keep references to its constant pool entries.
    385     }
    386 
    387 
    388     public void thisClassConstantAccept(ConstantVisitor constantVisitor)
    389     {
    390         // This class doesn't keep references to its constant pool entries.
    391     }
    392 
    393 
    394     public void superClassConstantAccept(ConstantVisitor constantVisitor)
    395     {
    396         // This class doesn't keep references to its constant pool entries.
    397     }
    398 
    399 
    400     public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
    401     {
    402         // This class doesn't keep references to its constant pool entries.
    403     }
    404 
    405 
    406     public void fieldsAccept(MemberVisitor memberVisitor)
    407     {
    408         for (int index = 0; index < fields.length; index++)
    409         {
    410             Field field = fields[index];
    411             if (field != null)
    412             {
    413                 field.accept(this, memberVisitor);
    414             }
    415         }
    416     }
    417 
    418 
    419     public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
    420     {
    421         Field field = findField(name, descriptor);
    422         if (field != null)
    423         {
    424             field.accept(this, memberVisitor);
    425         }
    426     }
    427 
    428 
    429     public void methodsAccept(MemberVisitor memberVisitor)
    430     {
    431         for (int index = 0; index < methods.length; index++)
    432         {
    433             Method method = methods[index];
    434             if (method != null)
    435             {
    436                 method.accept(this, memberVisitor);
    437             }
    438         }
    439     }
    440 
    441 
    442     public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
    443     {
    444         Method method = findMethod(name, descriptor);
    445         if (method != null)
    446         {
    447             method.accept(this, memberVisitor);
    448         }
    449     }
    450 
    451 
    452     public boolean mayHaveImplementations(Method method)
    453     {
    454         return
    455            (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
    456            (method == null ||
    457             ((method.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
    458                                          ClassConstants.INTERNAL_ACC_STATIC  |
    459                                          ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
    460                                                                                   !method.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
    461     }
    462 
    463 
    464     public void attributesAccept(AttributeVisitor attributeVisitor)
    465     {
    466         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
    467     }
    468 
    469 
    470     // Implementations for VisitorAccepter.
    471 
    472     public Object getVisitorInfo()
    473     {
    474         return visitorInfo;
    475     }
    476 
    477     public void setVisitorInfo(Object visitorInfo)
    478     {
    479         this.visitorInfo = visitorInfo;
    480     }
    481 
    482 
    483     // Implementations for Object.
    484 
    485     public String toString()
    486     {
    487         return "LibraryClass("+getName()+")";
    488     }
    489 }
    490