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