InnerUsageMarker.java revision b72c5c2e5482cf10117b2b25f642f7616b2326c3
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.shrink;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.visitor.*;
26import proguard.classfile.constant.*;
27import proguard.classfile.constant.visitor.ConstantVisitor;
28import proguard.classfile.util.SimplifiedVisitor;
29import 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 */
39public class InnerUsageMarker
40extends      SimplifiedVisitor
41implements   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