1 | // RUN: %check_clang_tidy --match-partial-fixes %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; |
12 | Movable(const Movable &) {} |
13 | 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 { |
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. |
32 | Movable GlobalObj; |
33 | struct B { |
34 | B(const Movable &M) : M(GlobalObj) {} |
35 | Movable M; |
36 | }; |
37 | |
38 | // Test that a parameter with more than one reference to it won't be changed. |
39 | struct C { |
40 | // Tests extra-reference in body. |
41 | C(const Movable &M) : M(M) { this->i = M.a; } |
42 | |
43 | // Tests extra-reference in init-list. |
44 | C(const Movable &M, int) : M(M), i(M.a) {} |
45 | Movable M; |
46 | int i; |
47 | }; |
48 | |
49 | // Test that both declaration and definition are updated. |
50 | struct D { |
51 | D(const Movable &M); |
52 | // CHECK-FIXES: D(Movable M); |
53 | Movable M; |
54 | }; |
55 | D::D(const Movable &M) : M(M) {} |
56 | // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move |
57 | // CHECK-FIXES: D::D(Movable M) : M(std::move(M)) {} |
58 | |
59 | // Test with default parameter. |
60 | struct E { |
61 | E(const Movable &M = Movable()) : M(M) {} |
62 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
63 | // CHECK-FIXES: E(Movable M = Movable()) : M(std::move(M)) {} |
64 | Movable M; |
65 | }; |
66 | |
67 | // Test with object that can't be moved. |
68 | struct F { |
69 | F(const NotMovable &NM) : NM(NM) {} |
70 | NotMovable NM; |
71 | }; |
72 | |
73 | // Test unnamed parameter in declaration. |
74 | struct G { |
75 | G(const Movable &); |
76 | // CHECK-FIXES: G(Movable ); |
77 | Movable M; |
78 | }; |
79 | G::G(const Movable &M) : M(M) {} |
80 | // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move |
81 | // CHECK-FIXES: G::G(Movable M) : M(std::move(M)) {} |
82 | |
83 | // Test parameter with and without qualifier. |
84 | namespace ns_H { |
85 | typedef ::Movable HMovable; |
86 | } |
87 | struct H { |
88 | H(const ns_H::HMovable &M); |
89 | // CHECK-FIXES: H(ns_H::HMovable M); |
90 | ns_H::HMovable M; |
91 | }; |
92 | using namespace ns_H; |
93 | H::H(const HMovable &M) : M(M) {} |
94 | // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move |
95 | // CHECK-FIXES: H(HMovable M) : M(std::move(M)) {} |
96 | |
97 | // Try messing up with macros. |
98 | #define MOVABLE_PARAM(Name) const Movable & Name |
99 | // CHECK-FIXES: #define MOVABLE_PARAM(Name) const Movable & Name |
100 | struct I { |
101 | I(MOVABLE_PARAM(M)) : M(M) {} |
102 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
103 | // CHECK-FIXES: I(MOVABLE_PARAM(M)) : M(M) {} |
104 | Movable M; |
105 | }; |
106 | #undef MOVABLE_PARAM |
107 | |
108 | // Test that templates aren't modified. |
109 | template <typename T> struct J { |
110 | J(const T &M) : M(M) {} |
111 | T M; |
112 | }; |
113 | J<Movable> j1(Movable()); |
114 | J<NotMovable> j2(NotMovable()); |
115 | |
116 | template<class T> |
117 | struct MovableTemplateT |
118 | { |
119 | MovableTemplateT() {} |
120 | MovableTemplateT(const MovableTemplateT& o) { } |
121 | MovableTemplateT(MovableTemplateT&& o) { } |
122 | }; |
123 | |
124 | template <class T> |
125 | struct J2 { |
126 | J2(const MovableTemplateT<T>& A); |
127 | MovableTemplateT<T> M; |
128 | }; |
129 | |
130 | template <class T> |
131 | J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {} |
132 | J2<int> j3(MovableTemplateT<int>{}); |
133 | |
134 | struct K_Movable { |
135 | K_Movable() = default; |
136 | K_Movable(const K_Movable &) = default; |
137 | K_Movable(K_Movable &&o) { dummy = o.dummy; } |
138 | int dummy; |
139 | }; |
140 | |
141 | // Test with movable type with an user defined move constructor. |
142 | struct K { |
143 | K(const K_Movable &M) : M(M) {} |
144 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
145 | // CHECK-FIXES: K(K_Movable M) : M(std::move(M)) {} |
146 | K_Movable M; |
147 | }; |
148 | |
149 | template <typename T> struct L { |
150 | L(const Movable &M) : M(M) {} |
151 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
152 | // CHECK-FIXES: L(Movable M) : M(std::move(M)) {} |
153 | Movable M; |
154 | }; |
155 | L<int> l(Movable()); |
156 | |
157 | // Test with a non-instantiated template class. |
158 | template <typename T> struct N { |
159 | N(const Movable &M) : M(M) {} |
160 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
161 | // CHECK-FIXES: N(Movable M) : M(std::move(M)) {} |
162 | |
163 | Movable M; |
164 | T A; |
165 | }; |
166 | |
167 | // Test with value parameter. |
168 | struct O { |
169 | O(Movable M) : M(M) {} |
170 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
171 | // CHECK-FIXES: O(Movable M) : M(std::move(M)) {} |
172 | Movable M; |
173 | }; |
174 | |
175 | // Test with a const-value parameter. |
176 | struct P { |
177 | P(const Movable M) : M(M) {} |
178 | Movable M; |
179 | }; |
180 | |
181 | // Test with multiples parameters where some need to be changed and some don't. |
182 | // need to. |
183 | struct Q { |
184 | Q(const Movable &A, const Movable &B, const Movable &C, double D) |
185 | : A(A), B(B), C(C), D(D) {} |
186 | // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: pass by value and use std::move |
187 | // CHECK-MESSAGES: :[[@LINE-3]]:41: warning: pass by value and use std::move |
188 | // CHECK-FIXES: Q(const Movable &A, Movable B, Movable C, double D) |
189 | // CHECK-FIXES: : A(A), B(std::move(B)), C(std::move(C)), D(D) {} |
190 | const Movable &A; |
191 | Movable B; |
192 | Movable C; |
193 | double D; |
194 | }; |
195 | |
196 | // Test that value-parameters with a nested name specifier are left as-is. |
197 | namespace ns_R { |
198 | typedef ::Movable RMovable; |
199 | } |
200 | struct R { |
201 | R(ns_R::RMovable M) : M(M) {} |
202 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move |
203 | // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {} |
204 | ns_R::RMovable M; |
205 | }; |
206 | |
207 | // Test with rvalue parameter. |
208 | struct S { |
209 | S(Movable &&M) : M(M) {} |
210 | Movable M; |
211 | }; |
212 | |
213 | template <typename T, int N> struct array { T A[N]; }; |
214 | |
215 | // Test that types that are trivially copyable will not use std::move. This will |
216 | // cause problems with performance-move-const-arg, as it will revert it. |
217 | struct T { |
218 | T(array<int, 10> a) : a_(a) {} |
219 | array<int, 10> a_; |
220 | }; |
221 | |
222 | struct U { |
223 | U(const POD &M) : M(M) {} |
224 | POD M; |
225 | }; |
226 | |
227 | // The rewrite can't look through `typedefs` and `using`. |
228 | // Test that we don't partially rewrite one decl without rewriting the other. |
229 | using MovableConstRef = const Movable &; |
230 | struct V { |
231 | V(MovableConstRef M); |
232 | // CHECK-FIXES: V(MovableConstRef M); |
233 | Movable M; |
234 | }; |
235 | V::V(const Movable &M) : M(M) {} |
236 | // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move |
237 | // CHECK-FIXES: V::V(const Movable &M) : M(M) {} |
238 | |
239 | // Test with paired lvalue/rvalue overloads. |
240 | struct W1 { |
241 | W1(const Movable &M) : M(M) {} |
242 | W1(Movable &&M); |
243 | Movable M; |
244 | }; |
245 | struct W2 { |
246 | W2(const Movable &M, int) : M(M) {} |
247 | W2(Movable &&M, int); |
248 | Movable M; |
249 | }; |
250 | struct W3 { |
251 | W3(const W1 &, const Movable &M) : M(M) {} |
252 | W3(W1 &&, Movable &&M); |
253 | Movable M; |
254 | }; |
255 | |