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