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