// RUN: %check_clang_tidy %s misc-const-correctness %t -- \ // RUN: -config="{CheckOptions: {\ // RUN: misc-const-correctness.TransformValues: true, \ // RUN: misc-const-correctness.WarnPointersAsValues: false, \ // RUN: misc-const-correctness.TransformPointersAsValues: false \ // RUN: }}" -- -fno-delayed-template-parsing -fexceptions // ------- Provide test samples for primitive builtins --------- // - every 'p_*' variable is a 'potential_const_*' variable // - every 'np_*' variable is a 'non_potential_const_*' variable bool global; char np_global = 0; // globals can't be known to be const // FIXME: 'static' globals are not matched right now. They could be analyzed but aren't right now. static int p_static_global = 42; namespace foo { int scoped; float np_scoped = 1; // namespace variables are like globals } // namespace foo // FIXME: Similary to 'static' globals, anonymous globals are not matched and analyzed. namespace { int np_anonymous_global; int p_anonymous_global = 43; } // namespace // Lambdas should be ignored, because they do not follow the normal variable // semantic (e.g. the type is only known to the compiler). void lambdas() { auto Lambda = [](int i) { return i < 0; }; } void some_function(double, wchar_t); void some_function(double np_arg0, wchar_t np_arg1) { int p_local0 = 2; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local0; const int np_local1 = 42; unsigned int np_local2 = 3; np_local2 <<= 4; int np_local3 = 4; ++np_local3; int np_local4 = 4; np_local4++; int np_local5 = 4; --np_local5; int np_local6 = 4; np_local6--; } int function_try_block() try { int p_local0 = 0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 return p_local0; } catch (...) { return 0; } void nested_scopes() { int p_local0 = 2; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local0 = 42; { int p_local1 = 42; // CHECK-MESSAGES: [[@LINE-1]]:5: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 np_local0 *= 2; } } void ignore_reference_to_pointers() { int *np_local0 = nullptr; int *&np_local1 = np_local0; } void some_lambda_environment_capture_all_by_reference(double np_arg0) { int np_local0 = 0; int p_local0 = 1; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local2; const int np_local3 = 2; // Capturing all variables by reference prohibits making them const. [&]() { ++np_local0; }; int p_local1 = 0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 } void some_lambda_environment_capture_all_by_value(double np_arg0) { int np_local0 = 0; int p_local0 = 1; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local1; const int np_local2 = 2; // Capturing by value has no influence on them. [=]() { (void)p_local0; }; np_local0 += 10; } void function_inout_pointer(int *inout); void function_in_pointer(const int *in); void some_pointer_taking(int *out) { int np_local0 = 42; const int *const p0_np_local0 = &np_local0; int *const p1_np_local0 = &np_local0; int np_local1 = 42; const int *const p0_np_local1 = &np_local1; int *const p1_np_local1 = &np_local1; *p1_np_local0 = 43; int np_local2 = 42; function_inout_pointer(&np_local2); // Prevents const. int np_local3 = 42; out = &np_local3; // This returns and invalid address, its just about the AST int p_local1 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 const int *const p0_p_local1 = &p_local1; int p_local2 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local2 function_in_pointer(&p_local2); } void function_inout_ref(int &inout); void function_in_ref(const int &in); void some_reference_taking() { int np_local0 = 42; const int &r0_np_local0 = np_local0; int &r1_np_local0 = np_local0; r1_np_local0 = 43; const int &r2_np_local0 = r1_np_local0; int np_local1 = 42; function_inout_ref(np_local1); int p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 const int &r0_p_local0 = p_local0; int p_local1 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 function_in_ref(p_local1); } double *non_const_pointer_return() { double p_local0 = 0.0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local0 double np_local0 = 24.4; return &np_local0; } const double *const_pointer_return() { double p_local0 = 0.0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local0 double p_local1 = 24.4; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local1 return &p_local1; } // Also see const-correctness-values.cpp-before-cxx23.cpp for `non_const_ref_return` and `return_non_const_pointer_ref` const double &const_ref_return() { double p_local0 = 0.0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local0 double p_local1 = 24.4; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local1 return p_local1; } void overloaded_arguments(const int &in); void overloaded_arguments(int &inout); void overloaded_arguments(const int *in); void overloaded_arguments(int *inout); void function_calling() { int np_local0 = 42; overloaded_arguments(np_local0); const int np_local1 = 42; overloaded_arguments(np_local1); int np_local2 = 42; overloaded_arguments(&np_local2); const int np_local3 = 42; overloaded_arguments(&np_local3); } template void define_locals(T np_arg0, T &np_arg1, int np_arg2) { T np_local0 = 0; np_local0 += np_arg0 * np_arg1; T np_local1 = 42; np_local0 += np_local1; // Used as argument to an overloaded function with const and non-const. T np_local2 = 42; overloaded_arguments(np_local2); int np_local4 = 42; // non-template values are ok still. int p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 np_local4 += p_local0; } template void more_template_locals() { const T np_local0 = {}; auto np_local1 = T{}; T &np_local2 = np_local1; T *np_local_ptr = &np_local1; const auto np_local3 = T{}; // FIXME: False positive, the reference points to a template type and needs // to be excluded from analysis, but somehow isn't (matchers don't work) auto &np_local4 = np_local3; const auto *np_local5 = &np_local3; auto *np_local6 = &np_local1; using TypedefToTemplate = T; TypedefToTemplate np_local7{}; // FIXME: False positive, the reference points to a template type and needs // to be excluded from analysis, but somehow isn't (matchers don't work) // auto &np_local8 = np_local7; const auto &np_local9 = np_local7; auto np_local10 = np_local7; auto *np_local11 = &np_local10; const auto *const np_local12 = &np_local10; // FIXME: False positive, the reference points to a template type and needs // to be excluded from analysis, but somehow isn't (matchers don't work) // TypedefToTemplate &np_local13 = np_local7; TypedefToTemplate *np_local14 = &np_local7; } void template_instantiation() { const int np_local0 = 42; int np_local1 = 42; define_locals(np_local0, np_local1, np_local0); define_locals(np_local1, np_local1, np_local1); more_template_locals(); } struct ConstNonConstClass { ConstNonConstClass(); ConstNonConstClass(double &np_local0); double nonConstMethod() {} double constMethod() const {} double modifyingMethod(double &np_arg0) const; double NonConstMember; const double ConstMember; double &NonConstMemberRef; const double &ConstMemberRef; double *NonConstMemberPtr; const double *ConstMemberPtr; }; void direct_class_access() { ConstNonConstClass np_local0; np_local0.constMethod(); np_local0.nonConstMethod(); ConstNonConstClass p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local0 p_local0.constMethod(); ConstNonConstClass p_local1; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'ConstNonConstClass' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local1 double np_local1; p_local1.modifyingMethod(np_local1); double np_local2; ConstNonConstClass p_local2(np_local2); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'ConstNonConstClass' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local2(np_local2) ConstNonConstClass np_local3; np_local3.NonConstMember = 42.; ConstNonConstClass np_local4; np_local4.NonConstMemberRef = 42.; ConstNonConstClass p_local3; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'ConstNonConstClass' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local3 const double val0 = p_local3.NonConstMember; const double val1 = p_local3.NonConstMemberRef; const double val2 = *p_local3.NonConstMemberPtr; ConstNonConstClass p_local4; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'ConstNonConstClass' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local4 *np_local4.NonConstMemberPtr = 42.; } void class_access_array() { ConstNonConstClass np_local0[2]; np_local0[0].constMethod(); np_local0[1].constMethod(); np_local0[1].nonConstMethod(); ConstNonConstClass p_local0[2]; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass[2]' can be declared 'const' // CHECK-FIXES: ConstNonConstClass const p_local0[2] p_local0[0].constMethod(); np_local0[1].constMethod(); } struct OperatorsAsConstAsPossible { OperatorsAsConstAsPossible &operator+=(const OperatorsAsConstAsPossible &rhs); OperatorsAsConstAsPossible operator+(const OperatorsAsConstAsPossible &rhs) const; }; struct NonConstOperators { }; NonConstOperators operator+(NonConstOperators &lhs, NonConstOperators &rhs); NonConstOperators operator-(NonConstOperators lhs, NonConstOperators rhs); void internal_operator_calls() { OperatorsAsConstAsPossible np_local0; OperatorsAsConstAsPossible np_local1; OperatorsAsConstAsPossible p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'OperatorsAsConstAsPossible' can be declared 'const' // CHECK-FIXES: OperatorsAsConstAsPossible const p_local0 OperatorsAsConstAsPossible p_local1; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'OperatorsAsConstAsPossible' can be declared 'const' // CHECK-FIXES: OperatorsAsConstAsPossible const p_local1 np_local0 += p_local0; np_local1 = p_local0 + p_local1; NonConstOperators np_local2; NonConstOperators np_local3; NonConstOperators np_local4; np_local2 = np_local3 + np_local4; NonConstOperators p_local2; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'NonConstOperators' can be declared 'const' // CHECK-FIXES: NonConstOperators const p_local2 NonConstOperators p_local3 = p_local2 - p_local2; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'NonConstOperators' can be declared 'const' // CHECK-FIXES: NonConstOperators const p_local3 } struct MyVector { double *begin(); const double *begin() const; double *end(); const double *end() const; double &operator[](int index); double operator[](int index) const; double values[100]; }; void vector_usage() { double np_local0[10]; np_local0[5] = 42.; MyVector np_local1; np_local1[5] = 42.; double p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local0[10] double p_local1 = p_local0[5]; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local1 // The following subscript calls suprisingly choose the non-const operator // version. MyVector np_local2; double p_local2 = np_local2[42]; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local2 MyVector np_local3; const double np_local4 = np_local3[42]; // This subscript results in const overloaded operator. const MyVector np_local5{}; double p_local3 = np_local5[42]; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double' can be declared 'const' // CHECK-FIXES: double const p_local3 } void const_handle(const double &np_local0); void const_handle(const double *np_local0); void non_const_handle(double &np_local0); void non_const_handle(double *np_local0); void handle_from_array() { // Non-const handle from non-const array forbids declaring the array as const double np_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; double *p_local0 = &np_local0[1]; // Could be `double *const`, but warning deactivated by default double np_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; double &non_const_ref = np_local1[1]; non_const_ref = 42.; double np_local2[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; double *np_local3; np_local3 = &np_local2[5]; double np_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; non_const_handle(np_local4[2]); double np_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; non_const_handle(&np_local5[2]); // Constant handles are ok double p_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local1[10] const double *p_local2 = &p_local1[2]; // Could be `const double *const`, but warning deactivated by default double p_local3[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local3[10] const double &const_ref = p_local3[2]; double p_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local4[10] const double *const_ptr; const_ptr = &p_local4[2]; double p_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local5' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local5[10] const_handle(p_local5[2]); double p_local6[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local6' of type 'double[10]' can be declared 'const' // CHECK-FIXES: double const p_local6[10] const_handle(&p_local6[2]); } void range_for() { int np_local0[2] = {1, 2}; for (int &non_const_ref : np_local0) { non_const_ref = 42; } int np_local1[2] = {1, 2}; for (auto &non_const_ref : np_local1) { non_const_ref = 43; } int np_local2[2] = {1, 2}; for (auto &&non_const_ref : np_local2) { non_const_ref = 44; } int *np_local3[2] = {&np_local0[0], &np_local0[1]}; for (int *non_const_ptr : np_local3) { *non_const_ptr = 45; } // FIXME same as above, but silenced int *const np_local4[2] = {&np_local0[0], &np_local0[1]}; for (auto *non_const_ptr : np_local4) { *non_const_ptr = 46; } int p_local0[2] = {1, 2}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int[2]' can be declared 'const' // CHECK-FIXES: int const p_local0[2] for (int value : p_local0) { // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'value' of type 'int' can be declared 'const' // CHECK-FIXES: int const value } int p_local1[2] = {1, 2}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int[2]' can be declared 'const' // CHECK-FIXES: int const p_local1[2] for (const int &const_ref : p_local1) { } } void arrays_of_pointers_are_ignored() { int *np_local0[2] = {nullptr, nullptr}; using intPtr = int*; intPtr np_local1[2] = {nullptr, nullptr}; } inline void *operator new(decltype(sizeof(void *)), void *p) { return p; } struct Value { }; void placement_new() { Value Mem; Value *V = new (&Mem) Value; } struct ModifyingConversion { operator int() { return 15; } }; struct NonModifyingConversion { operator int() const { return 15; } }; void conversion_operators() { ModifyingConversion np_local0; NonModifyingConversion p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'NonModifyingConversion' can be declared 'const' // CHECK-FIXES: NonModifyingConversion const p_local0 int np_local1 = np_local0; np_local1 = p_local0; } void casts() { decltype(sizeof(void *)) p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'decltype(sizeof(void *))' // CHECK-FIXES: decltype(sizeof(void *)) const p_local0 auto np_local0 = reinterpret_cast(p_local0); np_local0 = nullptr; int p_local1 = 43; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 short p_local2 = static_cast(p_local1); // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'short' can be declared 'const' // CHECK-FIXES: short const p_local2 int np_local1 = p_local2; int &np_local2 = static_cast(np_local1); np_local2 = 5; } void ternary_operator() { int np_local0 = 1, np_local1 = 2; int &np_local2 = true ? np_local0 : np_local1; np_local2 = 2; int p_local0 = 3, np_local3 = 5; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-NOT-FIXES: int const p_local0 = 3 const int &np_local4 = true ? p_local0 : ++np_local3; int np_local5[3] = {1, 2, 3}; int &np_local6 = np_local5[1] < np_local5[2] ? np_local5[0] : np_local5[2]; np_local6 = 42; int np_local7[3] = {1, 2, 3}; int *np_local8 = np_local7[1] < np_local7[2] ? &np_local7[0] : &np_local7[2]; *np_local8 = 42; } // Taken from libcxx/include/type_traits and improved readability. template struct integral_constant { static constexpr const Tp value = v; using value_type = Tp; using type = integral_constant; constexpr operator value_type() const noexcept { return value; } constexpr value_type operator()() const noexcept { return value; } }; template struct is_integral : integral_constant {}; template <> struct is_integral : integral_constant {}; template struct not_integral : integral_constant {}; template <> struct not_integral : integral_constant {}; template struct enable_if {}; template struct enable_if { using type = Tp; }; template struct TMPClass { T alwaysConst() const { return T{}; } template ::value>::type> T sometimesConst() const { return T{}; } template ::value>::type> T sometimesConst() { return T{}; } }; void meta_type() { TMPClass p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'TMPClass' can be declared 'const' // CHECK-FIXES: TMPClass const p_local0 p_local0.alwaysConst(); p_local0.sometimesConst(); TMPClass p_local1; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'TMPClass' can be declared 'const' // CHECK-FIXES: TMPClass const p_local1 p_local1.alwaysConst(); TMPClass np_local0; np_local0.alwaysConst(); np_local0.sometimesConst(); } // This test is the essence from llvm/lib/Support/MemoryBuffer.cpp at line 450 template struct to_construct : T { to_construct(int &j) {} }; template void placement_new_in_unique_ptr() { int p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local0 = p_local0; new to_construct(np_local0); } struct stream_obj {}; stream_obj &operator>>(stream_obj &o, unsigned &foo); void input_operator() { stream_obj np_local0; unsigned np_local1 = 42; np_local0 >> np_local1; } struct stream_obj_template {}; template IStream &operator>>(IStream &o, unsigned &foo); template void input_operator_template() { Stream np_local0; unsigned np_local1 = 42; np_local0 >> np_local1; } // Test bit fields struct HardwareRegister { unsigned field : 5; unsigned : 7; unsigned another : 20; }; void TestRegisters() { HardwareRegister np_reg0; np_reg0.field = 3; HardwareRegister p_reg1{3, 22}; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_reg1' of type 'HardwareRegister' can be declared 'const' // CHECK-FIXES: HardwareRegister const p_reg1 const unsigned p_val = p_reg1.another; } struct IntWrapper { IntWrapper &operator=(unsigned value) { return *this; } template friend Istream &operator>>(Istream &is, IntWrapper &rhs); }; struct IntMaker { friend IntMaker &operator>>(IntMaker &, unsigned &); }; template Istream &operator>>(Istream &is, IntWrapper &rhs) { unsigned np_local0 = 0; is >> np_local0; return is; } struct Actuator { int actuations; }; struct Sensor { int observations; }; struct System : public Actuator, public Sensor { }; int some_computation(int arg); int test_inheritance() { System np_sys; np_sys.actuations = 5; return some_computation(np_sys.actuations); } struct AnotherActuator : Actuator { }; Actuator &test_return_polymorphic() { static AnotherActuator np_local0; return np_local0; } using f_signature = int *(*)(int &); int *my_alloc(int &size) { return new int[size]; } struct A { int f(int &i) { return i + 1; } int (A::*x)(int &); }; void f() { int p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local0 = 42; f_signature action = my_alloc; action(np_local0); my_alloc(np_local0); int np_local1 = 42; A a; a.x = &A::f; (a.*(a.x))(np_local1); } struct nested_data { int more_data; }; struct repro_assignment_to_reference { int my_data; nested_data nested; }; void assignment_reference() { repro_assignment_to_reference np_local0{42}; int &np_local1 = np_local0.my_data; np_local1++; repro_assignment_to_reference np_local2; int &np_local3 = np_local2.nested.more_data; np_local3++; } struct non_const_iterator { int data[42]; int *begin() { return &data[0]; } int *end() { return &data[41]; } }; // The problem is, that 'begin()' and 'end()' are not const overloaded, so // they are always a mutation. If 'np_local1' is fixed to const it results in // a compilation error. void for_bad_iterators() { non_const_iterator np_local0; non_const_iterator &np_local1 = np_local0; for (int np_local2 : np_local1) { np_local2++; } non_const_iterator np_local3; for (int p_local0 : np_local3) // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 ; // Horrible code constructs... { non_const_iterator np_local4; np_local4.data[0]++; non_const_iterator np_local5; for (int p_local1 : np_local4, np_local5) // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 ; non_const_iterator np_local6; non_const_iterator np_local7; for (int p_local2 : 1 > 2 ? np_local6 : np_local7) // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local2' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local2 ; non_const_iterator np_local8; non_const_iterator np_local9; for (int p_local3 : 2 > 1 ? np_local8 : (np_local8, np_local9)) // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local3' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local3 ; } } struct good_iterator { int data[3] = {1, 2, 3}; int *begin() { return &data[0]; } int *end() { return &data[2]; } const int *begin() const { return &data[0]; } const int *end() const { return &data[2]; } }; void good_iterators() { good_iterator p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'good_iterator' can be declared 'const' // CHECK-FIXES: good_iterator const p_local0 good_iterator &p_local1 = p_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'good_iterator &' can be declared 'const' // CHECK-FIXES: good_iterator const&p_local1 for (int p_local2 : p_local1) { // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local2' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local2 (void)p_local2; } good_iterator p_local3; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'good_iterator' can be declared 'const' // CHECK-FIXES: good_iterator const p_local3 for (int p_local4 : p_local3) // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local4' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local4 ; good_iterator np_local1; for (int &np_local2 : np_local1) np_local2++; } void for_bad_iterators_array() { int np_local0[42]; int(&np_local1)[42] = np_local0; for (int &np_local2 : np_local1) { np_local2++; } } void for_ok_iterators_array() { int np_local0[42]; int(&p_local0)[42] = np_local0; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int (&)[42]' can be declared 'const' // CHECK-FIXES: int const(&p_local0)[42] for (int p_local1 : p_local0) { // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local1' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local1 (void)p_local1; } } void take_ref(int &); void ternary_reference() { int np_local0 = 42; int np_local1 = 43; take_ref((np_local0 > np_local1 ? np_local0 : (np_local0, np_local1))); } void complex_usage() { int np_local0 = 42; int p_local0 = 42; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' // CHECK-FIXES: int const p_local0 int np_local1 = 42; (np_local0 == p_local0 ? np_local0 : (p_local0, np_local1))++; } void vlas() { int N = 1; // Can't make N 'const' because VLAs make everything awful sizeof(int[++N]); } struct base { int member; }; struct derived : base {}; struct another_struct { derived member; }; void another_struct_f() { another_struct np_local0{}; base &np_local1 = np_local0.member; np_local1.member++; } struct list_init { int &member; }; void create_false_positive() { int np_local0 = 42; list_init p_local0 = {np_local0}; // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init' can be declared 'const' // CHECK-FIXES: list_init const p_local0 } struct list_init_derived { base &member; }; void list_init_derived_func() { derived np_local0; list_init_derived p_local0 = {np_local0}; // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init_derived' can be declared 'const' // CHECK-FIXES: list_init_derived const p_local0 } template struct ref_pair { L &first; R &second; }; template void list_init_template() { T np_local0{}; ref_pair p_local0 = {np_local0, np_local0}; } void cast_in_class_hierarchy() { derived np_local0; base p_local1 = static_cast(np_local0); // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local1' of type 'base' can be declared 'const' // CHECK-FIXES: base const p_local1 } void function_ref_target(int); using my_function_type = void (&)(int); void func_references() { // Could be const, because the reference is not adjusted but adding that // has no effect and creates a compiler warning. my_function_type ptr = function_ref_target; } template T &return_ref() { static T global; return global; } template T *return_ptr() { return &return_ref(); } void auto_usage_variants() { auto auto_val0 = int{}; // CHECK-FIXES-NOT: auto const auto_val0 auto &auto_val1 = auto_val0; auto *auto_val2 = &auto_val0; auto auto_ref0 = return_ref(); // CHECK-FIXES-NOT: auto const auto_ref0 auto &auto_ref1 = return_ref(); // Bad auto *auto_ref2 = return_ptr(); auto auto_ptr0 = return_ptr(); // CHECK-FIXES-NOT: auto const auto_ptr0 auto &auto_ptr1 = auto_ptr0; auto *auto_ptr2 = return_ptr(); using MyTypedef = int; auto auto_td0 = MyTypedef{}; // CHECK-FIXES-NOT: auto const auto_td0 auto &auto_td1 = auto_td0; auto *auto_td2 = &auto_td0; } using PointerToMemberFunction = int (Value::*)(); void member_pointer(Value &x, PointerToMemberFunction m) { Value &member_pointer_tmp = x; (member_pointer_tmp.*m)(); } using PointerToConstMemberFunction = int (Value::*)() const; void member_pointer_const(Value &x, PointerToConstMemberFunction m) { Value &member_pointer_tmp = x; // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'member_pointer_tmp' of type 'Value &' can be declared 'const' (member_pointer_tmp.*m)(); }