.. _docs-style-doxygen:

===================
Doxygen style guide
===================
.. _Doxygen: https://www.doxygen.nl/index.html

``pigweed.dev`` uses `Doxygen`_ to auto-generate C and C++ API references
from code comments in header files. These specially formatted comments are
called **Doxygen comments**. This style guide shows you how to format Doxygen
comments and other related documentation.

.. _docs-style-doxygen-quickstart:

----------
Quickstart
----------
Auto-generating an API reference on ``pigweed.dev`` requires interacting with
a few different tools. This section provides an overview of when you interact
with each tool, using ``pw_i2c`` as an example.

.. inclusive-language: disable

.. _//pw_i2c/public/pw_i2c/device.h: https://cs.opensource.google/pigweed/pigweed/+/4c1a7158b663f114c297d9c0a806f412768e73f8:pw_i2c/public/pw_i2c/device.h
.. _Breathe directives: https://breathe.readthedocs.io/en/latest/directives.html
.. _Sphinx: https://www.sphinx-doc.org/en/master/
.. _//pw_i2c/reference.rst: https://cs.opensource.google/pigweed/pigweed/+/4c1a7158b663f114c297d9c0a806f412768e73f8:pw_i2c/reference.rst;l=44
.. _//docs/BUILD.gn: https://cs.opensource.google/pigweed/pigweed/+/4c1a7158b663f114c297d9c0a806f412768e73f8:docs/BUILD.gn;l=192

.. inclusive-language: enable

