public int generateType(StringBuilder buffer, PsiType type, PsiElement context, boolean generateLink, boolean useShortNames) {
    if (type instanceof PsiArrayType arrayType) {
      int len = generateType(buffer, arrayType.getDeepComponentType(), context, generateLink, useShortNames);

      int dimensions = arrayType.getArrayDimensions();
      PsiType curType = arrayType;
      for (int i = 0; i < dimensions; i++) {
        len += generateTypeAnnotations(buffer, curType, context, generateLink, true);
        if (i == dimensions - 1 && type instanceof PsiEllipsisType) {
          buffer.append("...");
          len += 3;
        }
        else {
          appendStyledSpan(buffer, getHighlightingManager().getBracketsAttributes(), "[]");
          len += 2;
        }
        curType = ((PsiArrayType)curType).getComponentType();
      }
      return len;
    }

    int typAnnoLength = generateTypeAnnotations(buffer, type, context, generateLink, false);

    if (type instanceof PsiPrimitiveType) {
      String text = type.getCanonicalText();
      appendStyledSpan(buffer, getHighlightingManager().getKeywordAttributes(), StringUtil.escapeXmlEntities(text));
      return typAnnoLength + text.length();
    }

    if (type instanceof PsiCapturedWildcardType) {
      type = ((PsiCapturedWildcardType)type).getWildcard();
    }

    if (type instanceof PsiWildcardType wt) {
      appendStyledSpan(buffer, getHighlightingManager().getOperationSignAttributes(), "?");
      PsiType bound = wt.getBound();
      if (bound != null) {
        String keyword = wt.isExtends() ? " extends " : " super ";
        appendStyledSpan(buffer, getHighlightingManager().getKeywordAttributes(), keyword);
        return typAnnoLength + generateType(buffer, bound, context, generateLink, useShortNames) + 1 + keyword.length();
      }
      else {
        return typAnnoLength + 1;
      }
    }

    if (type instanceof PsiClassType) {
      PsiClass psiClass = null;
      PsiSubstitutor psiSubst = null;
      try {
        PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics();
        psiClass = result.getElement();
        psiSubst = result.getSubstitutor();
      }
      catch (IndexNotReadyException e) {
        LOG.debug(e);
      }

      if (psiClass == null) {
        if (DumbService.isDumb(context.getProject())) {
          String text = ((PsiClassType)type).getClassName();
          buffer.append(StringUtil.escapeXmlEntities(text));
          return typAnnoLength + text.length();
        }
        String canonicalText = type.getCanonicalText();
        String text = getSpanForUnresolvedItem() + StringUtil.escapeXmlEntities(canonicalText) + "</span>";
        buffer.append(text);
        return typAnnoLength + canonicalText.length();
      }

      String qName = psiClass.getQualifiedName();

      if (qName == null || psiClass instanceof PsiTypeParameter) {
        String typeText = useShortNames ? type.getPresentableText() : type.getCanonicalText();
        appendStyledSpan(
          buffer, getHighlightingManager().getTypeParameterNameAttributes(), StringUtil.escapeXmlEntities(typeText));
        return typAnnoLength + typeText.length();
      }

      String name = useShortNames ? getClassNameWithOuterClasses(psiClass) : qName;

      int length = typAnnoLength;
      if (generateLink) {
        length += generateLink(buffer, name, null, context, false);
      }
      else {
        appendStyledSpan(buffer, getHighlightingManager().getClassDeclarationAttributes(psiClass), name);
        length += name.length();
      }

      if (psiClass.hasTypeParameters()) {
        StringBuilder subst = new StringBuilder();

        PsiTypeParameter[] params = psiClass.getTypeParameters();

        appendStyledSpan(subst, getHighlightingManager().getOperationSignAttributes(), LT);
        length += 1;
        boolean goodSubst = true;
        for (int i = 0; i < params.length; i++) {
          PsiType t = psiSubst.substitute(params[i]);

          if (t == null) {
            goodSubst = false;
            break;
          }

          length += generateType(subst, t, context, generateLink, useShortNames);

          if (i < params.length - 1) {
            appendStyledSpan(subst, getHighlightingManager().getCommaAttributes(), ", ");
            length += 2;
          }
        }

        appendStyledSpan(subst, getHighlightingManager().getOperationSignAttributes(), GT);
        length++;
        if (goodSubst) {
          buffer.append(subst);
        }
      }

      return length;
    }

    if (type instanceof PsiDisjunctionType || type instanceof PsiIntersectionType) {
      if (!generateLink) {
        String canonicalText = useShortNames ? type.getPresentableText() : type.getCanonicalText();
        buffer.append(StringUtil.escapeXmlEntities(canonicalText));
        return typAnnoLength + canonicalText.length();
      }
      else {
        String separator = type instanceof PsiDisjunctionType ? " | " : " & ";
        List<PsiType> componentTypes;
        if (type instanceof PsiIntersectionType) {
          componentTypes = Arrays.asList(((PsiIntersectionType)type).getConjuncts());
        }
        else {
          componentTypes = ((PsiDisjunctionType)type).getDisjunctions();
        }
        int length = typAnnoLength;
        for (PsiType psiType : componentTypes) {
          if (length > 0) {
            appendStyledSpan(buffer, getHighlightingManager().getOperationSignAttributes(), separator);
            length += 3;
          }
          length += generateType(buffer, psiType, context, true, useShortNames);
        }
        return length;
      }
    }

    return 0;
  }
public int generateType(StringBuilder buffer, PsiType type, PsiElement context, boolean generateLink, boolean useShortNames)