View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.dcd.asm;
5   
6   import java.lang.reflect.Array;
7   import java.util.ArrayList;
8   import java.util.List;
9   import org.objectweb.asm.Opcodes;
10  import org.objectweb.asm.signature.SignatureVisitor;
11  import net.sourceforge.pmd.dcd.ClassLoaderUtil;
12  
13  public class TypeSignatureVisitor extends SignatureVisitor {
14  
15      private static final boolean TRACE = false;
16  
17      private static final int NO_TYPE = 0;
18  
19      private static final int FIELD_TYPE = 1;
20  
21      private static final int RETURN_TYPE = 2;
22  
23      private static final int PARAMETER_TYPE = 3;
24  
25      // The type of the current Type
26      private int typeType;
27  
28      // The current Type identified.
29      private Class<?> type;
30  
31      // The number of dimensions on an array for the current Type.
32      private int arrayDimensions = 0;
33  
34      // Completed Field Type is stored here
35      private Class<?> fieldType;
36  
37      // Completed Return Type is stored here
38      private Class<?> returnType;
39  
40      // Completed Parameter Types are stored here
41      private List<Class<?>> parameterTypes = new ArrayList<>(0);
42  
43      private final PrintVisitor p;
44  
45      protected void println(String s) {
46          p.println(s);
47      }
48  
49      protected void printlnIndent(String s) {
50          p.printlnIndent(s);
51      }
52  
53      public TypeSignatureVisitor() {
54          super(Opcodes.ASM5);
55          p = new PrintVisitor();
56          init();
57      }
58  
59      public TypeSignatureVisitor(PrintVisitor parent) {
60          super(Opcodes.ASM5);
61          p = new PrintVisitor(parent);
62          init();
63      }
64  
65      public void init() {
66          typeType = FIELD_TYPE;
67          type = null;
68          arrayDimensions = 0;
69          parameterTypes.clear();
70      }
71  
72      public Class<?> getFieldType() {
73          popType();
74          if (fieldType == null) {
75              throw new RuntimeException();
76          }
77          return fieldType;
78      }
79  
80      public Class<?> getMethodReturnType() {
81          popType();
82          if (returnType == null) {
83              throw new RuntimeException();
84          }
85          return returnType;
86      }
87  
88      public Class<?>[] getMethodParameterTypes() {
89          popType();
90          if (parameterTypes == null) {
91              throw new RuntimeException();
92          }
93          if (parameterTypes != null) {
94              return parameterTypes.toArray(new Class<?>[parameterTypes.size()]);
95          } else {
96              return null;
97          }
98      }
99  
100     private void pushType(int type) {
101         this.typeType = type;
102     }
103 
104     private void popType() {
105         switch (typeType) {
106             case NO_TYPE:
107                 break;
108             case FIELD_TYPE:
109                 fieldType = getType();
110                 break;
111             case RETURN_TYPE:
112                 returnType = getType();
113                 break;
114             case PARAMETER_TYPE:
115                 parameterTypes.add(getType());
116                 break;
117             default:
118                 throw new RuntimeException("Unknown type type: " + typeType);
119         }
120 
121         typeType = NO_TYPE;
122         type = null;
123         arrayDimensions = 0;
124     }
125 
126     private Class<?> getType() {
127         Class<?> type = null;
128         if (this.type != null) {
129             type = this.type;
130             for (int i = 0; i < arrayDimensions; i++) {
131                 // Is there another way to get Array Classes?
132                 Object array = Array.newInstance(type, 0);
133                 type = array.getClass();
134             }
135         }
136         return type;
137     }
138 
139     public SignatureVisitor visitArrayType() {
140         if (TRACE) {
141             println("visitArrayType:");
142         }
143         arrayDimensions++;
144         return this;
145     }
146 
147     public void visitBaseType(char descriptor) {
148         if (TRACE) {
149             println("visitBaseType:");
150             printlnIndent("descriptor: " + descriptor);
151         }
152         switch (descriptor) {
153             case 'B':
154                 type = Byte.TYPE;
155                 break;
156             case 'C':
157                 type = Character.TYPE;
158                 break;
159             case 'D':
160                 type = Double.TYPE;
161                 break;
162             case 'F':
163                 type = Float.TYPE;
164                 break;
165             case 'I':
166                 type = Integer.TYPE;
167                 break;
168             case 'J':
169                 type = Long.TYPE;
170                 break;
171             case 'S':
172                 type = Short.TYPE;
173                 break;
174             case 'Z':
175                 type = Boolean.TYPE;
176                 break;
177             case 'V':
178                 type = Void.TYPE;
179                 break;
180             default:
181                 throw new RuntimeException("Unknown baseType descriptor: " + descriptor);
182         }
183     }
184 
185     public SignatureVisitor visitClassBound() {
186         if (TRACE) {
187             println("visitClassBound:");
188         }
189         return this;
190     }
191 
192     public void visitClassType(String name) {
193         if (TRACE) {
194             println("visitClassType:");
195             printlnIndent("name: " + name);
196         }
197         name = ClassLoaderUtil.fromInternalForm(name);
198         this.type = ClassLoaderUtil.getClass(name);
199     }
200 
201     public void visitEnd() {
202         if (TRACE) {
203             println("visitEnd:");
204         }
205         popType();
206     }
207 
208     public SignatureVisitor visitExceptionType() {
209         if (TRACE) {
210             println("visitExceptionType:");
211         }
212         return this;
213     }
214 
215     public void visitFormalTypeParameter(String name) {
216         if (TRACE) {
217             println("visitFormalTypeParameter:");
218             printlnIndent("name: " + name);
219         }
220     }
221 
222     public void visitInnerClassType(String name) {
223         if (TRACE) {
224             println("visitInnerClassType:");
225             printlnIndent("name: " + name);
226         }
227     }
228 
229     public SignatureVisitor visitInterface() {
230         if (TRACE) {
231             println("visitInterface:");
232         }
233         return this;
234     }
235 
236     public SignatureVisitor visitInterfaceBound() {
237         if (TRACE) {
238             println("visitInterfaceBound:");
239         }
240         return this;
241     }
242 
243     public SignatureVisitor visitParameterType() {
244         if (TRACE) {
245             println("visitParameterType:");
246         }
247         popType();
248         pushType(PARAMETER_TYPE);
249         return this;
250     }
251 
252     public SignatureVisitor visitReturnType() {
253         if (TRACE) {
254             println("visitReturnType:");
255         }
256         popType();
257         pushType(RETURN_TYPE);
258         return this;
259     }
260 
261     public SignatureVisitor visitSuperclass() {
262         if (TRACE) {
263             println("visitSuperclass:");
264         }
265         return this;
266     }
267 
268     public void visitTypeArgument() {
269         if (TRACE) {
270             println("visitTypeArgument:");
271         }
272     }
273 
274     public SignatureVisitor visitTypeArgument(char wildcard) {
275         if (TRACE) {
276             println("visitTypeArgument:");
277             printlnIndent("wildcard: " + wildcard);
278         }
279         return this;
280     }
281 
282     public void visitTypeVariable(String name) {
283         if (TRACE) {
284             println("visitTypeVariable:");
285             printlnIndent("name: " + name);
286         }
287     }
288 }