1// RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
2
3namespace std {
4
5template <typename _Tp>
6struct remove_reference { typedef _Tp type; };
7template <typename _Tp>
8struct remove_reference<_Tp&> { typedef _Tp type; };
9template <typename _Tp>
10struct remove_reference<_Tp&&> { typedef _Tp type; };
11
12template <typename _Tp>
13constexpr 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
19template <typename T>
20struct Iterator {
21 void operator++() {}
22 const T& operator*() {
23 static T* TT = new T();
24 return *TT;
25 }
26 bool operator!=(const Iterator &) { return false; }
27 typedef const T& const_reference;
28};
29template <typename T>
30struct View {
31 View() = default;
32 T begin() { return T(); }
33 T begin() const { return T(); }
34 T end() { return T(); }
35 T end() const { return T(); }
36 typedef typename T::const_reference const_reference;
37};
38
39struct ConstructorConvertible {
40};
41
42struct S {
43 S();
44 S(const S &);
45 S(const ConstructorConvertible&) {}
46 ~S();
47 S &operator=(const S &);
48};
49
50struct Point {
51 ~Point() {}
52 int x, y;
53};
54
55struct Convertible {
56 operator S() const {
57 return S();
58 }
59};
60
61void negativeConstReference() {
62 for (const S &S1 : View<Iterator<S>>()) {
63 }
64}
65
66void negativeUserDefinedConversion() {
67 Convertible C[0];
68 for (const S S1 : C) {
69 }
70}
71
72void negativeImplicitConstructorConversion() {
73 ConstructorConvertible C[0];
74 for (const S S1 : C) {
75 }
76}
77
78template <typename T>
79void uninstantiated() {
80 for (const S S1 : View<Iterator<S>>()) {}
81 // 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]
82 // CHECK-FIXES: {{^}} for (const S& S1 : View<Iterator<S>>()) {}
83
84 // Don't warn on dependent types.
85 for (const T t1 : View<Iterator<T>>()) {
86 }
87}
88
89template <typename T>
90void instantiated() {
91 for (const S S2 : View<Iterator<S>>()) {}
92 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
93 // CHECK-FIXES: {{^}} for (const S& S2 : View<Iterator<S>>()) {}
94
95 for (const auto [X, Y] : View<Iterator<Point>>()) {}
96 // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is
97 // CHECK-FIXES: {{^}} for (const auto& [X, Y] : View<Iterator<Point>>()) {}
98
99 for (const T T2 : View<Iterator<T>>()) {}
100 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
101 // CHECK-FIXES: {{^}} for (const T& T2 : View<Iterator<T>>()) {}
102}
103
104template <typename T>
105void instantiatedNegativeTypedefConstReference() {
106 for (typename T::const_reference T2 : T()) {
107 S S1 = T2;
108 }
109}
110
111void f() {
112 instantiated<int>();
113 instantiated<S>();
114 instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
115}
116
117struct Mutable {
118 Mutable() {}
119 Mutable(const Mutable &) = default;
120 Mutable(Mutable&&) = default;
121 Mutable(const Mutable &, const Mutable &) {}
122 void setBool(bool B) {}
123 bool constMethod() const {
124 return true;
125 }
126 Mutable& operator[](int I) {
127 return *this;
128 }
129 bool operator==(const Mutable &Other) const {
130 return true;
131 }
132 ~Mutable() {}
133};
134
135Mutable& operator<<(Mutable &Out, bool B) {
136 Out.setBool(B);
137 return Out;
138}
139
140bool operator!=(const Mutable& M1, const Mutable& M2) {
141 return false;
142}
143
144void use(const Mutable &M);
145void use(int I);
146void useTwice(const Mutable &M1, const Mutable &M2);
147void useByValue(Mutable M);
148void useByConstValue(const Mutable M);
149void mutate(Mutable *M);
150void mutate(Mutable &M);
151void mutate(int &);
152void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
153
154void negativeVariableIsMutated() {
155 for (auto M : View<Iterator<Mutable>>()) {
156 mutate(M);
157 }
158 for (auto M : View<Iterator<Mutable>>()) {
159 mutate(M: &M);
160 }
161 for (auto M : View<Iterator<Mutable>>()) {
162 M.setBool(true);
163 }
164}
165
166void negativeOnceConstOnceMutated() {
167 for (auto M : View<Iterator<Mutable>>()) {
168 onceConstOnceMutated(M1: M, M2&: M);
169 }
170}
171
172void negativeVarIsMoved() {
173 for (auto M : View<Iterator<Mutable>>()) {
174 auto Moved = std::move(M);
175 }
176}
177
178void negativeNonConstOperatorIsInvoked() {
179 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
180 auto& N = NonConstOperatorInvokee[0];
181 }
182}
183
184void negativeNonConstNonMemberOperatorInvoked() {
185 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
186 NonConstOperatorInvokee << true;
187 }
188}
189
190void negativeConstCheapToCopy() {
191 for (const int I : View<Iterator<int>>()) {
192 }
193}
194
195void negativeConstCheapToCopyTypedef() {
196 typedef const int ConstInt;
197 for (ConstInt C : View<Iterator<ConstInt>>()) {
198 }
199}
200
201void negativeCheapToCopy() {
202 for (int I : View<Iterator<int>>()) {
203 use(I);
204 }
205}
206
207void negativeCheapToCopyTypedef() {
208 typedef int Int;
209 for (Int I : View<Iterator<Int>>()) {
210 use(I);
211 }
212}
213
214void positiveOnlyConstMethodInvoked() {
215 for (auto M : View<Iterator<Mutable>>()) {
216 // 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]
217 // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
218 M.constMethod();
219 }
220}
221
222void positiveOnlyUsedAsConstArguments() {
223 for (auto UsedAsConst : View<Iterator<Mutable>>()) {
224 // 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]
225 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
226 use(M: UsedAsConst);
227 useTwice(M1: UsedAsConst, M2: UsedAsConst);
228 useByValue(M: UsedAsConst);
229 useByConstValue(M: UsedAsConst);
230 }
231}
232
233void positiveOnlyAccessedFieldAsConst() {
234 for (auto UsedAsConst : View<Iterator<Point>>()) {
235 // 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]
236 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
237 use(I: UsedAsConst.x);
238 use(I: UsedAsConst.y);
239 }
240}
241
242void positiveOnlyUsedAsConstBinding() {
243 for (auto [X, Y] : View<Iterator<Point>>()) {
244 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
245 // CHECK-FIXES: for (const auto& [X, Y] : View<Iterator<Point>>()) {
246 use(I: X);
247 use(I: Y);
248 }
249}
250
251void negativeMutatedBinding() {
252 for (auto [X, Y] : View<Iterator<Point>>()) {
253 use(I: X);
254 mutate(Y);
255 }
256}
257
258void positiveOnlyUsedInCopyConstructor() {
259 for (auto A : View<Iterator<Mutable>>()) {
260 // 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]
261 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
262 Mutable Copy = A;
263 Mutable Copy2(A);
264 }
265}
266
267void positiveTwoConstConstructorArgs() {
268 for (auto A : View<Iterator<Mutable>>()) {
269 // 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]
270 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
271 Mutable Copy(A, A);
272 }
273}
274
275void PositiveConstMemberOperatorInvoked() {
276 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
277 // 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]
278 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
279 bool result = ConstOperatorInvokee == Mutable();
280 }
281}
282
283void PositiveConstNonMemberOperatorInvoked() {
284 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
285 // 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]
286 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
287 bool result = ConstOperatorInvokee != Mutable();
288 }
289}
290
291void IgnoreLoopVariableNotUsedInLoopBody() {
292 for (auto _ : View<Iterator<S>>()) {
293 }
294}
295
296template <typename T>
297struct ValueReturningIterator {
298 void operator++() {}
299 T operator*() { return T(); }
300 bool operator!=(const ValueReturningIterator &) { return false; }
301 typedef const T &const_reference;
302};
303
304void negativeValueIterator() {
305 // Check does not trigger for iterators that return elements by value.
306 for (const S SS : View<ValueReturningIterator<S>>()) {
307 }
308}
309
310View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
311
312void positiveValueIteratorUsedElseWhere() {
313 for (const S SS : createView(*ValueReturningIterator<S>())) {
314 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
315 // a reference type; this creates a copy in each iteration; consider making
316 // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
317 // SS : createView(*ValueReturningIterator<S>())) {
318 }
319}
320
321void positiveConstMemberExpr() {
322 struct Struct {
323 Mutable Member;
324 };
325 for (Struct SS : View<Iterator<Struct>>()) {
326 // CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied
327 // CHECK-FIXES: for (const Struct& SS : View<Iterator<Struct>>()) {
328 auto MemberCopy = SS.Member;
329 const auto &ConstRef = SS.Member;
330 bool b = SS.Member.constMethod();
331 use(M: SS.Member);
332 useByConstValue(M: SS.Member);
333 useByValue(M: SS.Member);
334 }
335}
336
337void negativeNonConstMemberExpr() {
338 struct Struct {
339 Mutable Member;
340 };
341 for (Struct SS : View<Iterator<Struct>>()) {
342 SS.Member.setBool(true);
343 }
344 for (Struct SS : View<Iterator<Struct>>()) {
345 SS.Member[1];
346 }
347 for (Struct SS : View<Iterator<Struct>>()) {
348 mutate(M&: SS.Member);
349 }
350 for (Struct SS : View<Iterator<Struct>>()) {
351 mutate(M: &SS.Member);
352 }
353}
354
355

source code of clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp