.. title:: clang-tidy - modernize-use-std-print

modernize-use-std-print
=======================

Converts calls to ``printf``, ``fprintf``, ``absl::PrintF`` and
``absl::FPrintf`` to equivalent calls to C++23's ``std::print`` or
``std::println`` as appropriate, modifying the format string appropriately.
The replaced and replacement functions can be customised by configuration
options. Each argument that is the result of a call to ``std::string::c_str()`` and
``std::string::data()`` will have that now-unnecessary call removed in a
similar manner to the `readability-redundant-string-cstr` check.

In other words, it turns lines like:

.. code-block:: c++

  fprintf(stderr, "The %s is %3d\n", description.c_str(), value);

into:

.. code-block:: c++

  std::println(stderr, "The {} is {:3}", description, value);

If the `ReplacementPrintFunction` or `ReplacementPrintlnFunction` options
are left, or assigned to their default values then this check is only
enabled with `-std=c++23` or later.

The check doesn't do a bad job, but it's not perfect. In particular:

- It assumes that the format string is correct for the arguments. If you
  get any warnings when compiling with `-Wformat` then misbehaviour is
  possible.

- At the point that the check runs, the AST contains a single
  ``StringLiteral`` for the format string and any macro expansion, token
  pasting, adjacent string literal concatenation and escaping has been
  handled. Although it's possible for the check to automatically put the
  escapes back, they may not be exactly as they were written (e.g.
  ``"\x0a"`` will become ``"\n"`` and ``"ab" "cd"`` will become
  ``"abcd"``.) This is helpful since it means that the ``PRIx`` macros from
  ``<inttypes.h>`` are removed correctly.

- It supports field widths, precision, positional arguments, leading zeros,
  leading ``+``, alignment and alternative forms.

- Use of any unsupported flags or specifiers will cause the entire
  statement to be left alone and a warning to be emitted. Particular
  unsupported features are:

  - The ``%'`` flag for thousands separators.

  - The glibc extension ``%m``.

- ``printf`` and similar functions return the number of characters printed.
  ``std::print`` does not. This means that any invocations that use the
  return value will not be converted. Unfortunately this currently includes
  explicitly-casting to ``void``. Deficiencies in this check mean that any
  invocations inside ``GCC`` compound statements cannot be converted even
  if the resulting value is not used.

If conversion would be incomplete or unsafe then the entire invocation will
be left unchanged.

If the call is deemed suitable for conversion then:

- ``printf``, ``fprintf``, ``absl::PrintF``, ``absl::FPrintF`` and any
  functions specified by the `PrintfLikeFunctions` option or
  `FprintfLikeFunctions` are replaced with the function specified by the
  `ReplacementPrintlnFunction` option if the format string ends with ``\n``
  or `ReplacementPrintFunction` otherwise.
- the format string is rewritten to use the ``std::formatter`` language. If
  a ``\n`` is found at the end of the format string not preceded by ``r``
  then it is removed and `ReplacementPrintlnFunction` is used rather than
  `ReplacementPrintFunction`.
- any arguments that corresponded to ``%p`` specifiers that
  ``std::formatter`` wouldn't accept are wrapped in a ``static_cast``
  to ``const void *``.
- any arguments that corresponded to ``%s`` specifiers where the argument
  is of ``signed char`` or ``unsigned char`` type are wrapped in a
  ``reinterpret_cast<const char *>``.
- any arguments where the format string and the parameter differ in
  signedness will be wrapped in an approprate ``static_cast`` if `StrictMode`
  is enabled.
- any arguments that end in a call to ``std::string::c_str()`` or
  ``std::string::data()`` will have that call removed.

Options
-------

.. option:: StrictMode

   When `true`, the check will add casts when converting from variadic
   functions like ``printf`` and printing signed or unsigned integer types
   (including fixed-width integer types from ``<cstdint>``, ``ptrdiff_t``,
   ``size_t`` and ``ssize_t``) as the opposite signedness to ensure that
   the output matches that of ``printf``. This does not apply when
   converting from non-variadic functions such as ``absl::PrintF`` and
   ``fmt::printf``. For example, with `StrictMode` enabled:

  .. code-block:: c++

    int i = -42;
    unsigned int u = 0xffffffff;
    printf("%d %u\n", i, u);

  would be converted to:

  .. code-block:: c++

    std::print("{} {}\n", static_cast<unsigned int>(i), static_cast<int>(u));

  to ensure that the output will continue to be the unsigned representation
  of `-42` and the signed representation of `0xffffffff` (often
  `4294967254` and `-1` respectively.) When `false` (which is the default),
  these casts will not be added which may cause a change in the output.

.. option:: PrintfLikeFunctions

   A semicolon-separated list of (fully qualified) extra function names to
   replace, with the requirement that the first parameter contains the
   printf-style format string and the arguments to be formatted follow
   immediately afterwards. If neither this option nor
   `FprintfLikeFunctions` are set then the default value for this option
   is `printf; absl::PrintF`, otherwise it is empty.


.. option:: FprintfLikeFunctions

   A semicolon-separated list of (fully qualified) extra function names to
   replace, with the requirement that the first parameter is retained, the
   second parameter contains the printf-style format string and the
   arguments to be formatted follow immediately afterwards. If neither this
   option nor `PrintfLikeFunctions` are set then the default value for
   this option is `fprintf; absl::FPrintF`, otherwise it is empty.

.. option:: ReplacementPrintFunction

   The function that will be used to replace ``printf``, ``fprintf`` etc.
   during conversion rather than the default ``std::print`` when the
   originalformat string does not end with ``\n``. It is expected that the
   function provides an interface that is compatible with ``std::print``. A
   suitable candidate would be ``fmt::print``.

.. option:: ReplacementPrintlnFunction

   The function that will be used to replace ``printf``, ``fprintf`` etc.
   during conversion rather than the default ``std::println`` when the
   original format string ends with ``\n``. It is expected that the
   function provides an interface that is compatible with ``std::println``.
   A suitable candidate would be ``fmt::println``.

.. option:: PrintHeader

   The header that must be included for the declaration of
   `ReplacementPrintFunction` so that a ``#include`` directive can be
   added if required. If `ReplacementPrintFunction` is ``std::print``
   then this option will default to ``<print>``, otherwise this option will
   default to nothing and no ``#include`` directive will be added.
