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