Home | History | Annotate | Download | only in shrink
      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.shrink;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.*;
     26 import proguard.classfile.constant.*;
     27 import proguard.classfile.constant.visitor.ConstantVisitor;
     28 import proguard.classfile.util.SimplifiedVisitor;
     29 import proguard.classfile.visitor.ClassVisitor;
     30 
     31 /**
     32  * This AttributeVisitor recursively marks all necessary inner class information
     33  * in the attributes that it visits.
     34  *
     35  * @see UsageMarker
     36  *
     37  * @author Eric Lafortune
     38  */
     39 public class InnerUsageMarker
     40 extends      SimplifiedVisitor
     41 implements   AttributeVisitor,
     42              InnerClassesInfoVisitor,
     43              ConstantVisitor,
     44              ClassVisitor
     45 {
     46     private final UsageMarker usageMarker;
     47 
     48     // Fields acting as a return parameters for several methods.
     49     private boolean attributeUsed;
     50     private boolean classUsed;
     51 
     52 
     53     /**
     54      * Creates a new InnerUsageMarker.
     55      * @param usageMarker the usage marker that is used to mark the classes
     56      *                    and class members.
     57      */
     58     public InnerUsageMarker(UsageMarker usageMarker)
     59     {
     60         this.usageMarker = usageMarker;
     61     }
     62 
     63 
     64     // Implementations for AttributeVisitor.
     65 
     66     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
     67 
     68 
     69     public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
     70     {
     71         // Mark the necessary inner classes information.
     72         attributeUsed = false;
     73         innerClassesAttribute.innerClassEntriesAccept(clazz, this);
     74 
     75         if (attributeUsed)
     76         {
     77             // We got a positive used flag, so some inner class is being used.
     78             // Mark this attribute as being used as well.
     79             usageMarker.markAsUsed(innerClassesAttribute);
     80 
     81             markConstant(clazz, innerClassesAttribute.u2attributeNameIndex);
     82         }
     83     }
     84 
     85 
     86     // Implementations for InnerClassesInfoVisitor.
     87 
     88     public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
     89     {
     90         boolean innerClassesInfoUsed = usageMarker.isUsed(innerClassesInfo);
     91 
     92         if (!innerClassesInfoUsed)
     93         {
     94             // Check if the inner class (if any) is marked as being used.
     95             classUsed = true;
     96             innerClassesInfo.innerClassConstantAccept(clazz, this);
     97             innerClassesInfoUsed = classUsed;
     98 
     99             // Check if the outer class (if any) is marked as being used.
    100             classUsed = true;
    101             innerClassesInfo.outerClassConstantAccept(clazz, this);
    102             innerClassesInfoUsed &= classUsed;
    103 
    104             // If both the inner class and the outer class are marked as being
    105             // used, then mark this InnerClassesInfo as well.
    106             if (innerClassesInfoUsed)
    107             {
    108                 usageMarker.markAsUsed(innerClassesInfo);
    109 
    110                 innerClassesInfo.innerNameConstantAccept(clazz, this);
    111             }
    112         }
    113 
    114         // The return value.
    115         attributeUsed |= innerClassesInfoUsed;
    116     }
    117 
    118 
    119     // Implementations for ConstantVisitor.
    120 
    121     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    122     {
    123         classUsed = usageMarker.isUsed(classConstant);
    124 
    125         // Is the class constant marked as being used?
    126         if (!classUsed)
    127         {
    128             // Check the referenced class.
    129             classUsed = true;
    130             classConstant.referencedClassAccept(this);
    131 
    132             // Is the referenced class marked as being used?
    133             if (classUsed)
    134             {
    135                 // Mark the class constant and its Utf8 constant.
    136                 usageMarker.markAsUsed(classConstant);
    137 
    138                 markConstant(clazz, classConstant.u2nameIndex);
    139             }
    140         }
    141     }
    142 
    143 
    144     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
    145     {
    146         usageMarker.markAsUsed(utf8Constant);
    147     }
    148 
    149 
    150     // Implementations for ClassVisitor.
    151 
    152     public void visitProgramClass(ProgramClass programClass)
    153     {
    154         classUsed = usageMarker.isUsed(programClass);
    155     }
    156 
    157 
    158     public void visitLibraryClass(LibraryClass libraryClass)
    159     {
    160         classUsed = true;
    161     }
    162 
    163 
    164     // Small utility methods.
    165 
    166     /**
    167      * Marks the given constant pool entry of the given class. This includes
    168      * visiting any other referenced constant pool entries.
    169      */
    170     private void markConstant(Clazz clazz, int index)
    171     {
    172          clazz.constantPoolEntryAccept(index, this);
    173     }
    174 }
    175