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