1 // RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
2 
3 namespace std {
4 
5 template <typename _Tp>
6 struct remove_reference { typedef _Tp type; };
7 template <typename _Tp>
8 struct remove_reference<_Tp&> { typedef _Tp type; };
9 template <typename _Tp>
10 struct remove_reference<_Tp&&> { typedef _Tp type; };
11 
12 template <typename _Tp>
move(_Tp && __t)13 constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
14   return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
15 }
16 
17 } // std
18 
19 template <typename T>
20 struct Iterator {
operator ++Iterator21   void operator++() {}
operator *Iterator22   const T& operator*() {
23     static T* TT = new T();
24     return *TT;
25   }
operator !=Iterator26   bool operator!=(const Iterator &) { return false; }
27   typedef const T& const_reference;
28 };
29 template <typename T>
30 struct View {
31   View() = default;
beginView32   T begin() { return T(); }
beginView33   T begin() const { return T(); }
endView34   T end() { return T(); }
endView35   T end() const { return T(); }
36   typedef typename T::const_reference const_reference;
37 };
38 
39 struct ConstructorConvertible {
40 };
41 
42 struct S {
43   S();
44   S(const S &);
SS45   S(const ConstructorConvertible&) {}
46   ~S();
47   S &operator=(const S &);
48 };
49 
50 struct Convertible {
operator SConvertible51   operator S() const {
52     return S();
53   }
54 };
55 
negativeConstReference()56 void negativeConstReference() {
57   for (const S &S1 : View<Iterator<S>>()) {
58   }
59 }
60 
negativeUserDefinedConversion()61 void negativeUserDefinedConversion() {
62   Convertible C[0];
63   for (const S S1 : C) {
64   }
65 }
66 
negativeImplicitConstructorConversion()67 void negativeImplicitConstructorConversion() {
68   ConstructorConvertible C[0];
69   for (const S S1 : C) {
70   }
71 }
72 
73 template <typename T>
uninstantiated()74 void uninstantiated() {
75   for (const S S1 : View<Iterator<S>>()) {}
76   // 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]
77   // CHECK-FIXES: {{^}}  for (const S& S1 : View<Iterator<S>>()) {}
78 
79   // Don't warn on dependent types.
80   for (const T t1 : View<Iterator<T>>()) {
81   }
82 }
83 
84 template <typename T>
instantiated()85 void instantiated() {
86   for (const S S2 : View<Iterator<S>>()) {}
87   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
88   // CHECK-FIXES: {{^}}  for (const S& S2 : View<Iterator<S>>()) {}
89 
90   for (const T T2 : View<Iterator<T>>()) {}
91   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
92   // CHECK-FIXES: {{^}}  for (const T& T2 : View<Iterator<T>>()) {}
93 }
94 
95 template <typename T>
instantiatedNegativeTypedefConstReference()96 void instantiatedNegativeTypedefConstReference() {
97   for (typename T::const_reference T2 : T()) {
98     S S1 = T2;
99   }
100 }
101 
f()102 void f() {
103   instantiated<int>();
104   instantiated<S>();
105   instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
106 }
107 
108 struct Mutable {
MutableMutable109   Mutable() {}
110   Mutable(const Mutable &) = default;
111   Mutable(Mutable&&) = default;
MutableMutable112   Mutable(const Mutable &, const Mutable &) {}
setBoolMutable113   void setBool(bool B) {}
constMethodMutable114   bool constMethod() const {
115     return true;
116   }
operator []Mutable117   Mutable& operator[](int I) {
118     return *this;
119   }
operator ==Mutable120   bool operator==(const Mutable &Other) const {
121     return true;
122   }
~MutableMutable123   ~Mutable() {}
124 };
125 
126 struct Point {
~PointPoint127   ~Point() {}
128   int x, y;
129 };
130 
operator <<(Mutable & Out,bool B)131 Mutable& operator<<(Mutable &Out, bool B) {
132   Out.setBool(B);
133   return Out;
134 }
135 
operator !=(const Mutable & M1,const Mutable & M2)136 bool operator!=(const Mutable& M1, const Mutable& M2) {
137   return false;
138 }
139 
140 void use(const Mutable &M);
141 void use(int I);
142 void useTwice(const Mutable &M1, const Mutable &M2);
143 void useByValue(Mutable M);
144 void useByConstValue(const Mutable M);
145 void mutate(Mutable *M);
146 void mutate(Mutable &M);
147 void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
148 
negativeVariableIsMutated()149 void negativeVariableIsMutated() {
150   for (auto M : View<Iterator<Mutable>>()) {
151     mutate(M);
152   }
153   for (auto M : View<Iterator<Mutable>>()) {
154     mutate(&M);
155   }
156   for (auto M : View<Iterator<Mutable>>()) {
157     M.setBool(true);
158   }
159 }
160 
negativeOnceConstOnceMutated()161 void negativeOnceConstOnceMutated() {
162   for (auto M : View<Iterator<Mutable>>()) {
163     onceConstOnceMutated(M, M);
164   }
165 }
166 
negativeVarIsMoved()167 void negativeVarIsMoved() {
168   for (auto M : View<Iterator<Mutable>>()) {
169     auto Moved = std::move(M);
170   }
171 }
172 
negativeNonConstOperatorIsInvoked()173 void negativeNonConstOperatorIsInvoked() {
174   for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
175     auto& N = NonConstOperatorInvokee[0];
176   }
177 }
178 
negativeNonConstNonMemberOperatorInvoked()179 void negativeNonConstNonMemberOperatorInvoked() {
180   for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
181     NonConstOperatorInvokee << true;
182   }
183 }
184 
negativeConstCheapToCopy()185 void negativeConstCheapToCopy() {
186   for (const int I : View<Iterator<int>>()) {
187   }
188 }
189 
negativeConstCheapToCopyTypedef()190 void negativeConstCheapToCopyTypedef() {
191   typedef const int ConstInt;
192   for (ConstInt C  : View<Iterator<ConstInt>>()) {
193   }
194 }
195 
negativeCheapToCopy()196 void negativeCheapToCopy() {
197   for (int I : View<Iterator<int>>()) {
198     use(I);
199   }
200 }
201 
negativeCheapToCopyTypedef()202 void negativeCheapToCopyTypedef() {
203   typedef int Int;
204   for (Int I : View<Iterator<Int>>()) {
205     use(I);
206   }
207 }
208 
positiveOnlyConstMethodInvoked()209 void positiveOnlyConstMethodInvoked() {
210   for (auto M : View<Iterator<Mutable>>()) {
211     // 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]
212     // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
213     M.constMethod();
214   }
215 }
216 
positiveOnlyUsedAsConstArguments()217 void positiveOnlyUsedAsConstArguments() {
218   for (auto UsedAsConst : View<Iterator<Mutable>>()) {
219     // 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]
220     // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
221     use(UsedAsConst);
222     useTwice(UsedAsConst, UsedAsConst);
223     useByValue(UsedAsConst);
224     useByConstValue(UsedAsConst);
225   }
226 }
227 
positiveOnlyAccessedFieldAsConst()228 void positiveOnlyAccessedFieldAsConst() {
229   for (auto UsedAsConst : View<Iterator<Point>>()) {
230     // 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]
231     // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
232     use(UsedAsConst.x);
233     use(UsedAsConst.y);
234   }
235 }
236 
positiveOnlyUsedInCopyConstructor()237 void positiveOnlyUsedInCopyConstructor() {
238   for (auto A : View<Iterator<Mutable>>()) {
239     // 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]
240     // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
241     Mutable Copy = A;
242     Mutable Copy2(A);
243   }
244 }
245 
positiveTwoConstConstructorArgs()246 void positiveTwoConstConstructorArgs() {
247   for (auto A : View<Iterator<Mutable>>()) {
248     // 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]
249     // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
250     Mutable Copy(A, A);
251   }
252 }
253 
PositiveConstMemberOperatorInvoked()254 void PositiveConstMemberOperatorInvoked() {
255   for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
256     // 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]
257     // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
258     bool result = ConstOperatorInvokee == Mutable();
259   }
260 }
261 
PositiveConstNonMemberOperatorInvoked()262 void PositiveConstNonMemberOperatorInvoked() {
263   for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
264     // 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]
265     // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
266     bool result = ConstOperatorInvokee != Mutable();
267   }
268 }
269 
IgnoreLoopVariableNotUsedInLoopBody()270 void IgnoreLoopVariableNotUsedInLoopBody() {
271   for (auto _ : View<Iterator<S>>()) {
272   }
273 }
274 
275 template <typename T>
276 struct ValueReturningIterator {
operator ++ValueReturningIterator277   void operator++() {}
operator *ValueReturningIterator278   T operator*() { return T(); }
operator !=ValueReturningIterator279   bool operator!=(const ValueReturningIterator &) { return false; }
280   typedef const T &const_reference;
281 };
282 
negativeValueIterator()283 void negativeValueIterator() {
284   // Check does not trigger for iterators that return elements by value.
285   for (const S SS : View<ValueReturningIterator<S>>()) {
286   }
287 }
288 
createView(S)289 View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
290 
positiveValueIteratorUsedElseWhere()291 void positiveValueIteratorUsedElseWhere() {
292   for (const S SS : createView(*ValueReturningIterator<S>())) {
293     // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
294     // a reference type; this creates a copy in each iteration; consider making
295     // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
296     // SS : createView(*ValueReturningIterator<S>())) {
297   }
298 }
299