1 | // RUN: %check_clang_tidy -std=c++17-or-later %s performance-unnecessary-copy-initialization %t |
2 | |
3 | template <typename T> |
4 | struct Iterator { |
5 | void operator++(); |
6 | T &operator*() const; |
7 | bool operator!=(const Iterator &) const; |
8 | typedef const T &const_reference; |
9 | }; |
10 | |
11 | template <typename T> |
12 | struct ConstIterator { |
13 | void operator++(); |
14 | const T &operator*() const; |
15 | bool operator!=(const ConstIterator &) const; |
16 | typedef const T &const_reference; |
17 | }; |
18 | |
19 | struct ExpensiveToCopyType { |
20 | ExpensiveToCopyType(); |
21 | virtual ~ExpensiveToCopyType(); |
22 | const ExpensiveToCopyType &reference() const; |
23 | using ConstRef = const ExpensiveToCopyType &; |
24 | ConstRef referenceWithAlias() const; |
25 | const ExpensiveToCopyType *pointer() const; |
26 | void nonConstMethod(); |
27 | bool constMethod() const; |
28 | template <typename A> |
29 | const A &templatedAccessor() const; |
30 | operator int() const; // Implicit conversion to int. |
31 | }; |
32 | |
33 | template <typename T> |
34 | struct Container { |
35 | bool empty() const; |
36 | const T& operator[](int) const; |
37 | const T& operator[](int); |
38 | Iterator<T> begin(); |
39 | Iterator<T> end(); |
40 | ConstIterator<T> begin() const; |
41 | ConstIterator<T> end() const; |
42 | void nonConstMethod(); |
43 | bool constMethod() const; |
44 | |
45 | const T& at(int) const; |
46 | T& at(int); |
47 | |
48 | }; |
49 | |
50 | using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>; |
51 | |
52 | struct TrivialToCopyType { |
53 | const TrivialToCopyType &reference() const; |
54 | }; |
55 | |
56 | struct WeirdCopyCtorType { |
57 | WeirdCopyCtorType(); |
58 | WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true); |
59 | |
60 | void nonConstMethod(); |
61 | bool constMethod() const; |
62 | }; |
63 | |
64 | ExpensiveToCopyType global_expensive_to_copy_type; |
65 | |
66 | const ExpensiveToCopyType &ExpensiveTypeReference(); |
67 | const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &); |
68 | const ExpensiveToCopyType &freeFunctionWithDefaultArg( |
69 | const ExpensiveToCopyType *arg = nullptr); |
70 | const TrivialToCopyType &TrivialTypeReference(); |
71 | |
72 | void mutate(ExpensiveToCopyType &); |
73 | void mutate(ExpensiveToCopyType *); |
74 | void useAsConstPointer(const ExpensiveToCopyType *); |
75 | void useAsConstReference(const ExpensiveToCopyType &); |
76 | void useByValue(ExpensiveToCopyType); |
77 | |
78 | void PositiveFunctionCall() { |
79 | const auto AutoAssigned = ExpensiveTypeReference(); |
80 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization] |
81 | // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
82 | AutoAssigned.constMethod(); |
83 | |
84 | const auto AutoCopyConstructed(ExpensiveTypeReference()); |
85 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
86 | // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
87 | AutoCopyConstructed.constMethod(); |
88 | |
89 | const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
90 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
91 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
92 | VarAssigned.constMethod(); |
93 | |
94 | const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
95 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
96 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
97 | VarCopyConstructed.constMethod(); |
98 | } |
99 | |
100 | void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) { |
101 | const auto AutoAssigned = Obj.reference(); |
102 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
103 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
104 | AutoAssigned.constMethod(); |
105 | |
106 | const auto AutoCopyConstructed(Obj.reference()); |
107 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
108 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
109 | AutoCopyConstructed.constMethod(); |
110 | |
111 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
112 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
113 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
114 | VarAssigned.constMethod(); |
115 | |
116 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
117 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
118 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
119 | VarCopyConstructed.constMethod(); |
120 | } |
121 | |
122 | void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) { |
123 | const auto AutoAssigned = Obj.reference(); |
124 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
125 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
126 | AutoAssigned.constMethod(); |
127 | |
128 | const auto AutoCopyConstructed(Obj.reference()); |
129 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
130 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
131 | AutoCopyConstructed.constMethod(); |
132 | |
133 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
134 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
135 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
136 | VarAssigned.constMethod(); |
137 | |
138 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
139 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
140 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
141 | VarCopyConstructed.constMethod(); |
142 | } |
143 | |
144 | void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) { |
145 | const auto AutoAssigned = Obj->reference(); |
146 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
147 | // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
148 | AutoAssigned.constMethod(); |
149 | |
150 | const auto AutoCopyConstructed(Obj->reference()); |
151 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
152 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference()); |
153 | AutoCopyConstructed.constMethod(); |
154 | |
155 | const ExpensiveToCopyType VarAssigned = Obj->reference(); |
156 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
157 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference(); |
158 | VarAssigned.constMethod(); |
159 | |
160 | const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
161 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
162 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference()); |
163 | VarCopyConstructed.constMethod(); |
164 | } |
165 | |
166 | void PositiveOperatorCallConstReferenceParam(const Container<ExpensiveToCopyType> &C) { |
167 | const auto AutoAssigned = C[42]; |
168 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
169 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
170 | AutoAssigned.constMethod(); |
171 | |
172 | const auto AutoCopyConstructed(C[42]); |
173 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
174 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
175 | AutoCopyConstructed.constMethod(); |
176 | |
177 | const ExpensiveToCopyType VarAssigned = C[42]; |
178 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
179 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
180 | VarAssigned.constMethod(); |
181 | |
182 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
183 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
184 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
185 | VarCopyConstructed.constMethod(); |
186 | } |
187 | |
188 | void PositiveOperatorCallConstValueParam(const Container<ExpensiveToCopyType> C) { |
189 | const auto AutoAssigned = C[42]; |
190 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
191 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
192 | AutoAssigned.constMethod(); |
193 | |
194 | const auto AutoCopyConstructed(C[42]); |
195 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
196 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
197 | AutoCopyConstructed.constMethod(); |
198 | |
199 | const ExpensiveToCopyType VarAssigned = C[42]; |
200 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
201 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
202 | VarAssigned.constMethod(); |
203 | |
204 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
205 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
206 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
207 | VarCopyConstructed.constMethod(); |
208 | } |
209 | |
210 | void PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlias C) { |
211 | const auto AutoAssigned = C[42]; |
212 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
213 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
214 | AutoAssigned.constMethod(); |
215 | |
216 | const auto AutoCopyConstructed(C[42]); |
217 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
218 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
219 | AutoCopyConstructed.constMethod(); |
220 | |
221 | const ExpensiveToCopyType VarAssigned = C[42]; |
222 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
223 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
224 | VarAssigned.constMethod(); |
225 | |
226 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
227 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
228 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
229 | VarCopyConstructed.constMethod(); |
230 | } |
231 | |
232 | void PositiveOperatorCallConstPtrParam(const Container<ExpensiveToCopyType>* C) { |
233 | const auto AutoAssigned = (*C)[42]; |
234 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
235 | // CHECK-FIXES: const auto& AutoAssigned = (*C)[42]; |
236 | AutoAssigned.constMethod(); |
237 | |
238 | const auto AutoCopyConstructed((*C)[42]); |
239 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
240 | // CHECK-FIXES: const auto& AutoCopyConstructed((*C)[42]); |
241 | AutoCopyConstructed.constMethod(); |
242 | |
243 | const ExpensiveToCopyType VarAssigned = C->at(42); |
244 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
245 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C->at(42); |
246 | VarAssigned.constMethod(); |
247 | |
248 | const ExpensiveToCopyType VarCopyConstructed(C->at(42)); |
249 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
250 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->at(42)); |
251 | VarCopyConstructed.constMethod(); |
252 | } |
253 | |
254 | void PositiveLocalConstValue() { |
255 | const ExpensiveToCopyType Obj; |
256 | const auto UnnecessaryCopy = Obj.reference(); |
257 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
258 | // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference(); |
259 | UnnecessaryCopy.constMethod(); |
260 | } |
261 | |
262 | void PositiveLocalConstRef() { |
263 | const ExpensiveToCopyType Obj; |
264 | const ExpensiveToCopyType &ConstReference = Obj.reference(); |
265 | const auto UnnecessaryCopy = ConstReference.reference(); |
266 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
267 | // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference(); |
268 | UnnecessaryCopy.constMethod(); |
269 | } |
270 | |
271 | void PositiveLocalConstPointer() { |
272 | const ExpensiveToCopyType Obj; |
273 | const ExpensiveToCopyType *const ConstPointer = &Obj; |
274 | const auto UnnecessaryCopy = ConstPointer->reference(); |
275 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
276 | // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference(); |
277 | UnnecessaryCopy.constMethod(); |
278 | } |
279 | |
280 | void NegativeFunctionCallTrivialType() { |
281 | const auto AutoAssigned = TrivialTypeReference(); |
282 | const auto AutoCopyConstructed(TrivialTypeReference()); |
283 | const TrivialToCopyType VarAssigned = TrivialTypeReference(); |
284 | const TrivialToCopyType VarCopyConstructed(TrivialTypeReference()); |
285 | } |
286 | |
287 | void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) { |
288 | static const auto StaticVar = Obj.reference(); |
289 | } |
290 | |
291 | void PositiveFunctionCallExpensiveTypeNonConstVariable() { |
292 | auto AutoAssigned = ExpensiveTypeReference(); |
293 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoAssigned' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization] |
294 | // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
295 | AutoAssigned.constMethod(); |
296 | |
297 | auto AutoCopyConstructed(ExpensiveTypeReference()); |
298 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed' |
299 | // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
300 | AutoCopyConstructed.constMethod(); |
301 | |
302 | ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
303 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned' |
304 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
305 | VarAssigned.constMethod(); |
306 | |
307 | ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
308 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed' |
309 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
310 | VarCopyConstructed.constMethod(); |
311 | } |
312 | |
313 | void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { |
314 | { |
315 | auto Assigned = Obj.reference(); |
316 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned' |
317 | // CHECK-FIXES: const auto& Assigned = Obj.reference(); |
318 | Assigned.reference(); |
319 | useAsConstReference(Assigned); |
320 | useByValue(Assigned); |
321 | } |
322 | } |
323 | |
324 | void positiveNonConstVarInCodeBlockWithAlias(const ExpensiveToCopyType &Obj) { |
325 | { |
326 | const ExpensiveToCopyType Assigned = Obj.referenceWithAlias(); |
327 | // CHECK-MESSAGES: [[@LINE-1]]:31: warning: the const qualified variable |
328 | // CHECK-FIXES: const ExpensiveToCopyType& Assigned = Obj.referenceWithAlias(); |
329 | useAsConstReference(Assigned); |
330 | } |
331 | } |
332 | |
333 | void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) { |
334 | { |
335 | auto NonConstInvoked = Obj.reference(); |
336 | // CHECK-FIXES: auto NonConstInvoked = Obj.reference(); |
337 | NonConstInvoked.nonConstMethod(); |
338 | } |
339 | { |
340 | auto Reassigned = Obj.reference(); |
341 | // CHECK-FIXES: auto Reassigned = Obj.reference(); |
342 | Reassigned = ExpensiveToCopyType(); |
343 | } |
344 | { |
345 | auto MutatedByReference = Obj.reference(); |
346 | // CHECK-FIXES: auto MutatedByReference = Obj.reference(); |
347 | mutate(MutatedByReference); |
348 | } |
349 | { |
350 | auto MutatedByPointer = Obj.reference(); |
351 | // CHECK-FIXES: auto MutatedByPointer = Obj.reference(); |
352 | mutate(&MutatedByPointer); |
353 | } |
354 | } |
355 | |
356 | void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { |
357 | const auto AutoAssigned = Obj.reference(); |
358 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
359 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
360 | AutoAssigned.constMethod(); |
361 | } |
362 | |
363 | void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { |
364 | const auto AutoAssigned = Obj.reference(); |
365 | const auto AutoCopyConstructed(Obj.reference()); |
366 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
367 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
368 | mutate(&Obj); |
369 | } |
370 | |
371 | void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { |
372 | const auto AutoAssigned = Obj.reference(); |
373 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
374 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
375 | AutoAssigned.constMethod(); |
376 | } |
377 | |
378 | void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { |
379 | Obj.nonConstMethod(); |
380 | const auto AutoAssigned = Obj.reference(); |
381 | } |
382 | |
383 | void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { |
384 | const auto AutoAssigned = Obj->reference(); |
385 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
386 | // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
387 | Obj->constMethod(); |
388 | AutoAssigned.constMethod(); |
389 | } |
390 | |
391 | void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { |
392 | const auto AutoAssigned = Obj->reference(); |
393 | const auto AutoCopyConstructed(Obj->reference()); |
394 | const ExpensiveToCopyType VarAssigned = Obj->reference(); |
395 | const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
396 | mutate(Obj); |
397 | } |
398 | |
399 | void PositiveLocalVarIsNotModified() { |
400 | ExpensiveToCopyType LocalVar; |
401 | const auto AutoAssigned = LocalVar.reference(); |
402 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
403 | // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); |
404 | AutoAssigned.constMethod(); |
405 | } |
406 | |
407 | void NegativeLocalVarIsModified() { |
408 | ExpensiveToCopyType Obj; |
409 | const auto AutoAssigned = Obj.reference(); |
410 | Obj = AutoAssigned; |
411 | } |
412 | |
413 | struct NegativeConstructor { |
414 | NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {} |
415 | ExpensiveToCopyType Obj; |
416 | }; |
417 | |
418 | #define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \ |
419 | void functionWith##TYPE(const TYPE &T) { \ |
420 | auto AssignedInMacro = T.reference(); \ |
421 | } \ |
422 | // Ensure fix is not applied. |
423 | // CHECK-FIXES: auto AssignedInMacro = T.reference(); |
424 | |
425 | UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType) |
426 | // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is copy-constructed |
427 | |
428 | #define UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(ARGUMENT) ARGUMENT |
429 | |
430 | void PositiveMacroArgument(const ExpensiveToCopyType &Obj) { |
431 | UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(auto CopyInMacroArg = Obj.reference()); |
432 | // CHECK-MESSAGES: [[@LINE-1]]:48: warning: the variable 'CopyInMacroArg' is copy-constructed |
433 | // Ensure fix is not applied. |
434 | // CHECK-FIXES: auto CopyInMacroArg = Obj.reference() |
435 | CopyInMacroArg.constMethod(); |
436 | } |
437 | |
438 | void PositiveLocalCopyConstMethodInvoked() { |
439 | ExpensiveToCopyType orig; |
440 | ExpensiveToCopyType copy_1 = orig; |
441 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_1' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] |
442 | // CHECK-FIXES: const ExpensiveToCopyType& copy_1 = orig; |
443 | copy_1.constMethod(); |
444 | orig.constMethod(); |
445 | } |
446 | |
447 | void PositiveLocalCopyUsingExplicitCopyCtor() { |
448 | ExpensiveToCopyType orig; |
449 | ExpensiveToCopyType copy_2(orig); |
450 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_2' |
451 | // CHECK-FIXES: const ExpensiveToCopyType& copy_2(orig); |
452 | copy_2.constMethod(); |
453 | orig.constMethod(); |
454 | } |
455 | |
456 | void PositiveLocalCopyCopyIsArgument(const ExpensiveToCopyType &orig) { |
457 | ExpensiveToCopyType copy_3 = orig; |
458 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_3' |
459 | // CHECK-FIXES: const ExpensiveToCopyType& copy_3 = orig; |
460 | copy_3.constMethod(); |
461 | } |
462 | |
463 | void PositiveLocalCopyUsedAsConstRef() { |
464 | ExpensiveToCopyType orig; |
465 | ExpensiveToCopyType copy_4 = orig; |
466 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_4' |
467 | // CHECK-FIXES: const ExpensiveToCopyType& copy_4 = orig; |
468 | useAsConstReference(orig); |
469 | copy_4.constMethod(); |
470 | } |
471 | |
472 | void PositiveLocalCopyTwice() { |
473 | ExpensiveToCopyType orig; |
474 | ExpensiveToCopyType copy_5 = orig; |
475 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_5' |
476 | // CHECK-FIXES: const ExpensiveToCopyType& copy_5 = orig; |
477 | ExpensiveToCopyType copy_6 = copy_5; |
478 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_6' |
479 | // CHECK-FIXES: const ExpensiveToCopyType& copy_6 = copy_5; |
480 | copy_5.constMethod(); |
481 | copy_6.constMethod(); |
482 | orig.constMethod(); |
483 | } |
484 | |
485 | |
486 | void PositiveLocalCopyWeirdCopy() { |
487 | WeirdCopyCtorType orig; |
488 | WeirdCopyCtorType weird_1(orig); |
489 | // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_1' |
490 | // CHECK-FIXES: const WeirdCopyCtorType& weird_1(orig); |
491 | weird_1.constMethod(); |
492 | |
493 | WeirdCopyCtorType weird_2 = orig; |
494 | // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_2' |
495 | // CHECK-FIXES: const WeirdCopyCtorType& weird_2 = orig; |
496 | weird_2.constMethod(); |
497 | } |
498 | |
499 | void NegativeLocalCopySimpleTypes() { |
500 | int i1 = 0; |
501 | int i2 = i1; |
502 | } |
503 | |
504 | void NegativeLocalCopyCopyIsModified() { |
505 | ExpensiveToCopyType orig; |
506 | ExpensiveToCopyType neg_copy_1 = orig; |
507 | neg_copy_1.nonConstMethod(); |
508 | } |
509 | |
510 | void NegativeLocalCopyOriginalIsModified() { |
511 | ExpensiveToCopyType orig; |
512 | ExpensiveToCopyType neg_copy_2 = orig; |
513 | orig.nonConstMethod(); |
514 | } |
515 | |
516 | void NegativeLocalCopyUsedAsRefArg() { |
517 | ExpensiveToCopyType orig; |
518 | ExpensiveToCopyType neg_copy_3 = orig; |
519 | mutate(neg_copy_3); |
520 | } |
521 | |
522 | void NegativeLocalCopyUsedAsPointerArg() { |
523 | ExpensiveToCopyType orig; |
524 | ExpensiveToCopyType neg_copy_4 = orig; |
525 | mutate(&neg_copy_4); |
526 | } |
527 | |
528 | void NegativeLocalCopyCopyFromGlobal() { |
529 | ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type; |
530 | } |
531 | |
532 | void NegativeLocalCopyCopyToStatic() { |
533 | ExpensiveToCopyType orig; |
534 | static ExpensiveToCopyType neg_copy_6 = orig; |
535 | } |
536 | |
537 | void NegativeLocalCopyNonConstInForLoop() { |
538 | ExpensiveToCopyType orig; |
539 | for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod(); |
540 | orig.nonConstMethod()) { |
541 | orig.constMethod(); |
542 | } |
543 | } |
544 | |
545 | void NegativeLocalCopyWeirdNonCopy() { |
546 | WeirdCopyCtorType orig; |
547 | WeirdCopyCtorType neg_weird_1(orig, false); |
548 | WeirdCopyCtorType neg_weird_2(orig, true); |
549 | } |
550 | void WarningOnlyMultiDeclStmt() { |
551 | ExpensiveToCopyType orig; |
552 | ExpensiveToCopyType copy = orig, copy2; |
553 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] |
554 | // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; |
555 | copy.constMethod(); |
556 | } |
557 | |
558 | class Element {}; |
559 | |
560 | void implicitVarFalsePositive() { |
561 | for (const Element &E : Container<Element>()) { |
562 | } |
563 | } |
564 | |
565 | // This should not trigger the check as the argument could introduce an alias. |
566 | void negativeInitializedFromFreeFunctionWithArg() { |
567 | ExpensiveToCopyType Orig; |
568 | const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig); |
569 | } |
570 | |
571 | void negativeInitializedFromFreeFunctionWithDefaultArg() { |
572 | const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(); |
573 | } |
574 | |
575 | void negativeInitialzedFromFreeFunctionWithNonDefaultArg() { |
576 | ExpensiveToCopyType Orig; |
577 | const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(arg: &Orig); |
578 | } |
579 | |
580 | namespace std { |
581 | inline namespace __1 { |
582 | |
583 | template <class> |
584 | class function; |
585 | template <class R, class... ArgTypes> |
586 | class function<R(ArgTypes...)> { |
587 | public: |
588 | function(); |
589 | function(const function &Other); |
590 | R operator()(ArgTypes... Args) const; |
591 | }; |
592 | |
593 | } // namespace __1 |
594 | } // namespace std |
595 | |
596 | void negativeStdFunction() { |
597 | std::function<int()> Orig; |
598 | std::function<int()> Copy = Orig; |
599 | int i = Orig(); |
600 | } |
601 | |
602 | using Functor = std::function<int()>; |
603 | |
604 | void negativeAliasedStdFunction() { |
605 | Functor Orig; |
606 | Functor Copy = Orig; |
607 | int i = Orig(); |
608 | } |
609 | |
610 | typedef std::function<int()> TypedefFunc; |
611 | |
612 | void negativeTypedefedStdFunction() { |
613 | TypedefFunc Orig; |
614 | TypedefFunc Copy = Orig; |
615 | int i = Orig(); |
616 | } |
617 | |
618 | namespace fake { |
619 | namespace std { |
620 | template <class R, class... Args> |
621 | struct function { |
622 | // Custom copy constructor makes it expensive to copy; |
623 | function(const function &); |
624 | void constMethod() const; |
625 | }; |
626 | } // namespace std |
627 | |
628 | void positiveFakeStdFunction(std::function<void(int)> F) { |
629 | auto Copy = F; |
630 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified; |
631 | // CHECK-FIXES: const auto& Copy = F; |
632 | Copy.constMethod(); |
633 | } |
634 | |
635 | } // namespace fake |
636 | |
637 | void positiveInvokedOnStdFunction( |
638 | std::function<void(const ExpensiveToCopyType &)> Update, |
639 | const ExpensiveToCopyType Orig) { |
640 | auto Copy = Orig.reference(); |
641 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference |
642 | // CHECK-FIXES: const auto& Copy = Orig.reference(); |
643 | Update(Copy); |
644 | } |
645 | |
646 | void negativeInvokedOnStdFunction( |
647 | std::function<void(ExpensiveToCopyType &)> Update, |
648 | const ExpensiveToCopyType Orig) { |
649 | auto Copy = Orig.reference(); |
650 | Update(Copy); |
651 | } |
652 | |
653 | void negativeCopiedFromReferenceToModifiedVar() { |
654 | ExpensiveToCopyType Orig; |
655 | const auto &Ref = Orig; |
656 | const auto NecessaryCopy = Ref; |
657 | Orig.nonConstMethod(); |
658 | } |
659 | |
660 | void positiveCopiedFromReferenceToConstVar() { |
661 | ExpensiveToCopyType Orig; |
662 | const auto &Ref = Orig; |
663 | const auto UnnecessaryCopy = Ref; |
664 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of |
665 | // CHECK-FIXES: const auto& UnnecessaryCopy = Ref; |
666 | Orig.constMethod(); |
667 | UnnecessaryCopy.constMethod(); |
668 | } |
669 | |
670 | void negativeCopiedFromGetterOfReferenceToModifiedVar() { |
671 | ExpensiveToCopyType Orig; |
672 | const auto &Ref = Orig.reference(); |
673 | const auto NecessaryCopy = Ref.reference(); |
674 | Orig.nonConstMethod(); |
675 | } |
676 | |
677 | void negativeAliasNonCanonicalPointerType() { |
678 | ExpensiveToCopyType Orig; |
679 | // The use of auto here hides that the type is a pointer type. The check needs |
680 | // to look at the canonical type to detect the aliasing through this pointer. |
681 | const auto Pointer = Orig.pointer(); |
682 | const auto NecessaryCopy = Pointer->reference(); |
683 | Orig.nonConstMethod(); |
684 | } |
685 | |
686 | void negativeAliasTypedefedType() { |
687 | typedef const ExpensiveToCopyType &ReferenceType; |
688 | ExpensiveToCopyType Orig; |
689 | // The typedef hides the fact that this is a reference type. The check needs |
690 | // to look at the canonical type to detect the aliasing. |
691 | ReferenceType Ref = Orig.reference(); |
692 | const auto NecessaryCopy = Ref.reference(); |
693 | Orig.nonConstMethod(); |
694 | } |
695 | |
696 | void positiveCopiedFromGetterOfReferenceToConstVar() { |
697 | ExpensiveToCopyType Orig; |
698 | const auto &Ref = Orig.reference(); |
699 | auto UnnecessaryCopy = Ref.reference(); |
700 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is |
701 | // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference(); |
702 | Orig.constMethod(); |
703 | UnnecessaryCopy.constMethod(); |
704 | } |
705 | |
706 | void positiveUnusedReferenceIsRemoved() { |
707 | // clang-format off |
708 | const auto AutoAssigned = ExpensiveTypeReference(); int i = 0; // Foo bar. |
709 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference but is never used; consider removing the statement [performance-unnecessary-copy-initialization] |
710 | // CHECK-FIXES-NOT: const auto AutoAssigned = ExpensiveTypeReference(); |
711 | // CHECK-FIXES: int i = 0; // Foo bar. |
712 | auto = ExpensiveTypeReference(); // Trailing comment. |
713 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used; |
714 | // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); |
715 | // CHECK-FIXES-NOT: // Trailing comment. |
716 | // clang-format on |
717 | |
718 | auto UnusedAndUnnecessary = ExpensiveTypeReference(); |
719 | // Comments on a new line should not be deleted. |
720 | // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed |
721 | // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference(); |
722 | // CHECK-FIXES: // Comments on a new line should not be deleted. |
723 | } |
724 | |
725 | void positiveLoopedOverObjectIsConst() { |
726 | const Container<ExpensiveToCopyType> Orig; |
727 | for (const auto &Element : Orig) { |
728 | const auto Copy = Element; |
729 | // CHECK-MESSAGES: [[@LINE-1]]:16: warning: local copy 'Copy' |
730 | // CHECK-FIXES: const auto& Copy = Element; |
731 | Orig.constMethod(); |
732 | Copy.constMethod(); |
733 | } |
734 | |
735 | auto Lambda = []() { |
736 | const Container<ExpensiveToCopyType> Orig; |
737 | for (const auto &Element : Orig) { |
738 | const auto Copy = Element; |
739 | // CHECK-MESSAGES: [[@LINE-1]]:18: warning: local copy 'Copy' |
740 | // CHECK-FIXES: const auto& Copy = Element; |
741 | Orig.constMethod(); |
742 | Copy.constMethod(); |
743 | } |
744 | }; |
745 | } |
746 | |
747 | void negativeLoopedOverObjectIsModified() { |
748 | Container<ExpensiveToCopyType> Orig; |
749 | for (const auto &Element : Orig) { |
750 | const auto Copy = Element; |
751 | Orig.nonConstMethod(); |
752 | Copy.constMethod(); |
753 | } |
754 | |
755 | auto Lambda = []() { |
756 | Container<ExpensiveToCopyType> Orig; |
757 | for (const auto &Element : Orig) { |
758 | const auto Copy = Element; |
759 | Orig.nonConstMethod(); |
760 | Copy.constMethod(); |
761 | } |
762 | }; |
763 | } |
764 | |
765 | void negativeReferenceIsInitializedOutsideOfBlock() { |
766 | ExpensiveToCopyType Orig; |
767 | const auto &E2 = Orig; |
768 | if (1 != 2 * 3) { |
769 | const auto C2 = E2; |
770 | Orig.nonConstMethod(); |
771 | C2.constMethod(); |
772 | } |
773 | |
774 | auto Lambda = []() { |
775 | ExpensiveToCopyType Orig; |
776 | const auto &E2 = Orig; |
777 | if (1 != 2 * 3) { |
778 | const auto C2 = E2; |
779 | Orig.nonConstMethod(); |
780 | C2.constMethod(); |
781 | } |
782 | }; |
783 | } |
784 | |
785 | void negativeStructuredBinding() { |
786 | // Structured bindings are not yet supported but can trigger false positives |
787 | // since the DecompositionDecl itself is unused and the check doesn't traverse |
788 | // VarDecls of the BindingDecls. |
789 | struct Pair { |
790 | ExpensiveToCopyType first; |
791 | ExpensiveToCopyType second; |
792 | }; |
793 | |
794 | Pair P; |
795 | const auto [C, D] = P; |
796 | C.constMethod(); |
797 | D.constMethod(); |
798 | } |
799 | |
800 | template <typename A> |
801 | const A &templatedReference(); |
802 | |
803 | template <typename A, typename B> |
804 | void negativeTemplateTypes() { |
805 | A Orig; |
806 | // Different replaced template type params do not trigger the check. In some |
807 | // template instantiation this might not be a copy but an implicit |
808 | // conversion, so converting this to a reference might not work. |
809 | B AmbiguousCopy = Orig; |
810 | // CHECK-NOT-FIXES: B AmbiguousCopy = Orig; |
811 | |
812 | B NecessaryCopy = templatedReference<A>(); |
813 | // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference<A>(); |
814 | |
815 | B NecessaryCopy2 = Orig.template templatedAccessor<A>(); |
816 | |
817 | // Non-dependent types in template still trigger the check. |
818 | const auto UnnecessaryCopy = ExpensiveTypeReference(); |
819 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed |
820 | // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference(); |
821 | UnnecessaryCopy.constMethod(); |
822 | } |
823 | |
824 | void instantiateNegativeTemplateTypes() { |
825 | negativeTemplateTypes<ExpensiveToCopyType, ExpensiveToCopyType>(); |
826 | // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference. |
827 | negativeTemplateTypes<ExpensiveToCopyType, int>(); |
828 | } |
829 | |
830 | template <typename A> |
831 | void positiveSingleTemplateType() { |
832 | A Orig; |
833 | A SingleTmplParmTypeCopy = Orig; |
834 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified |
835 | // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig; |
836 | SingleTmplParmTypeCopy.constMethod(); |
837 | |
838 | A UnnecessaryCopy2 = templatedReference<A>(); |
839 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference |
840 | // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference<A>(); |
841 | UnnecessaryCopy2.constMethod(); |
842 | |
843 | A UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); |
844 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference |
845 | // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); |
846 | UnnecessaryCopy3.constMethod(); |
847 | } |
848 | |
849 | void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType<ExpensiveToCopyType>(); } |
850 | |
851 | struct Struct { |
852 | ExpensiveToCopyType Member; |
853 | }; |
854 | |
855 | void positiveConstMemberExpr() { |
856 | Struct Orig; |
857 | auto UC = Orig; |
858 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UC' |
859 | // CHECK-FIXES: const auto& UC = Orig; |
860 | const auto &ConstRef = UC.Member; |
861 | auto MemberCopy = UC.Member; |
862 | bool b = UC.Member.constMethod(); |
863 | useByValue(UC.Member); |
864 | useAsConstReference(UC.Member); |
865 | useByValue(UC.Member); |
866 | } |
867 | |
868 | void negativeNonConstMemberExpr() { |
869 | Struct Orig; |
870 | { |
871 | auto Copy = Orig; |
872 | Copy.Member.nonConstMethod(); |
873 | } |
874 | { |
875 | auto Copy = Orig; |
876 | mutate(Copy.Member); |
877 | } |
878 | { |
879 | auto Copy = Orig; |
880 | mutate(&Copy.Member); |
881 | } |
882 | } |
883 | |
884 | |