1// RUN: %check_clang_tidy -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
33template <typename T>
34struct 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
50using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>;
51
52struct TrivialToCopyType {
53 const TrivialToCopyType &reference() const;
54};
55
56struct WeirdCopyCtorType {
57 WeirdCopyCtorType();
58 WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true);
59
60 void nonConstMethod();
61 bool constMethod() const;
62};
63
64ExpensiveToCopyType global_expensive_to_copy_type;
65
66const ExpensiveToCopyType &ExpensiveTypeReference();
67const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
68const ExpensiveToCopyType &freeFunctionWithDefaultArg(
69 const ExpensiveToCopyType *arg = nullptr);
70const TrivialToCopyType &TrivialTypeReference();
71
72void mutate(ExpensiveToCopyType &);
73void mutate(ExpensiveToCopyType *);
74void useAsConstPointer(const ExpensiveToCopyType *);
75void useAsConstReference(const ExpensiveToCopyType &);
76void useByValue(ExpensiveToCopyType);
77
78void 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
100void 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
122void 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
144void 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
166void 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
188void 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
210void 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
232void 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
254void 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
262void 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
271void 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
280void NegativeFunctionCallTrivialType() {
281 const auto AutoAssigned = TrivialTypeReference();
282 const auto AutoCopyConstructed(TrivialTypeReference());
283 const TrivialToCopyType VarAssigned = TrivialTypeReference();
284 const TrivialToCopyType VarCopyConstructed(TrivialTypeReference());
285}
286
287void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) {
288 static const auto StaticVar = Obj.reference();
289}
290
291void 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
313void 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
324void 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
333void 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
356void 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
363void 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
371void 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
378void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) {
379 Obj.nonConstMethod();
380 const auto AutoAssigned = Obj.reference();
381}
382
383void 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
391void 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
399void 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
407void NegativeLocalVarIsModified() {
408 ExpensiveToCopyType Obj;
409 const auto AutoAssigned = Obj.reference();
410 Obj = AutoAssigned;
411}
412
413struct 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
425UNNECESSARY_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
430void 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
438void 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
447void 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
456void 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
463void 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
472void 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
486void 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
499void NegativeLocalCopySimpleTypes() {
500 int i1 = 0;
501 int i2 = i1;
502}
503
504void NegativeLocalCopyCopyIsModified() {
505 ExpensiveToCopyType orig;
506 ExpensiveToCopyType neg_copy_1 = orig;
507 neg_copy_1.nonConstMethod();
508}
509
510void NegativeLocalCopyOriginalIsModified() {
511 ExpensiveToCopyType orig;
512 ExpensiveToCopyType neg_copy_2 = orig;
513 orig.nonConstMethod();
514}
515
516void NegativeLocalCopyUsedAsRefArg() {
517 ExpensiveToCopyType orig;
518 ExpensiveToCopyType neg_copy_3 = orig;
519 mutate(neg_copy_3);
520}
521
522void NegativeLocalCopyUsedAsPointerArg() {
523 ExpensiveToCopyType orig;
524 ExpensiveToCopyType neg_copy_4 = orig;
525 mutate(&neg_copy_4);
526}
527
528void NegativeLocalCopyCopyFromGlobal() {
529 ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type;
530}
531
532void NegativeLocalCopyCopyToStatic() {
533 ExpensiveToCopyType orig;
534 static ExpensiveToCopyType neg_copy_6 = orig;
535}
536
537void NegativeLocalCopyNonConstInForLoop() {
538 ExpensiveToCopyType orig;
539 for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod();
540 orig.nonConstMethod()) {
541 orig.constMethod();
542 }
543}
544
545void NegativeLocalCopyWeirdNonCopy() {
546 WeirdCopyCtorType orig;
547 WeirdCopyCtorType neg_weird_1(orig, false);
548 WeirdCopyCtorType neg_weird_2(orig, true);
549}
550void 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
558class Element {};
559
560void 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.
566void negativeInitializedFromFreeFunctionWithArg() {
567 ExpensiveToCopyType Orig;
568 const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
569}
570
571void negativeInitializedFromFreeFunctionWithDefaultArg() {
572 const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
573}
574
575void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
576 ExpensiveToCopyType Orig;
577 const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(arg: &Orig);
578}
579
580namespace std {
581inline namespace __1 {
582
583template <class>
584class function;
585template <class R, class... ArgTypes>
586class function<R(ArgTypes...)> {
587public:
588 function();
589 function(const function &Other);
590 R operator()(ArgTypes... Args) const;
591};
592
593} // namespace __1
594} // namespace std
595
596void negativeStdFunction() {
597 std::function<int()> Orig;
598 std::function<int()> Copy = Orig;
599 int i = Orig();
600}
601
602using Functor = std::function<int()>;
603
604void negativeAliasedStdFunction() {
605 Functor Orig;
606 Functor Copy = Orig;
607 int i = Orig();
608}
609
610typedef std::function<int()> TypedefFunc;
611
612void negativeTypedefedStdFunction() {
613 TypedefFunc Orig;
614 TypedefFunc Copy = Orig;
615 int i = Orig();
616}
617
618namespace fake {
619namespace std {
620template <class R, class... Args>
621struct function {
622 // Custom copy constructor makes it expensive to copy;
623 function(const function &);
624 void constMethod() const;
625};
626} // namespace std
627
628void 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
637void 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
646void negativeInvokedOnStdFunction(
647 std::function<void(ExpensiveToCopyType &)> Update,
648 const ExpensiveToCopyType Orig) {
649 auto Copy = Orig.reference();
650 Update(Copy);
651}
652
653void negativeCopiedFromReferenceToModifiedVar() {
654 ExpensiveToCopyType Orig;
655 const auto &Ref = Orig;
656 const auto NecessaryCopy = Ref;
657 Orig.nonConstMethod();
658}
659
660void 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
670void negativeCopiedFromGetterOfReferenceToModifiedVar() {
671 ExpensiveToCopyType Orig;
672 const auto &Ref = Orig.reference();
673 const auto NecessaryCopy = Ref.reference();
674 Orig.nonConstMethod();
675}
676
677void 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
686void 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
696void 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
706void 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 TrailingCommentRemoved = 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
725void 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
747void 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
765void 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
785void 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
800template <typename A>
801const A &templatedReference();
802
803template <typename A, typename B>
804void 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
824void 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
830template <typename A>
831void 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
849void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType<ExpensiveToCopyType>(); }
850
851struct Struct {
852 ExpensiveToCopyType Member;
853};
854
855void 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
868void 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

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