Home | History | Annotate | Download | only in util
      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.util;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.constant.ClassConstant;
     25 import proguard.classfile.constant.visitor.ConstantVisitor;
     26 import proguard.classfile.visitor.ClassVisitor;
     27 
     28 /**
     29  * This ClassVisitor initializes the superclass hierarchy of all classes that
     30  * it visits.
     31  * <p>
     32  * Visited library classes get direct references to their superclasses and
     33  * interfaces, replacing the superclass names and interface names. The direct
     34  * references are equivalent to the names, but they are more efficient to work
     35  * with.
     36  * <p>
     37  * This visitor optionally prints warnings if some superclasses can't be found
     38  * or if they are in the program class pool.
     39  *
     40  * @author Eric Lafortune
     41  */
     42 public class ClassSuperHierarchyInitializer
     43 extends      SimplifiedVisitor
     44 implements   ClassVisitor,
     45              ConstantVisitor
     46 {
     47     private final ClassPool      programClassPool;
     48     private final ClassPool      libraryClassPool;
     49     private final WarningPrinter missingWarningPrinter;
     50     private final WarningPrinter dependencyWarningPrinter;
     51 
     52 
     53     /**
     54      * Creates a new ClassSuperHierarchyInitializer that initializes the super
     55      * hierarchy of all visited class files, optionally printing warnings if
     56      * some classes can't be found or if they are in the program class pool.
     57      */
     58     public ClassSuperHierarchyInitializer(ClassPool      programClassPool,
     59                                           ClassPool      libraryClassPool,
     60                                           WarningPrinter missingWarningPrinter,
     61                                           WarningPrinter dependencyWarningPrinter)
     62     {
     63         this.programClassPool         = programClassPool;
     64         this.libraryClassPool         = libraryClassPool;
     65         this.missingWarningPrinter    = missingWarningPrinter;
     66         this.dependencyWarningPrinter = dependencyWarningPrinter;
     67     }
     68 
     69 
     70     // Implementations for ClassVisitor.
     71 
     72     public void visitProgramClass(ProgramClass programClass)
     73     {
     74         // Link to the super class.
     75         programClass.superClassConstantAccept(this);
     76 
     77         // Link to the interfaces.
     78         programClass.interfaceConstantsAccept(this);
     79     }
     80 
     81 
     82     public void visitLibraryClass(LibraryClass libraryClass)
     83     {
     84         String className = libraryClass.getName();
     85 
     86         // Link to the super class.
     87         String superClassName = libraryClass.superClassName;
     88         if (superClassName != null)
     89         {
     90             // Keep a reference to the superclass.
     91             libraryClass.superClass = findClass(className, superClassName);
     92         }
     93 
     94         // Link to the interfaces.
     95         if (libraryClass.interfaceNames != null)
     96         {
     97             String[] interfaceNames   = libraryClass.interfaceNames;
     98             Clazz[]  interfaceClasses = new Clazz[interfaceNames.length];
     99 
    100             for (int index = 0; index < interfaceNames.length; index++)
    101             {
    102                 // Keep a reference to the interface class.
    103                 interfaceClasses[index] =
    104                     findClass(className, interfaceNames[index]);
    105             }
    106 
    107             libraryClass.interfaceClasses = interfaceClasses;
    108         }
    109 
    110         // Discard the name Strings. From now on, we'll use the object
    111         // references.
    112         libraryClass.superClassName = null;
    113         libraryClass.interfaceNames = null;
    114     }
    115 
    116 
    117     // Implementations for ConstantVisitor.
    118 
    119     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    120     {
    121         classConstant.referencedClass =
    122             findClass(clazz.getName(), classConstant.getName(clazz));
    123     }
    124 
    125 
    126     // Small utility methods.
    127 
    128     /**
    129      * Returns the class with the given name, either for the program class pool
    130      * or from the library class pool, or <code>null</code> if it can't be found.
    131      */
    132     private Clazz findClass(String referencingClassName, String name)
    133     {
    134         // First look for the class in the program class pool.
    135         Clazz clazz = programClassPool.getClass(name);
    136 
    137         // Otherwise look for the class in the library class pool.
    138         if (clazz == null)
    139         {
    140             clazz = libraryClassPool.getClass(name);
    141 
    142             if (clazz == null &&
    143                 missingWarningPrinter != null)
    144             {
    145                 // We didn't find the superclass or interface. Print a warning.
    146                 missingWarningPrinter.print(referencingClassName,
    147                                             name,
    148                                             "Warning: " +
    149                                             ClassUtil.externalClassName(referencingClassName) +
    150                                             ": can't find superclass or interface " +
    151                                             ClassUtil.externalClassName(name));
    152             }
    153         }
    154         else if (dependencyWarningPrinter != null)
    155         {
    156             // The superclass or interface was found in the program class pool.
    157             // Print a warning.
    158             dependencyWarningPrinter.print(referencingClassName,
    159                                            name,
    160                                            "Warning: library class " +
    161                                            ClassUtil.externalClassName(referencingClassName) +
    162                                            " extends or implements program class " +
    163                                            ClassUtil.externalClassName(name));
    164         }
    165 
    166         return clazz;
    167     }
    168 }
    169