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