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: CppCoreGuidelines ES.25 and AUTOSAR C++14 Rule A7-1-1 (6.7.1 Specifiers).

Please note that this 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.

// 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;

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

// Normal values like built-ins or objects.
int potential_const_int = 42; // 'const int potential_const_int = 42' suggestion.
int copy_of_value = potential_const_int;

MyClass could_be_const; // 'const MyClass could_be_const' suggestion;
could_be_const.const_qualified_method();

// References can be declared const as well.
int &reference_value = potential_const_int; // 'const int &reference_value' suggestion.
int another_copy = reference_value;

// The similar semantics of pointers are not (yet) analyzed.
int *pointer_variable = &potential_const_int; // Not '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 readability-isolate-declaration first.

Note that there is the check cppcoreguidelines-avoid-non-const-global-variables to enforce const correctness on all globals.

Known Limitations

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. It might be used differently in an independent translation unit.

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

// 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

AnalyzeValues (default = 1)

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

AnalyzeReferences (default = 1)

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

WarnPointersAsValues (default = 0)

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.

const int value = 42;
const int * const pointer_variable = &value;

// The following operations are forbidden for `pointer_variable`.
// *pointer_variable = 44;
// pointer_variable = nullptr;
TransformValues (default = 1)

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

// Emits a hint for 'value' to become 'const int value = 42;'.
int value = 42;
// Result is modified later in its life-time. No diagnostic and fixit hint will be emitted.
int result = value * 3;
result -= 10;
TransformReferences (default = 1)

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

// 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;'
int &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;
TransformPointersAsValues (default = 0)

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 1.

int value = 42;
// Emits a hint that 'ptr_value' may become 'int *const ptr_value = &value' because its pointee
// is not changed.
int *ptr_value = &value;

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

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