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