• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.classfile.editor;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.constant.*;
25 import proguard.classfile.util.*;
26 import proguard.classfile.visitor.*;
27 
28 /**
29  * This ClassVisitor fixes the access modifiers of all classes and class
30  * members that are referenced by the classes that it visits.
31  *
32  * @author Eric Lafortune
33  */
34 public class AccessFixer
35 extends      ReferencedClassVisitor
36 implements   ClassVisitor
37 {
38     /**
39      * Creates a new AccessFixer.
40      */
AccessFixer()41     public AccessFixer()
42     {
43         // Unfortunately, the inner class must be static to be passed to the
44         // super constructor. We therefore can't let it refer to this class;
45         // we'll let this class refer to the inner class instead.
46         super(new MyAccessFixer());
47     }
48 
49 
50     // Overridden methods for ClassVisitor.
51 
visitProgramClass(ProgramClass programClass)52     public void visitProgramClass(ProgramClass programClass)
53     {
54         // Remember the referencing class.
55         ((MyAccessFixer)classVisitor).referencingClass = programClass;
56 
57         // Start visiting and fixing the referenced classes and class members.
58         super.visitProgramClass(programClass);
59     }
60 
61 
visitLibraryClass(LibraryClass libraryClass)62     public void visitLibraryClass(LibraryClass libraryClass)
63     {
64         // Remember the referencing class.
65         ((MyAccessFixer)classVisitor).referencingClass = libraryClass;
66 
67         // Start visiting and fixing the referenced classes and class members.
68         super.visitLibraryClass(libraryClass);
69     }
70 
71 
72     // Overridden methods for MemberVisitor.
73 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)74     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
75     {
76         // Fix the referenced classes and class members.
77         super.visitProgramMember(programClass, programMethod);
78 
79         // Fix overridden or implemented methods higher up the hierarchy.
80         // We can ignore private and static methods and initializers.
81         if ((programMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
82                                                ClassConstants.ACC_STATIC)) == 0 &&
83             !ClassUtil.isInitializer(programMethod.getName(programClass)))
84         {
85             programClass.hierarchyAccept(false, true, false, false,
86                 new NamedMethodVisitor(programMethod.getName(programClass),
87                                        programMethod.getDescriptor(programClass),
88                 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
89                                           ClassConstants.ACC_STATIC,
90                                        (MemberVisitor)classVisitor)));
91         }
92     }
93 
94 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)95     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
96     {
97         // Fix the referenced classes and class members.
98         super.visitLibraryMember(libraryClass, libraryMethod);
99 
100         // Fix overridden or implemented methods higher up the hierarchy.
101         // We can ignore private and static methods and initializers.
102         if ((libraryMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
103                                                ClassConstants.ACC_STATIC)) == 0 &&
104             !ClassUtil.isInitializer(libraryMethod.getName(libraryClass)))
105         {
106             libraryClass.hierarchyAccept(false, true, false, false,
107                 new NamedMethodVisitor(libraryMethod.getName(libraryClass),
108                                        libraryMethod.getDescriptor(libraryClass),
109                 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
110                                           ClassConstants.ACC_STATIC,
111                                        (MemberVisitor)classVisitor)));
112         }
113     }
114 
115 
116     // Overridden methods for ConstantVisitor.
117 
visitStringConstant(Clazz clazz, StringConstant stringConstant)118     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
119     {
120         // Fix the access flags of the referenced class, if any.
121         super.visitStringConstant(clazz, stringConstant);
122 
123         // Fix the access flags of the referenced class member, if any.
124         stringConstant.referencedMemberAccept((MemberVisitor)classVisitor);
125     }
126 
127 
visitAnyRefConstant(Clazz clazz, RefConstant refConstant)128     public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
129     {
130         // Fix the access flags of the referenced class.
131         super.visitAnyRefConstant(clazz, refConstant);
132 
133         // Fix the access flags of the referenced class member.
134         refConstant.referencedMemberAccept((MemberVisitor)classVisitor);
135     }
136 
137 
138     /**
139      * This ClassVisitor and MemberVisitor fixes the access flags of the
140      * classes and class members that it visits, relative to the referencing
141      * class.
142      */
143     private static class MyAccessFixer
144     extends              SimplifiedVisitor
145     implements           ClassVisitor,
146                          MemberVisitor
147     {
148         private Clazz referencingClass;
149 
150 
151         // Implementations for ClassVisitor.
152 
visitLibraryClass(LibraryClass libraryClass)153         public void visitLibraryClass(LibraryClass libraryClass) {}
154 
155 
visitProgramClass(ProgramClass programClass)156         public void visitProgramClass(ProgramClass programClass)
157         {
158             int currentAccessFlags = programClass.getAccessFlags();
159             int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
160 
161             // Compute the required access level.
162             int requiredAccessLevel =
163                 inSamePackage(programClass, referencingClass) ?
164                     AccessUtil.PACKAGE_VISIBLE :
165                     AccessUtil.PUBLIC;
166 
167             // Fix the class access flags if necessary.
168             if (currentAccessLevel < requiredAccessLevel)
169             {
170                 programClass.u2accessFlags =
171                     AccessUtil.replaceAccessFlags(currentAccessFlags,
172                                                   AccessUtil.accessFlags(requiredAccessLevel));
173             }
174         }
175 
176 
177         // Implementations for MemberVisitor.
178 
visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)179         public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {}
180 
181 
visitProgramMember(ProgramClass programClass, ProgramMember programMember)182         public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
183         {
184             int currentAccessFlags = programMember.getAccessFlags();
185             int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
186 
187             // Compute the required access level.
188             int requiredAccessLevel =
189                 programClass.equals(referencingClass)         ? AccessUtil.PRIVATE         :
190                 inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE :
191                 programClass.extends_(referencingClass) &&
192                 referencingClass.extends_(programClass)       ? AccessUtil.PROTECTED       :
193                                                                 AccessUtil.PUBLIC;
194 
195             // Fix the class member access flags if necessary.
196             if (currentAccessLevel < requiredAccessLevel)
197             {
198                 programMember.u2accessFlags =
199                     AccessUtil.replaceAccessFlags(currentAccessFlags,
200                                                   AccessUtil.accessFlags(requiredAccessLevel));
201             }
202         }
203 
204 
205         // Small utility methods.
206 
207         /**
208          * Returns whether the two given classes are in the same package.
209          */
inSamePackage(ProgramClass class1, Clazz class2)210         private boolean inSamePackage(ProgramClass class1, Clazz class2)
211         {
212             return ClassUtil.internalPackageName(class1.getName()).equals(
213                    ClassUtil.internalPackageName(class2.getName()));
214         }
215     }
216 }
217