1 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\ 2 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 3 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 4 // RUN: -analyzer-checker debug.ExprInspection\ 5 // RUN: -verify=expected,peaceful,non-aggressive 6 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\ 7 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 8 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\ 9 // RUN: -analyzer-checker debug.ExprInspection\ 10 // RUN: -verify=expected,peaceful,non-aggressive 11 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\ 12 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 13 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 14 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\ 15 // RUN: -analyzer-checker debug.ExprInspection\ 16 // RUN: -verify=expected,non-aggressive 17 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\ 18 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 19 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\ 20 // RUN: -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\ 21 // RUN: -analyzer-checker debug.ExprInspection\ 22 // RUN: -verify=expected,non-aggressive 23 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\ 24 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 25 // RUN: -analyzer-config exploration_strategy=unexplored_first_queue\ 26 // RUN: -analyzer-config cplusplus.Move:WarnOn=All\ 27 // RUN: -analyzer-checker debug.ExprInspection\ 28 // RUN: -verify=expected,peaceful,aggressive 29 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\ 30 // RUN: -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\ 31 // RUN: -analyzer-config exploration_strategy=dfs -DDFS\ 32 // RUN: -analyzer-config cplusplus.Move:WarnOn=All\ 33 // RUN: -analyzer-checker debug.ExprInspection\ 34 // RUN: -verify=expected,peaceful,aggressive 35 36 // RUN: not %clang_analyze_cc1 -verify %s \ 37 // RUN: -analyzer-checker=core \ 38 // RUN: -analyzer-checker=cplusplus.Move \ 39 // RUN: -analyzer-config cplusplus.Move:WarnOn="a bunch of things" \ 40 // RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-MOVE-INVALID-VALUE 41 42 // CHECK-MOVE-INVALID-VALUE: (frontend): invalid input for checker option 43 // CHECK-MOVE-INVALID-VALUE-SAME: 'cplusplus.Move:WarnOn', that expects either 44 // CHECK-MOVE-INVALID-VALUE-SAME: "KnownsOnly", "KnownsAndLocals" or "All" 45 // CHECK-MOVE-INVALID-VALUE-SAME: string value 46 47 #include "Inputs/system-header-simulator-cxx.h" 48 49 void clang_analyzer_warnIfReached(); 50 51 class B { 52 public: 53 B() = default; 54 B(const B &) = default; 55 B(B &&) = default; 56 B& operator=(const B &q) = default; 57 void operator=(B &&b) { 58 return; 59 } 60 void foo() { return; } 61 }; 62 63 class A { 64 int i; 65 double d; 66 67 public: 68 B b; 69 A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {} 70 void moveconstruct(A &&other) { 71 std::swap(b, other.b); 72 std::swap(d, other.d); 73 std::swap(i, other.i); 74 return; 75 } 76 static A get() { 77 A v(12, 13); 78 return v; 79 } 80 A(A *a) { 81 moveconstruct(std::move(*a)); 82 } 83 A(const A &other) : i(other.i), d(other.d), b(other.b) {} 84 A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // aggressive-note{{Object 'b' is moved}} 85 } 86 A(A &&other, char *k) { 87 moveconstruct(std::move(other)); 88 } 89 void operator=(const A &other) { 90 i = other.i; 91 d = other.d; 92 b = other.b; 93 return; 94 } 95 void operator=(A &&other) { 96 moveconstruct(std::move(other)); 97 return; 98 } 99 int getI() { return i; } 100 int foo() const; 101 void bar() const; 102 void reset(); 103 void destroy(); 104 void clear(); 105 void resize(std::size_t); 106 void assign(const A &); 107 bool empty() const; 108 bool isEmpty() const; 109 operator bool() const; 110 111 void testUpdateField() { 112 A a; 113 A b = std::move(a); 114 a.i = 1; 115 a.foo(); // no-warning 116 } 117 void testUpdateFieldDouble() { 118 A a; 119 A b = std::move(a); 120 a.d = 1.0; 121 a.foo(); // no-warning 122 } 123 }; 124 125 int bignum(); 126 127 void moveInsideFunctionCall(A a) { 128 A b = std::move(a); 129 } 130 void leftRefCall(A &a) { 131 a.foo(); 132 } 133 void rightRefCall(A &&a) { 134 a.foo(); 135 } 136 void constCopyOrMoveCall(const A a) { 137 a.foo(); 138 } 139 140 void copyOrMoveCall(A a) { 141 a.foo(); 142 } 143 144 void simpleMoveCtorTest() { 145 { 146 A a; 147 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 148 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 149 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 150 } 151 { 152 A a; 153 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 154 b = a; // peaceful-warning {{Moved-from object 'a' is copied}} 155 // peaceful-note@-1 {{Moved-from object 'a' is copied}} 156 } 157 { 158 A a; 159 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 160 b = std::move(a); // peaceful-warning {{Moved-from object 'a' is moved}} 161 // peaceful-note@-1 {{Moved-from object 'a' is moved}} 162 } 163 } 164 165 void simpleMoveAssignementTest() { 166 { 167 A a; 168 A b; 169 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 170 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 171 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 172 } 173 { 174 A a; 175 A b; 176 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 177 A c(a); // peaceful-warning {{Moved-from object 'a' is copied}} 178 // peaceful-note@-1 {{Moved-from object 'a' is copied}} 179 } 180 { 181 A a; 182 A b; 183 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 184 A c(std::move(a)); // peaceful-warning {{Moved-from object 'a' is moved}} 185 // peaceful-note@-1 {{Moved-from object 'a' is moved}} 186 } 187 } 188 189 void moveInInitListTest() { 190 struct S { 191 A a; 192 }; 193 A a; 194 S s{std::move(a)}; // peaceful-note {{Object 'a' is moved}} 195 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 196 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 197 } 198 199 // Don't report a bug if the variable was assigned to in the meantime. 200 void reinitializationTest(int i) { 201 { 202 A a; 203 A b; 204 b = std::move(a); 205 a = A(); 206 a.foo(); 207 } 208 { 209 A a; 210 if (i == 1) { // peaceful-note 2 {{Assuming 'i' is not equal to 1}} 211 // peaceful-note@-1 2 {{Taking false branch}} 212 A b; 213 b = std::move(a); 214 a = A(); 215 } 216 if (i == 2) { // peaceful-note 2 {{Assuming 'i' is not equal to 2}} 217 // peaceful-note@-1 2 {{Taking false branch}} 218 a.foo(); // no-warning 219 } 220 } 221 { 222 A a; 223 if (i == 1) { // peaceful-note 2 {{Taking false branch}} 224 std::move(a); 225 } 226 if (i == 2) { // peaceful-note 2 {{Taking false branch}} 227 a = A(); 228 a.foo(); 229 } 230 } 231 // The built-in assignment operator should also be recognized as a 232 // reinitialization. (std::move() may be called on built-in types in template 233 // code.) 234 { 235 int a1 = 1, a2 = 2; 236 std::swap(a1, a2); 237 } 238 // A std::move() after the assignment makes the variable invalid again. 239 { 240 A a; 241 A b; 242 b = std::move(a); 243 a = A(); 244 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 245 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 246 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 247 } 248 // If a path exist where we not reinitialize the variable we report a bug. 249 { 250 A a; 251 A b; 252 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 253 if (i < 10) { // peaceful-note {{Assuming 'i' is >= 10}} 254 // peaceful-note@-1 {{Taking false branch}} 255 a = A(); 256 } 257 if (i > 5) { // peaceful-note {{Taking true branch}} 258 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 259 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 260 } 261 } 262 } 263 264 // Using decltype on an expression is not a use. 265 void decltypeIsNotUseTest() { 266 A a; 267 // A b(std::move(a)); 268 decltype(a) other_a; // no-warning 269 } 270 271 void loopTest() { 272 { 273 A a; 274 // FIXME: Execution doesn't jump to the end of the function yet. 275 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}} 276 rightRefCall(std::move(a)); // no-warning 277 } 278 } 279 { 280 A a; 281 for (int i = 0; i < 2; i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 282 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 283 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 284 rightRefCall(std::move(a)); // no-warning 285 } 286 } 287 { 288 A a; 289 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}} 290 leftRefCall(a); // no-warning 291 } 292 } 293 { 294 A a; 295 for (int i = 0; i < 2; i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 296 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 297 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 298 leftRefCall(a); // no-warning 299 } 300 } 301 { 302 A a; 303 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}} 304 constCopyOrMoveCall(a); // no-warning 305 } 306 } 307 { 308 A a; 309 for (int i = 0; i < 2; i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 310 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 311 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 312 constCopyOrMoveCall(a); // no-warning 313 } 314 } 315 { 316 A a; 317 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}} 318 moveInsideFunctionCall(a); // no-warning 319 } 320 } 321 { 322 A a; 323 for (int i = 0; i < 2; i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 324 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 325 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 326 moveInsideFunctionCall(a); // no-warning 327 } 328 } 329 { 330 A a; 331 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is false. Execution jumps to the end of the function}} 332 copyOrMoveCall(a); // no-warning 333 } 334 } 335 { 336 A a; 337 for (int i = 0; i < 2; i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 338 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 339 // peaceful-note@-2 {{Loop condition is false. Execution jumps to the end of the function}} 340 copyOrMoveCall(a); // no-warning 341 } 342 } 343 { 344 A a; 345 for (int i = 0; i < bignum(); i++) { // peaceful-note {{Loop condition is true. Entering loop body}} 346 // peaceful-note@-1 {{Loop condition is true. Entering loop body}} 347 constCopyOrMoveCall(std::move(a)); // peaceful-note {{Object 'a' is moved}} 348 // peaceful-warning@-1 {{Moved-from object 'a' is moved}} 349 // peaceful-note@-2 {{Moved-from object 'a' is moved}} 350 } 351 } 352 353 // Don't warn if we return after the move. 354 { 355 A a; 356 for (int i = 0; i < 3; ++i) { 357 a.bar(); 358 if (a.foo() > 0) { 359 A b; 360 b = std::move(a); // no-warning 361 return; 362 } 363 } 364 } 365 } 366 367 // Report a usage of a moved-from object only at the first use. 368 void uniqueTest(bool cond) { 369 A a(42, 42.0); 370 A b; 371 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 372 373 if (cond) { // peaceful-note {{Assuming 'cond' is not equal to 0}} 374 // peaceful-note@-1 {{Taking true branch}} 375 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 376 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 377 } 378 if (cond) { 379 a.bar(); // no-warning 380 } 381 382 a.bar(); // no-warning 383 } 384 385 void uniqueTest2() { 386 A a; 387 A a1 = std::move(a); // peaceful-note {{Object 'a' is moved}} 388 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 389 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 390 391 A a2 = std::move(a); // no-warning 392 a.foo(); // no-warning 393 } 394 395 // There are exceptions where we assume in general that the method works fine 396 //even on moved-from objects. 397 void moveSafeFunctionsTest() { 398 A a; 399 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 400 a.empty(); // no-warning 401 a.isEmpty(); // no-warning 402 (void)a; // no-warning 403 (bool)a; // expected-warning {{expression result unused}} 404 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 405 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 406 } 407 408 void moveStateResetFunctionsTest() { 409 { 410 A a; 411 A b = std::move(a); 412 a.reset(); // no-warning 413 a.foo(); // no-warning 414 // Test if resets the state of subregions as well. 415 a.b.foo(); // no-warning 416 } 417 { 418 A a; 419 A b = std::move(a); 420 a.destroy(); // no-warning 421 a.foo(); // no-warning 422 } 423 { 424 A a; 425 A b = std::move(a); 426 a.clear(); // no-warning 427 a.foo(); // no-warning 428 a.b.foo(); // no-warning 429 } 430 { 431 A a; 432 A b = std::move(a); 433 a.resize(0); // no-warning 434 a.foo(); // no-warning 435 a.b.foo(); // no-warning 436 } 437 { 438 A a; 439 A b = std::move(a); 440 a.assign(A()); // no-warning 441 a.foo(); // no-warning 442 a.b.foo(); // no-warning 443 } 444 } 445 446 // Moves or uses that occur as part of template arguments. 447 template <int> 448 class ClassTemplate { 449 public: 450 void foo(A a); 451 }; 452 453 template <int> 454 void functionTemplate(A a); 455 456 void templateArgIsNotUseTest() { 457 { 458 // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in 459 // Google Test. 460 A a; 461 ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning 462 } 463 { 464 A a; 465 functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning 466 } 467 } 468 469 // Moves of global variables are not reported. 470 A global_a; 471 void globalVariablesTest() { 472 std::move(global_a); 473 global_a.foo(); // no-warning 474 } 475 476 // Moves of member variables. 477 class memberVariablesTest { 478 A a; 479 static A static_a; 480 481 void f() { 482 A b; 483 b = std::move(a); // aggressive-note {{Object 'a' is moved}} 484 485 a.foo(); // aggressive-warning {{Method called on moved-from object 'a'}} 486 // aggressive-note@-1 {{Method called on moved-from object 'a'}} 487 488 b = std::move(static_a); // aggressive-note {{Object 'static_a' is moved}} 489 static_a.foo(); // aggressive-warning {{Method called on moved-from object 'static_a'}} 490 // aggressive-note@-1 {{Method called on moved-from object 'static_a'}} 491 } 492 }; 493 494 void PtrAndArrayTest() { 495 A *Ptr = new A(1, 1.5); 496 A Arr[10]; 497 Arr[2] = std::move(*Ptr); // aggressive-note{{Object is moved}} 498 (*Ptr).foo(); // aggressive-warning{{Method called on moved-from object}} 499 // aggressive-note@-1{{Method called on moved-from object}} 500 501 Ptr = &Arr[1]; 502 Arr[3] = std::move(Arr[1]); // aggressive-note {{Object is moved}} 503 Ptr->foo(); // aggressive-warning {{Method called on moved-from object}} 504 // aggressive-note@-1 {{Method called on moved-from object}} 505 506 Arr[3] = std::move(Arr[2]); // aggressive-note{{Object is moved}} 507 Arr[2].foo(); // aggressive-warning{{Method called on moved-from object}} 508 // aggressive-note@-1{{Method called on moved-from object}} 509 510 Arr[2] = std::move(Arr[3]); // reinitialization 511 Arr[2].foo(); // no-warning 512 } 513 514 void exclusiveConditionsTest(bool cond) { 515 A a; 516 if (cond) { 517 A b; 518 b = std::move(a); 519 } 520 if (!cond) { 521 a.bar(); // no-warning 522 } 523 } 524 525 void differentBranchesTest(int i) { 526 // Don't warn if the use is in a different branch from the move. 527 { 528 A a; 529 if (i > 0) { // peaceful-note {{Assuming 'i' is > 0}} 530 // peaceful-note@-1 {{Taking true branch}} 531 A b; 532 b = std::move(a); 533 } else { 534 a.foo(); // no-warning 535 } 536 } 537 // Same thing, but with a ternary operator. 538 { 539 A a, b; 540 i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // peaceful-note {{'?' condition is true}} 541 } 542 // A variation on the theme above. 543 { 544 A a; 545 a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); 546 #ifdef DFS 547 // peaceful-note@-2 {{Assuming the condition is false}} 548 // peaceful-note@-3 {{'?' condition is false}} 549 #else 550 // peaceful-note@-5 {{Assuming the condition is true}} 551 // peaceful-note@-6 {{'?' condition is true}} 552 #endif 553 } 554 // Same thing, but with a switch statement. 555 { 556 A a, b; 557 switch (i) { // peaceful-note {{Control jumps to 'case 1:'}} 558 case 1: 559 b = std::move(a); // no-warning 560 // FIXME: Execution doesn't jump to the end of the function yet. 561 break; // peaceful-note {{Execution jumps to the end of the function}} 562 case 2: 563 a.foo(); // no-warning 564 break; 565 } 566 } 567 // However, if there's a fallthrough, we do warn. 568 { 569 A a, b; 570 switch (i) { // peaceful-note {{Control jumps to 'case 1:'}} 571 case 1: 572 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 573 case 2: 574 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 575 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 576 break; 577 } 578 } 579 } 580 581 void tempTest() { 582 A a = A::get(); 583 A::get().foo(); // no-warning 584 for (int i = 0; i < bignum(); i++) { 585 A::get().foo(); // no-warning 586 } 587 } 588 589 void interFunTest1(A &a) { 590 a.bar(); // peaceful-warning {{Method called on moved-from object 'a'}} 591 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 592 } 593 594 void interFunTest2() { 595 A a; 596 A b; 597 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 598 interFunTest1(a); // peaceful-note {{Calling 'interFunTest1'}} 599 } 600 601 void foobar(A a, int i); 602 void foobar(int i, A a); 603 604 void paramEvaluateOrderTest() { 605 A a; 606 foobar(std::move(a), a.getI()); // peaceful-note {{Object 'a' is moved}} 607 // peaceful-warning@-1 {{Method called on moved-from object 'a'}} 608 // peaceful-note@-2 {{Method called on moved-from object 'a'}} 609 610 //FALSE NEGATIVE since parameters evaluate order is undefined 611 foobar(a.getI(), std::move(a)); //no-warning 612 } 613 614 void not_known_pass_by_ref(A &a); 615 void not_known_pass_by_const_ref(const A &a); 616 void not_known_pass_by_rvalue_ref(A &&a); 617 void not_known_pass_by_ptr(A *a); 618 void not_known_pass_by_const_ptr(const A *a); 619 620 void regionAndPointerEscapeTest() { 621 { 622 A a; 623 A b; 624 b = std::move(a); 625 not_known_pass_by_ref(a); 626 a.foo(); // no-warning 627 } 628 { 629 A a; 630 A b; 631 b = std::move(a); // peaceful-note{{Object 'a' is moved}} 632 not_known_pass_by_const_ref(a); 633 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 634 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 635 } 636 { 637 A a; 638 A b; 639 b = std::move(a); 640 not_known_pass_by_rvalue_ref(std::move(a)); 641 a.foo(); // no-warning 642 } 643 { 644 A a; 645 A b; 646 b = std::move(a); 647 not_known_pass_by_ptr(&a); 648 a.foo(); // no-warning 649 } 650 { 651 A a; 652 A b; 653 b = std::move(a); // peaceful-note {{Object 'a' is moved}} 654 not_known_pass_by_const_ptr(&a); 655 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 656 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 657 } 658 } 659 660 // A declaration statement containing multiple declarations sequences the 661 // initializer expressions. 662 void declarationSequenceTest() { 663 { 664 A a; 665 A a1 = a, a2 = std::move(a); // no-warning 666 } 667 { 668 A a; 669 A a1 = std::move(a), a2 = a; // peaceful-note {{Object 'a' is moved}} 670 // peaceful-warning@-1 {{Moved-from object 'a' is copied}} 671 // peaceful-note@-2 {{Moved-from object 'a' is copied}} 672 } 673 } 674 675 // The logical operators && and || sequence their operands. 676 void logicalOperatorsSequenceTest() { 677 { 678 A a; 679 if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // peaceful-note {{Assuming the condition is false}} 680 // peaceful-note@-1 {{Left side of '&&' is false}} 681 // peaceful-note@-2 {{Taking false branch}} 682 // And the other report: 683 // peaceful-note@-4 {{Assuming the condition is false}} 684 // peaceful-note@-5 {{Left side of '&&' is false}} 685 // peaceful-note@-6 {{Taking false branch}} 686 A().bar(); 687 } 688 } 689 // A variation: Negate the result of the && (which pushes the && further down 690 // into the AST). 691 { 692 A a; 693 if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // peaceful-note {{Assuming the condition is false}} 694 // peaceful-note@-1 {{Left side of '&&' is false}} 695 // peaceful-note@-2 {{Taking true branch}} 696 // And the other report: 697 // peaceful-note@-4 {{Assuming the condition is false}} 698 // peaceful-note@-5 {{Left side of '&&' is false}} 699 // peaceful-note@-6 {{Taking true branch}} 700 A().bar(); 701 } 702 } 703 { 704 A a; 705 if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // peaceful-note {{Object 'a' is moved}} 706 // peaceful-note@-1 {{Assuming the condition is true}} 707 // peaceful-note@-2 {{Left side of '&&' is true}} 708 // peaceful-warning@-3 {{Method called on moved-from object 'a'}} 709 // peaceful-note@-4 {{Method called on moved-from object 'a'}} 710 // And the other report: 711 // peaceful-note@-6 {{Assuming the condition is false}} 712 // peaceful-note@-7 {{Left side of '&&' is false}} 713 // peaceful-note@-8 {{Taking false branch}} 714 A().bar(); 715 } 716 } 717 { 718 A a; 719 if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // peaceful-note {{Assuming the condition is true}} 720 // peaceful-note@-1 {{Left side of '||' is true}} 721 // peaceful-note@-2 {{Taking true branch}} 722 A().bar(); 723 } 724 } 725 { 726 A a; 727 if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // peaceful-note {{Object 'a' is moved}} 728 // peaceful-note@-1 {{Assuming the condition is false}} 729 // peaceful-note@-2 {{Left side of '||' is false}} 730 // peaceful-warning@-3 {{Method called on moved-from object 'a'}} 731 // peaceful-note@-4 {{Method called on moved-from object 'a'}} 732 A().bar(); 733 } 734 } 735 } 736 737 // A range-based for sequences the loop variable declaration before the body. 738 void forRangeSequencesTest() { 739 A v[2] = {A(), A()}; 740 for (A &a : v) { 741 A b; 742 b = std::move(a); // no-warning 743 } 744 } 745 746 // If a variable is declared in an if statement, the declaration of the variable 747 // (which is treated like a reinitialization by the check) is sequenced before 748 // the evaluation of the condition (which constitutes a use). 749 void ifStmtSequencesDeclAndConditionTest() { 750 for (int i = 0; i < 3; ++i) { 751 if (A a = A()) { 752 A b; 753 b = std::move(a); // no-warning 754 } 755 } 756 } 757 758 struct C : public A { 759 [[clang::reinitializes]] void reinit(); 760 }; 761 762 void subRegionMoveTest() { 763 { 764 A a; 765 B b = std::move(a.b); // aggressive-note {{Object 'b' is moved}} 766 a.b.foo(); // aggressive-warning {{Method called on moved-from object 'b'}} 767 // aggressive-note@-1 {{Method called on moved-from object 'b'}} 768 } 769 { 770 A a; 771 A a1 = std::move(a); // aggressive-note {{Calling move constructor for 'A'}} 772 // aggressive-note@-1 {{Returning from move constructor for 'A'}} 773 a.b.foo(); // aggressive-warning{{Method called on moved-from object 'b'}} 774 // aggressive-note@-1{{Method called on moved-from object 'b'}} 775 } 776 // Don't report a misuse if any SuperRegion is already reported. 777 { 778 A a; 779 A a1 = std::move(a); // peaceful-note {{Object 'a' is moved}} 780 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 781 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 782 a.b.foo(); // no-warning 783 } 784 { 785 C c; 786 C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}} 787 c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}} 788 // peaceful-note@-1 {{Method called on moved-from object 'c'}} 789 c.b.foo(); // no-warning 790 } 791 } 792 793 void resetSuperClass() { 794 C c; 795 C c1 = std::move(c); 796 c.clear(); 797 C c2 = c; // no-warning 798 } 799 800 void resetSuperClass2() { 801 C c; 802 C c1 = std::move(c); 803 c.reinit(); 804 C c2 = c; // no-warning 805 } 806 807 void reportSuperClass() { 808 C c; 809 C c1 = std::move(c); // peaceful-note {{Object 'c' is moved}} 810 c.foo(); // peaceful-warning {{Method called on moved-from object 'c'}} 811 // peaceful-note@-1 {{Method called on moved-from object 'c'}} 812 C c2 = c; // no-warning 813 } 814 815 struct Empty {}; 816 817 Empty inlinedCall() { 818 // Used to warn because region 'e' failed to be cleaned up because no symbols 819 // have ever died during the analysis and the checkDeadSymbols callback 820 // was skipped entirely. 821 Empty e{}; 822 return e; // no-warning 823 } 824 825 void checkInlinedCallZombies() { 826 while (true) 827 inlinedCall(); 828 } 829 830 void checkLoopZombies() { 831 while (true) { 832 Empty e{}; 833 Empty f = std::move(e); // no-warning 834 } 835 } 836 837 void checkMoreLoopZombies1(bool flag) { 838 while (flag) { 839 Empty e{}; 840 if (true) 841 e; // expected-warning {{expression result unused}} 842 Empty f = std::move(e); // no-warning 843 } 844 } 845 846 bool coin(); 847 848 void checkMoreLoopZombies2(bool flag) { 849 while (flag) { 850 Empty e{}; 851 while (coin()) 852 e; // expected-warning {{expression result unused}} 853 Empty f = std::move(e); // no-warning 854 } 855 } 856 857 void checkMoreLoopZombies3(bool flag) { 858 while (flag) { 859 Empty e{}; 860 do 861 e; // expected-warning {{expression result unused}} 862 while (coin()); 863 Empty f = std::move(e); // no-warning 864 } 865 } 866 867 void checkMoreLoopZombies4(bool flag) { 868 while (flag) { 869 Empty e{}; 870 for (; coin();) 871 e; // expected-warning {{expression result unused}} 872 Empty f = std::move(e); // no-warning 873 } 874 } 875 876 struct MoveOnlyWithDestructor { 877 MoveOnlyWithDestructor(); 878 ~MoveOnlyWithDestructor(); 879 MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete; 880 MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m); 881 }; 882 883 MoveOnlyWithDestructor foo() { 884 MoveOnlyWithDestructor m; 885 return m; 886 } 887 888 class HasSTLField { 889 std::vector<int> V; 890 void testVector() { 891 // Warn even in non-aggressive mode when it comes to STL, because 892 // in STL the object is left in "valid but unspecified state" after move. 893 std::vector<int> W = std::move(V); // expected-note {{Object 'V' of type 'std::vector' is left in a valid but unspecified state after move}} 894 V.push_back(123); // expected-warning {{Method called on moved-from object 'V'}} 895 // expected-note@-1 {{Method called on moved-from object 'V'}} 896 } 897 898 std::unique_ptr<int> P; 899 void testUniquePtr() { 900 // unique_ptr remains in a well-defined state after move. 901 std::unique_ptr<int> Q = std::move(P); // aggressive-note {{Object 'P' is moved}} 902 // non-aggressive-note@-1 {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}} 903 P.get(); // aggressive-warning{{Method called on moved-from object 'P'}} 904 // aggressive-note@-1{{Method called on moved-from object 'P'}} 905 906 // Because that well-defined state is null, dereference is still UB. 907 // Note that in aggressive mode we already warned about 'P', 908 // so no extra warning is generated. 909 *P += 1; // non-aggressive-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 910 // non-aggressive-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 911 912 // The program should have crashed by now. 913 clang_analyzer_warnIfReached(); // no-warning 914 } 915 }; 916 917 void localRValueMove(A &&a) { 918 A b = std::move(a); // peaceful-note {{Object 'a' is moved}} 919 a.foo(); // peaceful-warning {{Method called on moved-from object 'a'}} 920 // peaceful-note@-1 {{Method called on moved-from object 'a'}} 921 } 922 923 void localUniquePtr(std::unique_ptr<int> P) { 924 // Even though unique_ptr is safe to use after move, 925 // reusing a local variable this way usually indicates a bug. 926 std::unique_ptr<int> Q = std::move(P); // peaceful-note {{Object 'P' is moved}} 927 P.get(); // peaceful-warning {{Method called on moved-from object 'P'}} 928 // peaceful-note@-1 {{Method called on moved-from object 'P'}} 929 } 930 931 void localUniquePtrWithArrow(std::unique_ptr<A> P) { 932 std::unique_ptr<A> Q = std::move(P); // expected-note{{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}} 933 P->foo(); // expected-warning{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 934 // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}} 935 } 936