jodd-proxetta/src/main/java/jodd/asm7/signature/SignatureReader.java
private static int parseType(
      final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
    int offset = startOffset; // Current offset in the parsed signature.
    char currentChar = signature.charAt(offset++); // The signature character at 'offset'.

    // Switch based on the first character of the JavaTypeSignature, which indicates its kind.
    switch (currentChar) {
      case 'Z':
      case 'C':
      case 'B':
      case 'S':
      case 'I':
      case 'F':
      case 'J':
      case 'D':
      case 'V':
        // Case of a BaseType or a VoidDescriptor.
        signatureVisitor.visitBaseType(currentChar);
        return offset;

      case '[':
        // Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
        return parseType(signature, offset, signatureVisitor.visitArrayType());

      case 'T':
        // Case of TypeVariableSignature, an identifier between 'T' and ';'.
        int endOffset = signature.indexOf(';', offset);
        signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
        return endOffset + 1;

      case 'L':
        // Case of a ClassTypeSignature, which ends with ';'.
        // These signatures have a main class type followed by zero or more inner class types
        // (separated by '.'). Each can have type arguments, inside '<' and '>'.
        int start = offset; // The start offset of the currently parsed main or inner class name.
        boolean visited = false; // Whether the currently parsed class name has been visited.
        boolean inner = false; // Whether we are currently parsing an inner class type.
        // Parses the signature, one character at a time.
        while (true) {
          currentChar = signature.charAt(offset++);
          if (currentChar == '.' || currentChar == ';') {
            // If a '.' or ';' is encountered, this means we have fully parsed the main class name
            // or an inner class name. This name may already have been visited it is was followed by
            // type arguments between '<' and '>'. If not, we need to visit it here.
            if (!visited) {
              String name = signature.substring(start, offset - 1);
              if (inner) {
                signatureVisitor.visitInnerClassType(name);
              } else {
                signatureVisitor.visitClassType(name);
              }
            }
            // If we reached the end of the ClassTypeSignature return, otherwise start the parsing
            // of a new class name, which is necessarily an inner class name.
            if (currentChar == ';') {
              signatureVisitor.visitEnd();
              break;
            }
            start = offset;
            visited = false;
            inner = true;
          } else if (currentChar == '<') {
            // If a '<' is encountered, this means we have fully parsed the main class name or an
            // inner class name, and that we now need to parse TypeArguments. First, we need to
            // visit the parsed class name.
            String name = signature.substring(start, offset - 1);
            if (inner) {
              signatureVisitor.visitInnerClassType(name);
            } else {
              signatureVisitor.visitClassType(name);
            }
            visited = true;
            // Now, parse the TypeArgument(s), one at a time.
            while ((currentChar = signature.charAt(offset)) != '>') {
              switch (currentChar) {
                case '*':
                  // Unbounded TypeArgument.
                  ++offset;
                  signatureVisitor.visitTypeArgument();
                  break;
                case '+':
                case '-':
                  // Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
                  offset =
                      parseType(
                          signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
                  break;
                default:
                  // Instanceof TypeArgument. The '=' is implicit.
                  offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
                  break;
              }
            }
          }
        }
        return offset;

      default:
        throw new IllegalArgumentException();
    }
  }
private static int parseType(
      final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
    int offset = startOffset; // Current offset in the parsed signature.
    char currentChar = signature.charAt(offset++); // The signature character at 'offset'.

    // Switch based on the first character of the JavaTypeSignature, which indicates its kind.
    switch (currentChar) {
      case 'Z':
      case 'C':
      case 'B':
      case 'S':
      case 'I':
      case 'F':
      case 'J':
      case 'D':
      case 'V':
        // Case of a BaseType or a VoidDescriptor.
        signatureVisitor.visitBaseType(currentChar);
        return offset;

      case '[':
        // Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
        return parseType(signature, offset, signatureVisitor.visitArrayType());

      case 'T':
        // Case of TypeVariableSignature, an identifier between 'T' and ';'.
        int endOffset = signature.indexOf(';', offset);
        signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
        return endOffset + 1;

      case 'L':
        // Case of a ClassTypeSignature, which ends with ';'.
        // These signatures have a main class type followed by zero or more inner class types
        // (separated by '.'). Each can have type arguments, inside '<' and '>'.
        int start = offset; // The start offset of the currently parsed main or inner class name.
        boolean visited = false; // Whether the currently parsed class name has been visited.
        boolean inner = false; // Whether we are currently parsing an inner class type.
        // Parses the signature, one character at a time.
        while (true) {
          currentChar = signature.charAt(offset++);
          if (currentChar == '.' || currentChar == ';') {
            // If a '.' or ';' is encountered, this means we have fully parsed the main class name
            // or an inner class name. This name may already have been visited it is was followed by
            // type arguments between '<' and '>'. If not, we need to visit it here.
            if (!visited) {
              String name = signature.substring(start, offset - 1);
              if (inner) {
                signatureVisitor.visitInnerClassType(name);
              } else {
                signatureVisitor.visitClassType(name);
              }
            }
            // If we reached the end of the ClassTypeSignature return, otherwise start the parsing
            // of a new class name, which is necessarily an inner class name.
            if (currentChar == ';') {
              signatureVisitor.visitEnd();
              break;
            }
            start = offset;
            visited = false;
            inner = true;
          } else if (currentChar == '<') {
            // If a '<' is encountered, this means we have fully parsed the main class name or an
            // inner class name, and that we now need to parse TypeArguments. First, we need to
            // visit the parsed class name.
            String name = signature.substring(start, offset - 1);
            if (inner) {
              signatureVisitor.visitInnerClassType(name);
            } else {
              signatureVisitor.visitClassType(name);
            }
            visited = true;
            // Now, parse the TypeArgument(s), one at a time.
            while ((currentChar = signature.charAt(offset)) != '>') {
              switch (currentChar) {
                case '*':
                  // Unbounded TypeArgument.
                  ++offset;
                  signatureVisitor.visitTypeArgument();
                  break;
                case '+':
                case '-':
                  // Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
                  offset =
                      parseType(
                          signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
                  break;
                default:
                  // Instanceof TypeArgument. The '=' is implicit.
                  offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
                  break;
              }
            }
          }
        }
        return offset;

      default:
        throw new IllegalArgumentException();
    }
  }
Parses a JavaTypeSignature and makes the given visitor visit it.

@param signature a string containing the signature that must be parsed.
@param startOffset index of the first character of the signature to parsed.
@param signatureVisitor the visitor that must visit this signature.
@return the index of the first character after the parsed signature.