1 // RUN: %check_clang_tidy %s misc-const-correctness %t -- \ 2 // RUN: -config="{CheckOptions: {\ 3 // RUN: misc-const-correctness.TransformValues: true, \ 4 // RUN: misc-const-correctness.WarnPointersAsValues: false, \ 5 // RUN: misc-const-correctness.TransformPointersAsValues: false \ 6 // RUN: }}" -- -fno-delayed-template-parsing 7 8 // ------- Provide test samples for primitive builtins --------- 9 // - every 'p_*' variable is a 'potential_const_*' variable 10 // - every 'np_*' variable is a 'non_potential_const_*' variable 11 12 bool global; 13 char np_global = 0; // globals can't be known to be const 14 15 // FIXME: 'static' globals are not matched right now. They could be analyzed but aren't right now. 16 static int p_static_global = 42; 17 18 namespace foo { 19 int scoped; 20 float np_scoped = 1; // namespace variables are like globals 21 } // namespace foo 22 23 // FIXME: Similary to 'static' globals, anonymous globals are not matched and analyzed. 24 namespace { 25 int np_anonymous_global; 26 int p_anonymous_global = 43; 27 } // namespace 28 29 // Lambdas should be ignored, because they do not follow the normal variable 30 // semantic (e.g. the type is only known to the compiler). 31 void lambdas() { 32 auto Lambda = [](int i) { return i < 0; }; 33 } 34 35 void some_function(double, wchar_t); 36 37 void some_function(double np_arg0, wchar_t np_arg1) { 38 int p_local0 = 2; 39 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 40 // CHECK-FIXES: int const p_local0 41 42 int np_local0; 43 const int np_local1 = 42; 44 45 unsigned int np_local2 = 3; 46 np_local2 <<= 4; 47 48 int np_local3 = 4; 49 ++np_local3; 50 int np_local4 = 4; 51 np_local4++; 52 53 int np_local5 = 4; 54 --np_local5; 55 int np_local6 = 4; 56 np_local6--; 57 } 58 59 void nested_scopes() { 60 int p_local0 = 2; 61 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 62 // CHECK-FIXES: int const p_local0 63 int np_local0 = 42; 64 65 { 66 int p_local1 = 42; 67 // CHECK-MESSAGES: [[@LINE-1]]:5: warning: variable 'p_local1' of type 'int' can be declared 'const' 68 // CHECK-FIXES: int const p_local1 69 np_local0 *= 2; 70 } 71 } 72 73 void ignore_reference_to_pointers() { 74 int *np_local0 = nullptr; 75 int *&np_local1 = np_local0; 76 } 77 78 void some_lambda_environment_capture_all_by_reference(double np_arg0) { 79 int np_local0 = 0; 80 int p_local0 = 1; 81 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 82 // CHECK-FIXES: int const p_local0 83 84 int np_local2; 85 const int np_local3 = 2; 86 87 // Capturing all variables by reference prohibits making them const. 88 [&]() { ++np_local0; }; 89 90 int p_local1 = 0; 91 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' 92 // CHECK-FIXES: int const p_local1 93 } 94 95 void some_lambda_environment_capture_all_by_value(double np_arg0) { 96 int np_local0 = 0; 97 int p_local0 = 1; 98 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 99 // CHECK-FIXES: int const p_local0 100 101 int np_local1; 102 const int np_local2 = 2; 103 104 // Capturing by value has no influence on them. 105 [=]() { (void)p_local0; }; 106 107 np_local0 += 10; 108 } 109 110 void function_inout_pointer(int *inout); 111 void function_in_pointer(const int *in); 112 113 void some_pointer_taking(int *out) { 114 int np_local0 = 42; 115 const int *const p0_np_local0 = &np_local0; 116 int *const p1_np_local0 = &np_local0; 117 118 int np_local1 = 42; 119 const int *const p0_np_local1 = &np_local1; 120 int *const p1_np_local1 = &np_local1; 121 *p1_np_local0 = 43; 122 123 int np_local2 = 42; 124 function_inout_pointer(&np_local2); 125 126 // Prevents const. 127 int np_local3 = 42; 128 out = &np_local3; // This returns and invalid address, its just about the AST 129 130 int p_local1 = 42; 131 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' 132 // CHECK-FIXES: int const p_local1 133 const int *const p0_p_local1 = &p_local1; 134 135 int p_local2 = 42; 136 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'int' can be declared 'const' 137 // CHECK-FIXES: int const p_local2 138 function_in_pointer(&p_local2); 139 } 140 141 void function_inout_ref(int &inout); 142 void function_in_ref(const int &in); 143 144 void some_reference_taking() { 145 int np_local0 = 42; 146 const int &r0_np_local0 = np_local0; 147 int &r1_np_local0 = np_local0; 148 r1_np_local0 = 43; 149 const int &r2_np_local0 = r1_np_local0; 150 151 int np_local1 = 42; 152 function_inout_ref(np_local1); 153 154 int p_local0 = 42; 155 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 156 // CHECK-FIXES: int const p_local0 157 const int &r0_p_local0 = p_local0; 158 159 int p_local1 = 42; 160 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' 161 // CHECK-FIXES: int const p_local1 162 function_in_ref(p_local1); 163 } 164 165 double *non_const_pointer_return() { 166 double p_local0 = 0.0; 167 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' 168 // CHECK-FIXES: double const p_local0 169 double np_local0 = 24.4; 170 171 return &np_local0; 172 } 173 174 const double *const_pointer_return() { 175 double p_local0 = 0.0; 176 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' 177 // CHECK-FIXES: double const p_local0 178 double p_local1 = 24.4; 179 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' 180 // CHECK-FIXES: double const p_local1 181 return &p_local1; 182 } 183 184 // Also see const-correctness-values.cpp-before-cxx23.cpp for `non_const_ref_return` and `return_non_const_pointer_ref` 185 const double &const_ref_return() { 186 double p_local0 = 0.0; 187 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' 188 // CHECK-FIXES: double const p_local0 189 double p_local1 = 24.4; 190 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' 191 // CHECK-FIXES: double const p_local1 192 return p_local1; 193 } 194 195 void overloaded_arguments(const int &in); 196 void overloaded_arguments(int &inout); 197 void overloaded_arguments(const int *in); 198 void overloaded_arguments(int *inout); 199 200 void function_calling() { 201 int np_local0 = 42; 202 overloaded_arguments(np_local0); 203 204 const int np_local1 = 42; 205 overloaded_arguments(np_local1); 206 207 int np_local2 = 42; 208 overloaded_arguments(&np_local2); 209 210 const int np_local3 = 42; 211 overloaded_arguments(&np_local3); 212 } 213 214 template <typename T> 215 void define_locals(T np_arg0, T &np_arg1, int np_arg2) { 216 T np_local0 = 0; 217 np_local0 += np_arg0 * np_arg1; 218 219 T np_local1 = 42; 220 np_local0 += np_local1; 221 222 // Used as argument to an overloaded function with const and non-const. 223 T np_local2 = 42; 224 overloaded_arguments(np_local2); 225 226 int np_local4 = 42; 227 // non-template values are ok still. 228 int p_local0 = 42; 229 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 230 // CHECK-FIXES: int const p_local0 231 np_local4 += p_local0; 232 } 233 234 template <typename T> 235 void more_template_locals() { 236 const T np_local0 = {}; 237 auto np_local1 = T{}; 238 T &np_local2 = np_local1; 239 T *np_local_ptr = &np_local1; 240 241 const auto np_local3 = T{}; 242 // FIXME: False positive, the reference points to a template type and needs 243 // to be excluded from analysis, but somehow isn't (matchers don't work) 244 auto &np_local4 = np_local3; 245 246 const auto *np_local5 = &np_local3; 247 auto *np_local6 = &np_local1; 248 249 using TypedefToTemplate = T; 250 TypedefToTemplate np_local7{}; 251 // FIXME: False positive, the reference points to a template type and needs 252 // to be excluded from analysis, but somehow isn't (matchers don't work) 253 // auto &np_local8 = np_local7; 254 const auto &np_local9 = np_local7; 255 auto np_local10 = np_local7; 256 auto *np_local11 = &np_local10; 257 const auto *const np_local12 = &np_local10; 258 259 // FIXME: False positive, the reference points to a template type and needs 260 // to be excluded from analysis, but somehow isn't (matchers don't work) 261 // TypedefToTemplate &np_local13 = np_local7; 262 TypedefToTemplate *np_local14 = &np_local7; 263 } 264 265 void template_instantiation() { 266 const int np_local0 = 42; 267 int np_local1 = 42; 268 269 define_locals(np_local0, np_local1, np_local0); 270 define_locals(np_local1, np_local1, np_local1); 271 more_template_locals<int>(); 272 } 273 274 struct ConstNonConstClass { 275 ConstNonConstClass(); 276 ConstNonConstClass(double &np_local0); 277 double nonConstMethod() {} 278 double constMethod() const {} 279 double modifyingMethod(double &np_arg0) const; 280 281 double NonConstMember; 282 const double ConstMember; 283 284 double &NonConstMemberRef; 285 const double &ConstMemberRef; 286 287 double *NonConstMemberPtr; 288 const double *ConstMemberPtr; 289 }; 290 291 void direct_class_access() { 292 ConstNonConstClass np_local0; 293 294 np_local0.constMethod(); 295 np_local0.nonConstMethod(); 296 297 ConstNonConstClass p_local0; 298 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass' can be declared 'const' 299 // CHECK-FIXES: ConstNonConstClass const p_local0 300 p_local0.constMethod(); 301 302 ConstNonConstClass p_local1; 303 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'ConstNonConstClass' can be declared 'const' 304 // CHECK-FIXES: ConstNonConstClass const p_local1 305 double np_local1; 306 p_local1.modifyingMethod(np_local1); 307 308 double np_local2; 309 ConstNonConstClass p_local2(np_local2); 310 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'ConstNonConstClass' can be declared 'const' 311 // CHECK-FIXES: ConstNonConstClass const p_local2(np_local2) 312 313 ConstNonConstClass np_local3; 314 np_local3.NonConstMember = 42.; 315 316 ConstNonConstClass np_local4; 317 np_local4.NonConstMemberRef = 42.; 318 319 ConstNonConstClass p_local3; 320 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'ConstNonConstClass' can be declared 'const' 321 // CHECK-FIXES: ConstNonConstClass const p_local3 322 const double val0 = p_local3.NonConstMember; 323 const double val1 = p_local3.NonConstMemberRef; 324 const double val2 = *p_local3.NonConstMemberPtr; 325 326 ConstNonConstClass p_local4; 327 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'ConstNonConstClass' can be declared 'const' 328 // CHECK-FIXES: ConstNonConstClass const p_local4 329 *np_local4.NonConstMemberPtr = 42.; 330 } 331 332 void class_access_array() { 333 ConstNonConstClass np_local0[2]; 334 np_local0[0].constMethod(); 335 np_local0[1].constMethod(); 336 np_local0[1].nonConstMethod(); 337 338 ConstNonConstClass p_local0[2]; 339 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass[2]' can be declared 'const' 340 // CHECK-FIXES: ConstNonConstClass const p_local0[2] 341 p_local0[0].constMethod(); 342 np_local0[1].constMethod(); 343 } 344 345 struct OperatorsAsConstAsPossible { 346 OperatorsAsConstAsPossible &operator+=(const OperatorsAsConstAsPossible &rhs); 347 OperatorsAsConstAsPossible operator+(const OperatorsAsConstAsPossible &rhs) const; 348 }; 349 350 struct NonConstOperators { 351 }; 352 NonConstOperators operator+(NonConstOperators &lhs, NonConstOperators &rhs); 353 NonConstOperators operator-(NonConstOperators lhs, NonConstOperators rhs); 354 355 void internal_operator_calls() { 356 OperatorsAsConstAsPossible np_local0; 357 OperatorsAsConstAsPossible np_local1; 358 OperatorsAsConstAsPossible p_local0; 359 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'OperatorsAsConstAsPossible' can be declared 'const' 360 // CHECK-FIXES: OperatorsAsConstAsPossible const p_local0 361 OperatorsAsConstAsPossible p_local1; 362 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'OperatorsAsConstAsPossible' can be declared 'const' 363 // CHECK-FIXES: OperatorsAsConstAsPossible const p_local1 364 365 np_local0 += p_local0; 366 np_local1 = p_local0 + p_local1; 367 368 NonConstOperators np_local2; 369 NonConstOperators np_local3; 370 NonConstOperators np_local4; 371 372 np_local2 = np_local3 + np_local4; 373 374 NonConstOperators p_local2; 375 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'NonConstOperators' can be declared 'const' 376 // CHECK-FIXES: NonConstOperators const p_local2 377 NonConstOperators p_local3 = p_local2 - p_local2; 378 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'NonConstOperators' can be declared 'const' 379 // CHECK-FIXES: NonConstOperators const p_local3 380 } 381 382 struct MyVector { 383 double *begin(); 384 const double *begin() const; 385 386 double *end(); 387 const double *end() const; 388 389 double &operator[](int index); 390 double operator[](int index) const; 391 392 double values[100]; 393 }; 394 395 void vector_usage() { 396 double np_local0[10]; 397 np_local0[5] = 42.; 398 399 MyVector np_local1; 400 np_local1[5] = 42.; 401 402 double p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 403 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double[10]' can be declared 'const' 404 // CHECK-FIXES: double const p_local0[10] 405 double p_local1 = p_local0[5]; 406 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' 407 // CHECK-FIXES: double const p_local1 408 409 // The following subscript calls suprisingly choose the non-const operator 410 // version. 411 MyVector np_local2; 412 double p_local2 = np_local2[42]; 413 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'double' can be declared 'const' 414 // CHECK-FIXES: double const p_local2 415 416 MyVector np_local3; 417 const double np_local4 = np_local3[42]; 418 419 // This subscript results in const overloaded operator. 420 const MyVector np_local5{}; 421 double p_local3 = np_local5[42]; 422 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double' can be declared 'const' 423 // CHECK-FIXES: double const p_local3 424 } 425 426 void const_handle(const double &np_local0); 427 void const_handle(const double *np_local0); 428 429 void non_const_handle(double &np_local0); 430 void non_const_handle(double *np_local0); 431 432 void handle_from_array() { 433 // Non-const handle from non-const array forbids declaring the array as const 434 double np_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 435 double *p_local0 = &np_local0[1]; // Could be `double *const`, but warning deactivated by default 436 437 double np_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 438 double &non_const_ref = np_local1[1]; 439 non_const_ref = 42.; 440 441 double np_local2[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 442 double *np_local3; 443 np_local3 = &np_local2[5]; 444 445 double np_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 446 non_const_handle(np_local4[2]); 447 double np_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 448 non_const_handle(&np_local5[2]); 449 450 // Constant handles are ok 451 double p_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 452 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double[10]' can be declared 'const' 453 // CHECK-FIXES: double const p_local1[10] 454 const double *p_local2 = &p_local1[2]; // Could be `const double *const`, but warning deactivated by default 455 456 double p_local3[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 457 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double[10]' can be declared 'const' 458 // CHECK-FIXES: double const p_local3[10] 459 const double &const_ref = p_local3[2]; 460 461 double p_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 462 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'double[10]' can be declared 'const' 463 // CHECK-FIXES: double const p_local4[10] 464 const double *const_ptr; 465 const_ptr = &p_local4[2]; 466 467 double p_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 468 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local5' of type 'double[10]' can be declared 'const' 469 // CHECK-FIXES: double const p_local5[10] 470 const_handle(p_local5[2]); 471 double p_local6[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; 472 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local6' of type 'double[10]' can be declared 'const' 473 // CHECK-FIXES: double const p_local6[10] 474 const_handle(&p_local6[2]); 475 } 476 477 void range_for() { 478 int np_local0[2] = {1, 2}; 479 for (int &non_const_ref : np_local0) { 480 non_const_ref = 42; 481 } 482 483 int np_local1[2] = {1, 2}; 484 for (auto &non_const_ref : np_local1) { 485 non_const_ref = 43; 486 } 487 488 int np_local2[2] = {1, 2}; 489 for (auto &&non_const_ref : np_local2) { 490 non_const_ref = 44; 491 } 492 493 int *np_local3[2] = {&np_local0[0], &np_local0[1]}; 494 for (int *non_const_ptr : np_local3) { 495 *non_const_ptr = 45; 496 } 497 498 // FIXME same as above, but silenced 499 int *const np_local4[2] = {&np_local0[0], &np_local0[1]}; 500 for (auto *non_const_ptr : np_local4) { 501 *non_const_ptr = 46; 502 } 503 504 int p_local0[2] = {1, 2}; 505 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int[2]' can be declared 'const' 506 // CHECK-FIXES: int const p_local0[2] 507 for (int value : p_local0) { 508 // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'value' of type 'int' can be declared 'const' 509 // CHECK-FIXES: int const value 510 } 511 512 int p_local1[2] = {1, 2}; 513 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int[2]' can be declared 'const' 514 // CHECK-FIXES: int const p_local1[2] 515 for (const int &const_ref : p_local1) { 516 } 517 } 518 519 void arrays_of_pointers_are_ignored() { 520 int *np_local0[2] = {nullptr, nullptr}; 521 522 using intPtr = int*; 523 intPtr np_local1[2] = {nullptr, nullptr}; 524 } 525 526 inline void *operator new(decltype(sizeof(void *)), void *p) { return p; } 527 528 struct Value { 529 }; 530 void placement_new() { 531 Value Mem; 532 Value *V = new (&Mem) Value; 533 } 534 535 struct ModifyingConversion { 536 operator int() { return 15; } 537 }; 538 struct NonModifyingConversion { 539 operator int() const { return 15; } 540 }; 541 void conversion_operators() { 542 ModifyingConversion np_local0; 543 NonModifyingConversion p_local0; 544 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'NonModifyingConversion' can be declared 'const' 545 // CHECK-FIXES: NonModifyingConversion const p_local0 546 547 int np_local1 = np_local0; 548 np_local1 = p_local0; 549 } 550 551 void casts() { 552 decltype(sizeof(void *)) p_local0 = 42; 553 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'decltype(sizeof(void *))' 554 // CHECK-FIXES: decltype(sizeof(void *)) const p_local0 555 auto np_local0 = reinterpret_cast<void *>(p_local0); 556 np_local0 = nullptr; 557 558 int p_local1 = 43; 559 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' 560 // CHECK-FIXES: int const p_local1 561 short p_local2 = static_cast<short>(p_local1); 562 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'short' can be declared 'const' 563 // CHECK-FIXES: short const p_local2 564 565 int np_local1 = p_local2; 566 int &np_local2 = static_cast<int &>(np_local1); 567 np_local2 = 5; 568 } 569 570 void ternary_operator() { 571 int np_local0 = 1, np_local1 = 2; 572 int &np_local2 = true ? np_local0 : np_local1; 573 np_local2 = 2; 574 575 int p_local0 = 3, np_local3 = 5; 576 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 577 // CHECK-NOT-FIXES: int const p_local0 = 3 578 const int &np_local4 = true ? p_local0 : ++np_local3; 579 580 int np_local5[3] = {1, 2, 3}; 581 int &np_local6 = np_local5[1] < np_local5[2] ? np_local5[0] : np_local5[2]; 582 np_local6 = 42; 583 584 int np_local7[3] = {1, 2, 3}; 585 int *np_local8 = np_local7[1] < np_local7[2] ? &np_local7[0] : &np_local7[2]; 586 *np_local8 = 42; 587 } 588 589 // Taken from libcxx/include/type_traits and improved readability. 590 template <class Tp, Tp v> 591 struct integral_constant { 592 static constexpr const Tp value = v; 593 using value_type = Tp; 594 using type = integral_constant; 595 constexpr operator value_type() const noexcept { return value; } 596 constexpr value_type operator()() const noexcept { return value; } 597 }; 598 599 template <typename T> 600 struct is_integral : integral_constant<bool, false> {}; 601 template <> 602 struct is_integral<int> : integral_constant<bool, true> {}; 603 604 template <typename T> 605 struct not_integral : integral_constant<bool, false> {}; 606 template <> 607 struct not_integral<double> : integral_constant<bool, true> {}; 608 609 template <bool, typename Tp = void> 610 struct enable_if {}; 611 612 template <typename Tp> 613 struct enable_if<true, Tp> { using type = Tp; }; 614 615 template <typename T> 616 struct TMPClass { 617 T alwaysConst() const { return T{}; } 618 619 template <typename T2 = T, typename = typename enable_if<is_integral<T2>::value>::type> 620 T sometimesConst() const { return T{}; } 621 622 template <typename T2 = T, typename = typename enable_if<not_integral<T2>::value>::type> 623 T sometimesConst() { return T{}; } 624 }; 625 626 void meta_type() { 627 TMPClass<int> p_local0; 628 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'TMPClass<int>' can be declared 'const' 629 // CHECK-FIXES: TMPClass<int> const p_local0 630 p_local0.alwaysConst(); 631 p_local0.sometimesConst(); 632 633 TMPClass<double> p_local1; 634 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'TMPClass<double>' can be declared 'const' 635 // CHECK-FIXES: TMPClass<double> const p_local1 636 p_local1.alwaysConst(); 637 638 TMPClass<double> np_local0; 639 np_local0.alwaysConst(); 640 np_local0.sometimesConst(); 641 } 642 643 // This test is the essence from llvm/lib/Support/MemoryBuffer.cpp at line 450 644 template <typename T> 645 struct to_construct : T { 646 to_construct(int &j) {} 647 }; 648 template <typename T> 649 void placement_new_in_unique_ptr() { 650 int p_local0 = 42; 651 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 652 // CHECK-FIXES: int const p_local0 653 int np_local0 = p_local0; 654 new to_construct<T>(np_local0); 655 } 656 657 struct stream_obj {}; 658 stream_obj &operator>>(stream_obj &o, unsigned &foo); 659 void input_operator() { 660 stream_obj np_local0; 661 unsigned np_local1 = 42; 662 np_local0 >> np_local1; 663 } 664 665 struct stream_obj_template {}; 666 template <typename IStream> 667 IStream &operator>>(IStream &o, unsigned &foo); 668 669 template <typename Stream> 670 void input_operator_template() { 671 Stream np_local0; 672 unsigned np_local1 = 42; 673 np_local0 >> np_local1; 674 } 675 676 // Test bit fields 677 struct HardwareRegister { 678 unsigned field : 5; 679 unsigned : 7; 680 unsigned another : 20; 681 }; 682 683 void TestRegisters() { 684 HardwareRegister np_reg0; 685 np_reg0.field = 3; 686 687 HardwareRegister p_reg1{3, 22}; 688 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_reg1' of type 'HardwareRegister' can be declared 'const' 689 // CHECK-FIXES: HardwareRegister const p_reg1 690 const unsigned p_val = p_reg1.another; 691 } 692 693 struct IntWrapper { 694 IntWrapper &operator=(unsigned value) { return *this; } 695 template <typename Istream> 696 friend Istream &operator>>(Istream &is, IntWrapper &rhs); 697 }; 698 struct IntMaker { 699 friend IntMaker &operator>>(IntMaker &, unsigned &); 700 }; 701 template <typename Istream> 702 Istream &operator>>(Istream &is, IntWrapper &rhs) { 703 unsigned np_local0 = 0; 704 is >> np_local0; 705 return is; 706 } 707 708 struct Actuator { 709 int actuations; 710 }; 711 struct Sensor { 712 int observations; 713 }; 714 struct System : public Actuator, public Sensor { 715 }; 716 int some_computation(int arg); 717 int test_inheritance() { 718 System np_sys; 719 np_sys.actuations = 5; 720 return some_computation(np_sys.actuations); 721 } 722 struct AnotherActuator : Actuator { 723 }; 724 Actuator &test_return_polymorphic() { 725 static AnotherActuator np_local0; 726 return np_local0; 727 } 728 729 using f_signature = int *(*)(int &); 730 int *my_alloc(int &size) { return new int[size]; } 731 struct A { 732 int f(int &i) { return i + 1; } 733 int (A::*x)(int &); 734 }; 735 void f() { 736 int p_local0 = 42; 737 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 738 // CHECK-FIXES: int const p_local0 739 int np_local0 = 42; 740 f_signature action = my_alloc; 741 action(np_local0); 742 my_alloc(np_local0); 743 744 int np_local1 = 42; 745 A a; 746 a.x = &A::f; 747 (a.*(a.x))(np_local1); 748 } 749 750 struct nested_data { 751 int more_data; 752 }; 753 struct repro_assignment_to_reference { 754 int my_data; 755 nested_data nested; 756 }; 757 void assignment_reference() { 758 repro_assignment_to_reference np_local0{42}; 759 int &np_local1 = np_local0.my_data; 760 np_local1++; 761 762 repro_assignment_to_reference np_local2; 763 int &np_local3 = np_local2.nested.more_data; 764 np_local3++; 765 } 766 767 struct non_const_iterator { 768 int data[42]; 769 770 int *begin() { return &data[0]; } 771 int *end() { return &data[41]; } 772 }; 773 774 // The problem is, that 'begin()' and 'end()' are not const overloaded, so 775 // they are always a mutation. If 'np_local1' is fixed to const it results in 776 // a compilation error. 777 void for_bad_iterators() { 778 non_const_iterator np_local0; 779 non_const_iterator &np_local1 = np_local0; 780 781 for (int np_local2 : np_local1) { 782 np_local2++; 783 } 784 785 non_const_iterator np_local3; 786 for (int p_local0 : np_local3) 787 // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local0' of type 'int' can be declared 'const' 788 // CHECK-FIXES: int const p_local0 789 ; 790 791 // Horrible code constructs... 792 { 793 non_const_iterator np_local4; 794 np_local4.data[0]++; 795 non_const_iterator np_local5; 796 for (int p_local1 : np_local4, np_local5) 797 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local1' of type 'int' can be declared 'const' 798 // CHECK-FIXES: int const p_local1 799 ; 800 801 non_const_iterator np_local6; 802 non_const_iterator np_local7; 803 for (int p_local2 : 1 > 2 ? np_local6 : np_local7) 804 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local2' of type 'int' can be declared 'const' 805 // CHECK-FIXES: int const p_local2 806 ; 807 808 non_const_iterator np_local8; 809 non_const_iterator np_local9; 810 for (int p_local3 : 2 > 1 ? np_local8 : (np_local8, np_local9)) 811 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local3' of type 'int' can be declared 'const' 812 // CHECK-FIXES: int const p_local3 813 ; 814 } 815 } 816 817 struct good_iterator { 818 int data[3] = {1, 2, 3}; 819 820 int *begin() { return &data[0]; } 821 int *end() { return &data[2]; } 822 const int *begin() const { return &data[0]; } 823 const int *end() const { return &data[2]; } 824 }; 825 826 void good_iterators() { 827 good_iterator p_local0; 828 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'good_iterator' can be declared 'const' 829 // CHECK-FIXES: good_iterator const p_local0 830 good_iterator &p_local1 = p_local0; 831 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'good_iterator &' can be declared 'const' 832 // CHECK-FIXES: good_iterator const&p_local1 833 834 for (int p_local2 : p_local1) { 835 // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local2' of type 'int' can be declared 'const' 836 // CHECK-FIXES: int const p_local2 837 (void)p_local2; 838 } 839 840 good_iterator p_local3; 841 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'good_iterator' can be declared 'const' 842 // CHECK-FIXES: good_iterator const p_local3 843 for (int p_local4 : p_local3) 844 // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local4' of type 'int' can be declared 'const' 845 // CHECK-FIXES: int const p_local4 846 ; 847 good_iterator np_local1; 848 for (int &np_local2 : np_local1) 849 np_local2++; 850 } 851 852 void for_bad_iterators_array() { 853 int np_local0[42]; 854 int(&np_local1)[42] = np_local0; 855 856 for (int &np_local2 : np_local1) { 857 np_local2++; 858 } 859 } 860 void for_ok_iterators_array() { 861 int np_local0[42]; 862 int(&p_local0)[42] = np_local0; 863 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int (&)[42]' can be declared 'const' 864 // CHECK-FIXES: int const(&p_local0)[42] 865 866 for (int p_local1 : p_local0) { 867 // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local1' of type 'int' can be declared 'const' 868 // CHECK-FIXES: int const p_local1 869 (void)p_local1; 870 } 871 } 872 873 void take_ref(int &); 874 void ternary_reference() { 875 int np_local0 = 42; 876 int np_local1 = 43; 877 take_ref((np_local0 > np_local1 ? np_local0 : (np_local0, np_local1))); 878 } 879 880 void complex_usage() { 881 int np_local0 = 42; 882 int p_local0 = 42; 883 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' 884 // CHECK-FIXES: int const p_local0 885 int np_local1 = 42; 886 (np_local0 == p_local0 ? np_local0 : (p_local0, np_local1))++; 887 } 888 889 void vlas() { 890 int N = 1; // Can't make N 'const' because VLAs make everything awful 891 sizeof(int[++N]); 892 } 893 894 struct base { 895 int member; 896 }; 897 struct derived : base {}; 898 struct another_struct { 899 derived member; 900 }; 901 void another_struct_f() { 902 another_struct np_local0{}; 903 base &np_local1 = np_local0.member; 904 np_local1.member++; 905 } 906 struct list_init { 907 int &member; 908 }; 909 void create_false_positive() { 910 int np_local0 = 42; 911 list_init p_local0 = {np_local0}; 912 // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init' can be declared 'const' 913 // CHECK-FIXES: list_init const p_local0 914 } 915 struct list_init_derived { 916 base &member; 917 }; 918 void list_init_derived_func() { 919 derived np_local0; 920 list_init_derived p_local0 = {np_local0}; 921 // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init_derived' can be declared 'const' 922 // CHECK-FIXES: list_init_derived const p_local0 923 } 924 template <typename L, typename R> 925 struct ref_pair { 926 L &first; 927 R &second; 928 }; 929 template <typename T> 930 void list_init_template() { 931 T np_local0{}; 932 ref_pair<T, T> p_local0 = {np_local0, np_local0}; 933 } 934 void cast_in_class_hierarchy() { 935 derived np_local0; 936 base p_local1 = static_cast<base &>(np_local0); 937 // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local1' of type 'base' can be declared 'const' 938 // CHECK-FIXES: base const p_local1 939 } 940 941 void function_ref_target(int); 942 using my_function_type = void (&)(int); 943 void func_references() { 944 // Could be const, because the reference is not adjusted but adding that 945 // has no effect and creates a compiler warning. 946 my_function_type ptr = function_ref_target; 947 } 948 949 template <typename T> 950 T &return_ref() { 951 static T global; 952 return global; 953 } 954 template <typename T> 955 T *return_ptr() { return &return_ref<T>(); } 956 957 void auto_usage_variants() { 958 auto auto_val0 = int{}; 959 // CHECK-FIXES-NOT: auto const auto_val0 960 auto &auto_val1 = auto_val0; 961 auto *auto_val2 = &auto_val0; 962 963 auto auto_ref0 = return_ref<int>(); 964 // CHECK-FIXES-NOT: auto const auto_ref0 965 auto &auto_ref1 = return_ref<int>(); // Bad 966 auto *auto_ref2 = return_ptr<int>(); 967 968 auto auto_ptr0 = return_ptr<int>(); 969 // CHECK-FIXES-NOT: auto const auto_ptr0 970 auto &auto_ptr1 = auto_ptr0; 971 auto *auto_ptr2 = return_ptr<int>(); 972 973 using MyTypedef = int; 974 auto auto_td0 = MyTypedef{}; 975 // CHECK-FIXES-NOT: auto const auto_td0 976 auto &auto_td1 = auto_td0; 977 auto *auto_td2 = &auto_td0; 978 } 979 980 using PointerToMemberFunction = int (Value::*)(); 981 void member_pointer(Value &x, PointerToMemberFunction m) { 982 Value &member_pointer_tmp = x; 983 (member_pointer_tmp.*m)(); 984 } 985 986 using PointerToConstMemberFunction = int (Value::*)() const; 987 void member_pointer_const(Value &x, PointerToConstMemberFunction m) { 988 Value &member_pointer_tmp = x; 989 // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'member_pointer_tmp' of type 'Value &' can be declared 'const' 990 (member_pointer_tmp.*m)(); 991 } 992