1 // RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \
2 // RUN: -config='{CheckOptions: \
3 // RUN:  [{key: modernize-pass-by-value.ValuesOnly, value: true}]}' \
4 // RUN: -- -isystem %S/Inputs/Headers
5 
6 #include <s.h>
7 
8 // CHECK-FIXES: #include <utility>
9 
10 template <class T> struct remove_reference      {typedef T type;};
11 template <class T> struct remove_reference<T&>  {typedef T type;};
12 template <class T> struct remove_reference<T&&> {typedef T type;};
13 
14 template <typename T>
move(T && arg)15 typename remove_reference<T>::type&& move(T&& arg) {
16   return static_cast<typename remove_reference<T>::type&&>(arg);
17 }
18 
19 struct C {
20   C() = default;
21   C(const C&) = default;
22 };
23 
24 struct B {
BB25   B() {}
BB26   B(const B&) {}
BB27   B(B &&) {}
28 };
29 
30 struct D : B {
DD31   D() : B() {}
DD32   D(const D &RHS) : B(RHS) {}
33   // CHECK-NOTES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [performance-move-constructor-init]
34   // CHECK-NOTES: 26:3: note: copy constructor being called
35   // CHECK-NOTES: 27:3: note: candidate move constructor here
DD36   D(D &&RHS) : B(RHS) {}
37 };
38 
39 struct E : B {
EE40   E() : B() {}
EE41   E(const E &RHS) : B(RHS) {}
EE42   E(E &&RHS) : B(move(RHS)) {} // ok
43 };
44 
45 struct F {
46   C M;
47 
FF48   F(F &&) : M(C()) {} // ok
49 };
50 
51 struct G {
52   G() = default;
53   G(const G&) = default;
54   G(G&&) = delete;
55 };
56 
57 struct H : G {
58   H() = default;
59   H(const H&) = default;
HH60   H(H &&RHS) : G(RHS) {} // ok
61 };
62 
63 struct I {
64   I(const I &) = default; // suppresses move constructor creation
65 };
66 
67 struct J : I {
JJ68   J(J &&RHS) : I(RHS) {} // ok
69 };
70 
71 struct K {}; // Has implicit copy and move constructors, is trivially copyable
72 struct L : K {
LL73   L(L &&RHS) : K(RHS) {} // ok
74 };
75 
76 struct M {
77   B Mem;
78   // CHECK-NOTES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [performance-move-constructor-init]
MM79   M(M &&RHS) : Mem(RHS.Mem) {}
80   // CHECK-NOTES: 26:3: note: copy constructor being called
81   // CHECK-NOTES: 27:3: note: candidate move constructor here
82 };
83 
84 struct N {
85   B Mem;
NN86   N(N &&RHS) : Mem(move(RHS.Mem)) {}
87 };
88 
89 struct O {
OO90   O(O&& other) : b(other.b) {} // ok
91   const B b;
92 };
93 
94 struct P {
PP95   P(O&& other) : b(other.b) {} // ok
96   B b;
97 };
98 
99 struct Movable {
100   Movable(Movable &&) = default;
101   Movable(const Movable &) = default;
102   Movable &operator=(const Movable &) = default;
~MovableMovable103   ~Movable() {}
104 };
105 
106 struct TriviallyCopyable {
107   TriviallyCopyable() = default;
108   TriviallyCopyable(TriviallyCopyable &&) = default;
109   TriviallyCopyable(const TriviallyCopyable &) = default;
110 };
111 
112 struct Positive {
PositivePositive113   Positive(Movable M) : M_(M) {}
114   // CHECK-NOTES: [[@LINE-1]]:12: warning: pass by value and use std::move [modernize-pass-by-value]
115   // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {}
116   Movable M_;
117 };
118 
119 struct NegativeMultipleInitializerReferences {
NegativeMultipleInitializerReferencesNegativeMultipleInitializerReferences120   NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {}
121   Movable M_;
122   Movable n_;
123 };
124 
125 struct NegativeReferencedInConstructorBody {
NegativeReferencedInConstructorBodyNegativeReferencedInConstructorBody126   NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; }
127   Movable M_;
128 };
129 
130 struct NegativeParamTriviallyCopyable {
NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable131   NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {}
NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable132   NegativeParamTriviallyCopyable(int I) : I_(I) {}
133 
134   TriviallyCopyable T_;
135   int I_;
136 };
137 
138 struct NegativeNotPassedByValue {
139   // This const ref constructor isn't warned about because the ValuesOnly option is set.
NegativeNotPassedByValueNegativeNotPassedByValue140   NegativeNotPassedByValue(const Movable &M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue141   NegativeNotPassedByValue(const Movable M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue142   NegativeNotPassedByValue(Movable &M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue143   NegativeNotPassedByValue(Movable *M) : M_(*M) {}
NegativeNotPassedByValueNegativeNotPassedByValue144   NegativeNotPassedByValue(const Movable *M) : M_(*M) {}
145   Movable M_;
146 };
147 
148 struct Immovable {
149   Immovable(const Immovable &) = default;
150   Immovable(Immovable &&) = delete;
151 };
152 
153 struct NegativeImmovableParameter {
NegativeImmovableParameterNegativeImmovableParameter154   NegativeImmovableParameter(Immovable I) : I_(I) {}
155   Immovable I_;
156 };
157