1 /* |
|
2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 package com.sun.classanalyzer; |
|
25 |
|
26 import com.sun.tools.classfile.*; |
|
27 import com.sun.tools.classfile.Type.*; |
|
28 import com.sun.tools.classfile.Descriptor.InvalidDescriptor; |
|
29 import static com.sun.tools.classfile.AccessFlags.*; |
|
30 |
|
31 import java.io.BufferedInputStream; |
|
32 import java.io.File; |
|
33 import java.io.FileInputStream; |
|
34 import java.io.IOException; |
|
35 import java.io.InputStream; |
|
36 import java.util.List; |
|
37 import java.util.Set; |
|
38 import java.util.TreeSet; |
|
39 |
|
40 /** |
|
41 * |
|
42 * @author Mandy Chung |
|
43 */ |
|
44 public class ClassFileParser { |
|
45 |
|
46 final Klass this_klass; |
|
47 final ClassFile classfile; |
|
48 final ConstantPoolParser constantPoolParser; |
|
49 final AnnotationParser annotationParser; |
|
50 final CodeAttributeParser codeAttributeParser; |
|
51 private final boolean buildDeps; |
|
52 |
|
53 protected ClassFileParser(InputStream in, long size, boolean buildDeps) throws IOException { |
|
54 try { |
|
55 this.classfile = ClassFile.read(in); |
|
56 this.this_klass = getKlass(this.classfile); |
|
57 this.buildDeps = buildDeps; |
|
58 this.constantPoolParser = new ConstantPoolParser(this); |
|
59 this.annotationParser = new AnnotationParser(this); |
|
60 this.codeAttributeParser = new CodeAttributeParser(this); |
|
61 } catch (ConstantPoolException ex) { |
|
62 throw new RuntimeException(ex); |
|
63 } |
|
64 } |
|
65 |
|
66 private Klass getKlass(ClassFile cf) throws ConstantPoolException { |
|
67 Klass k = Klass.getKlass(cf.getName()); |
|
68 k.setAccessFlags(cf.access_flags.flags); |
|
69 k.setFileSize(cf.byteLength()); |
|
70 return k; |
|
71 } |
|
72 |
|
73 public static ClassFileParser newParser(InputStream in, long size, boolean buildDeps) throws IOException { |
|
74 return new ClassFileParser(in, size, buildDeps); |
|
75 } |
|
76 |
|
77 public static ClassFileParser newParser(String classPathname, boolean buildDeps) throws IOException { |
|
78 return newParser(new File(classPathname), buildDeps); |
|
79 } |
|
80 |
|
81 public static ClassFileParser newParser(File f, boolean buildDeps) throws IOException { |
|
82 BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); |
|
83 try { |
|
84 return newParser(in, f.length(), buildDeps); |
|
85 } finally { |
|
86 in.close(); |
|
87 } |
|
88 } |
|
89 |
|
90 public void parseDependency(boolean publicAPIs) throws IOException { |
|
91 if (publicAPIs && !classfile.access_flags.is(ACC_PUBLIC)) { |
|
92 // process public APIs only |
|
93 return; |
|
94 } |
|
95 |
|
96 parseClassInfo(); |
|
97 if (!publicAPIs) { |
|
98 // parse all references in the classfile |
|
99 constantPoolParser.parseDependency(); |
|
100 } |
|
101 parseMethods(publicAPIs); |
|
102 parseFields(publicAPIs); |
|
103 } |
|
104 |
|
105 void parseClassInfo() throws IOException { |
|
106 ConstantPool cpool = classfile.constant_pool; |
|
107 try { |
|
108 Signature_attribute sigAttr = (Signature_attribute) classfile.attributes.get(Attribute.Signature); |
|
109 if (sigAttr == null) { |
|
110 // use info from class file header |
|
111 if (classfile.isClass() && classfile.super_class != 0) { |
|
112 String sn = classfile.getSuperclassName(); |
|
113 addExtends(sn); |
|
114 } |
|
115 for (int i = 0; i < classfile.interfaces.length; i++) { |
|
116 String interf = classfile.getInterfaceName(i); |
|
117 if (classfile.isClass()) { |
|
118 addImplements(interf); |
|
119 } else { |
|
120 addExtends(interf); |
|
121 } |
|
122 } |
|
123 } else { |
|
124 Type t = sigAttr.getParsedSignature().getType(cpool); |
|
125 // The signature parser cannot disambiguate between a |
|
126 // FieldType and a ClassSignatureType that only contains a superclass type. |
|
127 if (t instanceof Type.ClassSigType) { |
|
128 Type.ClassSigType cst = Type.ClassSigType.class.cast(t); |
|
129 if (cst.superclassType != null) { |
|
130 for (Klass k : getKlass(cst.superclassType)) { |
|
131 addExtends(k); |
|
132 } |
|
133 } |
|
134 if (cst.superinterfaceTypes != null) { |
|
135 for (Type t1 : cst.superinterfaceTypes) { |
|
136 for (Klass k : getKlass(t1)) { |
|
137 addImplements(k); |
|
138 } |
|
139 } |
|
140 } |
|
141 } else { |
|
142 for (Klass k : getKlass(t)) { |
|
143 addExtends(k); |
|
144 } |
|
145 } |
|
146 } |
|
147 // parse attributes |
|
148 annotationParser.parseAttributes(classfile.attributes); |
|
149 } catch (ConstantPoolException ex) { |
|
150 throw new RuntimeException(ex); |
|
151 } |
|
152 } |
|
153 |
|
154 private void parseFields(boolean publicAPIs) throws IOException { |
|
155 ConstantPool cpool = classfile.constant_pool; |
|
156 for (Field f : classfile.fields) { |
|
157 try { |
|
158 AccessFlags flags = f.access_flags; |
|
159 if (publicAPIs && !flags.is(ACC_PUBLIC) && !flags.is(ACC_PROTECTED)) { |
|
160 continue; |
|
161 } |
|
162 String fieldname = f.getName(cpool); |
|
163 Signature_attribute sigAttr = (Signature_attribute) f.attributes.get(Attribute.Signature); |
|
164 |
|
165 if (sigAttr == null) { |
|
166 Set<Klass> types = parseDescriptor(f.descriptor); |
|
167 String info = getFlag(flags) + " " + f.descriptor.getFieldType(cpool) + " " + fieldname; |
|
168 addFieldTypes(types, info, flags); |
|
169 } else { |
|
170 Type t = sigAttr.getParsedSignature().getType(cpool); |
|
171 String info = getFlag(flags) + " " + t + " " + fieldname; |
|
172 addFieldTypes(getKlass(t), info, flags); |
|
173 } |
|
174 // parse attributes |
|
175 annotationParser.parseAttributes(f.attributes); |
|
176 } catch (ConstantPoolException ex) { |
|
177 throw new RuntimeException(ex); |
|
178 } catch (InvalidDescriptor ex) { |
|
179 throw new RuntimeException(ex); |
|
180 } |
|
181 } |
|
182 } |
|
183 |
|
184 private void parseMethods(boolean publicAPIs) { |
|
185 for (Method m : classfile.methods) { |
|
186 if (publicAPIs && !m.access_flags.is(ACC_PUBLIC) && !m.access_flags.is(ACC_PROTECTED)) { |
|
187 // only interest in the API level |
|
188 return; |
|
189 } |
|
190 |
|
191 parseMethod(m); |
|
192 } |
|
193 } |
|
194 |
|
195 String checkClassName(String classname) { |
|
196 int i = 0; |
|
197 while (i < classname.length()) { |
|
198 switch (classname.charAt(i)) { |
|
199 case 'Z': |
|
200 case 'B': |
|
201 case 'C': |
|
202 case 'S': |
|
203 case 'I': |
|
204 case 'J': |
|
205 case 'F': |
|
206 case 'D': |
|
207 return ""; |
|
208 case 'L': |
|
209 if (!classname.endsWith(";")) { |
|
210 throw new RuntimeException("Invalid classname " + classname); |
|
211 } |
|
212 return classname.substring(i + 1, classname.length() - 1); |
|
213 case '[': |
|
214 i++; |
|
215 break; |
|
216 default: |
|
217 if (classname.endsWith(";")) { |
|
218 throw new RuntimeException("Invalid classname " + classname); |
|
219 } |
|
220 return classname; |
|
221 |
|
222 } |
|
223 } |
|
224 throw new RuntimeException("Invalid classname " + classname); |
|
225 } |
|
226 |
|
227 private void addExtends(String classname) throws IOException { |
|
228 if (!buildDeps) { |
|
229 return; |
|
230 } |
|
231 |
|
232 addExtends(Klass.getKlass(classname)); |
|
233 } |
|
234 |
|
235 private void addExtends(Klass k) { |
|
236 if (!buildDeps) { |
|
237 return; |
|
238 } |
|
239 |
|
240 ResolutionInfo resInfo = ResolutionInfo.resolvedExtends(this_klass, k); |
|
241 resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); |
|
242 this_klass.addDep(k, resInfo); |
|
243 k.addReferrer(this_klass, resInfo); |
|
244 } |
|
245 |
|
246 private void addImplements(String classname) throws IOException { |
|
247 if (!buildDeps) { |
|
248 return; |
|
249 } |
|
250 |
|
251 addImplements(Klass.getKlass(classname)); |
|
252 } |
|
253 |
|
254 private void addImplements(Klass k) { |
|
255 if (!buildDeps) { |
|
256 return; |
|
257 } |
|
258 |
|
259 ResolutionInfo resInfo = ResolutionInfo.resolvedImplements(this_klass, k); |
|
260 resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); |
|
261 |
|
262 this_klass.addDep(k, resInfo); |
|
263 |
|
264 k.addReferrer(this_klass, resInfo); |
|
265 } |
|
266 |
|
267 private Set<Klass> getKlass(Type type) throws IOException { |
|
268 Set<Klass> refTypes = new TreeSet<Klass>(); |
|
269 if (!buildDeps) { |
|
270 return refTypes; |
|
271 } |
|
272 |
|
273 type.accept(typevisitor, refTypes); |
|
274 return refTypes; |
|
275 } |
|
276 private Type.Visitor<Void, Set<Klass>> typevisitor = new Type.Visitor<Void, Set<Klass>>() { |
|
277 |
|
278 public Void visitSimpleType(SimpleType type, Set<Klass> klasses) { |
|
279 // nop |
|
280 return null; |
|
281 } |
|
282 |
|
283 public Void visitArrayType(ArrayType type, Set<Klass> klasses) { |
|
284 try { |
|
285 klasses.addAll(getKlass(type.elemType)); |
|
286 } catch (IOException ex) { |
|
287 throw new RuntimeException(ex); |
|
288 } |
|
289 return null; |
|
290 |
|
291 } |
|
292 |
|
293 public Void visitMethodType(MethodType type, Set<Klass> klasses) { |
|
294 throw new InternalError("Unexpected type " + type); |
|
295 } |
|
296 |
|
297 public Void visitClassSigType(ClassSigType type, Set<Klass> klasses) { |
|
298 try { |
|
299 if (type.superclassType != null) { |
|
300 klasses.addAll(getKlass(type.superclassType)); |
|
301 } |
|
302 if (type.superinterfaceTypes != null) { |
|
303 for (Type t : type.superinterfaceTypes) { |
|
304 klasses.addAll(getKlass(t)); |
|
305 } |
|
306 } |
|
307 if (type.typeParamTypes != null) { |
|
308 for (Type t : type.typeParamTypes) { |
|
309 klasses.addAll(getKlass(t)); |
|
310 } |
|
311 } |
|
312 } catch (IOException ex) { |
|
313 throw new RuntimeException(ex); |
|
314 } |
|
315 return null; |
|
316 } |
|
317 |
|
318 public Void visitClassType(ClassType type, Set<Klass> klasses) { |
|
319 klasses.add(Klass.getKlass(type.getBinaryName())); |
|
320 if (type.typeArgs != null) { |
|
321 for (Type t : type.typeArgs) { |
|
322 try { |
|
323 klasses.addAll(getKlass(t)); |
|
324 } catch (IOException ex) { |
|
325 throw new RuntimeException(ex); |
|
326 } |
|
327 } |
|
328 } |
|
329 return null; |
|
330 |
|
331 } |
|
332 |
|
333 public Void visitTypeParamType(TypeParamType type, Set<Klass> klasses) { |
|
334 try { |
|
335 if (type.classBound != null) { |
|
336 klasses.addAll(getKlass(type.classBound)); |
|
337 } |
|
338 if (type.interfaceBounds != null) { |
|
339 for (Type t : type.interfaceBounds) { |
|
340 klasses.addAll(getKlass(t)); |
|
341 } |
|
342 } |
|
343 |
|
344 } catch (IOException ex) { |
|
345 throw new RuntimeException(ex); |
|
346 } |
|
347 |
|
348 return null; |
|
349 |
|
350 } |
|
351 |
|
352 public Void visitWildcardType(WildcardType type, Set<Klass> klasses) { |
|
353 if (type.boundType != null) { |
|
354 try { |
|
355 klasses.addAll(getKlass(type.boundType)); |
|
356 } catch (IOException ex) { |
|
357 throw new RuntimeException(ex); |
|
358 } |
|
359 } |
|
360 return null; |
|
361 |
|
362 } |
|
363 }; |
|
364 |
|
365 private void printMethod(Method m) { |
|
366 try { |
|
367 System.out.println("parsing " + m.getName(classfile.constant_pool) + "(" + |
|
368 m.descriptor.getParameterTypes(classfile.constant_pool) + ") return type " + |
|
369 m.descriptor.getReturnType(classfile.constant_pool)); |
|
370 |
|
371 } catch (ConstantPoolException ex) { |
|
372 } catch (InvalidDescriptor ex) { |
|
373 } |
|
374 } |
|
375 |
|
376 private static StringBuilder appendWord(StringBuilder sb, String word) { |
|
377 if (sb.length() > 0) { |
|
378 sb.append(" "); |
|
379 } |
|
380 sb.append(word); |
|
381 return sb; |
|
382 } |
|
383 |
|
384 private static String getFlag(AccessFlags flags) { |
|
385 StringBuilder modifier = new StringBuilder(); |
|
386 if (flags.is(ACC_PUBLIC)) { |
|
387 modifier.append("public"); |
|
388 } |
|
389 if (flags.is(ACC_PRIVATE)) { |
|
390 modifier.append("private"); |
|
391 } |
|
392 if (flags.is(ACC_PROTECTED)) { |
|
393 modifier.append("protected"); |
|
394 } |
|
395 if (flags.is(ACC_STATIC)) { |
|
396 appendWord(modifier, "static"); |
|
397 } |
|
398 if (flags.is(ACC_FINAL)) { |
|
399 appendWord(modifier, "final"); |
|
400 } |
|
401 if (flags.is(ACC_SYNCHRONIZED)) { |
|
402 // return "synchronized"; |
|
403 } |
|
404 if (flags.is(0x80)) { |
|
405 // return (t == Type.Field ? "transient" : null); |
|
406 // return "transient"; |
|
407 } |
|
408 if (flags.is(ACC_VOLATILE)) { |
|
409 // return "volatile"; |
|
410 } |
|
411 if (flags.is(ACC_NATIVE)) { |
|
412 // return "native"; |
|
413 } |
|
414 if (flags.is(ACC_ABSTRACT)) { |
|
415 appendWord(modifier, "abstract"); |
|
416 } |
|
417 if (flags.is(ACC_STRICT)) { |
|
418 // return "strictfp"; |
|
419 } |
|
420 if (flags.is(ACC_MODULE)) { |
|
421 appendWord(modifier, "module"); |
|
422 } |
|
423 return modifier.toString(); |
|
424 } |
|
425 |
|
426 private Klass.Method toKlassMethod(Method m, Descriptor d) { |
|
427 try { |
|
428 ConstantPool cpool = classfile.constant_pool; |
|
429 String methodname = m.getName(cpool); |
|
430 StringBuilder sb = new StringBuilder(); |
|
431 sb.append(getFlag(m.access_flags)); |
|
432 if (methodname.equals("<init>")) { |
|
433 String s = this_klass.getBasename() + d.getParameterTypes(cpool); |
|
434 appendWord(sb, s); |
|
435 } else if (methodname.equals("<clinit>")) { |
|
436 // <clinit> |
|
437 appendWord(sb, methodname); |
|
438 } else { |
|
439 String s = d.getReturnType(cpool) + " " + methodname + d.getParameterTypes(cpool); |
|
440 appendWord(sb, s); |
|
441 } |
|
442 String signature = sb.toString().replace('/', '.'); |
|
443 return this_klass.getMethod(methodname, signature); |
|
444 } catch (ConstantPoolException ex) { |
|
445 throw new RuntimeException(ex); |
|
446 } catch (InvalidDescriptor ex) { |
|
447 throw new RuntimeException(ex); |
|
448 } |
|
449 } |
|
450 |
|
451 Klass.Method parseMethod(Method m) { |
|
452 AccessFlags flags = m.access_flags; |
|
453 Descriptor d; |
|
454 List<? extends Type> methodExceptions = null; |
|
455 try { |
|
456 ConstantPool cpool = classfile.constant_pool; |
|
457 Klass.Method kmethod; |
|
458 Signature_attribute sigAttr = (Signature_attribute) m.attributes.get(Attribute.Signature); |
|
459 if (sigAttr == null) { |
|
460 d = m.descriptor; |
|
461 Set<Klass> types = parseDescriptor(d); |
|
462 |
|
463 kmethod = toKlassMethod(m, d); |
|
464 addMethodTypes(types, kmethod, flags); |
|
465 } else { |
|
466 Type.MethodType methodType; |
|
467 Signature methodSig = sigAttr.getParsedSignature(); |
|
468 d = methodSig; |
|
469 try { |
|
470 kmethod = toKlassMethod(m, d); |
|
471 methodType = (Type.MethodType) methodSig.getType(cpool); |
|
472 addMethodTypes(getKlass(methodType.returnType), kmethod, flags); |
|
473 if (methodType.paramTypes != null) { |
|
474 for (Type t : methodType.paramTypes) { |
|
475 addMethodTypes(getKlass(t), kmethod, flags); |
|
476 } |
|
477 } |
|
478 if (methodType.typeParamTypes != null) { |
|
479 for (Type t : methodType.typeParamTypes) { |
|
480 addMethodTypes(getKlass(t), kmethod, flags); |
|
481 } |
|
482 } |
|
483 |
|
484 methodExceptions = methodType.throwsTypes; |
|
485 if (methodExceptions != null) { |
|
486 if (methodExceptions.size() == 0) { |
|
487 methodExceptions = null; |
|
488 } else { |
|
489 for (Type t : methodExceptions) { |
|
490 addCheckedExceptionTypes(getKlass(t), kmethod, flags); |
|
491 } |
|
492 } |
|
493 } |
|
494 } catch (ConstantPoolException e) { |
|
495 throw new RuntimeException(e); |
|
496 } |
|
497 } |
|
498 |
|
499 Attribute e_attr = m.attributes.get(Attribute.Exceptions); |
|
500 if (e_attr != null && methodExceptions == null) { |
|
501 // if there are generic exceptions, there must be erased exceptions |
|
502 if (e_attr instanceof Exceptions_attribute) { |
|
503 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; |
|
504 for (int i = 0; i < exceptions.number_of_exceptions; i++) { |
|
505 String classname = checkClassName(exceptions.getException(i, classfile.constant_pool)); |
|
506 if (classname.length() > 0 && buildDeps) { |
|
507 Klass to = Klass.getKlass(classname); |
|
508 ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, kmethod); |
|
509 resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); |
|
510 |
|
511 this_klass.addDep(to, resInfo); |
|
512 to.addReferrer(this_klass, resInfo); |
|
513 } |
|
514 } |
|
515 } else { |
|
516 throw new RuntimeException("Invalid attribute: " + e_attr); |
|
517 } |
|
518 } |
|
519 |
|
520 Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); |
|
521 if (c_attr != null) { |
|
522 codeAttributeParser.parse(c_attr, kmethod); |
|
523 } |
|
524 kmethod.isAbstract = classfile.access_flags.is(ACC_ABSTRACT); |
|
525 kmethod.setCodeLength(m.byteLength()); |
|
526 |
|
527 // parse annotation attributes |
|
528 annotationParser.parseAttributes(m.attributes, kmethod); |
|
529 return kmethod; |
|
530 } catch (ConstantPoolException ex) { |
|
531 throw new RuntimeException(ex); |
|
532 } catch (IOException ex) { |
|
533 throw new RuntimeException(ex); |
|
534 } |
|
535 } |
|
536 |
|
537 private void addFieldTypes(Set<Klass> types, String info, AccessFlags flags) { |
|
538 if (types.isEmpty() || !buildDeps) { |
|
539 return; |
|
540 } |
|
541 |
|
542 for (Klass to : types) { |
|
543 ResolutionInfo resInfo = ResolutionInfo.resolvedField(this_klass, to, info); |
|
544 resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); |
|
545 |
|
546 this_klass.addDep(to, resInfo); |
|
547 to.addReferrer(this_klass, resInfo); |
|
548 } |
|
549 } |
|
550 |
|
551 private void addReferencedTypes(Method m, Descriptor d, AccessFlags flags) { |
|
552 Set<Klass> types = parseDescriptor(d); |
|
553 |
|
554 Klass.Method method = toKlassMethod(m, d); |
|
555 addMethodTypes(types, method, flags); |
|
556 } |
|
557 |
|
558 private void addMethodTypes(Set<Klass> types, Klass.Method method, AccessFlags flags) { |
|
559 if (types.isEmpty() || !buildDeps) { |
|
560 return; |
|
561 } |
|
562 for (Klass to : types) { |
|
563 ResolutionInfo resInfo = ResolutionInfo.resolvedMethodSignature(this_klass, to, method); |
|
564 resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); |
|
565 |
|
566 this_klass.addDep(to, resInfo); |
|
567 to.addReferrer(this_klass, resInfo); |
|
568 } |
|
569 } |
|
570 |
|
571 private void addCheckedExceptionTypes(Set<Klass> types, Klass.Method method, AccessFlags flags) { |
|
572 if (types.isEmpty() || !buildDeps) { |
|
573 return; |
|
574 } |
|
575 for (Klass to : types) { |
|
576 ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, method); |
|
577 resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); |
|
578 |
|
579 this_klass.addDep(to, resInfo); |
|
580 to.addReferrer(this_klass, resInfo); |
|
581 } |
|
582 } |
|
583 |
|
584 private Set<Klass> parseDescriptor(Descriptor d) { |
|
585 Set<Klass> types = new TreeSet<Klass>(); |
|
586 try { |
|
587 String desc = d.getValue(classfile.constant_pool); |
|
588 int p = 0; |
|
589 while (p < desc.length()) { |
|
590 String type; |
|
591 char ch; |
|
592 switch (ch = desc.charAt(p++)) { |
|
593 case '(': |
|
594 case ')': |
|
595 case '[': |
|
596 case 'B': |
|
597 case 'C': |
|
598 case 'D': |
|
599 case 'F': |
|
600 case 'I': |
|
601 case 'J': |
|
602 case 'S': |
|
603 case 'Z': |
|
604 case 'V': |
|
605 continue; |
|
606 case 'L': |
|
607 int sep = desc.indexOf(';', p); |
|
608 if (sep == -1) { |
|
609 throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); |
|
610 } |
|
611 type = checkClassName(desc.substring(p, sep)); |
|
612 p = sep + 1; |
|
613 break; |
|
614 default: |
|
615 throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); |
|
616 } |
|
617 |
|
618 if (!type.isEmpty() && buildDeps) { |
|
619 Klass to = Klass.getKlass(type); |
|
620 types.add(to); |
|
621 |
|
622 } |
|
623 } |
|
624 } catch (ConstantPoolException ex) { |
|
625 throw new RuntimeException(ex); |
|
626 } |
|
627 return types; |
|
628 } |
|
629 } |
|