1// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -fno-delayed-template-parsing
2
3namespace {
4// POD types are trivially move constructible.
5struct POD {
6 int a, b, c;
7};
8
9struct Movable {
10 int a, b, c;
11 Movable() = default;
12 Movable(const Movable &) {}
13 Movable(Movable &&) {}
14};
15
16struct NotMovable {
17 NotMovable() = default;
18 NotMovable(const NotMovable &) = default;
19 NotMovable(NotMovable &&) = delete;
20 int a, b, c;
21};
22}
23
24struct A {
25 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.
32Movable GlobalObj;
33struct B {
34 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.
40struct C {
41 // Tests extra-reference in body.
42 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.
46 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.
53struct D {
54 D(const Movable &M);
55 // CHECK-FIXES: D(Movable M);
56 Movable M;
57};
58D::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.
63struct E {
64 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.
71struct F {
72 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.
78struct G {
79 G(const Movable &);
80 // CHECK-FIXES: G(Movable );
81 Movable M;
82};
83G::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.
88namespace ns_H {
89typedef ::Movable HMovable;
90}
91struct H {
92 H(const ns_H::HMovable &M);
93 // CHECK-FIXES: H(ns_H::HMovable M);
94 ns_H::HMovable M;
95};
96using namespace ns_H;
97H::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
104struct I {
105 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.
113template <typename T> struct J {
114 J(const T &M) : M(M) {}
115 // CHECK-FIXES: J(const T &M) : M(M) {}
116 T M;
117};
118J<Movable> j1(Movable());
119J<NotMovable> j2(NotMovable());
120
121template<class T>
122struct MovableTemplateT
123{
124 MovableTemplateT() {}
125 MovableTemplateT(const MovableTemplateT& o) { }
126 MovableTemplateT(MovableTemplateT&& o) { }
127};
128
129template <class T>
130struct J2 {
131 J2(const MovableTemplateT<T>& A);
132 // CHECK-FIXES: J2(const MovableTemplateT<T>& A);
133 MovableTemplateT<T> M;
134};
135
136template <class T>
137J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {}
138// CHECK-FIXES: J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {}
139J2<int> j3(MovableTemplateT<int>{});
140
141struct K_Movable {
142 K_Movable() = default;
143 K_Movable(const K_Movable &) = default;
144 K_Movable(K_Movable &&o) { dummy = o.dummy; }
145 int dummy;
146};
147
148// Test with movable type with an user defined move constructor.
149struct K {
150 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
156template <typename T> struct L {
157 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};
162L<int> l(Movable());
163
164// Test with a non-instantiated template class.
165template <typename T> struct N {
166 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.
175struct O {
176 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.
183struct P {
184 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.
191struct Q {
192 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.
205namespace ns_R {
206typedef ::Movable RMovable;
207}
208struct R {
209 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.
216struct S {
217 S(Movable &&M) : M(M) {}
218 // CHECK-FIXES: S(Movable &&M) : M(M) {}
219 Movable M;
220};
221
222template <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.
226struct T {
227 T(array<int, 10> a) : a_(a) {}
228 // CHECK-FIXES: T(array<int, 10> a) : a_(a) {}
229 array<int, 10> a_;
230};
231
232struct U {
233 U(const POD &M) : M(M) {}
234 // CHECK-FIXES: U(const POD &M) : M(M) {}
235 POD M;
236};
237
238// The rewrite can't look through `typedefs` and `using`.
239// Test that we don't partially rewrite one decl without rewriting the other.
240using MovableConstRef = const Movable &;
241struct V {
242 V(MovableConstRef M);
243 // CHECK-FIXES: V(MovableConstRef M);
244 Movable M;
245};
246V::V(const Movable &M) : M(M) {}
247// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
248// CHECK-FIXES: V::V(const Movable &M) : M(M) {}
249
250// Test with paired lvalue/rvalue overloads.
251struct W1 {
252 W1(const Movable &M) : M(M) {}
253 W1(Movable &&M);
254 Movable M;
255};
256struct W2 {
257 W2(const Movable &M, int) : M(M) {}
258 W2(Movable &&M, int);
259 Movable M;
260};
261struct W3 {
262 W3(const W1 &, const Movable &M) : M(M) {}
263 W3(W1 &&, Movable &&M);
264 Movable M;
265};
266

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value.cpp