Home | History | Annotate | Download | only in peephole
      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.optimize.peephole;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.*;
     26 import proguard.classfile.constant.ClassConstant;
     27 import proguard.classfile.constant.visitor.ConstantVisitor;
     28 import proguard.classfile.util.SimplifiedVisitor;
     29 import proguard.classfile.visitor.ClassVisitor;
     30 
     31 import java.util.Arrays;
     32 
     33 /**
     34  * This ClassVisitor removes InnerClasses and EnclosingMethod attributes in
     35  * classes that are retargeted or that refer to classes that are retargeted.
     36  *
     37  * @see ClassMerger
     38  * @author Eric Lafortune
     39  */
     40 public class RetargetedInnerClassAttributeRemover
     41 extends      SimplifiedVisitor
     42 implements   ClassVisitor,
     43              AttributeVisitor,
     44              InnerClassesInfoVisitor,
     45              ConstantVisitor
     46 {
     47     private boolean retargeted;
     48 
     49 
     50     // Implementations for ClassVisitor.
     51 
     52     public void visitProgramClass(ProgramClass programClass)
     53     {
     54         int         attributesCount = programClass.u2attributesCount;
     55         Attribute[] attributes      = programClass.attributes;
     56 
     57         int newAtributesCount = 0;
     58 
     59         // Copy over all non-retargeted attributes.
     60         for (int index = 0; index < attributesCount; index++)
     61         {
     62             Attribute attribute = attributes[index];
     63 
     64             // Check if it's an InnerClasses or EnclosingMethod attribute in
     65             // a retargeted class or referring to a retargeted class.
     66             retargeted = false;
     67             attribute.accept(programClass, this);
     68             if (!retargeted)
     69             {
     70                 attributes[newAtributesCount++] = attribute;
     71             }
     72         }
     73 
     74         // Clean up any remaining array elements.
     75         Arrays.fill(attributes, newAtributesCount, attributesCount, null);
     76 
     77         // Update the number of attributes.
     78         programClass.u2attributesCount = newAtributesCount;
     79     }
     80 
     81 
     82     // Implementations for AttributeVisitor.
     83 
     84     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
     85 
     86 
     87     public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
     88     {
     89         // Check whether the class itself is retargeted.
     90         checkTarget(clazz);
     91 
     92         if (!retargeted)
     93         {
     94             // Check whether the referenced classes are retargeted.
     95             innerClassesAttribute.innerClassEntriesAccept(clazz, this);
     96             int                classesCount = innerClassesAttribute.u2classesCount;
     97             InnerClassesInfo[] classes      = innerClassesAttribute.classes;
     98 
     99             int newClassesCount = 0;
    100 
    101             // Copy over all non-retargeted attributes.
    102             for (int index = 0; index < classesCount; index++)
    103             {
    104                 InnerClassesInfo classInfo = classes[index];
    105 
    106                 // Check if the outer class or inner class is a retargeted class.
    107                 retargeted = false;
    108                 classInfo.outerClassConstantAccept(clazz, this);
    109                 classInfo.innerClassConstantAccept(clazz, this);
    110                 if (!retargeted)
    111                 {
    112                     classes[newClassesCount++] = classInfo;
    113                 }
    114             }
    115 
    116             // Clean up any remaining array elements.
    117             Arrays.fill(classes, newClassesCount, classesCount, null);
    118 
    119             // Update the number of classes.
    120             innerClassesAttribute.u2classesCount = newClassesCount;
    121 
    122             // Remove the attribute altogether if it's empty.
    123             retargeted = newClassesCount == 0;
    124         }
    125     }
    126 
    127 
    128     public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
    129     {
    130         // Check whether the class itself is retargeted.
    131         checkTarget(clazz);
    132 
    133         // Check whether the referenced class is retargeted.
    134         checkTarget(enclosingMethodAttribute.referencedClass);
    135     }
    136 
    137 
    138     // Implementations for InnerClassesInfoVisitor.
    139 
    140     public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
    141     {
    142         // Check whether the inner class or the outer class are retargeted.
    143         innerClassesInfo.innerClassConstantAccept(clazz, this);
    144         innerClassesInfo.outerClassConstantAccept(clazz, this);
    145     }
    146 
    147 
    148     // Implementations for ConstantVisitor.
    149 
    150     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    151     {
    152         // Check whether the referenced class is retargeted.
    153         checkTarget(classConstant.referencedClass);
    154     }
    155 
    156 
    157     // Small utility methods.
    158 
    159     /**
    160      * Sets the global return value to true if the given class is retargeted.
    161      */
    162     private void checkTarget(Clazz clazz)
    163     {
    164         if (clazz != null &&
    165             ClassMerger.getTargetClass(clazz) != null)
    166         {
    167             retargeted = true;
    168         }
    169     }
    170 }