| // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t |
| |
| struct ExpensiveToCopyType { |
| ExpensiveToCopyType(); |
| virtual ~ExpensiveToCopyType(); |
| const ExpensiveToCopyType &reference() const; |
| void nonConstMethod(); |
| bool constMethod() const; |
| }; |
| |
| struct TrivialToCopyType { |
| const TrivialToCopyType &reference() const; |
| }; |
| |
| struct WeirdCopyCtorType { |
| WeirdCopyCtorType(); |
| WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true); |
| |
| void nonConstMethod(); |
| bool constMethod() const; |
| }; |
| |
| ExpensiveToCopyType global_expensive_to_copy_type; |
| |
| const ExpensiveToCopyType &ExpensiveTypeReference(); |
| const TrivialToCopyType &TrivialTypeReference(); |
| |
| void mutate(ExpensiveToCopyType &); |
| void mutate(ExpensiveToCopyType *); |
| void useAsConstPointer(const ExpensiveToCopyType *); |
| void useAsConstReference(const ExpensiveToCopyType &); |
| void useByValue(ExpensiveToCopyType); |
| |
| void PositiveFunctionCall() { |
| const auto AutoAssigned = ExpensiveTypeReference(); |
| // 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] |
| // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
| const auto AutoCopyConstructed(ExpensiveTypeReference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
| // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
| const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
| const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
| } |
| |
| void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) { |
| const auto AutoAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
| const auto AutoCopyConstructed(Obj.reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
| // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
| const ExpensiveToCopyType VarAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
| const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
| } |
| |
| void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) { |
| const auto AutoAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
| const auto AutoCopyConstructed(Obj.reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
| // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
| const ExpensiveToCopyType VarAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
| const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
| } |
| |
| void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) { |
| const auto AutoAssigned = Obj->reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
| const auto AutoCopyConstructed(Obj->reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
| // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference()); |
| const ExpensiveToCopyType VarAssigned = Obj->reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference(); |
| const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference()); |
| } |
| |
| void PositiveLocalConstValue() { |
| const ExpensiveToCopyType Obj; |
| const auto UnnecessaryCopy = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
| // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference(); |
| } |
| |
| void PositiveLocalConstRef() { |
| const ExpensiveToCopyType Obj; |
| const ExpensiveToCopyType &ConstReference = Obj.reference(); |
| const auto UnnecessaryCopy = ConstReference.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
| // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference(); |
| } |
| |
| void PositiveLocalConstPointer() { |
| const ExpensiveToCopyType Obj; |
| const ExpensiveToCopyType *const ConstPointer = &Obj; |
| const auto UnnecessaryCopy = ConstPointer->reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
| // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference(); |
| } |
| |
| void NegativeFunctionCallTrivialType() { |
| const auto AutoAssigned = TrivialTypeReference(); |
| const auto AutoCopyConstructed(TrivialTypeReference()); |
| const TrivialToCopyType VarAssigned = TrivialTypeReference(); |
| const TrivialToCopyType VarCopyConstructed(TrivialTypeReference()); |
| } |
| |
| void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) { |
| static const auto StaticVar = Obj.reference(); |
| } |
| |
| void PositiveFunctionCallExpensiveTypeNonConstVariable() { |
| auto AutoAssigned = ExpensiveTypeReference(); |
| // 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] |
| // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
| auto AutoCopyConstructed(ExpensiveTypeReference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed' |
| // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
| ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
| ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed' |
| // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
| } |
| |
| void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { |
| { |
| auto Assigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned' |
| // CHECK-FIXES: const auto& Assigned = Obj.reference(); |
| Assigned.reference(); |
| useAsConstReference(Assigned); |
| useByValue(Assigned); |
| } |
| } |
| |
| void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) { |
| { |
| auto NonConstInvoked = Obj.reference(); |
| // CHECK-FIXES: auto NonConstInvoked = Obj.reference(); |
| NonConstInvoked.nonConstMethod(); |
| } |
| { |
| auto Reassigned = Obj.reference(); |
| // CHECK-FIXES: auto Reassigned = Obj.reference(); |
| Reassigned = ExpensiveToCopyType(); |
| } |
| { |
| auto MutatedByReference = Obj.reference(); |
| // CHECK-FIXES: auto MutatedByReference = Obj.reference(); |
| mutate(MutatedByReference); |
| } |
| { |
| auto MutatedByPointer = Obj.reference(); |
| // CHECK-FIXES: auto MutatedByPointer = Obj.reference(); |
| mutate(&MutatedByPointer); |
| } |
| } |
| |
| void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { |
| const auto AutoAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
| } |
| |
| void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { |
| const auto AutoAssigned = Obj.reference(); |
| const auto AutoCopyConstructed(Obj.reference()); |
| const ExpensiveToCopyType VarAssigned = Obj.reference(); |
| const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
| mutate(&Obj); |
| } |
| |
| void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { |
| const auto AutoAssigned = Obj.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
| } |
| |
| void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { |
| Obj.nonConstMethod(); |
| const auto AutoAssigned = Obj.reference(); |
| } |
| |
| void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { |
| const auto AutoAssigned = Obj->reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
| Obj->constMethod(); |
| } |
| |
| void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { |
| const auto AutoAssigned = Obj->reference(); |
| const auto AutoCopyConstructed(Obj->reference()); |
| const ExpensiveToCopyType VarAssigned = Obj->reference(); |
| const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
| mutate(Obj); |
| } |
| |
| void PositiveLocalVarIsNotModified() { |
| ExpensiveToCopyType LocalVar; |
| const auto AutoAssigned = LocalVar.reference(); |
| // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
| // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); |
| } |
| |
| void NegativeLocalVarIsModified() { |
| ExpensiveToCopyType Obj; |
| const auto AutoAssigned = Obj.reference(); |
| Obj = AutoAssigned; |
| } |
| |
| struct NegativeConstructor { |
| NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {} |
| ExpensiveToCopyType Obj; |
| }; |
| |
| #define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \ |
| void functionWith##TYPE(const TYPE &T) { \ |
| auto AssignedInMacro = T.reference(); \ |
| } \ |
| // Ensure fix is not applied. |
| // CHECK-FIXES: auto AssignedInMacro = T.reference(); |
| |
| UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType) |
| // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is copy-constructed |
| |
| #define UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(ARGUMENT) ARGUMENT |
| |
| void PositiveMacroArgument(const ExpensiveToCopyType &Obj) { |
| UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(auto CopyInMacroArg = Obj.reference()); |
| // CHECK-MESSAGES: [[@LINE-1]]:48: warning: the variable 'CopyInMacroArg' is copy-constructed |
| // Ensure fix is not applied. |
| // CHECK-FIXES: auto CopyInMacroArg = Obj.reference() |
| } |
| |
| void PositiveLocalCopyConstMethodInvoked() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType copy_1 = orig; |
| // 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] |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_1 = orig; |
| copy_1.constMethod(); |
| orig.constMethod(); |
| } |
| |
| void PositiveLocalCopyUsingExplicitCopyCtor() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType copy_2(orig); |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_2' |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_2(orig); |
| copy_2.constMethod(); |
| orig.constMethod(); |
| } |
| |
| void PositiveLocalCopyCopyIsArgument(const ExpensiveToCopyType &orig) { |
| ExpensiveToCopyType copy_3 = orig; |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_3' |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_3 = orig; |
| copy_3.constMethod(); |
| } |
| |
| void PositiveLocalCopyUsedAsConstRef() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType copy_4 = orig; |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_4' |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_4 = orig; |
| useAsConstReference(orig); |
| } |
| |
| void PositiveLocalCopyTwice() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType copy_5 = orig; |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_5' |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_5 = orig; |
| ExpensiveToCopyType copy_6 = copy_5; |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_6' |
| // CHECK-FIXES: const ExpensiveToCopyType& copy_6 = copy_5; |
| copy_5.constMethod(); |
| copy_6.constMethod(); |
| orig.constMethod(); |
| } |
| |
| |
| void PositiveLocalCopyWeirdCopy() { |
| WeirdCopyCtorType orig; |
| WeirdCopyCtorType weird_1(orig); |
| // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_1' |
| // CHECK-FIXES: const WeirdCopyCtorType& weird_1(orig); |
| weird_1.constMethod(); |
| |
| WeirdCopyCtorType weird_2 = orig; |
| // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_2' |
| // CHECK-FIXES: const WeirdCopyCtorType& weird_2 = orig; |
| weird_2.constMethod(); |
| } |
| |
| void NegativeLocalCopySimpleTypes() { |
| int i1 = 0; |
| int i2 = i1; |
| } |
| |
| void NegativeLocalCopyCopyIsModified() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType neg_copy_1 = orig; |
| neg_copy_1.nonConstMethod(); |
| } |
| |
| void NegativeLocalCopyOriginalIsModified() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType neg_copy_2 = orig; |
| orig.nonConstMethod(); |
| } |
| |
| void NegativeLocalCopyUsedAsRefArg() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType neg_copy_3 = orig; |
| mutate(neg_copy_3); |
| } |
| |
| void NegativeLocalCopyUsedAsPointerArg() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType neg_copy_4 = orig; |
| mutate(&neg_copy_4); |
| } |
| |
| void NegativeLocalCopyCopyFromGlobal() { |
| ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type; |
| } |
| |
| void NegativeLocalCopyCopyToStatic() { |
| ExpensiveToCopyType orig; |
| static ExpensiveToCopyType neg_copy_6 = orig; |
| } |
| |
| void NegativeLocalCopyNonConstInForLoop() { |
| ExpensiveToCopyType orig; |
| for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod(); |
| orig.nonConstMethod()) { |
| orig.constMethod(); |
| } |
| } |
| |
| void NegativeLocalCopyWeirdNonCopy() { |
| WeirdCopyCtorType orig; |
| WeirdCopyCtorType neg_weird_1(orig, false); |
| WeirdCopyCtorType neg_weird_2(orig, true); |
| } |
| void WarningOnlyMultiDeclStmt() { |
| ExpensiveToCopyType orig; |
| ExpensiveToCopyType copy = orig, copy2; |
| // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] |
| // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; |
| } |
| |
| class Element {}; |
| class Container { |
| public: |
| class Iterator { |
| public: |
| void operator++(); |
| Element operator*(); |
| bool operator!=(const Iterator &); |
| WeirdCopyCtorType c; |
| }; |
| const Iterator &begin() const; |
| const Iterator &end() const; |
| }; |
| |
| void implicitVarFalsePositive() { |
| for (const Element &E : Container()) { |
| } |
| } |