1 // RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -fno-delayed-template-parsing
2 
3 namespace {
4 // POD types are trivially move constructible.
5 struct POD {
6   int a, b, c;
7 };
8 
9 struct Movable {
10   int a, b, c;
11   Movable() = default;
Movable__anon9b5a697d0111::Movable12   Movable(const Movable &) {}
Movable__anon9b5a697d0111::Movable13   Movable(Movable &&) {}
14 };
15 
16 struct NotMovable {
17   NotMovable() = default;
18   NotMovable(const NotMovable &) = default;
19   NotMovable(NotMovable &&) = delete;
20   int a, b, c;
21 };
22 }
23 
24 struct A {
AA25   A(const Movable &M) : M(M) {}
26   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]
27   // CHECK-FIXES: A(Movable M) : M(std::move(M)) {}
28   Movable M;
29 };
30 
31 // Test that we aren't modifying other things than a parameter.
32 Movable GlobalObj;
33 struct B {
BB34   B(const Movable &M) : M(GlobalObj) {}
35   // CHECK-FIXES: B(const Movable &M) : M(GlobalObj) {}
36   Movable M;
37 };
38 
39 // Test that a parameter with more than one reference to it won't be changed.
40 struct C {
41   // Tests extra-reference in body.
CC42   C(const Movable &M) : M(M) { this->i = M.a; }
43   // CHECK-FIXES: C(const Movable &M) : M(M) { this->i = M.a; }
44 
45   // Tests extra-reference in init-list.
CC46   C(const Movable &M, int) : M(M), i(M.a) {}
47   // CHECK-FIXES: C(const Movable &M, int) : M(M), i(M.a) {}
48   Movable M;
49   int i;
50 };
51 
52 // Test that both declaration and definition are updated.
53 struct D {
54   D(const Movable &M);
55   // CHECK-FIXES: D(Movable M);
56   Movable M;
57 };
D(const Movable & M)58 D::D(const Movable &M) : M(M) {}
59 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
60 // CHECK-FIXES: D::D(Movable M) : M(std::move(M)) {}
61 
62 // Test with default parameter.
63 struct E {
EE64   E(const Movable &M = Movable()) : M(M) {}
65   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
66   // CHECK-FIXES: E(Movable M = Movable()) : M(std::move(M)) {}
67   Movable M;
68 };
69 
70 // Test with object that can't be moved.
71 struct F {
FF72   F(const NotMovable &NM) : NM(NM) {}
73   // CHECK-FIXES: F(const NotMovable &NM) : NM(NM) {}
74   NotMovable NM;
75 };
76 
77 // Test unnamed parameter in declaration.
78 struct G {
79   G(const Movable &);
80   // CHECK-FIXES: G(Movable );
81   Movable M;
82 };
G(const Movable & M)83 G::G(const Movable &M) : M(M) {}
84 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
85 // CHECK-FIXES: G::G(Movable M) : M(std::move(M)) {}
86 
87 // Test parameter with and without qualifier.
88 namespace ns_H {
89 typedef ::Movable HMovable;
90 }
91 struct H {
92   H(const ns_H::HMovable &M);
93   // CHECK-FIXES: H(ns_H::HMovable M);
94   ns_H::HMovable M;
95 };
96 using namespace ns_H;
H(const HMovable & M)97 H::H(const HMovable &M) : M(M) {}
98 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
99 // CHECK-FIXES: H(HMovable M) : M(std::move(M)) {}
100 
101 // Try messing up with macros.
102 #define MOVABLE_PARAM(Name) const Movable & Name
103 // CHECK-FIXES: #define MOVABLE_PARAM(Name) const Movable & Name
104 struct I {
II105   I(MOVABLE_PARAM(M)) : M(M) {}
106   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
107   // CHECK-FIXES: I(MOVABLE_PARAM(M)) : M(M) {}
108   Movable M;
109 };
110 #undef MOVABLE_PARAM
111 
112 // Test that templates aren't modified.
113 template <typename T> struct J {
JJ114   J(const T &M) : M(M) {}
115   // CHECK-FIXES: J(const T &M) : M(M) {}
116   T M;
117 };
118 J<Movable> j1(Movable());
119 J<NotMovable> j2(NotMovable());
120 
121 template<class T>
122 struct MovableTemplateT
123 {
MovableTemplateTMovableTemplateT124   MovableTemplateT() {}
MovableTemplateTMovableTemplateT125   MovableTemplateT(const MovableTemplateT& o) { }
MovableTemplateTMovableTemplateT126   MovableTemplateT(MovableTemplateT&& o) { }
127 };
128 
129 template <class T>
130 struct J2 {
131   J2(const MovableTemplateT<T>& A);
132   // CHECK-FIXES: J2(const MovableTemplateT<T>& A);
133   MovableTemplateT<T> M;
134 };
135 
136 template <class T>
J2(const MovableTemplateT<T> & A)137 J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {}
138 // CHECK-FIXES: J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {}
139 J2<int> j3(MovableTemplateT<int>{});
140 
141 struct K_Movable {
142   K_Movable() = default;
143   K_Movable(const K_Movable &) = default;
K_MovableK_Movable144   K_Movable(K_Movable &&o) { dummy = o.dummy; }
145   int dummy;
146 };
147 
148 // Test with movable type with an user defined move constructor.
149 struct K {
KK150   K(const K_Movable &M) : M(M) {}
151   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
152   // CHECK-FIXES: K(K_Movable M) : M(std::move(M)) {}
153   K_Movable M;
154 };
155 
156 template <typename T> struct L {
LL157   L(const Movable &M) : M(M) {}
158   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
159   // CHECK-FIXES: L(Movable M) : M(std::move(M)) {}
160   Movable M;
161 };
162 L<int> l(Movable());
163 
164 // Test with a non-instantiated template class.
165 template <typename T> struct N {
NN166   N(const Movable &M) : M(M) {}
167   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
168   // CHECK-FIXES: N(Movable M) : M(std::move(M)) {}
169 
170   Movable M;
171   T A;
172 };
173 
174 // Test with value parameter.
175 struct O {
OO176   O(Movable M) : M(M) {}
177   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
178   // CHECK-FIXES: O(Movable M) : M(std::move(M)) {}
179   Movable M;
180 };
181 
182 // Test with a const-value parameter.
183 struct P {
PP184   P(const Movable M) : M(M) {}
185   // CHECK-FIXES: P(const Movable M) : M(M) {}
186   Movable M;
187 };
188 
189 // Test with multiples parameters where some need to be changed and some don't.
190 // need to.
191 struct Q {
QQ192   Q(const Movable &A, const Movable &B, const Movable &C, double D)
193       : A(A), B(B), C(C), D(D) {}
194   // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: pass by value and use std::move
195   // CHECK-MESSAGES: :[[@LINE-3]]:41: warning: pass by value and use std::move
196   // CHECK-FIXES:      Q(const Movable &A, Movable B, Movable C, double D)
197   // CHECK-FIXES:     : A(A), B(std::move(B)), C(std::move(C)), D(D) {}
198   const Movable &A;
199   Movable B;
200   Movable C;
201   double D;
202 };
203 
204 // Test that value-parameters with a nested name specifier are left as-is.
205 namespace ns_R {
206 typedef ::Movable RMovable;
207 }
208 struct R {
RR209   R(ns_R::RMovable M) : M(M) {}
210   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
211   // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {}
212   ns_R::RMovable M;
213 };
214 
215 // Test with rvalue parameter.
216 struct S {
SS217   S(Movable &&M) : M(M) {}
218   // CHECK-FIXES: S(Movable &&M) : M(M) {}
219   Movable M;
220 };
221 
222 template <typename T, int N> struct array { T A[N]; };
223 
224 // Test that types that are trivially copyable will not use std::move. This will
225 // cause problems with performance-move-const-arg, as it will revert it.
226 struct T {
TT227   T(array<int, 10> a) : a_(a) {}
228   // CHECK-FIXES: T(array<int, 10> a) : a_(a) {}
229   array<int, 10> a_;
230 };
231 
232 struct U {
UU233   U(const POD &M) : M(M) {}
234   POD M;
235 };
236