docs: def get_function_node(self, node):
          """Process a function node.
  
          :sig: (Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> FunctionNode
          :param node: Node to process.
          :return: Generated function node in stub tree.
          """
          decorators = []
          for d in node.decorator_list:
              if hasattr(d, "id"):
                  decorators.append(d.id)
              elif hasattr(d, "func"):
                  decorators.append(d.func.id)
              elif hasattr(d, "value"):
                  decorators.append(d.value.id + "." + d.attr)
  
          signature = get_signature(node)
  
          if signature is None:
              parent = self._parents[-1]
              if isinstance(parent, ClassNode) and (node.name == "__init__"):
                  signature = parent.signature
  
          if (signature is None) and (not self.generic):
              return None
  
          param_names = [arg.arg if PY3 else arg.id for arg in node.args.args]
          n_args = len(param_names)
  
          if signature is None:
              param_types, rtype, requires = ["Any"] * n_args, "Any", {"Any"}
          else:
              _logger.debug("parsing signature for %s", node.name)
              param_types, rtype, requires = parse_signature(signature)
  
          # TODO: only in classes
          if ((n_args > 0) and (param_names[0] == "self")) or (
              (n_args > 0) and (param_names[0] == "cls") and ("classmethod" in decorators)
          ):
              if signature is None:
                  param_types[0] = ""
              else:
                  param_types.insert(0, "")
  
          _logger.debug("parameter types: %s", param_types)
          _logger.debug("return type: %s", rtype)
          _logger.debug("required types: %s", requires)
  
          self.required_types |= requires
  
          if node.args.vararg is not None:
              param_names.append("*" + (node.args.vararg.arg if PY3 else node.args.vararg))
              param_types.append("")
  
          if node.args.kwarg is not None:
              param_names.append("**" + (node.args.kwarg.arg if PY3 else node.args.kwarg))
              param_types.append("")
  
          kwonly_args = getattr(node.args, "kwonlyargs", [])
          if len(kwonly_args) > 0:
              param_names.extend([arg.arg for arg in kwonly_args])
              if signature is None:
                  param_types.extend(["Any"] * len(kwonly_args))
  
          if len(param_types) != len(param_names):
              raise ValueError("Parameter names and types don't match: " + node.name)
  
          param_locs = [(a.lineno, a.col_offset) for a in (node.args.args + kwonly_args)]
          param_defaults = {
              bisect(param_locs, (d.lineno, d.col_offset)) - 1 for d in node.args.defaults
          }
  
          kwonly_defaults = getattr(node.args, "kw_defaults", [])
          for i, d in enumerate(kwonly_defaults):
              if d is not None:
                  param_defaults.add(n_args + i)
  
          params = [
              (name, type_, i in param_defaults)
              for i, (name, type_) in enumerate(zip(param_names, param_types))
          ]
  
          if len(kwonly_args) > 0:
              params.insert(n_args, ("*", "", False))
  
          stub_node = FunctionNode(
              node.name, parameters=params, rtype=rtype, decorators=decorators
          )
          self._parents[-1].add_child(stub_node)
  
          self._parents.append(stub_node)
          self.generic_visit(node)
          del self._parents[-1]
          return stub_node