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