Home | History | Annotate | Download | only in classfile
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 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.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 String getRefClassName(int constantIndex)
    141     {
    142         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    143     }
    144 
    145     public String getRefName(int constantIndex)
    146     {
    147         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    148     }
    149 
    150     public String getRefType(int constantIndex)
    151     {
    152         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store constant pool");
    153     }
    154 
    155 
    156     public void addSubClass(Clazz clazz)
    157     {
    158         if (subClasses == null)
    159         {
    160             subClasses = new Clazz[1];
    161         }
    162         else
    163         {
    164             // Copy the old elements into new larger array.
    165             Clazz[] temp     = new Clazz[subClasses.length+1];
    166             System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
    167             subClasses = temp;
    168         }
    169 
    170         subClasses[subClasses.length-1] = clazz;
    171     }
    172 
    173 
    174     public Clazz getSuperClass()
    175     {
    176         return superClass;
    177     }
    178 
    179 
    180     public Clazz getInterface(int index)
    181     {
    182         return interfaceClasses[index];
    183     }
    184 
    185 
    186     public boolean extends_(Clazz clazz)
    187     {
    188         if (this.equals(clazz))
    189         {
    190             return true;
    191         }
    192 
    193         return superClass != null &&
    194                superClass.extends_(clazz);
    195     }
    196 
    197 
    198     public boolean extends_(String className)
    199     {
    200         if (getName().equals(className))
    201         {
    202             return true;
    203         }
    204 
    205         return superClass != null &&
    206                superClass.extends_(className);
    207     }
    208 
    209 
    210     public boolean extendsOrImplements(Clazz clazz)
    211     {
    212         if (this.equals(clazz))
    213         {
    214             return true;
    215         }
    216 
    217         if (superClass != null &&
    218             superClass.extendsOrImplements(clazz))
    219         {
    220             return true;
    221         }
    222 
    223         if (interfaceClasses != null)
    224         {
    225             for (int index = 0; index < interfaceClasses.length; index++)
    226             {
    227                 Clazz interfaceClass = interfaceClasses[index];
    228                 if (interfaceClass != null &&
    229                     interfaceClass.extendsOrImplements(clazz))
    230                 {
    231                     return true;
    232                 }
    233             }
    234         }
    235 
    236         return false;
    237     }
    238 
    239 
    240     public boolean extendsOrImplements(String className)
    241     {
    242         if (getName().equals(className))
    243         {
    244             return true;
    245         }
    246 
    247         if (superClass != null &&
    248             superClass.extendsOrImplements(className))
    249         {
    250             return true;
    251         }
    252 
    253         if (interfaceClasses != null)
    254         {
    255             for (int index = 0; index < interfaceClasses.length; index++)
    256             {
    257                 Clazz interfaceClass = interfaceClasses[index];
    258                 if (interfaceClass != null &&
    259                     interfaceClass.extendsOrImplements(className))
    260                 {
    261                     return true;
    262                 }
    263             }
    264         }
    265 
    266         return false;
    267     }
    268 
    269 
    270     public Field findField(String name, String descriptor)
    271     {
    272         for (int index = 0; index < fields.length; index++)
    273         {
    274             Field field = fields[index];
    275             if (field != null &&
    276                 (name       == null || field.getName(this).equals(name)) &&
    277                 (descriptor == null || field.getDescriptor(this).equals(descriptor)))
    278             {
    279                 return field;
    280             }
    281         }
    282 
    283         return null;
    284     }
    285 
    286 
    287     public Method findMethod(String name, String descriptor)
    288     {
    289         for (int index = 0; index < methods.length; index++)
    290         {
    291             Method method = methods[index];
    292             if (method != null &&
    293                 (name       == null || method.getName(this).equals(name)) &&
    294                 (descriptor == null || method.getDescriptor(this).equals(descriptor)))
    295             {
    296                 return method;
    297             }
    298         }
    299 
    300         return null;
    301     }
    302 
    303 
    304     public void accept(ClassVisitor classVisitor)
    305     {
    306         classVisitor.visitLibraryClass(this);
    307     }
    308 
    309 
    310     public void hierarchyAccept(boolean      visitThisClass,
    311                                 boolean      visitSuperClass,
    312                                 boolean      visitInterfaces,
    313                                 boolean      visitSubclasses,
    314                                 ClassVisitor classVisitor)
    315     {
    316         // First visit the current classfile.
    317         if (visitThisClass)
    318         {
    319             accept(classVisitor);
    320         }
    321 
    322         // Then visit its superclass, recursively.
    323         if (visitSuperClass)
    324         {
    325             if (superClass != null)
    326             {
    327                 superClass.hierarchyAccept(true,
    328                                            true,
    329                                            visitInterfaces,
    330                                            false,
    331                                            classVisitor);
    332             }
    333         }
    334 
    335         // Then visit its interfaces, recursively.
    336         if (visitInterfaces)
    337         {
    338             // Visit the interfaces of the superclasses, if we haven't done so yet.
    339             if (!visitSuperClass)
    340             {
    341                 if (superClass != null)
    342                 {
    343                     superClass.hierarchyAccept(false,
    344                                                false,
    345                                                true,
    346                                                false,
    347                                                classVisitor);
    348                 }
    349             }
    350 
    351             // Visit the interfaces.
    352             if (interfaceClasses != null)
    353             {
    354                 for (int index = 0; index < interfaceClasses.length; index++)
    355                 {
    356                     Clazz interfaceClass = interfaceClasses[index];
    357                     if (interfaceClass != null)
    358                     {
    359                         interfaceClass.hierarchyAccept(true,
    360                                                        false,
    361                                                        true,
    362                                                        false,
    363                                                        classVisitor);
    364                     }
    365                 }
    366             }
    367         }
    368 
    369         // Then visit its subclasses, recursively.
    370         if (visitSubclasses)
    371         {
    372             if (subClasses != null)
    373             {
    374                 for (int index = 0; index < subClasses.length; index++)
    375                 {
    376                     subClasses[index].hierarchyAccept(true,
    377                                                       false,
    378                                                       false,
    379                                                       true,
    380                                                       classVisitor);
    381                 }
    382             }
    383         }
    384     }
    385 
    386 
    387     /**
    388      * Lets the given class visitor visit the superclass, if it is known.
    389      * @param classVisitor the <code>ClassVisitor</code> that will visit the
    390      *                     superclass.
    391      */
    392     public void superClassAccept(ClassVisitor classVisitor)
    393     {
    394         if (superClass != null)
    395         {
    396             superClass.accept(classVisitor);
    397         }
    398     }
    399 
    400 
    401     /**
    402      * Lets the given class visitor visit all known direct interfaces.
    403      * @param classVisitor the <code>ClassVisitor</code> that will visit the
    404      *                     interfaces.
    405      */
    406     public void interfacesAccept(ClassVisitor classVisitor)
    407     {
    408         if (interfaceClasses != null)
    409         {
    410             for (int index = 0; index < interfaceClasses.length; index++)
    411             {
    412                 Clazz interfaceClass = interfaceClasses[index];
    413                 if (interfaceClass != null)
    414                 {
    415                     interfaceClass.accept(classVisitor);
    416                 }
    417             }
    418         }
    419     }
    420 
    421 
    422     public void subclassesAccept(ClassVisitor classVisitor)
    423     {
    424         if (subClasses != null)
    425         {
    426             for (int index = 0; index < subClasses.length; index++)
    427             {
    428                 subClasses[index].accept(classVisitor);
    429             }
    430         }
    431     }
    432 
    433 
    434     public void constantPoolEntriesAccept(ConstantVisitor constantVisitor)
    435     {
    436         // This class doesn't keep references to its constant pool entries.
    437     }
    438 
    439 
    440     public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
    441     {
    442         // This class doesn't keep references to its constant pool entries.
    443     }
    444 
    445 
    446     public void thisClassConstantAccept(ConstantVisitor constantVisitor)
    447     {
    448         // This class doesn't keep references to its constant pool entries.
    449     }
    450 
    451 
    452     public void superClassConstantAccept(ConstantVisitor constantVisitor)
    453     {
    454         // This class doesn't keep references to its constant pool entries.
    455     }
    456 
    457 
    458     public void interfaceConstantsAccept(ConstantVisitor constantVisitor)
    459     {
    460         // This class doesn't keep references to its constant pool entries.
    461     }
    462 
    463 
    464     public void fieldsAccept(MemberVisitor memberVisitor)
    465     {
    466         for (int index = 0; index < fields.length; index++)
    467         {
    468             Field field = fields[index];
    469             if (field != null)
    470             {
    471                 field.accept(this, memberVisitor);
    472             }
    473         }
    474     }
    475 
    476 
    477     public void fieldAccept(String name, String descriptor, MemberVisitor memberVisitor)
    478     {
    479         Field field = findField(name, descriptor);
    480         if (field != null)
    481         {
    482             field.accept(this, memberVisitor);
    483         }
    484     }
    485 
    486 
    487     public void methodsAccept(MemberVisitor memberVisitor)
    488     {
    489         for (int index = 0; index < methods.length; index++)
    490         {
    491             Method method = methods[index];
    492             if (method != null)
    493             {
    494                 method.accept(this, memberVisitor);
    495             }
    496         }
    497     }
    498 
    499 
    500     public void methodAccept(String name, String descriptor, MemberVisitor memberVisitor)
    501     {
    502         Method method = findMethod(name, descriptor);
    503         if (method != null)
    504         {
    505             method.accept(this, memberVisitor);
    506         }
    507     }
    508 
    509 
    510     public boolean mayHaveImplementations(Method method)
    511     {
    512         return
    513            (u2accessFlags & ClassConstants.ACC_FINAL) == 0 &&
    514            (method == null ||
    515             ((method.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
    516                                          ClassConstants.ACC_STATIC  |
    517                                          ClassConstants.ACC_FINAL)) == 0 &&
    518              !method.getName(this).equals(ClassConstants.METHOD_NAME_INIT)));
    519     }
    520 
    521 
    522     public void attributesAccept(AttributeVisitor attributeVisitor)
    523     {
    524         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
    525     }
    526 
    527 
    528     public void attributeAccept(String name, AttributeVisitor attributeVisitor)
    529     {
    530         throw new UnsupportedOperationException("Library class ["+thisClassName+"] doesn't store attributes");
    531     }
    532 
    533 
    534     // Implementations for VisitorAccepter.
    535 
    536     public Object getVisitorInfo()
    537     {
    538         return visitorInfo;
    539     }
    540 
    541     public void setVisitorInfo(Object visitorInfo)
    542     {
    543         this.visitorInfo = visitorInfo;
    544     }
    545 
    546 
    547     // Implementations for Object.
    548 
    549     public String toString()
    550     {
    551         return "LibraryClass("+getName()+")";
    552     }
    553 }
    554