xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp (revision 8fd32b96caf37113dd425cd9d0ff8c839c6a048a)
189a1d03eSRichard // RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
289a1d03eSRichard 
389a1d03eSRichard namespace std {
489a1d03eSRichard 
589a1d03eSRichard template <typename _Tp>
689a1d03eSRichard struct remove_reference { typedef _Tp type; };
789a1d03eSRichard template <typename _Tp>
889a1d03eSRichard struct remove_reference<_Tp&> { typedef _Tp type; };
989a1d03eSRichard template <typename _Tp>
1089a1d03eSRichard struct remove_reference<_Tp&&> { typedef _Tp type; };
1189a1d03eSRichard 
1289a1d03eSRichard template <typename _Tp>
move(_Tp && __t)1389a1d03eSRichard constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
1489a1d03eSRichard   return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
1589a1d03eSRichard }
1689a1d03eSRichard 
1789a1d03eSRichard } // std
1889a1d03eSRichard 
1989a1d03eSRichard template <typename T>
2089a1d03eSRichard struct Iterator {
operator ++Iterator2189a1d03eSRichard   void operator++() {}
operator *Iterator2289a1d03eSRichard   const T& operator*() {
2389a1d03eSRichard     static T* TT = new T();
2489a1d03eSRichard     return *TT;
2589a1d03eSRichard   }
operator !=Iterator2689a1d03eSRichard   bool operator!=(const Iterator &) { return false; }
2789a1d03eSRichard   typedef const T& const_reference;
2889a1d03eSRichard };
2989a1d03eSRichard template <typename T>
3089a1d03eSRichard struct View {
3189a1d03eSRichard   View() = default;
beginView3289a1d03eSRichard   T begin() { return T(); }
beginView3389a1d03eSRichard   T begin() const { return T(); }
endView3489a1d03eSRichard   T end() { return T(); }
endView3589a1d03eSRichard   T end() const { return T(); }
3689a1d03eSRichard   typedef typename T::const_reference const_reference;
3789a1d03eSRichard };
3889a1d03eSRichard 
3989a1d03eSRichard struct ConstructorConvertible {
4089a1d03eSRichard };
4189a1d03eSRichard 
4289a1d03eSRichard struct S {
4389a1d03eSRichard   S();
4489a1d03eSRichard   S(const S &);
SS4589a1d03eSRichard   S(const ConstructorConvertible&) {}
4689a1d03eSRichard   ~S();
4789a1d03eSRichard   S &operator=(const S &);
4889a1d03eSRichard };
4989a1d03eSRichard 
50*8fd32b96SClement Courbet struct Point {
~PointPoint51*8fd32b96SClement Courbet   ~Point() {}
52*8fd32b96SClement Courbet   int x, y;
53*8fd32b96SClement Courbet };
54*8fd32b96SClement Courbet 
5589a1d03eSRichard struct Convertible {
operator SConvertible5689a1d03eSRichard   operator S() const {
5789a1d03eSRichard     return S();
5889a1d03eSRichard   }
5989a1d03eSRichard };
6089a1d03eSRichard 
negativeConstReference()6189a1d03eSRichard void negativeConstReference() {
6289a1d03eSRichard   for (const S &S1 : View<Iterator<S>>()) {
6389a1d03eSRichard   }
6489a1d03eSRichard }
6589a1d03eSRichard 
negativeUserDefinedConversion()6689a1d03eSRichard void negativeUserDefinedConversion() {
6789a1d03eSRichard   Convertible C[0];
6889a1d03eSRichard   for (const S S1 : C) {
6989a1d03eSRichard   }
7089a1d03eSRichard }
7189a1d03eSRichard 
negativeImplicitConstructorConversion()7289a1d03eSRichard void negativeImplicitConstructorConversion() {
7389a1d03eSRichard   ConstructorConvertible C[0];
7489a1d03eSRichard   for (const S S1 : C) {
7589a1d03eSRichard   }
7689a1d03eSRichard }
7789a1d03eSRichard 
7889a1d03eSRichard template <typename T>
uninstantiated()7989a1d03eSRichard void uninstantiated() {
8089a1d03eSRichard   for (const S S1 : View<Iterator<S>>()) {}
8189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]
8289a1d03eSRichard   // CHECK-FIXES: {{^}}  for (const S& S1 : View<Iterator<S>>()) {}
8389a1d03eSRichard 
8489a1d03eSRichard   // Don't warn on dependent types.
8589a1d03eSRichard   for (const T t1 : View<Iterator<T>>()) {
8689a1d03eSRichard   }
8789a1d03eSRichard }
8889a1d03eSRichard 
8989a1d03eSRichard template <typename T>
instantiated()9089a1d03eSRichard void instantiated() {
9189a1d03eSRichard   for (const S S2 : View<Iterator<S>>()) {}
9289a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
9389a1d03eSRichard   // CHECK-FIXES: {{^}}  for (const S& S2 : View<Iterator<S>>()) {}
9489a1d03eSRichard 
95*8fd32b96SClement Courbet   for (const auto [X, Y] : View<Iterator<Point>>()) {}
96*8fd32b96SClement Courbet   // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is
97*8fd32b96SClement Courbet   // CHECK-FIXES: {{^}}  for (const auto& [X, Y] : View<Iterator<Point>>()) {}
98*8fd32b96SClement Courbet 
9989a1d03eSRichard   for (const T T2 : View<Iterator<T>>()) {}
10089a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
10189a1d03eSRichard   // CHECK-FIXES: {{^}}  for (const T& T2 : View<Iterator<T>>()) {}
10289a1d03eSRichard }
10389a1d03eSRichard 
10489a1d03eSRichard template <typename T>
instantiatedNegativeTypedefConstReference()10589a1d03eSRichard void instantiatedNegativeTypedefConstReference() {
10689a1d03eSRichard   for (typename T::const_reference T2 : T()) {
10789a1d03eSRichard     S S1 = T2;
10889a1d03eSRichard   }
10989a1d03eSRichard }
11089a1d03eSRichard 
f()11189a1d03eSRichard void f() {
11289a1d03eSRichard   instantiated<int>();
11389a1d03eSRichard   instantiated<S>();
11489a1d03eSRichard   instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
11589a1d03eSRichard }
11689a1d03eSRichard 
11789a1d03eSRichard struct Mutable {
MutableMutable11889a1d03eSRichard   Mutable() {}
11989a1d03eSRichard   Mutable(const Mutable &) = default;
12089a1d03eSRichard   Mutable(Mutable&&) = default;
MutableMutable12189a1d03eSRichard   Mutable(const Mutable &, const Mutable &) {}
setBoolMutable12289a1d03eSRichard   void setBool(bool B) {}
constMethodMutable12389a1d03eSRichard   bool constMethod() const {
12489a1d03eSRichard     return true;
12589a1d03eSRichard   }
operator []Mutable12689a1d03eSRichard   Mutable& operator[](int I) {
12789a1d03eSRichard     return *this;
12889a1d03eSRichard   }
operator ==Mutable12989a1d03eSRichard   bool operator==(const Mutable &Other) const {
13089a1d03eSRichard     return true;
13189a1d03eSRichard   }
~MutableMutable13289a1d03eSRichard   ~Mutable() {}
13389a1d03eSRichard };
13489a1d03eSRichard 
operator <<(Mutable & Out,bool B)13589a1d03eSRichard Mutable& operator<<(Mutable &Out, bool B) {
13689a1d03eSRichard   Out.setBool(B);
13789a1d03eSRichard   return Out;
13889a1d03eSRichard }
13989a1d03eSRichard 
operator !=(const Mutable & M1,const Mutable & M2)14089a1d03eSRichard bool operator!=(const Mutable& M1, const Mutable& M2) {
14189a1d03eSRichard   return false;
14289a1d03eSRichard }
14389a1d03eSRichard 
14489a1d03eSRichard void use(const Mutable &M);
14589a1d03eSRichard void use(int I);
14689a1d03eSRichard void useTwice(const Mutable &M1, const Mutable &M2);
14789a1d03eSRichard void useByValue(Mutable M);
14889a1d03eSRichard void useByConstValue(const Mutable M);
14989a1d03eSRichard void mutate(Mutable *M);
15089a1d03eSRichard void mutate(Mutable &M);
151*8fd32b96SClement Courbet void mutate(int &);
15289a1d03eSRichard void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
15389a1d03eSRichard 
negativeVariableIsMutated()15489a1d03eSRichard void negativeVariableIsMutated() {
15589a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
15689a1d03eSRichard     mutate(M);
15789a1d03eSRichard   }
15889a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
15989a1d03eSRichard     mutate(&M);
16089a1d03eSRichard   }
16189a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
16289a1d03eSRichard     M.setBool(true);
16389a1d03eSRichard   }
16489a1d03eSRichard }
16589a1d03eSRichard 
negativeOnceConstOnceMutated()16689a1d03eSRichard void negativeOnceConstOnceMutated() {
16789a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
16889a1d03eSRichard     onceConstOnceMutated(M, M);
16989a1d03eSRichard   }
17089a1d03eSRichard }
17189a1d03eSRichard 
negativeVarIsMoved()17289a1d03eSRichard void negativeVarIsMoved() {
17389a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
17489a1d03eSRichard     auto Moved = std::move(M);
17589a1d03eSRichard   }
17689a1d03eSRichard }
17789a1d03eSRichard 
negativeNonConstOperatorIsInvoked()17889a1d03eSRichard void negativeNonConstOperatorIsInvoked() {
17989a1d03eSRichard   for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
18089a1d03eSRichard     auto& N = NonConstOperatorInvokee[0];
18189a1d03eSRichard   }
18289a1d03eSRichard }
18389a1d03eSRichard 
negativeNonConstNonMemberOperatorInvoked()18489a1d03eSRichard void negativeNonConstNonMemberOperatorInvoked() {
18589a1d03eSRichard   for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
18689a1d03eSRichard     NonConstOperatorInvokee << true;
18789a1d03eSRichard   }
18889a1d03eSRichard }
18989a1d03eSRichard 
negativeConstCheapToCopy()19089a1d03eSRichard void negativeConstCheapToCopy() {
19189a1d03eSRichard   for (const int I : View<Iterator<int>>()) {
19289a1d03eSRichard   }
19389a1d03eSRichard }
19489a1d03eSRichard 
negativeConstCheapToCopyTypedef()19589a1d03eSRichard void negativeConstCheapToCopyTypedef() {
19689a1d03eSRichard   typedef const int ConstInt;
19789a1d03eSRichard   for (ConstInt C  : View<Iterator<ConstInt>>()) {
19889a1d03eSRichard   }
19989a1d03eSRichard }
20089a1d03eSRichard 
negativeCheapToCopy()20189a1d03eSRichard void negativeCheapToCopy() {
20289a1d03eSRichard   for (int I : View<Iterator<int>>()) {
20389a1d03eSRichard     use(I);
20489a1d03eSRichard   }
20589a1d03eSRichard }
20689a1d03eSRichard 
negativeCheapToCopyTypedef()20789a1d03eSRichard void negativeCheapToCopyTypedef() {
20889a1d03eSRichard   typedef int Int;
20989a1d03eSRichard   for (Int I : View<Iterator<Int>>()) {
21089a1d03eSRichard     use(I);
21189a1d03eSRichard   }
21289a1d03eSRichard }
21389a1d03eSRichard 
positiveOnlyConstMethodInvoked()21489a1d03eSRichard void positiveOnlyConstMethodInvoked() {
21589a1d03eSRichard   for (auto M : View<Iterator<Mutable>>()) {
21689a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
21789a1d03eSRichard     // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
21889a1d03eSRichard     M.constMethod();
21989a1d03eSRichard   }
22089a1d03eSRichard }
22189a1d03eSRichard 
positiveOnlyUsedAsConstArguments()22289a1d03eSRichard void positiveOnlyUsedAsConstArguments() {
22389a1d03eSRichard   for (auto UsedAsConst : View<Iterator<Mutable>>()) {
22489a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
22589a1d03eSRichard     // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
22689a1d03eSRichard     use(UsedAsConst);
22789a1d03eSRichard     useTwice(UsedAsConst, UsedAsConst);
22889a1d03eSRichard     useByValue(UsedAsConst);
22989a1d03eSRichard     useByConstValue(UsedAsConst);
23089a1d03eSRichard   }
23189a1d03eSRichard }
23289a1d03eSRichard 
positiveOnlyAccessedFieldAsConst()23389a1d03eSRichard void positiveOnlyAccessedFieldAsConst() {
23489a1d03eSRichard   for (auto UsedAsConst : View<Iterator<Point>>()) {
23589a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
23689a1d03eSRichard     // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
23789a1d03eSRichard     use(UsedAsConst.x);
23889a1d03eSRichard     use(UsedAsConst.y);
23989a1d03eSRichard   }
24089a1d03eSRichard }
24189a1d03eSRichard 
positiveOnlyUsedAsConstBinding()242*8fd32b96SClement Courbet void positiveOnlyUsedAsConstBinding() {
243*8fd32b96SClement Courbet   for (auto [X, Y] : View<Iterator<Point>>()) {
244*8fd32b96SClement Courbet     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
245*8fd32b96SClement Courbet     // CHECK-FIXES: for (const auto& [X, Y] : View<Iterator<Point>>()) {
246*8fd32b96SClement Courbet     use(X);
247*8fd32b96SClement Courbet     use(Y);
248*8fd32b96SClement Courbet   }
249*8fd32b96SClement Courbet }
250*8fd32b96SClement Courbet 
negativeMutatedBinding()251*8fd32b96SClement Courbet void negativeMutatedBinding() {
252*8fd32b96SClement Courbet   for (auto [X, Y] : View<Iterator<Point>>()) {
253*8fd32b96SClement Courbet     use(X);
254*8fd32b96SClement Courbet     mutate(Y);
255*8fd32b96SClement Courbet   }
256*8fd32b96SClement Courbet }
257*8fd32b96SClement Courbet 
positiveOnlyUsedInCopyConstructor()25889a1d03eSRichard void positiveOnlyUsedInCopyConstructor() {
25989a1d03eSRichard   for (auto A : View<Iterator<Mutable>>()) {
26089a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
26189a1d03eSRichard     // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
26289a1d03eSRichard     Mutable Copy = A;
26389a1d03eSRichard     Mutable Copy2(A);
26489a1d03eSRichard   }
26589a1d03eSRichard }
26689a1d03eSRichard 
positiveTwoConstConstructorArgs()26789a1d03eSRichard void positiveTwoConstConstructorArgs() {
26889a1d03eSRichard   for (auto A : View<Iterator<Mutable>>()) {
26989a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
27089a1d03eSRichard     // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
27189a1d03eSRichard     Mutable Copy(A, A);
27289a1d03eSRichard   }
27389a1d03eSRichard }
27489a1d03eSRichard 
PositiveConstMemberOperatorInvoked()27589a1d03eSRichard void PositiveConstMemberOperatorInvoked() {
27689a1d03eSRichard   for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
27789a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
27889a1d03eSRichard     // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
27989a1d03eSRichard     bool result = ConstOperatorInvokee == Mutable();
28089a1d03eSRichard   }
28189a1d03eSRichard }
28289a1d03eSRichard 
PositiveConstNonMemberOperatorInvoked()28389a1d03eSRichard void PositiveConstNonMemberOperatorInvoked() {
28489a1d03eSRichard   for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
28589a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
28689a1d03eSRichard     // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
28789a1d03eSRichard     bool result = ConstOperatorInvokee != Mutable();
28889a1d03eSRichard   }
28989a1d03eSRichard }
29089a1d03eSRichard 
IgnoreLoopVariableNotUsedInLoopBody()29189a1d03eSRichard void IgnoreLoopVariableNotUsedInLoopBody() {
29289a1d03eSRichard   for (auto _ : View<Iterator<S>>()) {
29389a1d03eSRichard   }
29489a1d03eSRichard }
29589a1d03eSRichard 
29689a1d03eSRichard template <typename T>
29789a1d03eSRichard struct ValueReturningIterator {
operator ++ValueReturningIterator29889a1d03eSRichard   void operator++() {}
operator *ValueReturningIterator29989a1d03eSRichard   T operator*() { return T(); }
operator !=ValueReturningIterator30089a1d03eSRichard   bool operator!=(const ValueReturningIterator &) { return false; }
30189a1d03eSRichard   typedef const T &const_reference;
30289a1d03eSRichard };
30389a1d03eSRichard 
negativeValueIterator()30489a1d03eSRichard void negativeValueIterator() {
30589a1d03eSRichard   // Check does not trigger for iterators that return elements by value.
30689a1d03eSRichard   for (const S SS : View<ValueReturningIterator<S>>()) {
30789a1d03eSRichard   }
30889a1d03eSRichard }
30989a1d03eSRichard 
createView(S)31089a1d03eSRichard View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
31189a1d03eSRichard 
positiveValueIteratorUsedElseWhere()31289a1d03eSRichard void positiveValueIteratorUsedElseWhere() {
31389a1d03eSRichard   for (const S SS : createView(*ValueReturningIterator<S>())) {
31489a1d03eSRichard     // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
31589a1d03eSRichard     // a reference type; this creates a copy in each iteration; consider making
31689a1d03eSRichard     // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
31789a1d03eSRichard     // SS : createView(*ValueReturningIterator<S>())) {
31889a1d03eSRichard   }
31989a1d03eSRichard }
3201e512688SShivam Gupta 
positiveConstMemberExpr()3211e512688SShivam Gupta void positiveConstMemberExpr() {
3221e512688SShivam Gupta   struct Struct {
3231e512688SShivam Gupta     Mutable Member;
3241e512688SShivam Gupta   };
3251e512688SShivam Gupta   for (Struct SS : View<Iterator<Struct>>()) {
3261e512688SShivam Gupta     // CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied
3271e512688SShivam Gupta     // CHECK-FIXES: for (const Struct& SS : View<Iterator<Struct>>()) {
3281e512688SShivam Gupta     auto MemberCopy = SS.Member;
3291e512688SShivam Gupta     const auto &ConstRef = SS.Member;
3301e512688SShivam Gupta     bool b = SS.Member.constMethod();
3311e512688SShivam Gupta     use(SS.Member);
3321e512688SShivam Gupta     useByConstValue(SS.Member);
3331e512688SShivam Gupta     useByValue(SS.Member);
3341e512688SShivam Gupta   }
3351e512688SShivam Gupta }
3361e512688SShivam Gupta 
negativeNonConstMemberExpr()3371e512688SShivam Gupta void negativeNonConstMemberExpr() {
3381e512688SShivam Gupta   struct Struct {
3391e512688SShivam Gupta     Mutable Member;
3401e512688SShivam Gupta   };
3411e512688SShivam Gupta   for (Struct SS : View<Iterator<Struct>>()) {
3421e512688SShivam Gupta     SS.Member.setBool(true);
3431e512688SShivam Gupta   }
3441e512688SShivam Gupta   for (Struct SS : View<Iterator<Struct>>()) {
3451e512688SShivam Gupta     SS.Member[1];
3461e512688SShivam Gupta   }
3471e512688SShivam Gupta   for (Struct SS : View<Iterator<Struct>>()) {
3481e512688SShivam Gupta     mutate(SS.Member);
3491e512688SShivam Gupta   }
3501e512688SShivam Gupta   for (Struct SS : View<Iterator<Struct>>()) {
3511e512688SShivam Gupta     mutate(&SS.Member);
3521e512688SShivam Gupta   }
3531e512688SShivam Gupta }
3541e512688SShivam Gupta 
355