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.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      */
     68     public ProgramClass() {}
     69 
     70 
     71     /**
     72      * Returns the Constant at the given index in the constant pool.
     73      */
     74     public Constant getConstant(int constantIndex)
     75     {
     76         return constantPool[constantIndex];
     77     }
     78 
     79 
     80     // Implementations for Clazz.
     81 
     82     public int getAccessFlags()
     83     {
     84         return u2accessFlags;
     85     }
     86 
     87     public String getName()
     88     {
     89         return getClassName(u2thisClass);
     90     }
     91 
     92     public String getSuperName()
     93     {
     94         return u2superClass == 0 ? null : getClassName(u2superClass);
     95     }
     96 
     97     public int getInterfaceCount()
     98     {
     99         return u2interfacesCount;
    100     }
    101 
    102     public String getInterfaceName(int index)
    103     {
    104         return getClassName(u2interfaces[index]);
    105     }
    106 
    107     public int getTag(int constantIndex)
    108     {
    109         return constantPool[constantIndex].getTag();
    110     }
    111 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    228     public Clazz getSuperClass()
    229     {
    230         return u2superClass != 0 ?
    231             ((ClassConstant)constantPool[u2superClass]).referencedClass :
    232             null;
    233     }
    234 
    235 
    236     public Clazz getInterface(int index)
    237     {
    238         return ((ClassConstant)constantPool[u2interfaces[index]]).referencedClass;
    239     }
    240 
    241 
    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 
    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 
    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 
    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 
    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 
    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 
    356     public void accept(ClassVisitor classVisitor)
    357     {
    358         classVisitor.visitProgramClass(this);
    359     }
    360 
    361 
    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 
    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 
    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 
    463     public void constantPoolEntryAccept(int index, ConstantVisitor constantVisitor)
    464     {
    465         constantPool[index].accept(this, constantVisitor);
    466     }
    467 
    468 
    469     public void thisClassConstantAccept(ConstantVisitor constantVisitor)
    470     {
    471         constantPool[u2thisClass].accept(this, constantVisitor);
    472     }
    473 
    474 
    475     public void superClassConstantAccept(ConstantVisitor constantVisitor)
    476     {
    477         if (u2superClass != 0)
    478         {
    479             constantPool[u2superClass].accept(this, constantVisitor);
    480         }
    481     }
    482 
    483 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    567     public Object getVisitorInfo()
    568     {
    569         return visitorInfo;
    570     }
    571 
    572     public void setVisitorInfo(Object visitorInfo)
    573     {
    574         this.visitorInfo = visitorInfo;
    575     }
    576 
    577 
    578     // Implementations for Object.
    579 
    580     public String toString()
    581     {
    582         return "ProgramClass("+getName()+")";
    583     }
    584 }
    585