jdk/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java
changeset 8852 c228cf346138
parent 8851 e630c590eb10
parent 8717 f75a1efb1412
child 8853 6aa795396cc8
child 9067 c0b85430843d
equal deleted inserted replaced
8851:e630c590eb10 8852:c228cf346138
     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 }