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