#. Annotate your header file using `Doxygen`_ syntax. All of the comments
   that start with triple slashes (``///``) are Doxygen comments. Doxygen
   ignores double slash (``//``) comments.

   Example: `//pw_i2c/public/pw_i2c/device.h`_

#. Include the API reference content into a reStructuredText file using
   `Breathe directives`_. Breathe is the bridge between Doxygen and `Sphinx`_,
   the documentation generator that powers ``pigweed.dev``. See
   :ref:`docs-style-doxygen-breathe-overview` for more explanation.

   Example: `//pw_i2c/reference.rst`_

#. Add your header file's path to the ``_doxygen_input_files`` list in
   ``//docs/BUILD.gn``. The docs build system throws a "symbol not found"
   errors if you forget this step.

   Example: `//docs/BUILD.gn`_

.. _docs-style-doxygen-writing:

---------------------------
API reference writing style
---------------------------
.. _API reference code comments: https://developers.google.com/style/api-reference-comments

Follow the guidance in `API reference code comments`_.

.. _docs-style-doxygen-comment-style:

---------------------
Doxygen comment style
---------------------
This section explains how you should style the comments within header files
that Doxygen converts into API references.

.. _docs-style-doxygen-comment-syntax:

Comment syntax
==============
Use the triple slash (``///``) syntax.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// ...
      /// ...

.. _docs-style-doxygen-special-command-syntax:

Special command syntax
======================
.. _Special commands: https://www.doxygen.nl/manual/commands.html

`Special commands`_ like ``@code`` and ``@param`` are the core annotation
tools of Doxygen. Doxygen recognizes words that begin with either backslashes
(``\``) or at symbols (``@``) as special commands. For example, ``\code`` and
``@code`` are synonyms. Always use the at symbol (``@``) format.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @param[out] dest The memory area to copy to.

.. admonition:: **No**
   :class: error

   .. code-block:: none

      /// \param dest The memory area to copy to.

.. _docs-style-doxygen-structural-commands:

Structural commands
===================
.. _Doxygen structural commands: https://doxygen.nl/manual/docblocks.html#structuralcommands

`Doxygen structural commands`_ like ``@struct``, ``@fn``, ``@class``, and ``@file``
associate a comment to a symbol. Don't use structural commands if they're not
needed. In other words, if your Doxygen comment renders correctly without the
structural command, don't use it.

Code examples
=============
Use ``@code{.cpp}`` followed by the code example followed by ``@endcode``.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @code{.cpp}
      ///   #include "pw_kvs/key_value_store.h"
      ///   #include "pw_kvs/flash_test_partition.h"
      ///
      ///   ...
      /// @endcode

Omit or change ``{.cpp}`` if your code example isn't C++ code.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @code
      ///   START + I2C_ADDRESS + WRITE(0) + TX_BUFFER_BYTES + STOP
      ///   START + I2C_ADDRESS + READ(1) + RX_BUFFER_BYTES + STOP
      /// @endcode

.. _docs-style-doxygen-params:

Parameters
==========
Use ``@param[<direction>] <name> <description>`` for each parameter.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @param[out] dest The memory area to copy to.
      /// @param[in] src The memory area to copy from.
      /// @param[in] n The number of bytes to copy.

Put a newline between the parameters if you need multi-line descriptions.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @param[out] dest Lorem ipsum dolor sit amet, consectetur adipiscing
      /// elit, sed do eiusmod tempor incididunt ut labore et dolore magna...
      ///
      /// @param[in] src The memory area to copy from.
      ///
      /// @param[in] n The number of bytes to copy.

The direction annotation is required.

.. admonition:: **No**
   :class: error

   .. code-block:: none

      /// @param dest The memory area to copy to.
      /// @param src The memory area to copy from.
      /// @param n The number of bytes to copy.

   ``<direction>`` must be specified and the value must be either ``in`` or
   ``out``.

.. _docs-style-doxygen-pre:

Preconditions
=============
Use ``@pre <description>``.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @pre Description of a precondition that must be satisifed before
      /// invoking this function.

Deprecated features
===================
Use ``@deprecated <description>``.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @deprecated This function, class, or other entity is deprecated. Use
      /// the replacement instead.

.. _docs-style-doxygen-pw_status:

pw_status codes
===============
Use the following syntax when referring to ``pw_status`` codes:

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      @pw_status{...}

Replace ``...`` with a valid ``pw_status`` code. See
:ref:`module-pw_status-quickref`.

Doxygen converts this alias into a link to the status code's reference
documentation.

Don't use this syntax for functions or methods that return a set of
status codes. Use ``pw-status-codes``. See :ref:`pw-status-codes`.

.. _pw-status-codes:

Functions and methods that return pw::Status codes
==================================================
Use ``pw-status-codes`` to present the set of codes and descriptions as a
two-column table:

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @returns @rst
      ///
      /// .. pw-status-codes::
      ///
      ///    <code>: <description>
      ///
      ///    <code>: <description>
      ///
      /// @endrst

Example:

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @returns @rst
      ///
      /// .. pw-status-codes::
      ///
      ///    OK: The bulk read was successful.
      ///
      ///    RESOURCE_EXHAUSTED: The remaining space is too small to hold a
      ///    new block.
      ///
      /// @endrst

* Each ``<code>`` must be a valid :ref:`status code <module-pw_status-codes>`.
  The part before the colon must be plaintext.
* Each ``<description>`` should explain further what the code means in this
  particular scenario. The description must be a single paragraph. It can use
  inline reStructuredText features such as code formatting and cross-references.
* ``pw-status-codes`` needs to be wrapped in ``@rst`` and ``@endrst``
  because it's a reStructuredText directive and Doxygen doesn't natively
  support reST. The implementation is at
  ``//pw_docgen/py/pw_docgen/sphinx/pw_status_codes.py``.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: none

      /// @returns @rst
      ///
      /// .. pw-status-codes::
      ///
      ///    OK: Data successfully written to ``buffer``.
      ///
      ///    RESOURCE_EXHAUSTED: The remaining space is too small to hold a
      ///    new block. See :ref:`module-pw_example-troubleshooting`.
      ///
      /// @endrst

   It's OK to use reStructuredText features like code formatting and
   cross-references within the descriptions. The status code itself
   must be plaintext.

.. admonition:: **No**
   :class: error

   .. code-block:: none

      /// @returns @rst
      ///
      /// .. pw-status-codes::
      ///
      ///    RESOURCE_EXHAUSTED: The remaining space is too small to hold a
      ///                        new block.
      ///
      /// @endrst

   For items that span multiple lines, don't use whitespace like this.

.. _docs-style-doxygen-namespaces:

Use fully namespaced names
==========================
In general, write out the full namespace to Pigweed classes, methods, and
so on. If you're writing a code sample, and that code sample clearly shows
where the item comes from via a ``using`` statement, you don't need to use
full namespacing.

.. admonition:: Discussion

   Pigweed has over 160 modules. It can be overwhelming for beginners
   to figure out where an item is coming from.

.. _docs-style-doxygen-multisymbol:

Single comment block for multiple symbols
=========================================
Use ``@def <symbol>`` followed by the comment block.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: cpp

      /// @def PW_ASSERT_EXCLUSIVE_LOCK
      /// @def PW_ASSERT_SHARED_LOCK
      ///
      /// Documents functions that dynamically check to see if a lock is held, and
      /// fail if it is not held.

.. _docs-style-doxygen-xrefs:

Cross-references (x-refs)
=========================

.. _docs-style-doxygen-xrefs-comments:

X-refs in Doxygen comments
--------------------------
For C or C++ x-refs, use one of the following aliases:

.. csv-table::
   :header: Alias, reStructuredText equivalent

   ``@c_macro{<identifier>}``, ``:c:macro:`<identifier>```
   ``@cpp_func{<identifier>}``, ``:cpp:func:`<identifier>```
   ``@cpp_class{<identifier>}``, ``:cpp:class:`<identifier>```
   ``@cpp_type{<identifier>}``, ``:cpp:type:`<identifier>```

.. inclusive-language: disable

.. _Sphinx Domain: https://www.sphinx-doc.org/en/master/usage/domains/index.html

.. inclusive-language: enable

For all other x-refs, use Pigweed's custom basic alias,
``@crossref{<domain>,<type>,<identifier>}``. ``<domain>`` must be a valid
`Sphinx Domain`_ and ``<type>`` must be a valid type within that domain.
``@crossref`` can be used with any domain.

Avoid Doxygen x-refs
^^^^^^^^^^^^^^^^^^^^
Always use Pigweed's custom aliases for x-refs unless you have specific
reasons not to do so. Pigweed's x-ref aliases are built on top of Sphinx.
Doxygen provides its own features for x-refs but they should be avoided
because Sphinx's are better:

* Sphinx x-refs work for all identifiers known to Sphinx, including
  those documented with directives like ``.. cpp:class::`` or extracted from
  Python. Doxygen references can only refer to identifiers known to Doxygen.
* Sphinx x-refs always use consistent formatting. Doxygen
  x-refs sometimes render as plaintext instead of code-style
  monospace, or include ``()`` in macros that shouldn’t have them.
* Sphinx x-refs can refer to symbols that haven't yet been documented.
  They will be formatted correctly and become links once the symbols are
  documented.

Using Sphinx x-refs in Doxygen comments makes x-ref syntax more consistent
within Doxygen comments and between reStructuredText and Doxygen.

.. _docs-style-doxygen-xrefs-rest:

Cross-references in reST to Doxygen symbols
-------------------------------------------
After you've used Doxygen to generate API references, you can link to those
symbols from your reStructuredText with standard Sphinx x-ref
syntax.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      :cpp:class:`pw::sync::BinarySemaphore::BinarySemaphore`

.. inclusive-language: disable

.. _domain: https://www.sphinx-doc.org/en/master/usage/domains/index.html
.. _C++ Domain: https://www.sphinx-doc.org/en/master/usage/domains/cpp.html
.. _C Domain: https://www.sphinx-doc.org/en/master/usage/domains/c.html
.. _Python Domain: https://www.sphinx-doc.org/en/master/usage/domains/python.html

.. inclusive-language: enable

In the Sphinx docs the reference documentation for x-ref syntax is
provided in the `domain`_ docs:

* `C++ Domain`_
* `C Domain`_
* `Python Domain`_

.. _docs-style-doxygen-embedded-rest:

Embedded reStructuredText
=========================
To use reStructuredText (reST) within a Doxygen comment, wrap the reST
in ``@rst`` and ``@endrst``.

.. _docs-style-doxygen-breathe:

-------
Breathe
-------
.. _Breathe: https://breathe.readthedocs.io

This section provides guidance on how `Breathe`_ should and shouldn't be used
when authoring ``pigweed.dev`` docs.

.. _docs-style-doxygen-breathe-overview:

Overview
========
.. inclusive-language: disable

.. _Breathe directives: https://breathe.readthedocs.io/en/latest/directives.html
.. _Sphinx: https://www.sphinx-doc.org/en/master/

.. inclusive-language: enable

After you annotate your header comments as Doxygen comments, you need to
specify where to render the API reference within the ``pigweed.dev`` docs.
The reStructuredText files distributed across the main Pigweed repo are
the source code for ``pigweed.dev``. Updating these ``.rst`` files is how
you surface the API reference on ``pigweed.dev``. Doxygen doesn't natively
interact with `Sphinx`_, the documentation generator that powers
``pigweed.dev``. `Breathe`_ is the bridge and API that enables ``pigweed.dev``
and Doxygen to work together.

.. _docs-style-doxygen-breathe-doxygenclass:

doxygenclass
============
.. _doxygenclass: https://breathe.readthedocs.io/en/latest/directives.html#doxygenclass

OK to use. `doxygenclass`_ documents a class and its members.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. doxygenclass:: pw::sync::BinarySemaphore
         :members:

Classes that are a major part of a Pigweed module's API should have their
own section so that they're easy to find in the right-side page nav on
``pigweed.dev``.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. _module-pw_<name>-reference:

      =========
      Reference
      =========
      .. pigweed-module-subpage::
         :name: pw_<name>

      ...

      .. _module-pw_<name>-reference-<class>:

      -------------------
      pw::<name>::<class>
      -------------------
      .. doxygenclass:: pw::<name>::<class>
         :members:

.. _docs-style-doxygen-breathe-doxygenfunction:

doxygenfunction
===============
.. _doxygenfunction: https://breathe.readthedocs.io/en/latest/directives.html#doxygenfunction

OK to use. `doxygenfunction` documents a single function or method.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. doxygenfunction:: pw::tokenizer::EncodeArgs

.. _docs-style-doxygen-breathe-doxygendefine:

doxygendefine
=============
.. _doxygendefine: https://breathe.readthedocs.io/en/latest/directives.html#doxygendefine

OK to use. `doxygendefine`_ documents a preprocessor macro.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. doxygendefine:: PW_TOKENIZE_STRING

.. _docs-style-doxygen-breathe-doxygengroup:

doxygengroup
============
.. _doxygengroup: https://breathe.readthedocs.io/en/latest/directives.html#doxygengroup

`doxygengroup`_ lets you manually mark a set of symbols as belonging to the same
conceptual group.

``doxygengroup`` is OK to use when a simple
:ref:`docs-style-doxygen-breathe-doxygenclass`-based organization
doesn't work well for your module.

.. _@defgroup: https://www.doxygen.nl/manual/commands.html#cmddefgroup
.. _@addtogroup: https://www.doxygen.nl/manual/commands.html#cmdaddtogroup
.. _@ingroup: https://www.doxygen.nl/manual/commands.html#cmdingroup

To create a group, annotate your Doxygen comments with `@defgroup`_,
`@addtogroup`_, and `@ingroup`_. You can wrap a set of contiguous comments
in ``@{`` and ``@}`` to indicate that they all belong to a group.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: cpp

      /// @defgroup <name> <description>
      /// @{
      /// ...
      /// @}

.. _issue #772: https://github.com/breathe-doc/breathe/issues/772

Don't include namespaces in ``doxygengroup`` because Breathe doesn't handle
them correctly. See `issue #772`_.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. cpp:namespace:: my_namespace

      .. doxygengroup:: my_group
         :content-only:
         :members:

.. _docs-style-doxygen-breathe-doxygentypedef:

doxygentypedef
==============
.. _doxygentypedef: https://breathe.readthedocs.io/en/latest/directives.html#doxygentypedef

OK to use. `doxygentypedef`_ documents a ``typedef`` or ``using`` statement.

.. admonition:: **Yes**
   :class: checkmark

   .. code-block:: rst

      .. doxygentypedef:: pw::Function

.. _docs-style-doxygen-breathe-doxygenfile:

doxygenfile
===========
.. _doxygenfile: https://breathe.readthedocs.io/en/latest/directives.html#doxygenfile

Don't use `doxygenfile`_. Use :ref:`docs-style-doxygen-breathe-doxygengroup`
instead.

.. _docs-style-doxygen-disabled-include:

-----------------------------------------------
Disabled auto-generated ``#include`` statements
-----------------------------------------------
.. note::

   This is an FYI section. There's no prescriptive rule here.

Doxygen and Breathe have the ability to auto-generate ``#include`` statements
for class references. These have been disabled because:

* The auto-generated paths are inaccurate. E.g. the ``#include`` for
  ``pw::string::RandomGenerator`` was generated as ``#include <random.h>``
  when it should be ``#include "pw_random/random.h"``.
* The auto-generation is not consistent. They seem to only get generated when
  using the ``doxygennamespace`` directive but ``pigweed.dev`` frequently
  uses ``doxygenclass``, ``doxygenfunction``, etc.

In the future, if it's decided that these ``#include`` statements are needed,
there is a way to manually override each one. The code block below shows how
it's done. This approach wouldn't be great because it adds a lot of noise to
the header files.

.. code-block::

   /// @class RandomGenerator random.h "pw_random/random.h"``

See `b/295023422 <https://issues.pigweed.dev/issues/295023422>`_.
