Home | History | Annotate | Download | only in editor
      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.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.annotation.*;
     25 import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor;
     26 
     27 /**
     28  * This AnnotationVisitor adds all element values that it visits to the given
     29  * target annotation default attribute, annotation, or element value.
     30  *
     31  * @author Eric Lafortune
     32  */
     33 public class ElementValueAdder
     34 implements   ElementValueVisitor
     35 {
     36     private static final ElementValue[] EMPTY_ELEMENT_VALUES = new ElementValue[0];
     37 
     38 
     39     private final ProgramClass               targetClass;
     40     private final AnnotationDefaultAttribute targetAnnotationDefaultAttribute;
     41 
     42     private final ConstantAdder       constantAdder;
     43     private final ElementValuesEditor elementValuesEditor;
     44 
     45 
     46     /**
     47      * Creates a new ElementValueAdder that will copy element values into the
     48      * given target annotation default attribute value.
     49      */
     50     public ElementValueAdder(ProgramClass               targetClass,
     51                              AnnotationDefaultAttribute targetAnnotationDefaultAttribute,
     52                              boolean                    replaceElementValues)
     53     {
     54         this.targetClass                      = targetClass;
     55         this.targetAnnotationDefaultAttribute = targetAnnotationDefaultAttribute;
     56 
     57         constantAdder       = new ConstantAdder(targetClass);
     58         elementValuesEditor = null;
     59     }
     60 
     61 
     62     /**
     63      * Creates a new ElementValueAdder that will copy element values into the
     64      * given target annotation.
     65      */
     66     public ElementValueAdder(ProgramClass targetClass,
     67                              Annotation   targetAnnotation,
     68                              boolean      replaceElementValues)
     69     {
     70         this.targetClass                      = targetClass;
     71         this.targetAnnotationDefaultAttribute = null;
     72 
     73         constantAdder       = new ConstantAdder(targetClass);
     74         elementValuesEditor = new ElementValuesEditor(targetClass,
     75                                                       targetAnnotation,
     76                                                       replaceElementValues);
     77     }
     78 
     79 
     80     /**
     81      * Creates a new ElementValueAdder that will copy element values into the
     82      * given target element value.
     83      */
     84     public ElementValueAdder(ProgramClass      targetClass,
     85                              ArrayElementValue targetArrayElementValue,
     86                              boolean           replaceElementValues)
     87     {
     88         this.targetClass                      = targetClass;
     89         this.targetAnnotationDefaultAttribute = null;
     90 
     91         constantAdder       = new ConstantAdder(targetClass);
     92         elementValuesEditor = new ElementValuesEditor(targetClass,
     93                                                       targetArrayElementValue,
     94                                                       replaceElementValues);
     95     }
     96 
     97 
     98     // Implementations for ElementValueVisitor.
     99 
    100     public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
    101     {
    102         // Create a copy of the element value.
    103         ConstantElementValue newConstantElementValue =
    104             new ConstantElementValue(constantElementValue.u1tag,
    105                                      constantElementValue.u2elementNameIndex == 0 ? 0 :
    106                                      constantAdder.addConstant(clazz, constantElementValue.u2elementNameIndex),
    107                                      constantAdder.addConstant(clazz, constantElementValue.u2constantValueIndex));
    108 
    109         newConstantElementValue.referencedClass  = constantElementValue.referencedClass;
    110         newConstantElementValue.referencedMethod = constantElementValue.referencedMethod;
    111 
    112         // Add it to the target.
    113         addElementValue(newConstantElementValue);
    114     }
    115 
    116 
    117     public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
    118     {
    119         // Create a copy of the element value.
    120         EnumConstantElementValue newEnumConstantElementValue =
    121             new EnumConstantElementValue(enumConstantElementValue.u2elementNameIndex == 0 ? 0 :
    122                                          constantAdder.addConstant(clazz, enumConstantElementValue.u2elementNameIndex),
    123                                          constantAdder.addConstant(clazz, enumConstantElementValue.u2typeNameIndex),
    124                                          constantAdder.addConstant(clazz, enumConstantElementValue.u2constantNameIndex));
    125 
    126         newEnumConstantElementValue.referencedClass  = enumConstantElementValue.referencedClass;
    127         newEnumConstantElementValue.referencedMethod = enumConstantElementValue.referencedMethod;
    128 
    129         // TODO: Clone array.
    130         newEnumConstantElementValue.referencedClasses = enumConstantElementValue.referencedClasses;
    131 
    132         // Add it to the target.
    133         addElementValue(newEnumConstantElementValue);
    134     }
    135 
    136 
    137     public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
    138     {
    139         // Create a copy of the element value.
    140         ClassElementValue newClassElementValue =
    141             new ClassElementValue(classElementValue.u2elementNameIndex == 0 ? 0 :
    142                                   constantAdder.addConstant(clazz, classElementValue.u2elementNameIndex),
    143                                   constantAdder.addConstant(clazz, classElementValue.u2classInfoIndex));
    144 
    145         newClassElementValue.referencedClass  = classElementValue.referencedClass;
    146         newClassElementValue.referencedMethod = classElementValue.referencedMethod;
    147 
    148         // TODO: Clone array.
    149         newClassElementValue.referencedClasses = classElementValue.referencedClasses;
    150 
    151         // Add it to the target.
    152         addElementValue(newClassElementValue);
    153     }
    154 
    155 
    156     public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
    157     {
    158         // Create a copy of the element value.
    159         AnnotationElementValue newAnnotationElementValue =
    160             new AnnotationElementValue(annotationElementValue.u2elementNameIndex == 0 ? 0 :
    161                                        constantAdder.addConstant(clazz, annotationElementValue.u2elementNameIndex),
    162                                        new Annotation());
    163 
    164         newAnnotationElementValue.referencedClass  = annotationElementValue.referencedClass;
    165         newAnnotationElementValue.referencedMethod = annotationElementValue.referencedMethod;
    166 
    167         annotationElementValue.annotationAccept(clazz,
    168                                                 new AnnotationAdder(targetClass,
    169                                                                     newAnnotationElementValue));
    170 
    171         // Add it to the target.
    172         addElementValue(newAnnotationElementValue);
    173     }
    174 
    175 
    176     public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
    177     {
    178         // Create a copy of the element value.
    179         ArrayElementValue newArrayElementValue =
    180             new ArrayElementValue(arrayElementValue.u2elementNameIndex == 0 ? 0 :
    181                                   constantAdder.addConstant(clazz, arrayElementValue.u2elementNameIndex),
    182                                   0,
    183                                   arrayElementValue.u2elementValuesCount > 0 ?
    184                                       new ElementValue[arrayElementValue.u2elementValuesCount] :
    185                                       EMPTY_ELEMENT_VALUES);
    186 
    187         newArrayElementValue.referencedClass  = arrayElementValue.referencedClass;
    188         newArrayElementValue.referencedMethod = arrayElementValue.referencedMethod;
    189 
    190         arrayElementValue.elementValuesAccept(clazz,
    191                                               annotation,
    192                                               new ElementValueAdder(targetClass,
    193                                                                     newArrayElementValue,
    194                                                                     false));
    195 
    196         // Add it to the target.
    197         addElementValue(newArrayElementValue);
    198     }
    199 
    200 
    201     // Small utility methods.
    202 
    203     private void addElementValue(ElementValue newElementValue)
    204     {
    205         // What's the target?
    206         if (targetAnnotationDefaultAttribute != null)
    207         {
    208             // Simply set the completed element value.
    209             targetAnnotationDefaultAttribute.defaultValue = newElementValue;
    210         }
    211         else
    212         {
    213             // Add it to the target.
    214             elementValuesEditor.addElementValue(newElementValue);
    215         }
    216     }
    217 }