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