1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 Eric Lafortune (eric@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 */
21package proguard.classfile.editor;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.annotation.*;
25import 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 */
33public class ElementValueAdder
34implements   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}