content: /*
   * Javassist, a Java-bytecode translator toolkit.
   * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
   *
   * The contents of this file are subject to the Mozilla Public License Version
   * 1.1 (the "License"); you may not use this file except in compliance with
   * the License.  Alternatively, the contents of this file may be used under
   * the terms of the GNU Lesser General Public License Version 2.1 or later,
   * or the Apache License Version 2.0.
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the specific language governing rights and limitations under the
   * License.
   */
  
  package copy.javassist.bytecode;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * <code>Signature_attribute</code>.
   */
  public class SignatureAttribute {
  
      static private class Cursor {
          int position = 0;
  
          int indexOf(String s, int ch) throws BadBytecode {
              int i = s.indexOf(ch, position);
              if (i < 0)
                  throw error(s);
              position = i + 1;
              return i;
          }
      }
  
      /**
       * Class signature.
       */
      public static class ClassSignature {
          TypeParameter[] params;
          ClassType superClass;
          ClassType[] interfaces;
  
          /**
           * Constructs a class signature.
           *
           * @param params     type parameters.
           * @param superClass the super class.
           * @param interfaces the interface types.
           */
          public ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces) {
              this.params = params == null ? new TypeParameter[0] : params;
              this.superClass = superClass == null ? ClassType.OBJECT : superClass;
              this.interfaces = interfaces == null ? new ClassType[0] : interfaces;
          }
  
          /**
           * Constructs a class signature.
           *
           * @param p type parameters.
           */
          public ClassSignature(TypeParameter[] p) {
              this(p, null, null);
          }
  
          /**
           * Returns the type parameters.
           *
           * @return a zero-length array if the type parameters are not specified.
           */
          public TypeParameter[] getParameters() {
              return params;
          }
  
          /**
           * Returns the super class.
           */
          public ClassType getSuperClass() {
              return superClass;
          }
  
          /**
           * Returns the super interfaces.
           *
           * @return a zero-length array if the super interfaces are not specified.
           */
          public ClassType[] getInterfaces() {
              return interfaces;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              StringBuffer sbuf = new StringBuffer();
  
              TypeParameter.toString(sbuf, params);
              sbuf.append(" extends ").append(superClass);
              if (interfaces.length > 0) {
                  sbuf.append(" implements ");
                  Type.toString(sbuf, interfaces);
              }
  
              return sbuf.toString();
          }
  
          /**
           * Returns the encoded string representing the method type signature.
           */
          public String encode() {
              StringBuffer sbuf = new StringBuffer();
              if (params.length > 0) {
                  sbuf.append('<');
                  for (int i = 0; i < params.length; i++)
                      params[i].encode(sbuf);
  
                  sbuf.append('>');
              }
  
              superClass.encode(sbuf);
              for (int i = 0; i < interfaces.length; i++)
                  interfaces[i].encode(sbuf);
  
              return sbuf.toString();
          }
      }
  
      /**
       * Method type signature.
       */
      public static class MethodSignature {
          TypeParameter[] typeParams;
          Type[] params;
          Type retType;
          ObjectType[] exceptions;
  
          /**
           * Constructs a method type signature.  Any parameter can be null
           * to represent <code>void</code> or nothing.
           *
           * @param tp     type parameters.
           * @param params parameter types.
           * @param ret    a return type, or null if the return type is <code>void</code>.
           * @param ex     exception types.
           */
          public MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex) {
              typeParams = tp == null ? new TypeParameter[0] : tp;
              this.params = params == null ? new Type[0] : params;
              retType = ret == null ? new BaseType("void") : ret;
              exceptions = ex == null ? new ObjectType[0] : ex;
          }
  
          /**
           * Returns the formal type parameters.
           *
           * @return a zero-length array if the type parameters are not specified.
           */
          public TypeParameter[] getTypeParameters() {
              return typeParams;
          }
  
          /**
           * Returns the types of the formal parameters.
           *
           * @return a zero-length array if no formal parameter is taken.
           */
          public Type[] getParameterTypes() {
              return params;
          }
  
          /**
           * Returns the type of the returned value.
           */
          public Type getReturnType() {
              return retType;
          }
  
          /**
           * Returns the types of the exceptions that may be thrown.
           *
           * @return a zero-length array if exceptions are never thrown or
           * the exception types are not parameterized types or type variables.
           */
          public ObjectType[] getExceptionTypes() {
              return exceptions;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              StringBuffer sbuf = new StringBuffer();
  
              TypeParameter.toString(sbuf, typeParams);
              sbuf.append(" (");
              Type.toString(sbuf, params);
              sbuf.append(") ");
              sbuf.append(retType);
              if (exceptions.length > 0) {
                  sbuf.append(" throws ");
                  Type.toString(sbuf, exceptions);
              }
  
              return sbuf.toString();
          }
  
          /**
           * Returns the encoded string representing the method type signature.
           */
          public String encode() {
              StringBuffer sbuf = new StringBuffer();
              if (typeParams.length > 0) {
                  sbuf.append('<');
                  for (int i = 0; i < typeParams.length; i++)
                      typeParams[i].encode(sbuf);
  
                  sbuf.append('>');
              }
  
              sbuf.append('(');
              for (int i = 0; i < params.length; i++)
                  params[i].encode(sbuf);
  
              sbuf.append(')');
              retType.encode(sbuf);
              if (exceptions.length > 0)
                  for (int i = 0; i < exceptions.length; i++) {
                      sbuf.append('^');
                      exceptions[i].encode(sbuf);
                  }
  
              return sbuf.toString();
          }
      }
  
      /**
       * Formal type parameters.
       *
       * @see TypeArgument
       */
      public static class TypeParameter {
          String name;
          ObjectType superClass;
          ObjectType[] superInterfaces;
  
          TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) {
              name = sig.substring(nb, ne);
              superClass = sc;
              superInterfaces = si;
          }
  
          /**
           * Constructs a <code>TypeParameter</code> representing a type parametre
           * like <code>&lt;T extends ... &gt;</code>.
           *
           * @param name            parameter name.
           * @param superClass      an upper bound class-type (or null).
           * @param superInterfaces an upper bound interface-type (or null).
           */
          public TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces) {
              this.name = name;
              this.superClass = superClass;
              if (superInterfaces == null)
                  this.superInterfaces = new ObjectType[0];
              else
                  this.superInterfaces = superInterfaces;
          }
  
          /**
           * Constructs a <code>TypeParameter</code> representing a type parameter
           * like <code>&lt;T&gt;</code>.
           *
           * @param name parameter name.
           */
          public TypeParameter(String name) {
              this(name, null, null);
          }
  
          /**
           * Returns the name of the type parameter.
           */
          public String getName() {
              return name;
          }
  
          /**
           * Returns the class bound of this parameter.
           */
          public ObjectType getClassBound() {
              return superClass;
          }
  
          /**
           * Returns the interface bound of this parameter.
           *
           * @return a zero-length array if the interface bound is not specified.
           */
          public ObjectType[] getInterfaceBound() {
              return superInterfaces;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              StringBuffer sbuf = new StringBuffer(getName());
              if (superClass != null)
                  sbuf.append(" extends ").append(superClass.toString());
  
              int len = superInterfaces.length;
              if (len > 0) {
                  for (int i = 0; i < len; i++) {
                      if (i > 0 || superClass != null)
                          sbuf.append(" & ");
                      else
                          sbuf.append(" extends ");
  
                      sbuf.append(superInterfaces[i].toString());
                  }
              }
  
              return sbuf.toString();
          }
  
          static void toString(StringBuffer sbuf, TypeParameter[] tp) {
              sbuf.append('<');
              for (int i = 0; i < tp.length; i++) {
                  if (i > 0)
                      sbuf.append(", ");
  
                  sbuf.append(tp[i]);
              }
  
              sbuf.append('>');
          }
  
          void encode(StringBuffer sb) {
              sb.append(name);
              if (superClass == null)
                  sb.append(":Ljava/lang/Object;");
              else {
                  sb.append(':');
                  superClass.encode(sb);
              }
  
              for (int i = 0; i < superInterfaces.length; i++) {
                  sb.append(':');
                  superInterfaces[i].encode(sb);
              }
          }
      }
  
      /**
       * Type argument.
       *
       * @see TypeParameter
       */
      public static class TypeArgument {
          ObjectType arg;
          char wildcard;
  
          TypeArgument(ObjectType a, char w) {
              arg = a;
              wildcard = w;
          }
  
          /**
           * Constructs a <code>TypeArgument</code>.
           * A type argument is <code>&lt;String&gt;</code>, <code>&lt;int[]&gt;</code>,
           * or a type variable <code>&lt;T&gt;</code>, etc.
           *
           * @param t a class type, an array type, or a type variable.
           */
          public TypeArgument(ObjectType t) {
              this(t, ' ');
          }
  
          /**
           * Constructs a <code>TypeArgument</code> representing <code>&lt;?&gt;</code>.
           */
          public TypeArgument() {
              this(null, '*');
          }
  
          /**
           * A factory method constructing a <code>TypeArgument</code> with an upper bound.
           * It represents <code>&lt;? extends ... &gt;</code>
           *
           * @param t an upper bound type.
           */
          public static TypeArgument subclassOf(ObjectType t) {
              return new TypeArgument(t, '+');
          }
  
          /**
           * A factory method constructing a <code>TypeArgument</code> with an lower bound.
           * It represents <code>&lt;? super ... &gt;</code>
           *
           * @param t an lower bbound type.
           */
          public static TypeArgument superOf(ObjectType t) {
              return new TypeArgument(t, '-');
          }
  
          /**
           * Returns the kind of this type argument.
           *
           * @return <code>' '</code> (not-wildcard), <code>'*'</code> (wildcard), <code>'+'</code> (wildcard with
           * upper bound), or <code>'-'</code> (wildcard with lower bound).
           */
          public char getKind() {
              return wildcard;
          }
  
          /**
           * Returns true if this type argument is a wildcard type
           * such as <code>?</code>, <code>? extends String</code>, or <code>? super Integer</code>.
           */
          public boolean isWildcard() {
              return wildcard != ' ';
          }
  
          /**
           * Returns the type represented by this argument
           * if the argument is not a wildcard type.  Otherwise, this method
           * returns the upper bound (if the kind is '+'),
           * the lower bound (if the kind is '-'), or null (if the upper or lower
           * bound is not specified).
           */
          public ObjectType getType() {
              return arg;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              if (wildcard == '*')
                  return "?";
  
              String type = arg.toString();
              if (wildcard == ' ')
                  return type;
              else if (wildcard == '+')
                  return "? extends " + type;
              else
                  return "? super " + type;
          }
  
          static void encode(StringBuffer sb, TypeArgument[] args) {
              sb.append('<');
              for (int i = 0; i < args.length; i++) {
                  TypeArgument ta = args[i];
                  if (ta.isWildcard())
                      sb.append(ta.wildcard);
  
                  if (ta.getType() != null)
                      ta.getType().encode(sb);
              }
  
              sb.append('>');
          }
      }
  
      /**
       * Primitive types and object types.
       */
      public static abstract class Type {
          abstract void encode(StringBuffer sb);
  
          static void toString(StringBuffer sbuf, Type[] ts) {
              for (int i = 0; i < ts.length; i++) {
                  if (i > 0)
                      sbuf.append(", ");
  
                  sbuf.append(ts[i]);
              }
          }
  
          /**
           * Returns the type name in the JVM internal style.
           * For example, if the type is a nested class {@code foo.Bar.Baz},
           * then {@code foo.Bar$Baz} is returned.
           */
          public String jvmTypeName() {
              return toString();
          }
      }
  
      /**
       * Primitive types.
       */
      public static class BaseType extends Type {
          char descriptor;
  
          BaseType(char c) {
              descriptor = c;
          }
  
          /**
           * Constructs a <code>BaseType</code>.
           *
           * @param typeName <code>void</code>, <code>int</code>, ...
           */
          public BaseType(String typeName) {
              this(typeName.charAt(0));
          }
  
          @Override
          void encode(StringBuffer sb) {
              sb.append(descriptor);
          }
  
          // javassist-3.30.2-GA中增加的方法
  
          /**
           * Returns the descriptor representing this primitive type.
           *
           * @see javassist.bytecode.Descriptor
           */
          public char getDescriptor() {
              return descriptor;
          }
      }
  
      /**
       * Class types, array types, and type variables.
       * This class is also used for representing a field type.
       */
      public static abstract class ObjectType extends Type {
          /**
           * Returns the encoded string representing the object type signature.
           */
          public String encode() {
              StringBuffer sb = new StringBuffer();
              encode(sb);
              return sb.toString();
          }
      }
  
      /**
       * Class types.
       */
      public static class ClassType extends ObjectType {
          String name;
          TypeArgument[] arguments;
  
          static ClassType make(String s, int b, int e,
                                TypeArgument[] targs, ClassType parent) {
              if (parent == null)
                  return new ClassType(s, b, e, targs);
              return new NestedClassType(s, b, e, targs, parent);
          }
  
          ClassType(String signature, int begin, int end, TypeArgument[] targs) {
              name = signature.substring(begin, end).replace('/', '.');
              arguments = targs;
          }
  
          /**
           * A class type representing <code>java.lang.Object</code>.
           */
          public static ClassType OBJECT = new ClassType("java.lang.Object", null);
  
          /**
           * Constructs a <code>ClassType</code>.  It represents
           * the name of a non-nested class.
           *
           * @param className a fully qualified class name.
           * @param args      type arguments or null.
           */
          public ClassType(String className, TypeArgument[] args) {
              name = className;
              arguments = args;
          }
  
          /**
           * Constructs a <code>ClassType</code>.  It represents
           * the name of a non-nested class.
           *
           * @param className a fully qualified class name.
           */
          public ClassType(String className) {
              this(className, null);
          }
  
          /**
           * Returns the class name.
           */
          public String getName() {
              return name;
          }
  
          /**
           * Returns the type arguments.
           *
           * @return null if no type arguments are given to this class.
           */
          public TypeArgument[] getTypeArguments() {
              return arguments;
          }
  
          /**
           * If this class is a member of another class, returns the
           * class in which this class is declared.
           *
           * @return null if this class is not a member of another class.
           */
          public ClassType getDeclaringClass() {
              return null;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              StringBuffer sbuf = new StringBuffer();
              ClassType parent = getDeclaringClass();
              if (parent != null)
                  sbuf.append(parent.toString()).append('.');
  
              return toString2(sbuf);
          }
  
          private String toString2(StringBuffer sbuf) {
              sbuf.append(name);
              if (arguments != null) {
                  sbuf.append('<');
                  int n = arguments.length;
                  for (int i = 0; i < n; i++) {
                      if (i > 0)
                          sbuf.append(", ");
  
                      sbuf.append(arguments[i].toString());
                  }
  
                  sbuf.append('>');
              }
  
              return sbuf.toString();
          }
  
          /**
           * Returns the type name in the JVM internal style.
           * For example, if the type is a nested class {@code foo.Bar.Baz},
           * then {@code foo.Bar$Baz} is returned.
           */
          @Override
          public String jvmTypeName() {
              StringBuffer sbuf = new StringBuffer();
              ClassType parent = getDeclaringClass();
              if (parent != null)
                  sbuf.append(parent.jvmTypeName()).append('$');
  
              return toString2(sbuf);
          }
  
          @Override
          void encode(StringBuffer sb) {
              sb.append('L');
              encode2(sb);
              sb.append(';');
          }
  
          void encode2(StringBuffer sb) {
              ClassType parent = getDeclaringClass();
              if (parent != null) {
                  parent.encode2(sb);
                  sb.append('$');
              }
  
              sb.append(name.replace('.', '/'));
              if (arguments != null)
                  TypeArgument.encode(sb, arguments);
          }
      }
  
      /**
       * Nested class types.
       */
      public static class NestedClassType extends ClassType {
          ClassType parent;
  
          NestedClassType(String s, int b, int e,
                          TypeArgument[] targs, ClassType p) {
              super(s, b, e, targs);
              parent = p;
          }
  
          /**
           * Constructs a <code>NestedClassType</code>.
           *
           * @param parent    the class surrounding this class type.
           * @param className a simple class name.  It does not include
           *                  a package name or a parent's class name.
           * @param args      type parameters or null.
           */
          public NestedClassType(ClassType parent, String className, TypeArgument[] args) {
              super(className, args);
              this.parent = parent;
          }
  
          /**
           * Returns the class that declares this nested class.
           * This nested class is a member of that declaring class.
           */
          @Override
          public ClassType getDeclaringClass() {
              return parent;
          }
      }
  
      /**
       * Array types.
       */
      public static class ArrayType extends ObjectType {
          int dim;
          Type componentType;
  
          /**
           * Constructs an <code>ArrayType</code>.
           *
           * @param d    dimension.
           * @param comp the component type.
           */
          public ArrayType(int d, Type comp) {
              dim = d;
              componentType = comp;
          }
  
          /**
           * Returns the dimension of the array.
           */
          public int getDimension() {
              return dim;
          }
  
          /**
           * Returns the component type.
           */
          public Type getComponentType() {
              return componentType;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              StringBuffer sbuf = new StringBuffer(componentType.toString());
              for (int i = 0; i < dim; i++)
                  sbuf.append("[]");
  
              return sbuf.toString();
          }
  
          @Override
          void encode(StringBuffer sb) {
              for (int i = 0; i < dim; i++)
                  sb.append('[');
  
              componentType.encode(sb);
          }
      }
  
      /**
       * Type variables.
       */
      public static class TypeVariable extends ObjectType {
          String name;
  
          TypeVariable(String sig, int begin, int end) {
              name = sig.substring(begin, end);
          }
  
          /**
           * Constructs a <code>TypeVariable</code>.
           *
           * @param name the name of a type variable.
           */
          public TypeVariable(String name) {
              this.name = name;
          }
  
          /**
           * Returns the variable name.
           */
          public String getName() {
              return name;
          }
  
          /**
           * Returns the string representation.
           */
          @Override
          public String toString() {
              return name;
          }
  
          @Override
          void encode(StringBuffer sb) {
              sb.append('T').append(name).append(';');
          }
      }
  
      /**
       * Parses the given signature string as a class signature.
       *
       * @param sig the signature obtained from the <code>SignatureAttribute</code>
       *            of a <code>ClassFile</code>.
       * @return a tree-like data structure representing a class signature.  It provides
       * convenient accessor methods.
       * @throws javassist.bytecode.BadBytecode thrown when a syntactical error is found.
       * @since 3.5
       */
      public static ClassSignature toClassSignature(String sig) throws BadBytecode {
          try {
              return parseSig(sig);
          } catch (IndexOutOfBoundsException e) {
              throw error(sig);
          }
      }
  
      private static ClassSignature parseSig(String sig)
              throws BadBytecode, IndexOutOfBoundsException {
          Cursor cur = new Cursor();
          TypeParameter[] tp = parseTypeParams(sig, cur);
          ClassType superClass = parseClassType(sig, cur);
          int sigLen = sig.length();
          List<ClassType> ifArray = new ArrayList<ClassType>();
          while (cur.position < sigLen && sig.charAt(cur.position) == 'L')
              ifArray.add(parseClassType(sig, cur));
  
          ClassType[] ifs
                  = ifArray.toArray(new ClassType[ifArray.size()]);
          return new ClassSignature(tp, superClass, ifs);
      }
  
      /**
       * Parses the given signature string as a method type signature.
       *
       * @param sig the signature obtained from the <code>SignatureAttribute</code>
       *            of a <code>MethodInfo</code>.
       * @return @return  a tree-like data structure representing a method signature.  It provides
       * convenient accessor methods.
       * @throws BadBytecode thrown when a syntactical error is found.
       * @see #getSignature()
       * @since 3.5
       */
      public static MethodSignature toMethodSignature(String sig) throws BadBytecode {
          try {
              return parseMethodSig(sig);
          } catch (IndexOutOfBoundsException e) {
              throw error(sig);
          }
      }
  
      /**
       * Parses the given signature string as a field type signature.
       *
       * @param sig the signature string obtained from the <code>SignatureAttribute</code>
       *            of a <code>FieldInfo</code>.
       * @return the field type signature.
       * @throws BadBytecode thrown when a syntactical error is found.
       * @see #getSignature()
       * @since 3.5
       */
      public static ObjectType toFieldSignature(String sig) throws BadBytecode {
          try {
              return parseObjectType(sig, new Cursor(), false);
          } catch (IndexOutOfBoundsException e) {
              throw error(sig);
          }
      }
  
      private static MethodSignature parseMethodSig(String sig)
              throws BadBytecode {
          Cursor cur = new Cursor();
          TypeParameter[] tp = parseTypeParams(sig, cur);
          if (sig.charAt(cur.position++) != '(')
              throw error(sig);
  
          List<Type> params = new ArrayList<Type>();
          while (sig.charAt(cur.position) != ')') {
              Type t = parseType(sig, cur);
              params.add(t);
          }
  
          cur.position++;
          Type ret = parseType(sig, cur);
          int sigLen = sig.length();
          List<ObjectType> exceptions = new ArrayList<ObjectType>();
          while (cur.position < sigLen && sig.charAt(cur.position) == '^') {
              cur.position++;
              ObjectType t = parseObjectType(sig, cur, false);
              if (t instanceof ArrayType)
                  throw error(sig);
  
              exceptions.add(t);
          }
  
          Type[] p = params.toArray(new Type[params.size()]);
          ObjectType[] ex = exceptions.toArray(new ObjectType[exceptions.size()]);
          return new MethodSignature(tp, p, ret, ex);
      }
  
      private static TypeParameter[] parseTypeParams(String sig, Cursor cur)
              throws BadBytecode {
          List<TypeParameter> typeParam = new ArrayList<TypeParameter>();
          if (sig.charAt(cur.position) == '<') {
              cur.position++;
              while (sig.charAt(cur.position) != '>') {
                  int nameBegin = cur.position;
                  int nameEnd = cur.indexOf(sig, ':');
                  ObjectType classBound = parseObjectType(sig, cur, true);
                  List<ObjectType> ifBound = new ArrayList<ObjectType>();
                  while (sig.charAt(cur.position) == ':') {
                      cur.position++;
                      ObjectType t = parseObjectType(sig, cur, false);
                      ifBound.add(t);
                  }
  
                  TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd,
                          classBound, ifBound.toArray(new ObjectType[ifBound.size()]));
                  typeParam.add(p);
              }
  
              cur.position++;
          }
  
          return typeParam.toArray(new TypeParameter[typeParam.size()]);
      }
  
      private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow)
              throws BadBytecode {
          int i;
          int begin = c.position;
          switch (sig.charAt(begin)) {
              case 'L':
                  return parseClassType2(sig, c, null);
              case 'T':
                  i = c.indexOf(sig, ';');
                  return new TypeVariable(sig, begin + 1, i);
              case '[':
                  return parseArray(sig, c);
              default:
                  if (dontThrow)
                      return null;
                  throw error(sig);
          }
      }
  
      private static ClassType parseClassType(String sig, Cursor c)
              throws BadBytecode {
          if (sig.charAt(c.position) == 'L')
              return parseClassType2(sig, c, null);
          throw error(sig);
      }
  
      private static ClassType parseClassType2(String sig, Cursor c, ClassType parent)
              throws BadBytecode {
          int start = ++c.position;
          char t;
          do {
              t = sig.charAt(c.position++);
          } while (t != '$' && t != '<' && t != ';');
          int end = c.position - 1;
          TypeArgument[] targs;
          if (t == '<') {
              targs = parseTypeArgs(sig, c);
              t = sig.charAt(c.position++);
          } else
              targs = null;
  
          ClassType thisClass = ClassType.make(sig, start, end, targs, parent);
          if (t == '$' || t == '.') {
              c.position--;
              return parseClassType2(sig, c, thisClass);
          }
          return thisClass;
      }
  
      private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode {
          List<TypeArgument> args = new ArrayList<TypeArgument>();
          char t;
          while ((t = sig.charAt(c.position++)) != '>') {
              TypeArgument ta;
              if (t == '*')
                  ta = new TypeArgument(null, '*');
              else {
                  if (t != '+' && t != '-') {
                      t = ' ';
                      c.position--;
                  }
  
                  ta = new TypeArgument(parseObjectType(sig, c, false), t);
              }
  
              args.add(ta);
          }
  
          return args.toArray(new TypeArgument[args.size()]);
      }
  
      private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode {
          int dim = 1;
          while (sig.charAt(++c.position) == '[')
              dim++;
  
          return new ArrayType(dim, parseType(sig, c));
      }
  
      private static Type parseType(String sig, Cursor c) throws BadBytecode {
          Type t = parseObjectType(sig, c, true);
          if (t == null)
              t = new BaseType(sig.charAt(c.position++));
  
          return t;
      }
  
      private static BadBytecode error(String sig) {
          return new BadBytecode("bad signature: " + sig);
      }
  }
  