1b4d9ac8bSUtkarsh Saxena // RUN: %check_clang_tidy -std=c++17-or-later %s performance-unnecessary-copy-initialization %t 289a1d03eSRichard 389a1d03eSRichard template <typename T> 489a1d03eSRichard struct Iterator { 589a1d03eSRichard void operator++(); 689a1d03eSRichard T &operator*() const; 789a1d03eSRichard bool operator!=(const Iterator &) const; 889a1d03eSRichard typedef const T &const_reference; 989a1d03eSRichard }; 1089a1d03eSRichard 1189a1d03eSRichard template <typename T> 1289a1d03eSRichard struct ConstIterator { 1389a1d03eSRichard void operator++(); 1489a1d03eSRichard const T &operator*() const; 1589a1d03eSRichard bool operator!=(const ConstIterator &) const; 1689a1d03eSRichard typedef const T &const_reference; 1789a1d03eSRichard }; 1889a1d03eSRichard 1989a1d03eSRichard struct ExpensiveToCopyType { 2089a1d03eSRichard ExpensiveToCopyType(); 2189a1d03eSRichard virtual ~ExpensiveToCopyType(); 2289a1d03eSRichard const ExpensiveToCopyType &reference() const; 2389a1d03eSRichard using ConstRef = const ExpensiveToCopyType &; 2489a1d03eSRichard ConstRef referenceWithAlias() const; 2589a1d03eSRichard const ExpensiveToCopyType *pointer() const; 2689a1d03eSRichard void nonConstMethod(); 2789a1d03eSRichard bool constMethod() const; 2889a1d03eSRichard template <typename A> 2989a1d03eSRichard const A &templatedAccessor() const; 3089a1d03eSRichard operator int() const; // Implicit conversion to int. 31*a5364444SBarnabás Pőcze 32*a5364444SBarnabás Pőcze static const ExpensiveToCopyType &instance(); 3389a1d03eSRichard }; 3489a1d03eSRichard 3589a1d03eSRichard template <typename T> 3689a1d03eSRichard struct Container { 37415a82c6SClement Courbet using reference = T&; 38415a82c6SClement Courbet using const_reference = const T&; 39415a82c6SClement Courbet 4089a1d03eSRichard bool empty() const; 4189a1d03eSRichard const T& operator[](int) const; 4289a1d03eSRichard const T& operator[](int); 4389a1d03eSRichard Iterator<T> begin(); 4489a1d03eSRichard Iterator<T> end(); 4589a1d03eSRichard ConstIterator<T> begin() const; 4689a1d03eSRichard ConstIterator<T> end() const; 4789a1d03eSRichard void nonConstMethod(); 4889a1d03eSRichard bool constMethod() const; 4994ca854dSClement Courbet 50415a82c6SClement Courbet reference at(int) const; 51415a82c6SClement Courbet const_reference at(int); 5294ca854dSClement Courbet 5389a1d03eSRichard }; 5489a1d03eSRichard 5589a1d03eSRichard using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>; 5689a1d03eSRichard 5789a1d03eSRichard struct TrivialToCopyType { 5889a1d03eSRichard const TrivialToCopyType &reference() const; 5989a1d03eSRichard }; 6089a1d03eSRichard 6189a1d03eSRichard struct WeirdCopyCtorType { 6289a1d03eSRichard WeirdCopyCtorType(); 6389a1d03eSRichard WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true); 6489a1d03eSRichard 6589a1d03eSRichard void nonConstMethod(); 6689a1d03eSRichard bool constMethod() const; 6789a1d03eSRichard }; 6889a1d03eSRichard 6989a1d03eSRichard ExpensiveToCopyType global_expensive_to_copy_type; 7089a1d03eSRichard 7189a1d03eSRichard const ExpensiveToCopyType &ExpensiveTypeReference(); 7289a1d03eSRichard const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &); 7389a1d03eSRichard const ExpensiveToCopyType &freeFunctionWithDefaultArg( 7489a1d03eSRichard const ExpensiveToCopyType *arg = nullptr); 7589a1d03eSRichard const TrivialToCopyType &TrivialTypeReference(); 7689a1d03eSRichard 7789a1d03eSRichard void mutate(ExpensiveToCopyType &); 7889a1d03eSRichard void mutate(ExpensiveToCopyType *); 7989a1d03eSRichard void useAsConstPointer(const ExpensiveToCopyType *); 8089a1d03eSRichard void useAsConstReference(const ExpensiveToCopyType &); 8189a1d03eSRichard void useByValue(ExpensiveToCopyType); 8289a1d03eSRichard 8389a1d03eSRichard void PositiveFunctionCall() { 8489a1d03eSRichard const auto AutoAssigned = ExpensiveTypeReference(); 8589a1d03eSRichard // 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] 8689a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); 8789a1d03eSRichard AutoAssigned.constMethod(); 8889a1d03eSRichard 8989a1d03eSRichard const auto AutoCopyConstructed(ExpensiveTypeReference()); 9089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 9189a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); 9289a1d03eSRichard AutoCopyConstructed.constMethod(); 9389a1d03eSRichard 9489a1d03eSRichard const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); 9589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 9689a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); 9789a1d03eSRichard VarAssigned.constMethod(); 9889a1d03eSRichard 9989a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); 10089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 10189a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); 10289a1d03eSRichard VarCopyConstructed.constMethod(); 10389a1d03eSRichard } 10489a1d03eSRichard 105*a5364444SBarnabás Pőcze void PositiveStaticMethodCall() { 106*a5364444SBarnabás Pőcze const auto AutoAssigned = ExpensiveToCopyType::instance(); 107*a5364444SBarnabás Pőcze // 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*a5364444SBarnabás Pőcze // CHECK-FIXES: const auto& AutoAssigned = ExpensiveToCopyType::instance(); 109*a5364444SBarnabás Pőcze AutoAssigned.constMethod(); 110*a5364444SBarnabás Pőcze 111*a5364444SBarnabás Pőcze const auto AutoCopyConstructed(ExpensiveToCopyType::instance()); 112*a5364444SBarnabás Pőcze // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 113*a5364444SBarnabás Pőcze // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveToCopyType::instance()); 114*a5364444SBarnabás Pőcze AutoCopyConstructed.constMethod(); 115*a5364444SBarnabás Pőcze 116*a5364444SBarnabás Pőcze const ExpensiveToCopyType VarAssigned = ExpensiveToCopyType::instance(); 117*a5364444SBarnabás Pőcze // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 118*a5364444SBarnabás Pőcze // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveToCopyType::instance(); 119*a5364444SBarnabás Pőcze VarAssigned.constMethod(); 120*a5364444SBarnabás Pőcze 121*a5364444SBarnabás Pőcze const ExpensiveToCopyType VarCopyConstructed(ExpensiveToCopyType::instance()); 122*a5364444SBarnabás Pőcze // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 123*a5364444SBarnabás Pőcze // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveToCopyType::instance()); 124*a5364444SBarnabás Pőcze VarCopyConstructed.constMethod(); 125*a5364444SBarnabás Pőcze } 126*a5364444SBarnabás Pőcze 12789a1d03eSRichard void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) { 12889a1d03eSRichard const auto AutoAssigned = Obj.reference(); 12989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 13089a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); 13189a1d03eSRichard AutoAssigned.constMethod(); 13289a1d03eSRichard 13389a1d03eSRichard const auto AutoCopyConstructed(Obj.reference()); 13489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 13589a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); 13689a1d03eSRichard AutoCopyConstructed.constMethod(); 13789a1d03eSRichard 13889a1d03eSRichard const ExpensiveToCopyType VarAssigned = Obj.reference(); 13989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 14089a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); 14189a1d03eSRichard VarAssigned.constMethod(); 14289a1d03eSRichard 14389a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); 14489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 14589a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); 14689a1d03eSRichard VarCopyConstructed.constMethod(); 14789a1d03eSRichard } 14889a1d03eSRichard 14989a1d03eSRichard void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) { 15089a1d03eSRichard const auto AutoAssigned = Obj.reference(); 15189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 15289a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); 15389a1d03eSRichard AutoAssigned.constMethod(); 15489a1d03eSRichard 15589a1d03eSRichard const auto AutoCopyConstructed(Obj.reference()); 15689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 15789a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); 15889a1d03eSRichard AutoCopyConstructed.constMethod(); 15989a1d03eSRichard 16089a1d03eSRichard const ExpensiveToCopyType VarAssigned = Obj.reference(); 16189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 16289a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); 16389a1d03eSRichard VarAssigned.constMethod(); 16489a1d03eSRichard 16589a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); 16689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 16789a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); 16889a1d03eSRichard VarCopyConstructed.constMethod(); 16989a1d03eSRichard } 17089a1d03eSRichard 17189a1d03eSRichard void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) { 17289a1d03eSRichard const auto AutoAssigned = Obj->reference(); 17389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 17489a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); 17589a1d03eSRichard AutoAssigned.constMethod(); 17689a1d03eSRichard 17789a1d03eSRichard const auto AutoCopyConstructed(Obj->reference()); 17889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 17989a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference()); 18089a1d03eSRichard AutoCopyConstructed.constMethod(); 18189a1d03eSRichard 18289a1d03eSRichard const ExpensiveToCopyType VarAssigned = Obj->reference(); 18389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 18489a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference(); 18589a1d03eSRichard VarAssigned.constMethod(); 18689a1d03eSRichard 18789a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); 18889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 18989a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference()); 19089a1d03eSRichard VarCopyConstructed.constMethod(); 19189a1d03eSRichard } 19289a1d03eSRichard 19389a1d03eSRichard void PositiveOperatorCallConstReferenceParam(const Container<ExpensiveToCopyType> &C) { 19489a1d03eSRichard const auto AutoAssigned = C[42]; 19589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 19689a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = C[42]; 19789a1d03eSRichard AutoAssigned.constMethod(); 19889a1d03eSRichard 19989a1d03eSRichard const auto AutoCopyConstructed(C[42]); 20089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 20189a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); 20289a1d03eSRichard AutoCopyConstructed.constMethod(); 20389a1d03eSRichard 20489a1d03eSRichard const ExpensiveToCopyType VarAssigned = C[42]; 20589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 20689a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; 20789a1d03eSRichard VarAssigned.constMethod(); 20889a1d03eSRichard 20989a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(C[42]); 21089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 21189a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); 21289a1d03eSRichard VarCopyConstructed.constMethod(); 21389a1d03eSRichard } 21489a1d03eSRichard 21589a1d03eSRichard void PositiveOperatorCallConstValueParam(const Container<ExpensiveToCopyType> C) { 21689a1d03eSRichard const auto AutoAssigned = C[42]; 21789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 21889a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = C[42]; 21989a1d03eSRichard AutoAssigned.constMethod(); 22089a1d03eSRichard 22189a1d03eSRichard const auto AutoCopyConstructed(C[42]); 22289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 22389a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); 22489a1d03eSRichard AutoCopyConstructed.constMethod(); 22589a1d03eSRichard 22689a1d03eSRichard const ExpensiveToCopyType VarAssigned = C[42]; 22789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 22889a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; 22989a1d03eSRichard VarAssigned.constMethod(); 23089a1d03eSRichard 23189a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(C[42]); 23289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 23389a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); 23489a1d03eSRichard VarCopyConstructed.constMethod(); 23589a1d03eSRichard } 23689a1d03eSRichard 237415a82c6SClement Courbet void PositiveOperatorValueParam(Container<ExpensiveToCopyType> C) { 238415a82c6SClement Courbet const auto AutoAssigned = C[42]; 239415a82c6SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 240415a82c6SClement Courbet // CHECK-FIXES: const auto& AutoAssigned = C[42]; 241415a82c6SClement Courbet AutoAssigned.constMethod(); 242415a82c6SClement Courbet 243415a82c6SClement Courbet const auto AutoCopyConstructed(C[42]); 244415a82c6SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 245415a82c6SClement Courbet // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); 246415a82c6SClement Courbet AutoCopyConstructed.constMethod(); 247415a82c6SClement Courbet 248415a82c6SClement Courbet const ExpensiveToCopyType VarAssigned = C.at(42); 249415a82c6SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 250415a82c6SClement Courbet // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C.at(42); 251415a82c6SClement Courbet VarAssigned.constMethod(); 252415a82c6SClement Courbet 253415a82c6SClement Courbet const ExpensiveToCopyType VarCopyConstructed(C.at(42)); 254415a82c6SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 255415a82c6SClement Courbet // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C.at(42)); 256415a82c6SClement Courbet VarCopyConstructed.constMethod(); 257415a82c6SClement Courbet } 258415a82c6SClement Courbet 25989a1d03eSRichard void PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlias C) { 26089a1d03eSRichard const auto AutoAssigned = C[42]; 26189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 26289a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = C[42]; 26389a1d03eSRichard AutoAssigned.constMethod(); 26489a1d03eSRichard 26589a1d03eSRichard const auto AutoCopyConstructed(C[42]); 26689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 26789a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); 26889a1d03eSRichard AutoCopyConstructed.constMethod(); 26989a1d03eSRichard 27089a1d03eSRichard const ExpensiveToCopyType VarAssigned = C[42]; 27189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 27289a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; 27389a1d03eSRichard VarAssigned.constMethod(); 27489a1d03eSRichard 27589a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(C[42]); 27689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 27789a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); 27889a1d03eSRichard VarCopyConstructed.constMethod(); 27989a1d03eSRichard } 28089a1d03eSRichard 28194ca854dSClement Courbet void PositiveOperatorCallConstPtrParam(const Container<ExpensiveToCopyType>* C) { 28289a1d03eSRichard const auto AutoAssigned = (*C)[42]; 28394ca854dSClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 28494ca854dSClement Courbet // CHECK-FIXES: const auto& AutoAssigned = (*C)[42]; 28589a1d03eSRichard AutoAssigned.constMethod(); 28689a1d03eSRichard 28789a1d03eSRichard const auto AutoCopyConstructed((*C)[42]); 28894ca854dSClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' 28994ca854dSClement Courbet // CHECK-FIXES: const auto& AutoCopyConstructed((*C)[42]); 29089a1d03eSRichard AutoCopyConstructed.constMethod(); 29189a1d03eSRichard 29294ca854dSClement Courbet const ExpensiveToCopyType VarAssigned = C->at(42); 29394ca854dSClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' 29494ca854dSClement Courbet // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C->at(42); 29589a1d03eSRichard VarAssigned.constMethod(); 29689a1d03eSRichard 29794ca854dSClement Courbet const ExpensiveToCopyType VarCopyConstructed(C->at(42)); 29894ca854dSClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' 29994ca854dSClement Courbet // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->at(42)); 30089a1d03eSRichard VarCopyConstructed.constMethod(); 30189a1d03eSRichard } 30289a1d03eSRichard 30389a1d03eSRichard void PositiveLocalConstValue() { 30489a1d03eSRichard const ExpensiveToCopyType Obj; 30589a1d03eSRichard const auto UnnecessaryCopy = Obj.reference(); 30689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' 30789a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference(); 30889a1d03eSRichard UnnecessaryCopy.constMethod(); 30989a1d03eSRichard } 31089a1d03eSRichard 31189a1d03eSRichard void PositiveLocalConstRef() { 31289a1d03eSRichard const ExpensiveToCopyType Obj; 31389a1d03eSRichard const ExpensiveToCopyType &ConstReference = Obj.reference(); 31489a1d03eSRichard const auto UnnecessaryCopy = ConstReference.reference(); 31589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' 31689a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference(); 31789a1d03eSRichard UnnecessaryCopy.constMethod(); 31889a1d03eSRichard } 31989a1d03eSRichard 32089a1d03eSRichard void PositiveLocalConstPointer() { 32189a1d03eSRichard const ExpensiveToCopyType Obj; 32289a1d03eSRichard const ExpensiveToCopyType *const ConstPointer = &Obj; 32389a1d03eSRichard const auto UnnecessaryCopy = ConstPointer->reference(); 32489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' 32589a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference(); 32689a1d03eSRichard UnnecessaryCopy.constMethod(); 32789a1d03eSRichard } 32889a1d03eSRichard 32989a1d03eSRichard void NegativeFunctionCallTrivialType() { 33089a1d03eSRichard const auto AutoAssigned = TrivialTypeReference(); 33189a1d03eSRichard const auto AutoCopyConstructed(TrivialTypeReference()); 33289a1d03eSRichard const TrivialToCopyType VarAssigned = TrivialTypeReference(); 33389a1d03eSRichard const TrivialToCopyType VarCopyConstructed(TrivialTypeReference()); 33489a1d03eSRichard } 33589a1d03eSRichard 33689a1d03eSRichard void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) { 33789a1d03eSRichard static const auto StaticVar = Obj.reference(); 33889a1d03eSRichard } 33989a1d03eSRichard 34089a1d03eSRichard void PositiveFunctionCallExpensiveTypeNonConstVariable() { 34189a1d03eSRichard auto AutoAssigned = ExpensiveTypeReference(); 34289a1d03eSRichard // 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] 34389a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); 34489a1d03eSRichard AutoAssigned.constMethod(); 34589a1d03eSRichard 34689a1d03eSRichard auto AutoCopyConstructed(ExpensiveTypeReference()); 34789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed' 34889a1d03eSRichard // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); 34989a1d03eSRichard AutoCopyConstructed.constMethod(); 35089a1d03eSRichard 35189a1d03eSRichard ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); 35289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned' 35389a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); 35489a1d03eSRichard VarAssigned.constMethod(); 35589a1d03eSRichard 35689a1d03eSRichard ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); 35789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed' 35889a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); 35989a1d03eSRichard VarCopyConstructed.constMethod(); 36089a1d03eSRichard } 36189a1d03eSRichard 36289a1d03eSRichard void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { 36389a1d03eSRichard { 36489a1d03eSRichard auto Assigned = Obj.reference(); 36589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned' 36689a1d03eSRichard // CHECK-FIXES: const auto& Assigned = Obj.reference(); 36789a1d03eSRichard Assigned.reference(); 36889a1d03eSRichard useAsConstReference(Assigned); 36989a1d03eSRichard useByValue(Assigned); 37089a1d03eSRichard } 37189a1d03eSRichard } 37289a1d03eSRichard 37389a1d03eSRichard void positiveNonConstVarInCodeBlockWithAlias(const ExpensiveToCopyType &Obj) { 37489a1d03eSRichard { 37589a1d03eSRichard const ExpensiveToCopyType Assigned = Obj.referenceWithAlias(); 37689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:31: warning: the const qualified variable 37789a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& Assigned = Obj.referenceWithAlias(); 37889a1d03eSRichard useAsConstReference(Assigned); 37989a1d03eSRichard } 38089a1d03eSRichard } 38189a1d03eSRichard 38289a1d03eSRichard void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) { 38389a1d03eSRichard { 38489a1d03eSRichard auto NonConstInvoked = Obj.reference(); 38589a1d03eSRichard // CHECK-FIXES: auto NonConstInvoked = Obj.reference(); 38689a1d03eSRichard NonConstInvoked.nonConstMethod(); 38789a1d03eSRichard } 38889a1d03eSRichard { 38989a1d03eSRichard auto Reassigned = Obj.reference(); 39089a1d03eSRichard // CHECK-FIXES: auto Reassigned = Obj.reference(); 39189a1d03eSRichard Reassigned = ExpensiveToCopyType(); 39289a1d03eSRichard } 39389a1d03eSRichard { 39489a1d03eSRichard auto MutatedByReference = Obj.reference(); 39589a1d03eSRichard // CHECK-FIXES: auto MutatedByReference = Obj.reference(); 39689a1d03eSRichard mutate(MutatedByReference); 39789a1d03eSRichard } 39889a1d03eSRichard { 39989a1d03eSRichard auto MutatedByPointer = Obj.reference(); 40089a1d03eSRichard // CHECK-FIXES: auto MutatedByPointer = Obj.reference(); 40189a1d03eSRichard mutate(&MutatedByPointer); 40289a1d03eSRichard } 40389a1d03eSRichard } 40489a1d03eSRichard 40589a1d03eSRichard void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { 40689a1d03eSRichard const auto AutoAssigned = Obj.reference(); 40789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 40889a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); 40989a1d03eSRichard AutoAssigned.constMethod(); 41089a1d03eSRichard } 41189a1d03eSRichard 41289a1d03eSRichard void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { 41389a1d03eSRichard const auto AutoAssigned = Obj.reference(); 41489a1d03eSRichard const auto AutoCopyConstructed(Obj.reference()); 41589a1d03eSRichard const ExpensiveToCopyType VarAssigned = Obj.reference(); 41689a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); 41789a1d03eSRichard mutate(&Obj); 41889a1d03eSRichard } 41989a1d03eSRichard 42089a1d03eSRichard void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { 42189a1d03eSRichard const auto AutoAssigned = Obj.reference(); 42289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 42389a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); 42489a1d03eSRichard AutoAssigned.constMethod(); 42589a1d03eSRichard } 42689a1d03eSRichard 42789a1d03eSRichard void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { 42889a1d03eSRichard Obj.nonConstMethod(); 42989a1d03eSRichard const auto AutoAssigned = Obj.reference(); 43089a1d03eSRichard } 43189a1d03eSRichard 43289a1d03eSRichard void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { 43389a1d03eSRichard const auto AutoAssigned = Obj->reference(); 43489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 43589a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); 43689a1d03eSRichard Obj->constMethod(); 43789a1d03eSRichard AutoAssigned.constMethod(); 43889a1d03eSRichard } 43989a1d03eSRichard 44089a1d03eSRichard void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { 44189a1d03eSRichard const auto AutoAssigned = Obj->reference(); 44289a1d03eSRichard const auto AutoCopyConstructed(Obj->reference()); 44389a1d03eSRichard const ExpensiveToCopyType VarAssigned = Obj->reference(); 44489a1d03eSRichard const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); 44589a1d03eSRichard mutate(Obj); 44689a1d03eSRichard } 44789a1d03eSRichard 44889a1d03eSRichard void PositiveLocalVarIsNotModified() { 44989a1d03eSRichard ExpensiveToCopyType LocalVar; 45089a1d03eSRichard const auto AutoAssigned = LocalVar.reference(); 45189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' 45289a1d03eSRichard // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); 45389a1d03eSRichard AutoAssigned.constMethod(); 45489a1d03eSRichard } 45589a1d03eSRichard 45689a1d03eSRichard void NegativeLocalVarIsModified() { 45789a1d03eSRichard ExpensiveToCopyType Obj; 45889a1d03eSRichard const auto AutoAssigned = Obj.reference(); 45989a1d03eSRichard Obj = AutoAssigned; 46089a1d03eSRichard } 46189a1d03eSRichard 46289a1d03eSRichard struct NegativeConstructor { 46389a1d03eSRichard NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {} 46489a1d03eSRichard ExpensiveToCopyType Obj; 46589a1d03eSRichard }; 46689a1d03eSRichard 46789a1d03eSRichard #define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \ 46889a1d03eSRichard void functionWith##TYPE(const TYPE &T) { \ 46989a1d03eSRichard auto AssignedInMacro = T.reference(); \ 47089a1d03eSRichard } \ 47189a1d03eSRichard // Ensure fix is not applied. 47289a1d03eSRichard // CHECK-FIXES: auto AssignedInMacro = T.reference(); 47389a1d03eSRichard 47489a1d03eSRichard UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType) 47589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is copy-constructed 47689a1d03eSRichard 47789a1d03eSRichard #define UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(ARGUMENT) ARGUMENT 47889a1d03eSRichard 47989a1d03eSRichard void PositiveMacroArgument(const ExpensiveToCopyType &Obj) { 48089a1d03eSRichard UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(auto CopyInMacroArg = Obj.reference()); 48189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:48: warning: the variable 'CopyInMacroArg' is copy-constructed 48289a1d03eSRichard // Ensure fix is not applied. 48389a1d03eSRichard // CHECK-FIXES: auto CopyInMacroArg = Obj.reference() 48489a1d03eSRichard CopyInMacroArg.constMethod(); 48589a1d03eSRichard } 48689a1d03eSRichard 48789a1d03eSRichard void PositiveLocalCopyConstMethodInvoked() { 48889a1d03eSRichard ExpensiveToCopyType orig; 48989a1d03eSRichard ExpensiveToCopyType copy_1 = orig; 49089a1d03eSRichard // 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] 49189a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_1 = orig; 49289a1d03eSRichard copy_1.constMethod(); 49389a1d03eSRichard orig.constMethod(); 49489a1d03eSRichard } 49589a1d03eSRichard 49689a1d03eSRichard void PositiveLocalCopyUsingExplicitCopyCtor() { 49789a1d03eSRichard ExpensiveToCopyType orig; 49889a1d03eSRichard ExpensiveToCopyType copy_2(orig); 49989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_2' 50089a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_2(orig); 50189a1d03eSRichard copy_2.constMethod(); 50289a1d03eSRichard orig.constMethod(); 50389a1d03eSRichard } 50489a1d03eSRichard 50589a1d03eSRichard void PositiveLocalCopyCopyIsArgument(const ExpensiveToCopyType &orig) { 50689a1d03eSRichard ExpensiveToCopyType copy_3 = orig; 50789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_3' 50889a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_3 = orig; 50989a1d03eSRichard copy_3.constMethod(); 51089a1d03eSRichard } 51189a1d03eSRichard 51289a1d03eSRichard void PositiveLocalCopyUsedAsConstRef() { 51389a1d03eSRichard ExpensiveToCopyType orig; 51489a1d03eSRichard ExpensiveToCopyType copy_4 = orig; 51589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_4' 51689a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_4 = orig; 51789a1d03eSRichard useAsConstReference(orig); 51889a1d03eSRichard copy_4.constMethod(); 51989a1d03eSRichard } 52089a1d03eSRichard 52189a1d03eSRichard void PositiveLocalCopyTwice() { 52289a1d03eSRichard ExpensiveToCopyType orig; 52389a1d03eSRichard ExpensiveToCopyType copy_5 = orig; 52489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_5' 52589a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_5 = orig; 52689a1d03eSRichard ExpensiveToCopyType copy_6 = copy_5; 52789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_6' 52889a1d03eSRichard // CHECK-FIXES: const ExpensiveToCopyType& copy_6 = copy_5; 52989a1d03eSRichard copy_5.constMethod(); 53089a1d03eSRichard copy_6.constMethod(); 53189a1d03eSRichard orig.constMethod(); 53289a1d03eSRichard } 53389a1d03eSRichard 53489a1d03eSRichard 53589a1d03eSRichard void PositiveLocalCopyWeirdCopy() { 53689a1d03eSRichard WeirdCopyCtorType orig; 53789a1d03eSRichard WeirdCopyCtorType weird_1(orig); 53889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_1' 53989a1d03eSRichard // CHECK-FIXES: const WeirdCopyCtorType& weird_1(orig); 54089a1d03eSRichard weird_1.constMethod(); 54189a1d03eSRichard 54289a1d03eSRichard WeirdCopyCtorType weird_2 = orig; 54389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_2' 54489a1d03eSRichard // CHECK-FIXES: const WeirdCopyCtorType& weird_2 = orig; 54589a1d03eSRichard weird_2.constMethod(); 54689a1d03eSRichard } 54789a1d03eSRichard 54889a1d03eSRichard void NegativeLocalCopySimpleTypes() { 54989a1d03eSRichard int i1 = 0; 55089a1d03eSRichard int i2 = i1; 55189a1d03eSRichard } 55289a1d03eSRichard 55389a1d03eSRichard void NegativeLocalCopyCopyIsModified() { 55489a1d03eSRichard ExpensiveToCopyType orig; 55589a1d03eSRichard ExpensiveToCopyType neg_copy_1 = orig; 55689a1d03eSRichard neg_copy_1.nonConstMethod(); 55789a1d03eSRichard } 55889a1d03eSRichard 55989a1d03eSRichard void NegativeLocalCopyOriginalIsModified() { 56089a1d03eSRichard ExpensiveToCopyType orig; 56189a1d03eSRichard ExpensiveToCopyType neg_copy_2 = orig; 56289a1d03eSRichard orig.nonConstMethod(); 56389a1d03eSRichard } 56489a1d03eSRichard 56589a1d03eSRichard void NegativeLocalCopyUsedAsRefArg() { 56689a1d03eSRichard ExpensiveToCopyType orig; 56789a1d03eSRichard ExpensiveToCopyType neg_copy_3 = orig; 56889a1d03eSRichard mutate(neg_copy_3); 56989a1d03eSRichard } 57089a1d03eSRichard 57189a1d03eSRichard void NegativeLocalCopyUsedAsPointerArg() { 57289a1d03eSRichard ExpensiveToCopyType orig; 57389a1d03eSRichard ExpensiveToCopyType neg_copy_4 = orig; 57489a1d03eSRichard mutate(&neg_copy_4); 57589a1d03eSRichard } 57689a1d03eSRichard 57789a1d03eSRichard void NegativeLocalCopyCopyFromGlobal() { 57889a1d03eSRichard ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type; 57989a1d03eSRichard } 58089a1d03eSRichard 58189a1d03eSRichard void NegativeLocalCopyCopyToStatic() { 58289a1d03eSRichard ExpensiveToCopyType orig; 58389a1d03eSRichard static ExpensiveToCopyType neg_copy_6 = orig; 58489a1d03eSRichard } 58589a1d03eSRichard 58689a1d03eSRichard void NegativeLocalCopyNonConstInForLoop() { 58789a1d03eSRichard ExpensiveToCopyType orig; 58889a1d03eSRichard for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod(); 58989a1d03eSRichard orig.nonConstMethod()) { 59089a1d03eSRichard orig.constMethod(); 59189a1d03eSRichard } 59289a1d03eSRichard } 59389a1d03eSRichard 59489a1d03eSRichard void NegativeLocalCopyWeirdNonCopy() { 59589a1d03eSRichard WeirdCopyCtorType orig; 59689a1d03eSRichard WeirdCopyCtorType neg_weird_1(orig, false); 59789a1d03eSRichard WeirdCopyCtorType neg_weird_2(orig, true); 59889a1d03eSRichard } 59989a1d03eSRichard void WarningOnlyMultiDeclStmt() { 60089a1d03eSRichard ExpensiveToCopyType orig; 60189a1d03eSRichard ExpensiveToCopyType copy = orig, copy2; 60289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] 60389a1d03eSRichard // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; 60489a1d03eSRichard copy.constMethod(); 60589a1d03eSRichard } 60689a1d03eSRichard 60789a1d03eSRichard class Element {}; 60889a1d03eSRichard 60989a1d03eSRichard void implicitVarFalsePositive() { 61089a1d03eSRichard for (const Element &E : Container<Element>()) { 61189a1d03eSRichard } 61289a1d03eSRichard } 61389a1d03eSRichard 61489a1d03eSRichard // This should not trigger the check as the argument could introduce an alias. 61589a1d03eSRichard void negativeInitializedFromFreeFunctionWithArg() { 61689a1d03eSRichard ExpensiveToCopyType Orig; 61789a1d03eSRichard const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig); 61889a1d03eSRichard } 61989a1d03eSRichard 62089a1d03eSRichard void negativeInitializedFromFreeFunctionWithDefaultArg() { 62189a1d03eSRichard const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(); 62289a1d03eSRichard } 62389a1d03eSRichard 62489a1d03eSRichard void negativeInitialzedFromFreeFunctionWithNonDefaultArg() { 62589a1d03eSRichard ExpensiveToCopyType Orig; 62689a1d03eSRichard const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig); 62789a1d03eSRichard } 62889a1d03eSRichard 62989a1d03eSRichard namespace std { 63089a1d03eSRichard inline namespace __1 { 63189a1d03eSRichard 63289a1d03eSRichard template <class> 63389a1d03eSRichard class function; 63489a1d03eSRichard template <class R, class... ArgTypes> 63589a1d03eSRichard class function<R(ArgTypes...)> { 63689a1d03eSRichard public: 63789a1d03eSRichard function(); 63889a1d03eSRichard function(const function &Other); 63989a1d03eSRichard R operator()(ArgTypes... Args) const; 64089a1d03eSRichard }; 64189a1d03eSRichard 64289a1d03eSRichard } // namespace __1 64389a1d03eSRichard } // namespace std 64489a1d03eSRichard 64589a1d03eSRichard void negativeStdFunction() { 64689a1d03eSRichard std::function<int()> Orig; 64789a1d03eSRichard std::function<int()> Copy = Orig; 64889a1d03eSRichard int i = Orig(); 64989a1d03eSRichard } 65089a1d03eSRichard 65189a1d03eSRichard using Functor = std::function<int()>; 65289a1d03eSRichard 65389a1d03eSRichard void negativeAliasedStdFunction() { 65489a1d03eSRichard Functor Orig; 65589a1d03eSRichard Functor Copy = Orig; 65689a1d03eSRichard int i = Orig(); 65789a1d03eSRichard } 65889a1d03eSRichard 65989a1d03eSRichard typedef std::function<int()> TypedefFunc; 66089a1d03eSRichard 66189a1d03eSRichard void negativeTypedefedStdFunction() { 66289a1d03eSRichard TypedefFunc Orig; 66389a1d03eSRichard TypedefFunc Copy = Orig; 66489a1d03eSRichard int i = Orig(); 66589a1d03eSRichard } 66689a1d03eSRichard 66789a1d03eSRichard namespace fake { 66889a1d03eSRichard namespace std { 66989a1d03eSRichard template <class R, class... Args> 67089a1d03eSRichard struct function { 67189a1d03eSRichard // Custom copy constructor makes it expensive to copy; 67289a1d03eSRichard function(const function &); 67389a1d03eSRichard void constMethod() const; 67489a1d03eSRichard }; 67589a1d03eSRichard } // namespace std 67689a1d03eSRichard 67789a1d03eSRichard void positiveFakeStdFunction(std::function<void(int)> F) { 67889a1d03eSRichard auto Copy = F; 67989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified; 68089a1d03eSRichard // CHECK-FIXES: const auto& Copy = F; 68189a1d03eSRichard Copy.constMethod(); 68289a1d03eSRichard } 68389a1d03eSRichard 68489a1d03eSRichard } // namespace fake 68589a1d03eSRichard 68689a1d03eSRichard void positiveInvokedOnStdFunction( 68789a1d03eSRichard std::function<void(const ExpensiveToCopyType &)> Update, 68889a1d03eSRichard const ExpensiveToCopyType Orig) { 68989a1d03eSRichard auto Copy = Orig.reference(); 69089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference 69189a1d03eSRichard // CHECK-FIXES: const auto& Copy = Orig.reference(); 69289a1d03eSRichard Update(Copy); 69389a1d03eSRichard } 69489a1d03eSRichard 69589a1d03eSRichard void negativeInvokedOnStdFunction( 69689a1d03eSRichard std::function<void(ExpensiveToCopyType &)> Update, 69789a1d03eSRichard const ExpensiveToCopyType Orig) { 69889a1d03eSRichard auto Copy = Orig.reference(); 69989a1d03eSRichard Update(Copy); 70089a1d03eSRichard } 70189a1d03eSRichard 70289a1d03eSRichard void negativeCopiedFromReferenceToModifiedVar() { 70389a1d03eSRichard ExpensiveToCopyType Orig; 70489a1d03eSRichard const auto &Ref = Orig; 70589a1d03eSRichard const auto NecessaryCopy = Ref; 70689a1d03eSRichard Orig.nonConstMethod(); 70789a1d03eSRichard } 70889a1d03eSRichard 70989a1d03eSRichard void positiveCopiedFromReferenceToConstVar() { 71089a1d03eSRichard ExpensiveToCopyType Orig; 71189a1d03eSRichard const auto &Ref = Orig; 71289a1d03eSRichard const auto UnnecessaryCopy = Ref; 71389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of 71489a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = Ref; 71589a1d03eSRichard Orig.constMethod(); 71689a1d03eSRichard UnnecessaryCopy.constMethod(); 71789a1d03eSRichard } 71889a1d03eSRichard 71989a1d03eSRichard void negativeCopiedFromGetterOfReferenceToModifiedVar() { 72089a1d03eSRichard ExpensiveToCopyType Orig; 72189a1d03eSRichard const auto &Ref = Orig.reference(); 72289a1d03eSRichard const auto NecessaryCopy = Ref.reference(); 72389a1d03eSRichard Orig.nonConstMethod(); 72489a1d03eSRichard } 72589a1d03eSRichard 72689a1d03eSRichard void negativeAliasNonCanonicalPointerType() { 72789a1d03eSRichard ExpensiveToCopyType Orig; 72889a1d03eSRichard // The use of auto here hides that the type is a pointer type. The check needs 72989a1d03eSRichard // to look at the canonical type to detect the aliasing through this pointer. 73089a1d03eSRichard const auto Pointer = Orig.pointer(); 73189a1d03eSRichard const auto NecessaryCopy = Pointer->reference(); 73289a1d03eSRichard Orig.nonConstMethod(); 73389a1d03eSRichard } 73489a1d03eSRichard 73589a1d03eSRichard void negativeAliasTypedefedType() { 73689a1d03eSRichard typedef const ExpensiveToCopyType &ReferenceType; 73789a1d03eSRichard ExpensiveToCopyType Orig; 73889a1d03eSRichard // The typedef hides the fact that this is a reference type. The check needs 73989a1d03eSRichard // to look at the canonical type to detect the aliasing. 74089a1d03eSRichard ReferenceType Ref = Orig.reference(); 74189a1d03eSRichard const auto NecessaryCopy = Ref.reference(); 74289a1d03eSRichard Orig.nonConstMethod(); 74389a1d03eSRichard } 74489a1d03eSRichard 74589a1d03eSRichard void positiveCopiedFromGetterOfReferenceToConstVar() { 74689a1d03eSRichard ExpensiveToCopyType Orig; 74789a1d03eSRichard const auto &Ref = Orig.reference(); 74889a1d03eSRichard auto UnnecessaryCopy = Ref.reference(); 74989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is 75089a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference(); 75189a1d03eSRichard Orig.constMethod(); 75289a1d03eSRichard UnnecessaryCopy.constMethod(); 75389a1d03eSRichard } 75489a1d03eSRichard 75589a1d03eSRichard void positiveUnusedReferenceIsRemoved() { 75689a1d03eSRichard // clang-format off 75789a1d03eSRichard const auto AutoAssigned = ExpensiveTypeReference(); int i = 0; // Foo bar. 75889a1d03eSRichard // 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] 75989a1d03eSRichard // CHECK-FIXES-NOT: const auto AutoAssigned = ExpensiveTypeReference(); 76089a1d03eSRichard // CHECK-FIXES: int i = 0; // Foo bar. 76189a1d03eSRichard auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment. 76289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used; 76389a1d03eSRichard // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); 76489a1d03eSRichard // CHECK-FIXES-NOT: // Trailing comment. 76589a1d03eSRichard // clang-format on 76689a1d03eSRichard 76789a1d03eSRichard auto UnusedAndUnnecessary = ExpensiveTypeReference(); 76889a1d03eSRichard // Comments on a new line should not be deleted. 76989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed 77089a1d03eSRichard // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference(); 77189a1d03eSRichard // CHECK-FIXES: // Comments on a new line should not be deleted. 77289a1d03eSRichard } 77389a1d03eSRichard 77489a1d03eSRichard void positiveLoopedOverObjectIsConst() { 77589a1d03eSRichard const Container<ExpensiveToCopyType> Orig; 77689a1d03eSRichard for (const auto &Element : Orig) { 77789a1d03eSRichard const auto Copy = Element; 77889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:16: warning: local copy 'Copy' 77989a1d03eSRichard // CHECK-FIXES: const auto& Copy = Element; 78089a1d03eSRichard Orig.constMethod(); 78189a1d03eSRichard Copy.constMethod(); 78289a1d03eSRichard } 78389a1d03eSRichard 78489a1d03eSRichard auto Lambda = []() { 78589a1d03eSRichard const Container<ExpensiveToCopyType> Orig; 78689a1d03eSRichard for (const auto &Element : Orig) { 78789a1d03eSRichard const auto Copy = Element; 78889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:18: warning: local copy 'Copy' 78989a1d03eSRichard // CHECK-FIXES: const auto& Copy = Element; 79089a1d03eSRichard Orig.constMethod(); 79189a1d03eSRichard Copy.constMethod(); 79289a1d03eSRichard } 79389a1d03eSRichard }; 79489a1d03eSRichard } 79589a1d03eSRichard 79689a1d03eSRichard void negativeLoopedOverObjectIsModified() { 79789a1d03eSRichard Container<ExpensiveToCopyType> Orig; 79889a1d03eSRichard for (const auto &Element : Orig) { 79989a1d03eSRichard const auto Copy = Element; 80089a1d03eSRichard Orig.nonConstMethod(); 80189a1d03eSRichard Copy.constMethod(); 80289a1d03eSRichard } 80389a1d03eSRichard 80489a1d03eSRichard auto Lambda = []() { 80589a1d03eSRichard Container<ExpensiveToCopyType> Orig; 80689a1d03eSRichard for (const auto &Element : Orig) { 80789a1d03eSRichard const auto Copy = Element; 80889a1d03eSRichard Orig.nonConstMethod(); 80989a1d03eSRichard Copy.constMethod(); 81089a1d03eSRichard } 81189a1d03eSRichard }; 81289a1d03eSRichard } 81389a1d03eSRichard 81489a1d03eSRichard void negativeReferenceIsInitializedOutsideOfBlock() { 81589a1d03eSRichard ExpensiveToCopyType Orig; 81689a1d03eSRichard const auto &E2 = Orig; 81789a1d03eSRichard if (1 != 2 * 3) { 81889a1d03eSRichard const auto C2 = E2; 81989a1d03eSRichard Orig.nonConstMethod(); 82089a1d03eSRichard C2.constMethod(); 82189a1d03eSRichard } 82289a1d03eSRichard 82389a1d03eSRichard auto Lambda = []() { 82489a1d03eSRichard ExpensiveToCopyType Orig; 82589a1d03eSRichard const auto &E2 = Orig; 82689a1d03eSRichard if (1 != 2 * 3) { 82789a1d03eSRichard const auto C2 = E2; 82889a1d03eSRichard Orig.nonConstMethod(); 82989a1d03eSRichard C2.constMethod(); 83089a1d03eSRichard } 83189a1d03eSRichard }; 83289a1d03eSRichard } 83389a1d03eSRichard 83489a1d03eSRichard void negativeStructuredBinding() { 83589a1d03eSRichard // Structured bindings are not yet supported but can trigger false positives 83689a1d03eSRichard // since the DecompositionDecl itself is unused and the check doesn't traverse 83789a1d03eSRichard // VarDecls of the BindingDecls. 83889a1d03eSRichard struct Pair { 83989a1d03eSRichard ExpensiveToCopyType first; 84089a1d03eSRichard ExpensiveToCopyType second; 84189a1d03eSRichard }; 84289a1d03eSRichard 84389a1d03eSRichard Pair P; 84489a1d03eSRichard const auto [C, D] = P; 84589a1d03eSRichard C.constMethod(); 84689a1d03eSRichard D.constMethod(); 84789a1d03eSRichard } 84889a1d03eSRichard 84989a1d03eSRichard template <typename A> 85089a1d03eSRichard const A &templatedReference(); 85189a1d03eSRichard 85289a1d03eSRichard template <typename A, typename B> 85389a1d03eSRichard void negativeTemplateTypes() { 85489a1d03eSRichard A Orig; 85589a1d03eSRichard // Different replaced template type params do not trigger the check. In some 85689a1d03eSRichard // template instantiation this might not be a copy but an implicit 85789a1d03eSRichard // conversion, so converting this to a reference might not work. 85889a1d03eSRichard B AmbiguousCopy = Orig; 85989a1d03eSRichard // CHECK-NOT-FIXES: B AmbiguousCopy = Orig; 86089a1d03eSRichard 86189a1d03eSRichard B NecessaryCopy = templatedReference<A>(); 86289a1d03eSRichard // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference<A>(); 86389a1d03eSRichard 86489a1d03eSRichard B NecessaryCopy2 = Orig.template templatedAccessor<A>(); 86589a1d03eSRichard 86689a1d03eSRichard // Non-dependent types in template still trigger the check. 86789a1d03eSRichard const auto UnnecessaryCopy = ExpensiveTypeReference(); 86889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed 86989a1d03eSRichard // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference(); 87089a1d03eSRichard UnnecessaryCopy.constMethod(); 87189a1d03eSRichard } 87289a1d03eSRichard 87389a1d03eSRichard void instantiateNegativeTemplateTypes() { 87489a1d03eSRichard negativeTemplateTypes<ExpensiveToCopyType, ExpensiveToCopyType>(); 87589a1d03eSRichard // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference. 87689a1d03eSRichard negativeTemplateTypes<ExpensiveToCopyType, int>(); 87789a1d03eSRichard } 87889a1d03eSRichard 87989a1d03eSRichard template <typename A> 88089a1d03eSRichard void positiveSingleTemplateType() { 88189a1d03eSRichard A Orig; 88289a1d03eSRichard A SingleTmplParmTypeCopy = Orig; 88389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified 88489a1d03eSRichard // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig; 88589a1d03eSRichard SingleTmplParmTypeCopy.constMethod(); 88689a1d03eSRichard 88789a1d03eSRichard A UnnecessaryCopy2 = templatedReference<A>(); 88889a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference 88989a1d03eSRichard // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference<A>(); 89089a1d03eSRichard UnnecessaryCopy2.constMethod(); 89189a1d03eSRichard 89289a1d03eSRichard A UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); 89389a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference 89489a1d03eSRichard // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); 89589a1d03eSRichard UnnecessaryCopy3.constMethod(); 89689a1d03eSRichard } 89789a1d03eSRichard 89889a1d03eSRichard void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType<ExpensiveToCopyType>(); } 8991e512688SShivam Gupta 9001e512688SShivam Gupta struct Struct { 9011e512688SShivam Gupta ExpensiveToCopyType Member; 9021e512688SShivam Gupta }; 9031e512688SShivam Gupta 9041e512688SShivam Gupta void positiveConstMemberExpr() { 9051e512688SShivam Gupta Struct Orig; 9061e512688SShivam Gupta auto UC = Orig; 9071e512688SShivam Gupta // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UC' 9081e512688SShivam Gupta // CHECK-FIXES: const auto& UC = Orig; 9091e512688SShivam Gupta const auto &ConstRef = UC.Member; 9101e512688SShivam Gupta auto MemberCopy = UC.Member; 9111e512688SShivam Gupta bool b = UC.Member.constMethod(); 9121e512688SShivam Gupta useByValue(UC.Member); 9131e512688SShivam Gupta useAsConstReference(UC.Member); 9141e512688SShivam Gupta useByValue(UC.Member); 9151e512688SShivam Gupta } 9161e512688SShivam Gupta 9171e512688SShivam Gupta void negativeNonConstMemberExpr() { 9181e512688SShivam Gupta Struct Orig; 9191e512688SShivam Gupta { 9201e512688SShivam Gupta auto Copy = Orig; 9211e512688SShivam Gupta Copy.Member.nonConstMethod(); 9221e512688SShivam Gupta } 9231e512688SShivam Gupta { 9241e512688SShivam Gupta auto Copy = Orig; 9251e512688SShivam Gupta mutate(Copy.Member); 9261e512688SShivam Gupta } 9271e512688SShivam Gupta { 9281e512688SShivam Gupta auto Copy = Orig; 9291e512688SShivam Gupta mutate(&Copy.Member); 9301e512688SShivam Gupta } 9311e512688SShivam Gupta } 93294ca854dSClement Courbet 9338348d720SClement Courbet 9348348d720SClement Courbet bool operator==(ExpensiveToCopyType, ExpensiveToCopyType); 9358348d720SClement Courbet 9368348d720SClement Courbet template<typename T> bool OperatorWithNoDirectCallee(T t) { 9378348d720SClement Courbet ExpensiveToCopyType a1; 9388348d720SClement Courbet ExpensiveToCopyType a2 = a1; 9398348d720SClement Courbet return a1 == t; 9408348d720SClement Courbet } 9418348d720SClement Courbet 942