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.util;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.visitor.*;
25 
26 /**
27  * This MemberVisitor lets a given parameter visitor visit all the parameters
28  * of the methods that it visits. The parameters do not include or count the
29  * 'this' parameter or the return value.
30  *
31  * @author Eric Lafortune
32  */
33 public class AllParameterVisitor
34 implements   MemberVisitor
35 {
36     private final ParameterVisitor parameterVisitor;
37 
38 
39     /**
40      * Creates a new AllParameterVisitor for the given parameter
41      * visitor.
42      */
AllParameterVisitor(ParameterVisitor parameterVisitor)43     public AllParameterVisitor(ParameterVisitor parameterVisitor)
44     {
45         this.parameterVisitor = parameterVisitor;
46     }
47 
48 
49     // Implementations for MemberVisitor.
50 
visitProgramField(ProgramClass programClass, ProgramField programField)51     public void visitProgramField(ProgramClass programClass, ProgramField programField)
52     {
53         visitFieldType(programClass,
54                        programField,
55                        programField.referencedClass);
56     }
57 
58 
visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)59     public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
60     {
61         visitFieldType(libraryClass,
62                        libraryField,
63                        libraryField.referencedClass);
64     }
65 
66 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)67     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
68     {
69         visitParameters(programClass,
70                         programMethod,
71                         programMethod.referencedClasses);
72     }
73 
74 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)75     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
76     {
77         visitParameters(libraryClass,
78                         libraryMethod,
79                         libraryMethod.referencedClasses);
80     }
81 
82 
83     // Small utility methods.
84 
85     /**
86      * Lets the parameter visitor visit the type of the given field.
87      */
visitFieldType(Clazz clazz, Field field, Clazz referencedClass)88     private void visitFieldType(Clazz clazz,
89                                 Field field,
90                                 Clazz referencedClass)
91     {
92         String descriptor = field.getDescriptor(clazz);
93         parameterVisitor.visitParameter(clazz,
94                                         field,
95                                         0,
96                                         1,
97                                         0,
98                                         ClassUtil.internalTypeSize(descriptor),
99                                         descriptor,
100                                         referencedClass);
101     }
102 
103 
104     /**
105      * Lets the parameter visitor visit the parameters of the given method.
106      */
visitParameters(Clazz clazz, Method method, Clazz[] referencedClasses)107     private void visitParameters(Clazz   clazz,
108                                  Method  method,
109                                  Clazz[] referencedClasses)
110     {
111         String descriptor = method.getDescriptor(clazz);
112 
113         // Count the number of parameters and their total size.
114         int parameterCount = 0;
115         int parameterSize  = 0;
116 
117         int index = 1;
118 
119         loop: while (true)
120         {
121             char c = descriptor.charAt(index++);
122             switch (c)
123             {
124                 case ClassConstants.TYPE_LONG:
125                 case ClassConstants.TYPE_DOUBLE:
126                 {
127                     // Long and double primitive types.
128                     parameterSize++;
129                     break;
130                 }
131                 default:
132                 {
133                     // All other primitive types.
134                     break;
135                 }
136                 case ClassConstants.TYPE_CLASS_START:
137                 {
138                     // Class types.
139                     // Skip the class name.
140                     index = descriptor.indexOf(ClassConstants.TYPE_CLASS_END, index) + 1;
141                     break;
142                 }
143                 case ClassConstants.TYPE_ARRAY:
144                 {
145                     // Array types.
146                     // Skip all array characters.
147                     while ((c = descriptor.charAt(index++)) == ClassConstants.TYPE_ARRAY) {}
148 
149                     if (c == ClassConstants.TYPE_CLASS_START)
150                     {
151                         // Skip the class type.
152                         index = descriptor.indexOf(ClassConstants.TYPE_CLASS_END, index) + 1;
153                     }
154                     break;
155                 }
156                 case ClassConstants.METHOD_ARGUMENTS_CLOSE:
157                 {
158                     break loop;
159                 }
160             }
161 
162             parameterCount++;
163             parameterSize++;
164         }
165 
166         // Visit the parameters.
167         int parameterIndex      = 0;
168         int parameterOffset     = 0;
169         int referenceClassIndex = 0;
170 
171         index = 1;
172 
173         while (true)
174         {
175             int    newIndex          = index + 1;
176             int    thisParameterSize = 1;
177             Clazz  referencedClass   = null;
178 
179             char c = descriptor.charAt(index);
180             switch (c)
181             {
182                 case ClassConstants.TYPE_LONG:
183                 case ClassConstants.TYPE_DOUBLE:
184                 {
185                     // Long and double primitive types.
186                     thisParameterSize = 2;
187                     break;
188                 }
189                 default:
190                 {
191                     // All other primitive types.
192                     break;
193                 }
194                 case ClassConstants.TYPE_CLASS_START:
195                 {
196                     // Class types.
197                     // Skip the class name.
198                     newIndex = descriptor.indexOf(ClassConstants.TYPE_CLASS_END, newIndex) + 1;
199                     referencedClass = referencedClasses == null ? null :
200                         referencedClasses[referenceClassIndex++];
201                     break;
202                 }
203                 case ClassConstants.TYPE_ARRAY:
204                 {
205                     // Array types.
206                     // Skip all array characters.
207                     while ((c = descriptor.charAt(newIndex++)) == ClassConstants.TYPE_ARRAY) {}
208 
209                     if (c == ClassConstants.TYPE_CLASS_START)
210                     {
211                         // Skip the class type.
212                         newIndex = descriptor.indexOf(ClassConstants.TYPE_CLASS_END, newIndex) + 1;
213                         referencedClass = referencedClasses == null ? null :
214                             referencedClasses[referenceClassIndex++];
215                     }
216                     break;
217                 }
218                 case ClassConstants.METHOD_ARGUMENTS_CLOSE:
219                 {
220                     // End of the method parameters.
221                     return;
222                 }
223             }
224 
225             parameterVisitor.visitParameter(clazz,
226                                             method,
227                                             parameterIndex++,
228                                             parameterCount,
229                                             parameterOffset,
230                                             parameterSize,
231                                             descriptor.substring(index, newIndex),
232                                             referencedClass);
233 
234             // Continue with the next parameter.
235             index = newIndex;
236             parameterOffset += thisParameterSize;
237         }
238     }
239 }
240