1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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.obfuscate;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.annotation.*;
26import proguard.classfile.attribute.annotation.visitor.*;
27import proguard.classfile.attribute.preverification.*;
28import proguard.classfile.attribute.visitor.*;
29import proguard.classfile.constant.*;
30import proguard.classfile.constant.visitor.ConstantVisitor;
31import proguard.classfile.util.SimplifiedVisitor;
32import proguard.classfile.visitor.*;
33
34/**
35 * This ClassVisitor marks all UTF-8 constant pool entries that are
36 * being used in the program classes it visits.
37 *
38 * @see Utf8Shrinker
39 *
40 * @author Eric Lafortune
41 */
42public class Utf8UsageMarker
43extends      SimplifiedVisitor
44implements   ClassVisitor,
45             MemberVisitor,
46             ConstantVisitor,
47             AttributeVisitor,
48             InnerClassesInfoVisitor,
49             LocalVariableInfoVisitor,
50             LocalVariableTypeInfoVisitor,
51             AnnotationVisitor,
52             ElementValueVisitor
53{
54    // A visitor info flag to indicate the UTF-8 constant pool entry is being used.
55    private static final Object USED = new Object();
56
57
58    // Implementations for ClassVisitor.
59
60    public void visitProgramClass(ProgramClass programClass)
61    {
62        // Mark the UTF-8 entries referenced by the other constant pool entries.
63        programClass.constantPoolEntriesAccept(this);
64
65        // Mark the UTF-8 entries referenced by the fields and methods.
66        programClass.fieldsAccept(this);
67        programClass.methodsAccept(this);
68
69        // Mark the UTF-8 entries referenced by the attributes.
70        programClass.attributesAccept(this);
71    }
72
73
74    // Implementations for MemberVisitor.
75
76    public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
77    {
78        // Mark the name and descriptor UTF-8 entries.
79        markCpUtf8Entry(programClass, programMember.u2nameIndex);
80        markCpUtf8Entry(programClass, programMember.u2descriptorIndex);
81
82        // Mark the UTF-8 entries referenced by the attributes.
83        programMember.attributesAccept(programClass, this);
84    }
85
86
87    // Implementations for ConstantVisitor.
88
89    public void visitAnyConstant(Clazz clazz, Constant constant) {}
90
91
92    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
93    {
94        markCpUtf8Entry(clazz, stringConstant.u2stringIndex);
95    }
96
97
98    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
99    {
100        markCpUtf8Entry(clazz, classConstant.u2nameIndex);
101    }
102
103
104    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
105    {
106        markCpUtf8Entry(clazz, nameAndTypeConstant.u2nameIndex);
107        markCpUtf8Entry(clazz, nameAndTypeConstant.u2descriptorIndex);
108    }
109
110
111    // Implementations for AttributeVisitor.
112
113    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
114    {
115        // This is the best we can do for unknown attributes.
116        markCpUtf8Entry(clazz, unknownAttribute.u2attributeNameIndex);
117    }
118
119
120    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
121    {
122        markCpUtf8Entry(clazz, sourceFileAttribute.u2attributeNameIndex);
123
124        markCpUtf8Entry(clazz, sourceFileAttribute.u2sourceFileIndex);
125    }
126
127
128    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
129    {
130        markCpUtf8Entry(clazz, sourceDirAttribute.u2attributeNameIndex);
131
132        markCpUtf8Entry(clazz, sourceDirAttribute.u2sourceDirIndex);
133    }
134
135
136    public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
137    {
138        markCpUtf8Entry(clazz, innerClassesAttribute.u2attributeNameIndex);
139
140        // Mark the UTF-8 entries referenced by the inner classes.
141        innerClassesAttribute.innerClassEntriesAccept(clazz, this);
142    }
143
144
145    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
146    {
147        markCpUtf8Entry(clazz, enclosingMethodAttribute.u2attributeNameIndex);
148
149        // These entries have already been marked in the constant pool.
150        //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2classIndex);
151        //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2nameAndTypeIndex);
152    }
153
154
155    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
156    {
157        markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex);
158    }
159
160
161    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
162    {
163        markCpUtf8Entry(clazz, syntheticAttribute.u2attributeNameIndex);
164    }
165
166
167    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
168    {
169        markCpUtf8Entry(clazz, signatureAttribute.u2attributeNameIndex);
170
171        markCpUtf8Entry(clazz, signatureAttribute.u2signatureIndex);
172    }
173
174
175    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
176    {
177        markCpUtf8Entry(clazz, constantValueAttribute.u2attributeNameIndex);
178    }
179
180
181    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
182    {
183        markCpUtf8Entry(clazz, exceptionsAttribute.u2attributeNameIndex);
184    }
185
186
187    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
188    {
189        markCpUtf8Entry(clazz, codeAttribute.u2attributeNameIndex);
190
191        // Mark the UTF-8 entries referenced by the attributes.
192        codeAttribute.attributesAccept(clazz, method, this);
193    }
194
195
196    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
197    {
198        markCpUtf8Entry(clazz, stackMapAttribute.u2attributeNameIndex);
199    }
200
201
202    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
203    {
204        markCpUtf8Entry(clazz, stackMapTableAttribute.u2attributeNameIndex);
205    }
206
207
208    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
209    {
210        markCpUtf8Entry(clazz, lineNumberTableAttribute.u2attributeNameIndex);
211    }
212
213
214    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
215    {
216        markCpUtf8Entry(clazz, localVariableTableAttribute.u2attributeNameIndex);
217
218        // Mark the UTF-8 entries referenced by the local variables.
219        localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
220    }
221
222
223    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
224    {
225        markCpUtf8Entry(clazz, localVariableTypeTableAttribute.u2attributeNameIndex);
226
227        // Mark the UTF-8 entries referenced by the local variable types.
228        localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
229    }
230
231
232    public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
233    {
234        markCpUtf8Entry(clazz, annotationsAttribute.u2attributeNameIndex);
235
236        // Mark the UTF-8 entries referenced by the annotations.
237        annotationsAttribute.annotationsAccept(clazz, this);
238    }
239
240
241    public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
242    {
243        markCpUtf8Entry(clazz, parameterAnnotationsAttribute.u2attributeNameIndex);
244
245        // Mark the UTF-8 entries referenced by the annotations.
246        parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
247    }
248
249
250    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
251    {
252        markCpUtf8Entry(clazz, annotationDefaultAttribute.u2attributeNameIndex);
253
254        // Mark the UTF-8 entries referenced by the element value.
255        annotationDefaultAttribute.defaultValueAccept(clazz, this);
256    }
257
258
259    // Implementations for InnerClassesInfoVisitor.
260
261    public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
262    {
263        if (innerClassesInfo.u2innerNameIndex != 0)
264        {
265            markCpUtf8Entry(clazz, innerClassesInfo.u2innerNameIndex);
266        }
267    }
268
269
270    // Implementations for LocalVariableInfoVisitor.
271
272    public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
273    {
274        markCpUtf8Entry(clazz, localVariableInfo.u2nameIndex);
275        markCpUtf8Entry(clazz, localVariableInfo.u2descriptorIndex);
276    }
277
278
279    // Implementations for LocalVariableTypeInfoVisitor.
280
281    public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
282    {
283        markCpUtf8Entry(clazz, localVariableTypeInfo.u2nameIndex);
284        markCpUtf8Entry(clazz, localVariableTypeInfo.u2signatureIndex);
285    }
286
287
288    // Implementations for AnnotationVisitor.
289
290    public void visitAnnotation(Clazz clazz, Annotation annotation)
291    {
292        markCpUtf8Entry(clazz, annotation.u2typeIndex);
293
294        // Mark the UTF-8 entries referenced by the element values.
295        annotation.elementValuesAccept(clazz, this);
296    }
297
298
299    // Implementations for ElementValueVisitor.
300
301    public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
302    {
303        if (constantElementValue.u2elementNameIndex != 0)
304        {
305            markCpUtf8Entry(clazz, constantElementValue.u2elementNameIndex);
306        }
307
308        // Only the string constant element value refers to a UTF-8 entry.
309        if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT)
310        {
311            markCpUtf8Entry(clazz, constantElementValue.u2constantValueIndex);
312        }
313    }
314
315
316    public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
317    {
318        if (enumConstantElementValue.u2elementNameIndex != 0)
319        {
320            markCpUtf8Entry(clazz, enumConstantElementValue.u2elementNameIndex);
321        }
322
323        markCpUtf8Entry(clazz, enumConstantElementValue.u2typeNameIndex);
324        markCpUtf8Entry(clazz, enumConstantElementValue.u2constantNameIndex);
325    }
326
327
328    public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
329    {
330        if (classElementValue.u2elementNameIndex != 0)
331        {
332            markCpUtf8Entry(clazz, classElementValue.u2elementNameIndex);
333        }
334
335        markCpUtf8Entry(clazz, classElementValue.u2classInfoIndex);
336    }
337
338
339    public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
340    {
341        if (annotationElementValue.u2elementNameIndex != 0)
342        {
343            markCpUtf8Entry(clazz, annotationElementValue.u2elementNameIndex);
344        }
345
346        // Mark the UTF-8 entries referenced by the annotation.
347        annotationElementValue.annotationAccept(clazz, this);
348    }
349
350
351    public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
352    {
353        if (arrayElementValue.u2elementNameIndex != 0)
354        {
355            markCpUtf8Entry(clazz, arrayElementValue.u2elementNameIndex);
356        }
357
358        // Mark the UTF-8 entries referenced by the element values.
359        arrayElementValue.elementValuesAccept(clazz, annotation, this);
360    }
361
362
363    // Small utility methods.
364
365    /**
366     * Marks the given UTF-8 constant pool entry of the given class.
367     */
368    private void markCpUtf8Entry(Clazz clazz, int index)
369    {
370         markAsUsed((Utf8Constant)((ProgramClass)clazz).getConstant(index));
371    }
372
373
374    /**
375     * Marks the given VisitorAccepter as being used.
376     * In this context, the VisitorAccepter will be a Utf8Constant object.
377     */
378    private static void markAsUsed(VisitorAccepter visitorAccepter)
379    {
380        visitorAccepter.setVisitorInfo(USED);
381    }
382
383
384    /**
385     * Returns whether the given VisitorAccepter has been marked as being used.
386     * In this context, the VisitorAccepter will be a Utf8Constant object.
387     */
388    static boolean isUsed(VisitorAccepter visitorAccepter)
389    {
390        return visitorAccepter.getVisitorInfo() == USED;
391    }
392}
393