.. title:: clang-tidy - misc-const-correctness

misc-const-correctness
======================

This check implements detection of local variables which could be declared as
``const`` but are not. Declaring variables as ``const`` is required or recommended by many
coding guidelines, such as:
`ES.25 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es25-declare-an-object-const-or-constexpr-unless-you-want-to-modify-its-value-later-on>`_
from the C++ Core Guidelines.

Please note that this check's analysis is type-based only. Variables that are not modified
but used to create a non-const handle that might escape the scope are not diagnosed
as potential ``const``.

.. code-block:: c++

  // Declare a variable, which is not ``const`` ...
  int i = 42;
  // but use it as read-only. This means that `i` can be declared ``const``.
  int result = i * i;       // Before transformation
  int const result = i * i; // After transformation

The check can analyze values, pointers and references but not (yet) pointees:

.. code-block:: c++

  // Normal values like built-ins or objects.
  int potential_const_int = 42;       // Before transformation
  int const potential_const_int = 42; // After transformation
  int copy_of_value = potential_const_int;

  MyClass could_be_const;       // Before transformation
  MyClass const could_be_const; // After transformation
  could_be_const.const_qualified_method();

  // References can be declared const as well.
  int &reference_value = potential_const_int;       // Before transformation
  int const& reference_value = potential_const_int; // After transformation
  int another_copy = reference_value;

  // The similar semantics of pointers are not (yet) analyzed.
  int *pointer_variable = &potential_const_int; // _NO_ 'const int *pointer_variable' suggestion.
  int last_copy = *pointer_variable;

The automatic code transformation is only applied to variables that are declared in single
declarations. You may want to prepare your code base with
:doc:`readability-isolate-declaration <../readability/isolate-declaration>` first.

Note that there is the check
:doc:`cppcoreguidelines-avoid-non-const-global-variables <../cppcoreguidelines/avoid-non-const-global-variables>`
to enforce ``const`` correctness on all globals.

Known Limitations
-----------------

The check does not run on `C` code.

The check will not analyze templated variables or variables that are instantiation dependent.
Different instantiations can result in different ``const`` correctness properties and in general it
is not possible to find all instantiations of a template. The template might be used differently in
an independent translation unit.

Pointees can not be analyzed for constness yet. The following code shows this limitation.

.. code-block:: c++

  // Declare a variable that will not be modified.
  int constant_value = 42;

  // Declare a pointer to that variable, that does not modify either, but misses 'const'.
  // Could be 'const int *pointer_to_constant = &constant_value;'
  int *pointer_to_constant = &constant_value;

  // Usage:
  int result = 520 * 120 * (*pointer_to_constant);

This limitation affects the capability to add ``const`` to methods which is not possible, too.

Options
-------

.. option:: AnalyzeValues (default = true)

  Enable or disable the analysis of ordinary value variables, like ``int i = 42;``

  .. code-block:: c++

    // Warning
    int i = 42;
    // No warning
    int const i = 42;

    // Warning
    int a[] = {42, 42, 42};
    // No warning
    int const a[] = {42, 42, 42};

.. option:: AnalyzeReferences (default = true)

  Enable or disable the analysis of reference variables, like ``int &ref = i;``

  .. code-block:: c++

    int i = 42;
    // Warning
    int& ref = i;
    // No warning
    int const& ref = i;

.. option:: WarnPointersAsValues (default = false)

  This option enables the suggestion for ``const`` of the pointer itself.
  Pointer values have two possibilities to be ``const``, the pointer
  and the value pointing to.

  .. code-block:: c++

    int value = 42;

    // Warning
    const int * pointer_variable = &value;
    // No warning
    const int *const pointer_variable = &value;

.. option:: TransformValues (default = true)

  Provides fixit-hints for value types that automatically add ``const`` if its a single declaration.

  .. code-block:: c++

    // Before
    int value = 42;
    // After
    int const value = 42;

    // Before
    int a[] = {42, 42, 42};
    // After
    int const a[] = {42, 42, 42};

    // Result is modified later in its life-time. No diagnostic and fixit hint will be emitted.
    int result = value * 3;
    result -= 10;

.. option:: TransformReferences (default = true)

  Provides fixit-hints for reference types that automatically add ``const`` if its a single
  declaration.

  .. code-block:: c++

    // This variable could still be a constant. But because there is a non-const reference to
    // it, it can not be transformed (yet).
    int value = 42;
    // The reference 'ref_value' is not modified and can be made 'const int &ref_value = value;'
    // Before
    int &ref_value = value;
    // After
    int const &ref_value = value;

    // Result is modified later in its life-time. No diagnostic and fixit hint will be emitted.
    int result = ref_value * 3;
    result -= 10;

.. option:: TransformPointersAsValues (default = false)

  Provides fixit-hints for pointers if their pointee is not changed. This does not analyze if the
  value-pointed-to is unchanged!

  Requires 'WarnPointersAsValues' to be 'true'.

  .. code-block:: c++

    int value = 42;

    // Before
    const int * pointer_variable = &value;
    // After
    const int *const pointer_variable = &value;

    // Before
    const int * a[] = {&value, &value};
    // After
    const int *const a[] = {&value, &value};

    // Before
    int *ptr_value = &value;
    // After
    int *const ptr_value = &value;

    int result = 100 * (*ptr_value); // Does not modify the pointer itself.
    // This modification of the pointee is still allowed and not diagnosed.
    *ptr_value = 0;

    // The following pointer may not become a 'int *const'.
    int *changing_pointee = &value;
    changing_pointee = &result;
