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

// 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 and pointees:

// 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 analyzed.
int *pointer_variable = &potential_const_int; // Before transformation
int const*const pointer_variable = &potential_const_int; // After transformation, both pointer itself and pointee are supported.
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 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.

Options

AnalyzeValues

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

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

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

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

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

Enable or disable the analysis of pointers variables, like int *ptr = &i;. For specific checks, see WarnPointersAsValues and WarnPointersAsPointers. Default is true.

WarnPointersAsValues

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. Default is false.

int value = 42;

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

This option enables the suggestion for const of the value pointing to. Default is true.

Requires AnalyzePointers to be true.

int value = 42;

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

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

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

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

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

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

Requires ‘WarnPointersAsValues’ to be ‘true’.

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

Provides fix-it hints for pointers if the value it pointing to is not changed. Default is false.

Requires WarnPointersAsPointers to be true.

int value = 42;

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

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

A semicolon-separated list of names of types that will be excluded from const-correctness checking. Regular expressions are accepted, e.g. [Rr]ef(erence)?$ matches every type with suffix Ref, ref, Reference and reference. If a name in the list contains the sequence ::, it is matched against the qualified type name (i.e. namespace::Type), otherwise it is matched against only the type name (i.e. Type). Default is empty string.