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   static const ExpensiveToCopyType &instance();
33 };
34 
35 template <typename T>
36 struct 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 
55 using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>;
56 
57 struct TrivialToCopyType {
58   const TrivialToCopyType &reference() const;
59 };
60 
61 struct WeirdCopyCtorType {
62   WeirdCopyCtorType();
63   WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true);
64 
65   void nonConstMethod();
66   bool constMethod() const;
67 };
68 
69 ExpensiveToCopyType global_expensive_to_copy_type;
70 
71 const ExpensiveToCopyType &ExpensiveTypeReference();
72 const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
73 const ExpensiveToCopyType &freeFunctionWithDefaultArg(
74     const ExpensiveToCopyType *arg = nullptr);
75 const TrivialToCopyType &TrivialTypeReference();
76 
77 void mutate(ExpensiveToCopyType &);
78 void mutate(ExpensiveToCopyType *);
79 void useAsConstPointer(const ExpensiveToCopyType *);
80 void useAsConstReference(const ExpensiveToCopyType &);
81 void useByValue(ExpensiveToCopyType);
82 
83 void 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 
105 void 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 
127 void 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 
149 void 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 
171 void 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 
193 void 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 
215 void 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 
237 void 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 
259 void 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 
281 void 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 
303 void 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 
311 void 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 
320 void 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 
329 void NegativeFunctionCallTrivialType() {
330   const auto AutoAssigned = TrivialTypeReference();
331   const auto AutoCopyConstructed(TrivialTypeReference());
332   const TrivialToCopyType VarAssigned = TrivialTypeReference();
333   const TrivialToCopyType VarCopyConstructed(TrivialTypeReference());
334 }
335 
336 void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) {
337   static const auto StaticVar = Obj.reference();
338 }
339 
340 void 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 
362 void 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 
373 void 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 
382 void 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 
405 void 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 
412 void 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 
420 void 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 
427 void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) {
428   Obj.nonConstMethod();
429   const auto AutoAssigned = Obj.reference();
430 }
431 
432 void 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 
440 void 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 
448 void 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 
456 void NegativeLocalVarIsModified() {
457   ExpensiveToCopyType Obj;
458   const auto AutoAssigned = Obj.reference();
459   Obj = AutoAssigned;
460 }
461 
462 struct 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 
474 UNNECESSARY_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 
479 void 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 
487 void 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 
496 void 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 
505 void 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 
512 void 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 
521 void 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 
535 void 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 
548 void NegativeLocalCopySimpleTypes() {
549   int i1 = 0;
550   int i2 = i1;
551 }
552 
553 void NegativeLocalCopyCopyIsModified() {
554   ExpensiveToCopyType orig;
555   ExpensiveToCopyType neg_copy_1 = orig;
556   neg_copy_1.nonConstMethod();
557 }
558 
559 void NegativeLocalCopyOriginalIsModified() {
560   ExpensiveToCopyType orig;
561   ExpensiveToCopyType neg_copy_2 = orig;
562   orig.nonConstMethod();
563 }
564 
565 void NegativeLocalCopyUsedAsRefArg() {
566   ExpensiveToCopyType orig;
567   ExpensiveToCopyType neg_copy_3 = orig;
568   mutate(neg_copy_3);
569 }
570 
571 void NegativeLocalCopyUsedAsPointerArg() {
572   ExpensiveToCopyType orig;
573   ExpensiveToCopyType neg_copy_4 = orig;
574   mutate(&neg_copy_4);
575 }
576 
577 void NegativeLocalCopyCopyFromGlobal() {
578   ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type;
579 }
580 
581 void NegativeLocalCopyCopyToStatic() {
582   ExpensiveToCopyType orig;
583   static ExpensiveToCopyType neg_copy_6 = orig;
584 }
585 
586 void NegativeLocalCopyNonConstInForLoop() {
587   ExpensiveToCopyType orig;
588   for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod();
589        orig.nonConstMethod()) {
590     orig.constMethod();
591   }
592 }
593 
594 void NegativeLocalCopyWeirdNonCopy() {
595   WeirdCopyCtorType orig;
596   WeirdCopyCtorType neg_weird_1(orig, false);
597   WeirdCopyCtorType neg_weird_2(orig, true);
598 }
599 void 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 
607 class Element {};
608 
609 void 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.
615 void negativeInitializedFromFreeFunctionWithArg() {
616   ExpensiveToCopyType Orig;
617   const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
618 }
619 
620 void negativeInitializedFromFreeFunctionWithDefaultArg() {
621   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
622 }
623 
624 void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
625   ExpensiveToCopyType Orig;
626   const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
627 }
628 
629 namespace std {
630 inline namespace __1 {
631 
632 template <class>
633 class function;
634 template <class R, class... ArgTypes>
635 class function<R(ArgTypes...)> {
636 public:
637   function();
638   function(const function &Other);
639   R operator()(ArgTypes... Args) const;
640 };
641 
642 } // namespace __1
643 } // namespace std
644 
645 void negativeStdFunction() {
646   std::function<int()> Orig;
647   std::function<int()> Copy = Orig;
648   int i = Orig();
649 }
650 
651 using Functor = std::function<int()>;
652 
653 void negativeAliasedStdFunction() {
654   Functor Orig;
655   Functor Copy = Orig;
656   int i = Orig();
657 }
658 
659 typedef std::function<int()> TypedefFunc;
660 
661 void negativeTypedefedStdFunction() {
662   TypedefFunc Orig;
663   TypedefFunc Copy = Orig;
664   int i = Orig();
665 }
666 
667 namespace fake {
668 namespace std {
669 template <class R, class... Args>
670 struct function {
671   // Custom copy constructor makes it expensive to copy;
672   function(const function &);
673   void constMethod() const;
674 };
675 } // namespace std
676 
677 void 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 
686 void 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 
695 void negativeInvokedOnStdFunction(
696     std::function<void(ExpensiveToCopyType &)> Update,
697     const ExpensiveToCopyType Orig) {
698   auto Copy = Orig.reference();
699   Update(Copy);
700 }
701 
702 void negativeCopiedFromReferenceToModifiedVar() {
703   ExpensiveToCopyType Orig;
704   const auto &Ref = Orig;
705   const auto NecessaryCopy = Ref;
706   Orig.nonConstMethod();
707 }
708 
709 void 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 
719 void negativeCopiedFromGetterOfReferenceToModifiedVar() {
720   ExpensiveToCopyType Orig;
721   const auto &Ref = Orig.reference();
722   const auto NecessaryCopy = Ref.reference();
723   Orig.nonConstMethod();
724 }
725 
726 void 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 
735 void 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 
745 void 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 
755 void 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 
774 void 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 
796 void 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 
814 void 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 
834 void 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 
849 template <typename A>
850 const A &templatedReference();
851 
852 template <typename A, typename B>
853 void 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 
873 void 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 
879 template <typename A>
880 void 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 
898 void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType<ExpensiveToCopyType>(); }
899 
900 struct Struct {
901   ExpensiveToCopyType Member;
902 };
903 
904 void 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 
917 void 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 
934 bool operator==(ExpensiveToCopyType, ExpensiveToCopyType);
935 
936 template<typename T> bool OperatorWithNoDirectCallee(T t) {
937   ExpensiveToCopyType a1;
938   ExpensiveToCopyType a2 = a1;
939   return a1 == t;
940 }
941 
942