1 // RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions 2 3 extern void __assert_fail (__const char *__assertion, __const char *__file, 4 unsigned int __line, __const char *__function) 5 __attribute__ ((__noreturn__)); 6 #define assert(expr) \ 7 ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) 8 9 class Simple1 { 10 int n; 11 double x; 12 13 public: 14 Simple1() { 15 // CHECK-FIXES: Simple1() : n(0), x(0.0) { 16 n = 0; 17 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 18 // CHECK-FIXES: {{^\ *$}} 19 x = 0.0; 20 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 21 // CHECK-FIXES: {{^\ *$}} 22 } 23 24 Simple1(int nn, double xx) { 25 // CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) { 26 n = nn; 27 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 28 // CHECK-FIXES: {{^\ *$}} 29 x = xx; 30 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 31 // CHECK-FIXES: {{^\ *$}} 32 } 33 34 ~Simple1() = default; 35 }; 36 37 class Simple2 { 38 int n; 39 double x; 40 41 public: 42 Simple2() : n(0) { 43 // CHECK-FIXES: Simple2() : n(0), x(0.0) { 44 x = 0.0; 45 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 46 // CHECK-FIXES: {{^\ *$}} 47 } 48 49 Simple2(int nn, double xx) : n(nn) { 50 // CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) { 51 x = xx; 52 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 53 // CHECK-FIXES: {{^\ *$}} 54 } 55 56 ~Simple2() = default; 57 }; 58 59 class Simple3 { 60 int n; 61 double x; 62 63 public: 64 Simple3() : x(0.0) { 65 // CHECK-FIXES: Simple3() : n(0), x(0.0) { 66 n = 0; 67 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 68 // CHECK-FIXES: {{^\ *$}} 69 } 70 71 Simple3(int nn, double xx) : x(xx) { 72 // CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) { 73 n = nn; 74 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 75 // CHECK-FIXES: {{^\ *$}} 76 } 77 78 ~Simple3() = default; 79 }; 80 81 int something_int(); 82 double something_double(); 83 84 class Simple4 { 85 int n; 86 87 public: 88 Simple4() { 89 // CHECK-FIXES: Simple4() : n(something_int()) { 90 n = something_int(); 91 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 92 // CHECK-FIXES: {{^\ *$}} 93 } 94 95 ~Simple4() = default; 96 }; 97 98 static bool dice(); 99 100 class Complex1 { 101 int n; 102 int m; 103 104 public: 105 Complex1() : n(0) { 106 if (dice()) 107 m = 1; 108 // NO-MESSAGES: initialization of 'm' is nested in a conditional expression 109 } 110 111 ~Complex1() = default; 112 }; 113 114 class Complex2 { 115 int n; 116 int m; 117 118 public: 119 Complex2() : n(0) { 120 if (!dice()) 121 return; 122 m = 1; 123 // NO-MESSAGES: initialization of 'm' follows a conditional expression 124 } 125 126 ~Complex2() = default; 127 }; 128 129 class Complex3 { 130 int n; 131 int m; 132 133 public: 134 Complex3() : n(0) { 135 while (dice()) 136 m = 1; 137 // NO-MESSAGES: initialization of 'm' is nested in a conditional loop 138 } 139 140 ~Complex3() = default; 141 }; 142 143 class Complex4 { 144 int n; 145 int m; 146 147 public: 148 Complex4() : n(0) { 149 while (!dice()) 150 return; 151 m = 1; 152 // NO-MESSAGES: initialization of 'm' follows a conditional loop 153 } 154 155 ~Complex4() = default; 156 }; 157 158 class Complex5 { 159 int n; 160 int m; 161 162 public: 163 Complex5() : n(0) { 164 do { 165 m = 1; 166 // NO-MESSAGES: initialization of 'm' is nested in a conditional loop 167 } while (dice()); 168 } 169 170 ~Complex5() = default; 171 }; 172 173 class Complex6 { 174 int n; 175 int m; 176 177 public: 178 Complex6() : n(0) { 179 do { 180 return; 181 } while (!dice()); 182 m = 1; 183 // NO-MESSAGES: initialization of 'm' follows a conditional loop 184 } 185 186 ~Complex6() = default; 187 }; 188 189 class Complex7 { 190 int n; 191 int m; 192 193 public: 194 Complex7() : n(0) { 195 for (int i = 2; i < 1; ++i) { 196 m = 1; 197 } 198 // NO-MESSAGES: initialization of 'm' is nested into a conditional loop 199 } 200 201 ~Complex7() = default; 202 }; 203 204 class Complex8 { 205 int n; 206 int m; 207 208 public: 209 Complex8() : n(0) { 210 for (int i = 0; i < 2; ++i) { 211 return; 212 } 213 m = 1; 214 // NO-MESSAGES: initialization of 'm' follows a conditional loop 215 } 216 217 ~Complex8() = default; 218 }; 219 220 class Complex9 { 221 int n; 222 int m; 223 224 public: 225 Complex9() : n(0) { 226 switch (dice()) { 227 case 1: 228 m = 1; 229 // NO-MESSAGES: initialization of 'm' is nested in a conditional expression 230 break; 231 default: 232 break; 233 } 234 } 235 236 ~Complex9() = default; 237 }; 238 239 class Complex10 { 240 int n; 241 int m; 242 243 public: 244 Complex10() : n(0) { 245 switch (dice()) { 246 case 1: 247 return; 248 break; 249 default: 250 break; 251 } 252 m = 1; 253 // NO-MESSAGES: initialization of 'm' follows a conditional expression 254 } 255 256 ~Complex10() = default; 257 }; 258 259 class E {}; 260 int risky(); // may throw 261 262 class Complex11 { 263 int n; 264 int m; 265 266 public: 267 Complex11() : n(0) { 268 try { 269 risky(); 270 m = 1; 271 // NO-MESSAGES: initialization of 'm' follows is nested in a try-block 272 } catch (const E& e) { 273 return; 274 } 275 } 276 277 ~Complex11() = default; 278 }; 279 280 class Complex12 { 281 int n; 282 int m; 283 284 public: 285 Complex12() : n(0) { 286 try { 287 risky(); 288 } catch (const E& e) { 289 return; 290 } 291 m = 1; 292 // NO-MESSAGES: initialization of 'm' follows a try-block 293 } 294 295 ~Complex12() = default; 296 }; 297 298 class Complex13 { 299 int n; 300 int m; 301 302 public: 303 Complex13() : n(0) { 304 return; 305 m = 1; 306 // NO-MESSAGES: initialization of 'm' follows a return statement 307 } 308 309 ~Complex13() = default; 310 }; 311 312 class Complex14 { 313 int n; 314 int m; 315 316 public: 317 Complex14() : n(0) { 318 goto X; 319 m = 1; 320 // NO-MESSAGES: initialization of 'm' follows a goto statement 321 X: 322 ; 323 } 324 325 ~Complex14() = default; 326 }; 327 328 void returning(); 329 330 class Complex15 { 331 int n; 332 int m; 333 334 public: 335 Complex15() : n(0) { 336 // CHECK-FIXES: Complex15() : n(0), m(1) { 337 returning(); 338 m = 1; 339 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 340 // CHECK-FIXES: {{^\ *$}} 341 } 342 343 ~Complex15() = default; 344 }; 345 346 [[noreturn]] void not_returning(); 347 348 class Complex16 { 349 int n; 350 int m; 351 352 public: 353 Complex16() : n(0) { 354 not_returning(); 355 m = 1; 356 // NO-MESSAGES: initialization of 'm' follows a non-returning function call 357 } 358 359 ~Complex16() = default; 360 }; 361 362 class Complex17 { 363 int n; 364 int m; 365 366 public: 367 Complex17() : n(0) { 368 throw 1; 369 m = 1; 370 // NO-MESSAGES: initialization of 'm' follows a 'throw' statement; 371 } 372 373 ~Complex17() = default; 374 }; 375 376 class Complex18 { 377 int n; 378 379 public: 380 Complex18() try { 381 n = risky(); 382 // NO-MESSAGES: initialization of 'n' in a 'try' body; 383 } catch (const E& e) { 384 n = 0; 385 } 386 387 ~Complex18() = default; 388 }; 389 390 class Complex19 { 391 int n; 392 public: 393 Complex19() { 394 // CHECK-FIXES: Complex19() : n(0) { 395 n = 0; 396 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 397 // CHECK-FIXES: {{^\ *$}} 398 } 399 400 explicit Complex19(int) { 401 // CHECK-FIXES: Complex19(int) : n(12) { 402 n = 12; 403 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 404 // CHECK-FIXES: {{^\ *$}} 405 } 406 407 ~Complex19() = default; 408 }; 409 410 class Complex20 { 411 int n; 412 int m; 413 414 public: 415 Complex20(int k) : n(0) { 416 assert(k > 0); 417 m = 1; 418 // NO-MESSAGES: initialization of 'm' follows an assertion 419 } 420 421 ~Complex20() = default; 422 }; 423 424 class VeryComplex1 { 425 int n1, n2, n3; 426 double x1, x2, x3; 427 int n4, n5, n6; 428 double x4, x5, x6; 429 430 VeryComplex1() : n3(something_int()), x3(something_double()), 431 n5(something_int()), x4(something_double()), 432 x5(something_double()) { 433 // CHECK-FIXES: VeryComplex1() : n2(something_int()), n1(something_int()), n3(something_int()), x2(something_double()), x1(something_double()), x3(something_double()), 434 // CHECK-FIXES: n4(something_int()), n5(something_int()), n6(something_int()), x4(something_double()), 435 // CHECK-FIXES: x5(something_double()), x6(something_double()) { 436 437 // FIXME: Order of elements on the constructor initializer list should match 438 // the order of the declaration of the fields. Thus the correct fixes 439 // should look like these: 440 // 441 // C ECK-FIXES: VeryComplex1() : n2(something_int()), n1(something_int()), n3(something_int()), x2(something_double()), x1(something_double()), x3(something_double()), 442 // C ECK-FIXES: n4(something_int()), n5(something_int()), n6(something_int()), x4(something_double()), 443 // C ECK-FIXES: x5(something_double()), x6(something_double()) { 444 // 445 // However, the Diagnostics Engine processes fixes in the order of the 446 // diagnostics and insertions to the same position are handled in left to 447 // right order thus in the case two adjacent fields are initialized 448 // inside the constructor in reverse order the provided fix is a 449 // constructor initializer list that does not match the order of the 450 // declaration of the fields. 451 452 x2 = something_double(); 453 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x2' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 454 // CHECK-FIXES: {{^\ *$}} 455 n2 = something_int(); 456 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n2' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 457 // CHECK-FIXES: {{^\ *$}} 458 x6 = something_double(); 459 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x6' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 460 // CHECK-FIXES: {{^\ *$}} 461 x1 = something_double(); 462 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x1' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 463 // CHECK-FIXES: {{^\ *$}} 464 n6 = something_int(); 465 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n6' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 466 // CHECK-FIXES: {{^\ *$}} 467 n1 = something_int(); 468 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n1' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 469 // CHECK-FIXES: {{^\ *$}} 470 n4 = something_int(); 471 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n4' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 472 // CHECK-FIXES: {{^\ *$}} 473 } 474 }; 475 476 struct Outside { 477 int n; 478 double x; 479 Outside(); 480 }; 481 482 Outside::Outside() { 483 // CHECK-FIXES: Outside::Outside() : n(1), x(1.0) { 484 n = 1; 485 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 486 // CHECK-FIXES: {{^\ *$}} 487 x = 1.0; 488 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 489 // CHECK-FIXES: {{^\ *$}} 490 } 491 492 struct SafeDependancy { 493 int m; 494 int n; 495 SafeDependancy(int M) : m(M) { 496 // CHECK-FIXES: SafeDependancy(int M) : m(M), n(m) { 497 n = m; 498 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor 499 } 500 // We match against direct field dependancy as well as descendant field 501 // dependancy, ensure both are accounted for. 502 SafeDependancy(short M) : m(M) { 503 // CHECK-FIXES: SafeDependancy(short M) : m(M), n(m + 1) { 504 n = m + 1; 505 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor 506 } 507 }; 508 509 struct BadDependancy { 510 int m; 511 int n; 512 BadDependancy(int N) : n(N) { 513 m = n; 514 } 515 BadDependancy(short N) : n(N) { 516 m = n + 1; 517 } 518 }; 519 520 struct InitFromVarDecl { 521 int m; 522 InitFromVarDecl() { 523 // Can't apply this fix as n is declared in the body of the constructor. 524 int n = 3; 525 m = n; 526 } 527 }; 528 529 struct HasInClassInit { 530 int m = 4; 531 HasInClassInit() { 532 m = 3; 533 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm' should be initialized in a member initializer of the constructor 534 } 535 }; 536 537 struct HasInitListInit { 538 int M; 539 // CHECK-MESSAGES: :[[@LINE+5]]:5: warning: 'M' should be initialized in a member initializer of the constructor 540 // CHECK-FIXES: HasInitListInit(const HasInitListInit &Other) : M(Other.M) { 541 // CHECK-FIXES-NEXT: {{^ $}} 542 // CHECK-FIXES-NEXT: } 543 HasInitListInit(const HasInitListInit &Other) : M(4) { 544 M = Other.M; 545 } 546 // CHECK-MESSAGES: :[[@LINE+5]]:5: warning: 'M' should be initialized in a member initializer of the constructor 547 // CHECK-FIXES: HasInitListInit(HasInitListInit &&Other) : M(Other.M) { 548 // CHECK-FIXES-NEXT: {{^ $}} 549 // CHECK-FIXES-NEXT: } 550 HasInitListInit(HasInitListInit &&Other) : M() { 551 M = Other.M; 552 } 553 }; 554 555 #define ASSIGN_IN_MACRO(FIELD, VALUE) FIELD = (VALUE); 556 557 struct MacroCantFix { 558 int n; // NoFix 559 // CHECK-FIXES: int n; // NoFix 560 MacroCantFix() { 561 ASSIGN_IN_MACRO(n, 0) 562 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'n' should be initialized in a member initializer of the constructor 563 // CHECK-FIXES: ASSIGN_IN_MACRO(n, 0) 564 } 565 }; 566 567 struct PR52818 { 568 PR52818() : bar(5) {} 569 PR52818(int) : PR52818() { bar = 3; } 570 571 int bar; 572 }; 573 574 struct RefReassignment { 575 RefReassignment(int &i) : m_i{i} { 576 m_i = 1; 577 } 578 int & m_i; 579 }; 580 581 struct ReassignmentAfterUnsafetyAssignment { 582 ReassignmentAfterUnsafetyAssignment() { 583 int a = 10; 584 m_i = a; 585 m_i = 1; 586 } 587 int m_i; 588 }; 589 590 namespace PR70189 { 591 #define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16))) 592 #define INVALID_HANDLE_VALUE ((void*)(unsigned long long)-1) 593 #define SIMPLE 12 594 595 class Foo { 596 public: 597 Foo() { 598 // CHECK-FIXES: Foo() : m_color(RGB(255, 128, 0)), m_handle(INVALID_HANDLE_VALUE), m_myval(SIMPLE) { 599 m_color = RGB(255, 128, 0); 600 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_color' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 601 // CHECK-FIXES: {{^\ *$}} 602 m_handle = INVALID_HANDLE_VALUE; 603 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_handle' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 604 // CHECK-FIXES: {{^\ *$}} 605 m_myval = SIMPLE; 606 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_myval' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 607 // CHECK-FIXES: {{^\ *$}} 608 } 609 private: 610 unsigned long m_color; 611 void* m_handle; 612 int m_myval; 613 }; 614 615 #undef SIMPLE 616 #undef INVALID_HANDLE_VALUE 617 #undef RGB 618 } 619 620 namespace GH77684 { 621 struct S1 { 622 // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 623 S1() : M{} { M = 0; } 624 // CHECK-FIXES: S1() : M{0} { } 625 int M; 626 }; 627 struct S2 { 628 // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 629 S2() : M{2} { M = 1; } 630 // CHECK-FIXES: S2() : M{1} { } 631 int M; 632 }; 633 struct T { int a; int b; int c; }; 634 T v; 635 struct S3 { 636 // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer] 637 S3() : M{1,2,3} { M = v; } 638 // CHECK-FIXES: S3() : M{v} { } 639 T M; 640 }; 641 } 642 643 namespace GH82970 { 644 struct InitFromBindingDecl { 645 int m; 646 InitFromBindingDecl() { 647 struct { int i; } a; 648 auto [n] = a; 649 m = n; 650 } 651 }; 652 } // namespace GH82970 653