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