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

source code of clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp