1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 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  */
21 package proguard.shrink;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.*;
26 import proguard.classfile.constant.*;
27 import proguard.classfile.constant.visitor.ConstantVisitor;
28 import proguard.classfile.util.SimplifiedVisitor;
29 import 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  */
39 public class InnerUsageMarker
40 extends      SimplifiedVisitor
41 implements   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      */
InnerUsageMarker(UsageMarker usageMarker)58     public InnerUsageMarker(UsageMarker usageMarker)
59     {
60         this.usageMarker = usageMarker;
61     }
62 
63 
64     // Implementations for AttributeVisitor.
65 
visitAnyAttribute(Clazz clazz, Attribute attribute)66     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
67 
68 
visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)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 
visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)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 
visitClassConstant(Clazz clazz, ClassConstant classConstant)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 
visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)144     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
145     {
146         usageMarker.markAsUsed(utf8Constant);
147     }
148 
149 
150     // Implementations for ClassVisitor.
151 
visitProgramClass(ProgramClass programClass)152     public void visitProgramClass(ProgramClass programClass)
153     {
154         classUsed = usageMarker.isUsed(programClass);
155     }
156 
157 
visitLibraryClass(LibraryClass libraryClass)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      */
markConstant(Clazz clazz, int index)170     private void markConstant(Clazz clazz, int index)
171     {
172          clazz.constantPoolEntryAccept(index, this);
173     }
174 }
175