docs: public static @CheckForNull
      Type getType(String signature) {
          try {
              // ensure signature only has one type
              final Iterator<String> signatureIterator = new GenericSignatureParser("(" + signature + ")V")
                      .parameterSignatureIterator();
              signature = signatureIterator.next();
  
              if (signatureIterator.hasNext()) {
                  throw new IllegalArgumentException("the following signature does not contain exactly one type: " + signature);
              }
  
              int index = 0;
  
              if (signature.startsWith("L")) {
                  index = lastMatchedLeftAngleBracket(signature);
                  if (index < 0) {
                      return Type.getType(stripAngleBrackets(signature));
                  }
  
                  String typeParameters = signature.substring(index + 1, nextUnmatchedRightAngleBracket(signature, index + 1));
                  List<ReferenceType> parameters = GenericUtilities.getTypeParameters(typeParameters);
                  if (parameters == null) {
                      return null;
                  }
                  String baseType = removeMatchedAngleBrackets(signature.substring(1, index)).replace('.', '$');
                  return new GenericObjectType(baseType, parameters);
  
              } else if (signature.startsWith("T")) {
                  int i = signature.indexOf(';');
                  if (i > 0) {
                      String var = signature.substring(1, i);
                      if (var.indexOf('<') == -1) {
                          return new GenericObjectType(var);
                      }
                  }
                  // can't handle type variables
                  return null;
  
              } else if (signature.startsWith("[")) {
                  index++;
                  while (signature.charAt(index) == '[') {
                      index++;
                  }
                  Type componentType = getType(signature.substring(index));
                  if (componentType == null) {
                      return null;
                  }
                  return new ArrayType(componentType, index);
  
              } else if (signature.startsWith("*")) {
                  return new GenericObjectType("*");
  
              } else if (signature.startsWith("+") || signature.startsWith("-")) {
                  Type baseType = getType(signature.substring(1));
                  if (baseType == null) {
                      return null;
                  }
                  return new GenericObjectType(signature.substring(0, 1), (ReferenceType) baseType);
  
              } else {
                  // assert signature contains no generic information
                  return Type.getType(signature);
              }
          } catch (IllegalStateException e) {
              AnalysisContext.logError("Error parsing signature " + signature, e);
              return null;
          }
      }