private void buildFromAttributeDoc() {
    PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
    assert cls != null;
    String type =
        PyUtil.isInstanceAttribute((PyExpression) myElement)
            ? "Instance attribute "
            : "Class attribute ";
    myProlog
        .addItem(type)
        .addWith(TagBold, $().addWith(TagCode, $(((PyTargetExpression) myElement).getName())))
        .addItem(" of class ")
        .addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName())))
        .addItem(BR);

    final String docString = ((PyTargetExpression) myElement).getDocStringValue();
    if (docString != null) {
      addFormattedDocString(myElement, docString, myBody, myEpilog);
    }
  }
  private void buildFromParameter(
      @NotNull final TypeEvalContext context,
      @Nullable final PsiElement outerElement,
      @NotNull final PsiElement elementDefinition) {
    myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(elementDefinition, false)));
    boolean typeFromDocstringAdded =
        addTypeAndDescriptionFromDocstring((PyNamedParameter) elementDefinition);
    if (outerElement instanceof PyExpression) {
      PyType type = context.getType((PyExpression) outerElement);
      if (type != null) {
        String typeString = null;
        if (type instanceof PyDynamicallyEvaluatedType) {
          if (!typeFromDocstringAdded) {
            typeString = "\nDynamically inferred type: ";
          }
        } else {
          if (outerElement.getReference() != null) {
            PsiElement target = outerElement.getReference().resolve();

            if (target instanceof PyTargetExpression) {
              final String targetName = ((PyTargetExpression) target).getName();
              if (targetName != null
                  && targetName.equals(((PyNamedParameter) elementDefinition).getName())) {
                typeString = "\nReassigned value has type: ";
              }
            }
          }
        }
        if (typeString == null && !typeFromDocstringAdded) {
          typeString = "\nInferred type: ";
        }
        if (typeString != null) {
          myBody.addItem(combUp(typeString));
          PythonDocumentationProvider.describeTypeWithLinks(
              myBody, elementDefinition, type, context);
        }
      }
    }
  }
 private boolean isAttribute() {
   return myElement instanceof PyTargetExpression
       && PyUtil.isAttribute((PyTargetExpression) myElement);
 }
  private boolean buildFromProperty(
      PsiElement elementDefinition,
      @Nullable final PsiElement outerElement,
      @NotNull final TypeEvalContext context) {
    if (myOriginalElement == null) {
      return false;
    }
    final String elementName = myOriginalElement.getText();
    if (!PyNames.isIdentifier(elementName)) {
      return false;
    }
    if (!(outerElement instanceof PyQualifiedExpression)) {
      return false;
    }
    final PyExpression qualifier = ((PyQualifiedExpression) outerElement).getQualifier();
    if (qualifier == null) {
      return false;
    }
    final PyType type = context.getType(qualifier);
    if (!(type instanceof PyClassType)) {
      return false;
    }
    final PyClass cls = ((PyClassType) type).getPyClass();
    final Property property = cls.findProperty(elementName, true, null);
    if (property == null) {
      return false;
    }

    final AccessDirection direction = AccessDirection.of((PyElement) outerElement);
    final Maybe<PyCallable> accessor = property.getByDirection(direction);
    myProlog
        .addItem("property ")
        .addWith(TagBold, $().addWith(TagCode, $(elementName)))
        .addItem(" of ")
        .add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
    if (accessor.isDefined() && property.getDoc() != null) {
      myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
    } else {
      final PyCallable getter = property.getGetter().valueOrNull();
      if (getter != null && getter != myElement && getter instanceof PyFunction) {
        // not in getter, getter's doc comment may be useful
        final PyStringLiteralExpression docstring = ((PyFunction) getter).getDocStringExpression();
        if (docstring != null) {
          myProlog
              .addItem(BR)
              .addWith(TagItalic, $("Copied from getter:"))
              .addItem(BR)
              .addItem(docstring.getStringValue());
        }
      }
      myBody.addItem(BR);
    }
    myBody.addItem(BR);
    if (accessor.isDefined() && accessor.value() == null) elementDefinition = null;
    final String accessorKind = getAccessorKind(direction);
    if (elementDefinition != null) {
      myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
    }

    if (!(elementDefinition instanceof PyDocStringOwner)) {
      myBody
          .addWith(
              TagItalic,
              elementDefinition != null ? $("Declaration: ") : $(accessorKind + " is not defined."))
          .addItem(BR);
      if (elementDefinition != null) {
        myBody.addItem(combUp(PyUtil.getReadableRepr(elementDefinition, false)));
      }
    }
    return true;
  }