@Nullable
  private TypeInfo parseTypeInfo(PsiBuilder builder, int flags, boolean badWildcard) {
    if (builder.getTokenType() == null) return null;

    TypeInfo typeInfo = new TypeInfo();

    PsiBuilder.Marker type = builder.mark();
    PsiBuilder.Marker anno = myParser.getDeclarationParser().parseAnnotations(builder);

    IElementType tokenType = builder.getTokenType();
    if (tokenType == JavaTokenType.IDENTIFIER &&
        isSet(flags, VAR_TYPE) &&
        builder.lookAhead(1) != JavaTokenType.DOT &&
        builder.lookAhead(1) != JavaTokenType.COLON &&
        PsiKeyword.VAR.equals(builder.getTokenText()) &&
        JavaFeature.LVTI.isSufficient(getLanguageLevel(builder))) {
      builder.remapCurrentToken(tokenType = JavaTokenType.VAR_KEYWORD);
    }
    else if (tokenType == JavaTokenType.VAR_KEYWORD && !isSet(flags, VAR_TYPE)) {
      builder.remapCurrentToken(tokenType = JavaTokenType.IDENTIFIER);
    }

    if (expect(builder, BasicElementTypes.BASIC_PRIMITIVE_TYPE_BIT_SET)) {
      typeInfo.isPrimitive = true;
    }
    else if ((isSet(flags, WILDCARD) || badWildcard) && (tokenType == JavaTokenType.QUEST)) {
      builder.advanceLexer();
      completeWildcardType(builder, isSet(flags, WILDCARD), type);
      typeInfo.marker = type;
      return typeInfo;
    }
    else if (tokenType == JavaTokenType.IDENTIFIER) {
      parseJavaCodeReference(builder, isSet(flags, EAT_LAST_DOT), true, false, false, false, isSet(flags, DIAMONDS), typeInfo);
    }
    else if (tokenType == JavaTokenType.VAR_KEYWORD) {
      builder.advanceLexer();
      type.done(myJavaElementTypeContainer.TYPE);
      typeInfo.marker = type;
      return typeInfo;
    }
    else if (isSet(flags, DIAMONDS) && tokenType == JavaTokenType.GT) {
      if (anno == null) {
        emptyElement(builder, myJavaElementTypeContainer.DIAMOND_TYPE);
      }
      else {
        error(builder, JavaPsiBundle.message("expected.identifier"));
        typeInfo.hasErrors = true;
      }
      type.done(myJavaElementTypeContainer.TYPE);
      typeInfo.marker = type;
      return typeInfo;
    }
    else {
      type.drop();
      if (anno != null && isSet(flags, INCOMPLETE_ANNO)) {
        error(builder, JavaPsiBundle.message("expected.type"));
        typeInfo.marker = anno;
        typeInfo.hasErrors = true;
        return typeInfo;
      }
      return null;
    }

    type.done(myJavaElementTypeContainer.TYPE);
    while (true) {
      myParser.getDeclarationParser().parseAnnotations(builder);

      PsiBuilder.Marker bracket = builder.mark();
      if (!expect(builder, JavaTokenType.LBRACKET)) {
        bracket.drop();
        break;
      }
      if (!expect(builder, JavaTokenType.RBRACKET)) {
        bracket.rollbackTo();
        break;
      }
      bracket.drop();
      typeInfo.isArray = true;
    }

    if (isSet(flags, ELLIPSIS) && builder.getTokenType() == JavaTokenType.ELLIPSIS) {
      builder.advanceLexer();
      typeInfo.isVarArg = true;
    }

    if (typeInfo.isVarArg || typeInfo.isArray) {
      type = type.precede();
      type.done(myJavaElementTypeContainer.TYPE);
    }

    typeInfo.marker = type;
    return typeInfo;
  }
@Nullable
  private TypeInfo parseTypeInfo(PsiBuilder builder, int flags, boolean badWildcard)