@Nullable
  private static String parseClassSignature(
      final CharacterIterator signatureIterator, final List<String> convertedInterfaces)
      throws ClsFormatException {
    final String convertedSuper =
        SignatureParsing.parseTopLevelClassRefSignature(signatureIterator);
    while (signatureIterator.current() != CharacterIterator.DONE) {
      final String ifs = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator);
      if (ifs == null) throw new ClsFormatException();

      convertedInterfaces.add(ifs);
    }
    return convertedSuper;
  }
 @NotNull
 private static TypeInfo fieldType(String desc, String signature) {
   if (signature != null) {
     try {
       return TypeInfo.fromString(
           SignatureParsing.parseTypeString(new StringCharacterIterator(signature, 0)));
     } catch (ClsFormatException e) {
       return fieldTypeViaDescription(desc);
     }
   } else {
     return fieldTypeViaDescription(desc);
   }
 }
  @NotNull
  public static String parseMethodViaGenericSignature(
      @NotNull String signature,
      @NotNull PsiMethodStubImpl stub,
      @NotNull List<String> args,
      @Nullable List<String> throwables)
      throws ClsFormatException {
    StringCharacterIterator iterator = new StringCharacterIterator(signature);
    SignatureParsing.parseTypeParametersDeclaration(iterator, stub);

    if (iterator.current() != '(') {
      throw new ClsFormatException();
    }
    iterator.next();

    while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) {
      args.add(SignatureParsing.parseTypeString(iterator));
    }

    if (iterator.current() != ')') {
      throw new ClsFormatException();
    }
    iterator.next();

    String returnType = SignatureParsing.parseTypeString(iterator);

    while (iterator.current() == '^') {
      iterator.next();
      String exType = SignatureParsing.parseTypeString(iterator);
      if (throwables != null) {
        throwables.add(exType);
      }
    }

    return returnType;
  }
  @Override
  public void visit(
      int version,
      int access,
      String name,
      String signature,
      String superName,
      String[] interfaces) {
    String fqn = getFqn(name, myShortName);
    String shortName =
        myShortName != null && name.endsWith(myShortName)
            ? myShortName
            : PsiNameHelper.getShortClassName(fqn);

    int flags = myAccess | access;
    boolean isDeprecated = (flags & Opcodes.ACC_DEPRECATED) != 0;
    boolean isInterface = (flags & Opcodes.ACC_INTERFACE) != 0;
    boolean isEnum = (flags & Opcodes.ACC_ENUM) != 0;
    boolean isAnnotationType = (flags & Opcodes.ACC_ANNOTATION) != 0;

    byte stubFlags =
        PsiClassStubImpl.packFlags(
            isDeprecated, isInterface, isEnum, false, false, isAnnotationType, false, false);
    myResult =
        new PsiClassStubImpl(JavaStubElementTypes.CLASS, myParent, fqn, shortName, null, stubFlags);

    LanguageLevel languageLevel = ClsParsingUtil.getLanguageLevelByVersion(version);
    if (languageLevel == null) languageLevel = LanguageLevel.HIGHEST;
    ((PsiClassStubImpl) myResult).setLanguageLevel(languageLevel);

    myModList = new PsiModifierListStubImpl(myResult, packClassFlags(flags));

    CharacterIterator signatureIterator =
        signature != null ? new StringCharacterIterator(signature) : null;
    if (signatureIterator != null) {
      try {
        SignatureParsing.parseTypeParametersDeclaration(signatureIterator, myResult);
      } catch (ClsFormatException e) {
        signatureIterator = null;
      }
    } else {
      new PsiTypeParameterListStubImpl(myResult);
    }

    String convertedSuper;
    List<String> convertedInterfaces = new ArrayList<String>();
    if (signatureIterator == null) {
      convertedSuper = parseClassDescription(superName, interfaces, convertedInterfaces);
    } else {
      try {
        convertedSuper = parseClassSignature(signatureIterator, convertedInterfaces);
      } catch (ClsFormatException e) {
        new PsiTypeParameterListStubImpl(myResult);
        convertedSuper = parseClassDescription(superName, interfaces, convertedInterfaces);
      }
    }

    if (isInterface) {
      if (isAnnotationType) {
        convertedInterfaces.remove(JAVA_LANG_ANNOTATION_ANNOTATION);
      }
      newReferenceList(
          JavaStubElementTypes.EXTENDS_LIST,
          myResult,
          ArrayUtil.toStringArray(convertedInterfaces));
      newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult);
    } else {
      if (convertedSuper == null
          || JAVA_LANG_OBJECT.equals(convertedSuper)
          || isEnum
              && (JAVA_LANG_ENUM.equals(convertedSuper)
                  || (JAVA_LANG_ENUM + "<" + fqn + ">").equals(convertedSuper))) {
        newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult);
      } else {
        newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, convertedSuper);
      }
      newReferenceList(
          JavaStubElementTypes.IMPLEMENTS_LIST,
          myResult,
          ArrayUtil.toStringArray(convertedInterfaces));
    }
  }