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