@Nullable
  public @Nls String build() {
    final PsiElement outerElement = myOriginalElement != null ? myOriginalElement.getParent() : null;

    PsiElement elementDefinition = resolveToDocStringOwner();
    final PsiElement propertyDefinition = buildFromProperty(elementDefinition, outerElement);
    boolean isProperty = false;
    if (propertyDefinition != null) {
      isProperty = true;
      elementDefinition = propertyDefinition;
    }

    if (elementDefinition instanceof PyDocStringOwner) {
      buildFromDocstring(((PyDocStringOwner)elementDefinition), isProperty);
    }
    else if (elementDefinition instanceof PyNamedParameter) {
      buildFromParameter((PyNamedParameter)elementDefinition);
    }
    else if (elementDefinition instanceof PyTypeParameter typeParameter) {
      buildFromTypeParameter(typeParameter);
    }
    else if (elementDefinition instanceof PyTypeAliasStatement typeAliasStatement) {
      buildFromTypeAliasStatement(typeAliasStatement);
    }

    final ASTNode node = elementDefinition.getNode();
    if (node != null) {
      final var elementType = node.getElementType();
      if (PythonDialectsTokenSetProvider.getInstance().getKeywordTokens().contains(elementType)) {
        buildForKeyword(getDocFileNameForKeywordElement(elementDefinition, elementType));
      }
    }

    if (!mySectionsMap.isEmpty()) {
      final List<String> canonicalSectionOrder =
        List.of(PyPsiBundle.message("QDOC.attributes"),
                PyPsiBundle.message("QDOC.params"),
                PyPsiBundle.message("QDOC.keyword.args"),
                PyPsiBundle.message("QDOC.returns"),
                PyPsiBundle.message("QDOC.raises"));

      final List<String> topSections = new ArrayList<>(canonicalSectionOrder);
      topSections.retainAll(mySectionsMap.keySet());

      final ArrayList<String> remainingSections = new ArrayList<>(mySectionsMap.keySet());
      remainingSections.removeAll(topSections);

      // FactoryMap's entrySet() returns pairs without particular order even for LinkedHashMap
      for (@NlsSafe String header : ContainerUtil.concat(topSections, remainingSections)) {
        mySections.append(HtmlChunk.tag("tr").children(
          HtmlChunk.text(header).wrapWith(SECTION_HEADER_CELL),
          mySectionsMap.get(header).wrapWith(SECTION_CONTENT_CELL)
        ));
      }
    }

    for (PythonDocumentationQuickInfoProvider point : PythonDocumentationQuickInfoProvider.EP_NAME.getExtensionList()) {
      final String info = point.getHoverAdditionalQuickInfo(myContext, outerElement);
      if (info != null) {
        myBody.br();
        myBody.append(info);
        break;
      }
    }


    if (myBody.isEmpty() && myContent.isEmpty()) {
      return null; // got nothing substantial to say!
    }
    else {
      final HtmlBuilder result = new HtmlBuilder();
      final HtmlBuilder definitionBuilder = new HtmlBuilder();

      if (!myProlog.isEmpty()) {
        definitionBuilder.append(myProlog);
      }
      if (!myBody.isEmpty()) {
        definitionBuilder.append(myBody.wrapWith(PRE_ELEMENT).wrapWith(DEFINITION_ELEMENT));
      }
      result.append(definitionBuilder);
      if (!myContent.isEmpty()) {
        result.append(myContent.wrapWith(CONTENT_ELEMENT));
      }
      if (!mySectionsMap.isEmpty()) {
        result.append(mySections.wrapWith(SECTIONS_TABLE));
      }
      return result.wrapWithHtmlBody().toString();
    }
  }
@Nullable
  public @Nls String build()