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.optimize.info;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.constant.*;
25 import proguard.classfile.constant.visitor.ConstantVisitor;
26 import proguard.classfile.util.SimplifiedVisitor;
27 import proguard.classfile.visitor.*;
28 
29 /**
30  * This ClassVisitor marks all class members that can not be made private in the
31  * classes that it visits, and in the classes to which they refer.
32  *
33  * @author Eric Lafortune
34  */
35 public class NonPrivateMemberMarker
36 extends      SimplifiedVisitor
37 implements   ClassVisitor,
38              ConstantVisitor,
39              MemberVisitor
40 {
41     private final MethodImplementationFilter filteredMethodMarker = new MethodImplementationFilter(this);
42 
43 
44     // Implementations for ClassVisitor.
45 
visitProgramClass(ProgramClass programClass)46     public void visitProgramClass(ProgramClass programClass)
47     {
48         // Mark all referenced class members in different classes.
49         programClass.constantPoolEntriesAccept(this);
50 
51         // Explicitly mark the <clinit> method.
52         programClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
53                                   ClassConstants.METHOD_TYPE_CLINIT,
54                                   this);
55 
56         // Explicitly mark the parameterless <init> method.
57         programClass.methodAccept(ClassConstants.METHOD_NAME_INIT,
58                                   ClassConstants.METHOD_TYPE_INIT,
59                                   this);
60 
61         // Mark all methods that may have implementations.
62         programClass.methodsAccept(filteredMethodMarker);
63     }
64 
65 
visitLibraryClass(LibraryClass libraryClass)66     public void visitLibraryClass(LibraryClass libraryClass)
67     {
68         // Go over all methods.
69         libraryClass.methodsAccept(this);
70     }
71 
72 
73     // Implementations for ConstantVisitor.
74 
visitAnyConstant(Clazz clazz, Constant constant)75     public void visitAnyConstant(Clazz clazz, Constant constant) {}
76 
77 
visitStringConstant(Clazz clazz, StringConstant stringConstant)78     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
79     {
80         // The referenced class member, if any, can never be made private,
81         // even if it's in the same class.
82         stringConstant.referencedMemberAccept(this);
83     }
84 
85 
visitAnyRefConstant(Clazz clazz, RefConstant refConstant)86     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
87     {
88         Clazz referencedClass = refConstant.referencedClass;
89 
90         // Is it referring to a class member in another class?
91         // The class member might be in another class, or
92         // it may be referenced through another class.
93         if (referencedClass != null &&
94             !referencedClass.equals(clazz) ||
95             !refConstant.getClassName(clazz).equals(clazz.getName()))
96         {
97             // The referenced class member can never be made private.
98             refConstant.referencedMemberAccept(this);
99         }
100     }
101 
102 
103     // Implementations for MemberVisitor.
104 
visitProgramField(ProgramClass programClass, ProgramField programField)105     public void visitProgramField(ProgramClass programClass, ProgramField programField)
106     {
107         markCanNotBeMadePrivate(programField);
108     }
109 
110 
visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)111     public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
112     {
113         markCanNotBeMadePrivate(libraryField);
114     }
115 
116 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)117     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
118     {
119         markCanNotBeMadePrivate(programMethod);
120     }
121 
122 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)123     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
124     {
125         markCanNotBeMadePrivate(libraryMethod);
126     }
127 
128 
129     // Small utility methods.
130 
markCanNotBeMadePrivate(Field field)131     private static void markCanNotBeMadePrivate(Field field)
132     {
133         FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
134         if (info != null)
135         {
136             info.setCanNotBeMadePrivate();
137         }
138     }
139 
140 
141     /**
142      * Returns whether the given field can be made private.
143      */
canBeMadePrivate(Field field)144     public static boolean canBeMadePrivate(Field field)
145     {
146         FieldOptimizationInfo info = FieldOptimizationInfo.getFieldOptimizationInfo(field);
147         return info != null &&
148                info.canBeMadePrivate();
149     }
150 
151 
markCanNotBeMadePrivate(Method method)152     private static void markCanNotBeMadePrivate(Method method)
153     {
154         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
155         if (info != null)
156         {
157             info.setCanNotBeMadePrivate();
158         }
159     }
160 
161 
162     /**
163      * Returns whether the given method can be made private.
164      */
canBeMadePrivate(Method method)165     public static boolean canBeMadePrivate(Method method)
166     {
167         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
168         return info != null &&
169                info.canBeMadePrivate();
170     }
171 }
172