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