docs: def process_docstring(app, what, name, obj, options, lines):
      """Modify the docstring before generating documentation.
  
      This will insert type declarations for parameters and return type
      into the docstring, and remove the signature field so that it will
      be excluded from the generated document.
      """
      aliases = getattr(app, "_sigaliases", None)
      if aliases is None:
          if what == "module":
              aliases = get_aliases(inspect.getsource(obj).splitlines())
              app._sigaliases = aliases
  
      sig_marker = ":" + SIG_FIELD + ":"
      is_class = what in ("class", "exception")
  
      signature = extract_signature("\n".join(lines))
      if signature is None:
          if not is_class:
              return
  
          init_method = getattr(obj, "__init__")
          init_doc = init_method.__doc__
          init_lines = init_doc.splitlines()[1:]
          if len(init_lines) > 1:
              init_doc = textwrap.dedent("\n".join(init_lines[1:]))
              init_lines = init_doc.splitlines()
          if sig_marker not in init_doc:
              return
  
          sig_started = False
          for line in init_lines:
              if line.lstrip().startswith(sig_marker):
                  sig_started = True
              if sig_started:
                  lines.append(line)
          signature = extract_signature("\n".join(lines))
  
      if is_class:
          obj = init_method
  
      param_types, rtype, _ = parse_signature(signature)
      param_names = [p for p in inspect.signature(obj).parameters]
  
      if is_class and (param_names[0] == "self"):
          del param_names[0]
  
      # if something goes wrong, don't insert parameter types
      if len(param_names) == len(param_types):
          for name, type_ in zip(param_names, param_types):
              find = ":param %(name)s:" % {"name": name}
              alias = aliases.get(type_)
              if alias is not None:
                  type_ = "*%(type)s* :sup:`%(alias)s`" % {"type": type_, "alias": alias}
              for i, line in enumerate(lines):
                  if line.startswith(find):
                      lines.insert(i, ":type %(name)s: %(type)s" % {"name": name, "type": type_})
                      break
  
      if not is_class:
          for i, line in enumerate(lines):
              if line.startswith((":return:", ":returns:")):
                  lines.insert(i, ":rtype: " + rtype)
                  break
  
      # remove the signature field
      sig_start = 0
      while sig_start < len(lines):
          if lines[sig_start].startswith(sig_marker):
              break
          sig_start += 1
      sig_end = sig_start + 1
      while sig_end < len(lines):
          if (not lines[sig_end]) or (lines[sig_end][0] != " "):
              break
          sig_end += 1
      for i in reversed(range(sig_start, sig_end)):
          del lines[i]