private static @Nullable StringBuilder addRequiredAttributes(XmlElementDescriptor descriptor,
                                                               @Nullable XmlTag tag,
                                                               Template template,
                                                               PsiFile containingFile) {

    Set<String> notRequiredAttributes = Collections.emptySet();

    if (tag instanceof HtmlTag) {
      final InspectionProfile profile = InspectionProjectProfileManager.getInstance(tag.getProject()).getCurrentProfile();
      XmlEntitiesInspection inspection = (XmlEntitiesInspection)profile.getUnwrappedTool(
        XmlEntitiesInspection.REQUIRED_ATTRIBUTES_SHORT_NAME, tag);

      if (inspection != null) {
        StringTokenizer tokenizer = new StringTokenizer(inspection.getAdditionalEntries());
        notRequiredAttributes = new HashSet<>();

        while(tokenizer.hasMoreElements()) notRequiredAttributes.add(tokenizer.nextToken());
      }
    }

    XmlAttributeDescriptor[] attributes;
    if (ApplicationManager.getApplication().isHeadlessEnvironment() || ApplicationManager.getApplication().isUnitTestMode()) {
      attributes = descriptor.getAttributesDescriptors(tag);
    }
    else {
      // Try not to block EDT for a long time
      attributes = ProgressIndicatorUtils.withTimeout(500, () -> descriptor.getAttributesDescriptors(tag));
    }

    if (attributes == null || attributes.length == 0) {
      return null;
    }

    StringBuilder indirectRequiredAttrs = null;

    if (WebEditorOptions.getInstance().isAutomaticallyInsertRequiredAttributes()) {
      final XmlExtension extension = XmlExtension.getExtension(containingFile);

      for (XmlAttributeDescriptor attributeDecl : attributes) {
        String attributeName = attributeDecl.getName(tag);

        boolean shouldBeInserted = extension.shouldBeInserted(attributeDecl);
        if (!shouldBeInserted) continue;

        AttributeValuePresentation presenter =
          extension.getAttributeValuePresentation(tag, attributeName, XmlEditUtil.getAttributeQuote(containingFile));
        boolean htmlCode = HtmlUtil.hasHtml(containingFile) || HtmlUtil.supportsXmlTypedHandlers(containingFile);
        if (tag == null || tag.getAttributeValue(attributeName) == null) {
          if (!notRequiredAttributes.contains(attributeName)) {
            if (!extension.isIndirectSyntax(attributeDecl)) {
              template.addTextSegment(" " + attributeName + "=" + presenter.getPrefix());
              template.addVariable(presenter.showAutoPopup() ? new MacroCallNode(new CompleteMacro()) : new EmptyExpression(), true);
              template.addTextSegment(presenter.getPostfix());
            }
            else {
              if (indirectRequiredAttrs == null) indirectRequiredAttrs = new StringBuilder();
              indirectRequiredAttrs.append("\n<jsp:attribute name=\"").append(attributeName).append("\"></jsp:attribute>\n");
            }
          }
        }
        else if (attributeDecl.isFixed() && attributeDecl.getDefaultValue() != null && !htmlCode) {
          template.addTextSegment(" " + attributeName + "=" +
                                  presenter.getPrefix() + attributeDecl.getDefaultValue() + presenter.getPostfix());
        }
      }
    }
    return indirectRequiredAttrs;
  }
private static @Nullable StringBuilder addRequiredAttributes(XmlElementDescriptor descriptor,
                                                               @Nullable XmlTag tag,
                                                               Template template,
                                                               PsiFile containingFile)