1 | // RUN: %check_clang_tidy %s modernize-loop-convert %t |
2 | |
3 | struct Str { |
4 | Str() = default; |
5 | Str(const Str &) = default; |
6 | void constMember(int) const; |
7 | void nonConstMember(int); |
8 | bool operator<(const Str &str) const; // const operator. |
9 | Str &operator=(const Str &str) = default; // non const operator. |
10 | }; |
11 | |
12 | // This class is non-trivially copyable because the copy-constructor and copy |
13 | // assignment take non-const references and are user-provided. |
14 | struct ModifiesRightSide { |
15 | ModifiesRightSide() = default; |
16 | ModifiesRightSide(ModifiesRightSide &); |
17 | bool operator<(ModifiesRightSide &) const; |
18 | ModifiesRightSide &operator=(ModifiesRightSide &); |
19 | }; |
20 | |
21 | template <typename T> |
22 | void copyArg(T); |
23 | |
24 | template <typename T> |
25 | void nonConstRefArg(T &); |
26 | |
27 | // If we define this as a template, the type is deduced to "T&", |
28 | // and "const (T&) &" is the same as "T& &", and this collapses to "T&". |
29 | void constRefArg(const Str &); |
30 | void constRefArg(const ModifiesRightSide &); |
31 | void constRefArg(const int &); |
32 | |
33 | void foo(); |
34 | |
35 | const int N = 10; |
36 | Str Array[N], OtherStr; |
37 | ModifiesRightSide Right[N], OtherRight; |
38 | int Ints[N], OtherInt; |
39 | |
40 | void memberFunctionsAndOperators() { |
41 | // Calling const member functions or operator is a const usage. |
42 | for (int I = 0; I < N; ++I) { |
43 | Array[I].constMember(0); |
44 | } |
45 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert] |
46 | // CHECK-FIXES: for (auto I : Array) |
47 | // CHECK-FIXES-NEXT: I.constMember(0); |
48 | |
49 | for (int I = 0; I < N; ++I) { |
50 | if (Array[I] < OtherStr) |
51 | foo(); |
52 | } |
53 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
54 | // CHECK-FIXES: for (auto I : Array) |
55 | // CHECK-FIXES-NEXT: if (I < OtherStr) |
56 | for (int I = 0; I < N; ++I) { |
57 | if (Right[I] < OtherRight) |
58 | foo(); |
59 | } |
60 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
61 | // CHECK-FIXES: for (const auto & I : Right) |
62 | // CHECK-FIXES-NEXT: if (I < OtherRight) |
63 | |
64 | // Calling non-const member functions is not. |
65 | for (int I = 0; I < N; ++I) { |
66 | Array[I].nonConstMember(0); |
67 | } |
68 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
69 | // CHECK-FIXES: for (auto & I : Array) |
70 | // CHECK-FIXES-NEXT: I.nonConstMember(0); |
71 | |
72 | for (int I = 0; I < N; ++I) { |
73 | Array[I] = OtherStr; |
74 | } |
75 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
76 | // CHECK-FIXES: for (auto & I : Array) |
77 | // CHECK-FIXES-NEXT: I = OtherStr; |
78 | |
79 | for (int I = 0; I < N; ++I) { |
80 | Right[I] = OtherRight; |
81 | } |
82 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
83 | // CHECK-FIXES: for (auto & I : Right) |
84 | // CHECK-FIXES-NEXT: I = OtherRight; |
85 | } |
86 | |
87 | void usedAsParameterToFunctionOrOperator() { |
88 | // Copying is OK, as long as the copy constructor takes a const-reference. |
89 | for (int I = 0; I < N; ++I) { |
90 | copyArg(Array[I]); |
91 | } |
92 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
93 | // CHECK-FIXES: for (auto I : Array) |
94 | // CHECK-FIXES-NEXT: copyArg(I); |
95 | |
96 | for (int I = 0; I < N; ++I) { |
97 | copyArg(Right[I]); |
98 | } |
99 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
100 | // CHECK-FIXES: for (auto & I : Right) |
101 | // CHECK-FIXES-NEXT: copyArg(I); |
102 | |
103 | // Using as a const reference argument is allowed. |
104 | for (int I = 0; I < N; ++I) { |
105 | constRefArg(Array[I]); |
106 | } |
107 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
108 | // CHECK-FIXES: for (auto I : Array) |
109 | // CHECK-FIXES-NEXT: constRefArg(I); |
110 | |
111 | for (int I = 0; I < N; ++I) { |
112 | if (OtherStr < Array[I]) |
113 | foo(); |
114 | } |
115 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
116 | // CHECK-FIXES: for (auto I : Array) |
117 | // CHECK-FIXES-NEXT: if (OtherStr < I) |
118 | |
119 | for (int I = 0; I < N; ++I) { |
120 | constRefArg(Right[I]); |
121 | } |
122 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
123 | // CHECK-FIXES: for (const auto & I : Right) |
124 | // CHECK-FIXES-NEXT: constRefArg(I); |
125 | |
126 | // Using as a non-const reference is not. |
127 | for (int I = 0; I < N; ++I) { |
128 | nonConstRefArg(Array[I]); |
129 | } |
130 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
131 | // CHECK-FIXES: for (auto & I : Array) |
132 | // CHECK-FIXES-NEXT: nonConstRefArg(I); |
133 | for (int I = 0; I < N; ++I) { |
134 | nonConstRefArg(Right[I]); |
135 | } |
136 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
137 | // CHECK-FIXES: for (auto & I : Right) |
138 | // CHECK-FIXES-NEXT: nonConstRefArg(I); |
139 | for (int I = 0; I < N; ++I) { |
140 | if (OtherRight < Right[I]) |
141 | foo(); |
142 | } |
143 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
144 | // CHECK-FIXES: for (auto & I : Right) |
145 | // CHECK-FIXES-NEXT: if (OtherRight < I) |
146 | } |
147 | |
148 | void primitiveTypes() { |
149 | // As argument to a function. |
150 | for (int I = 0; I < N; ++I) { |
151 | copyArg(Ints[I]); |
152 | } |
153 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
154 | // CHECK-FIXES: for (int Int : Ints) |
155 | // CHECK-FIXES-NEXT: copyArg(Int); |
156 | for (int I = 0; I < N; ++I) { |
157 | constRefArg(Ints[I]); |
158 | } |
159 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
160 | // CHECK-FIXES: for (int Int : Ints) |
161 | // CHECK-FIXES-NEXT: constRefArg(Int); |
162 | for (int I = 0; I < N; ++I) { |
163 | nonConstRefArg(Ints[I]); |
164 | } |
165 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
166 | // CHECK-FIXES: for (int & Int : Ints) |
167 | // CHECK-FIXES-NEXT: nonConstRefArg(Int); |
168 | |
169 | // Builtin operators. |
170 | // Comparisons. |
171 | for (int I = 0; I < N; ++I) { |
172 | if (Ints[I] < N) |
173 | foo(); |
174 | } |
175 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
176 | // CHECK-FIXES: for (int Int : Ints) |
177 | // CHECK-FIXES-NEXT: if (Int < N) |
178 | |
179 | for (int I = 0; I < N; ++I) { |
180 | if (N == Ints[I]) |
181 | foo(); |
182 | } |
183 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
184 | // CHECK-FIXES: for (int Int : Ints) |
185 | // CHECK-FIXES-NEXT: if (N == Int) |
186 | |
187 | // Assignment. |
188 | for (int I = 0; I < N; ++I) { |
189 | Ints[I] = OtherInt; |
190 | } |
191 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
192 | // CHECK-FIXES: for (int & Int : Ints) |
193 | // CHECK-FIXES-NEXT: Int = OtherInt; |
194 | |
195 | for (int I = 0; I < N; ++I) { |
196 | OtherInt = Ints[I]; |
197 | } |
198 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
199 | // CHECK-FIXES: for (int Int : Ints) |
200 | // CHECK-FIXES-NEXT: OtherInt = Int; |
201 | |
202 | for (int I = 0; I < N; ++I) { |
203 | OtherInt = Ints[I] = OtherInt; |
204 | } |
205 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
206 | // CHECK-FIXES: for (int & Int : Ints) |
207 | // CHECK-FIXES-NEXT: OtherInt = Int = OtherInt; |
208 | |
209 | // Arithmetic operations. |
210 | for (int I = 0; I < N; ++I) { |
211 | OtherInt += Ints[I]; |
212 | } |
213 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
214 | // CHECK-FIXES: for (int Int : Ints) |
215 | // CHECK-FIXES-NEXT: OtherInt += Int; |
216 | |
217 | for (int I = 0; I < N; ++I) { |
218 | Ints[I] += Ints[I]; |
219 | } |
220 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
221 | // CHECK-FIXES: for (int & Int : Ints) |
222 | // CHECK-FIXES-NEXT: Int += Int; |
223 | |
224 | for (int I = 0; I < N; ++I) { |
225 | int Res = 5 * (Ints[I] + 1) - Ints[I]; |
226 | } |
227 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
228 | // CHECK-FIXES: for (int Int : Ints) |
229 | // CHECK-FIXES-NEXT: int Res = 5 * (Int + 1) - Int; |
230 | } |
231 | |
232 | void takingReferences() { |
233 | // We do it twice to prevent the check from thinking that they are aliases. |
234 | |
235 | // Class type. |
236 | for (int I = 0; I < N; ++I) { |
237 | Str &J = Array[I]; |
238 | Str &K = Array[I]; |
239 | } |
240 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
241 | // CHECK-FIXES: for (auto & I : Array) |
242 | // CHECK-FIXES-NEXT: Str &J = I; |
243 | // CHECK-FIXES-NEXT: Str &K = I; |
244 | for (int I = 0; I < N; ++I) { |
245 | const Str &J = Array[I]; |
246 | const Str &K = Array[I]; |
247 | } |
248 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
249 | // CHECK-FIXES: for (auto I : Array) |
250 | // CHECK-FIXES-NEXT: const Str &J = I; |
251 | // CHECK-FIXES-NEXT: const Str &K = I; |
252 | |
253 | // Primitive type. |
254 | for (int I = 0; I < N; ++I) { |
255 | int &J = Ints[I]; |
256 | int &K = Ints[I]; |
257 | } |
258 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
259 | // CHECK-FIXES: for (int & Int : Ints) |
260 | // CHECK-FIXES-NEXT: int &J = Int; |
261 | // CHECK-FIXES-NEXT: int &K = Int; |
262 | for (int I = 0; I < N; ++I) { |
263 | const int &J = Ints[I]; |
264 | const int &K = Ints[I]; |
265 | } |
266 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
267 | // CHECK-FIXES: for (int Int : Ints) |
268 | // CHECK-FIXES-NEXT: const int &J = Int; |
269 | // CHECK-FIXES-NEXT: const int &K = Int; |
270 | |
271 | // Aliases. |
272 | for (int I = 0; I < N; ++I) { |
273 | const Str &J = Array[I]; |
274 | (void)J; |
275 | } |
276 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
277 | // CHECK-FIXES: for (auto J : Array) |
278 | for (int I = 0; I < N; ++I) { |
279 | Str &J = Array[I]; |
280 | (void)J; |
281 | } |
282 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
283 | // CHECK-FIXES: for (auto & J : Array) |
284 | |
285 | for (int I = 0; I < N; ++I) { |
286 | const int &J = Ints[I]; |
287 | (void)J; |
288 | } |
289 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
290 | // CHECK-FIXES: for (int J : Ints) |
291 | |
292 | for (int I = 0; I < N; ++I) { |
293 | int &J = Ints[I]; |
294 | (void)J; |
295 | } |
296 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
297 | // CHECK-FIXES: for (int & J : Ints) |
298 | } |
299 | |
300 | template <class T> |
301 | struct vector { |
302 | unsigned size() const; |
303 | const T &operator[](int) const; |
304 | T &operator[](int); |
305 | T *begin(); |
306 | T *end(); |
307 | const T *begin() const; |
308 | const T *end() const; |
309 | }; |
310 | |
311 | // If the elements are already constant, we won't do any ImplicitCast to const. |
312 | void testContainerOfConstIents() { |
313 | const int Ints[N]{}; |
314 | for (int I = 0; I < N; ++I) { |
315 | OtherInt -= Ints[I]; |
316 | } |
317 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop |
318 | // CHECK-FIXES: for (int Int : Ints) |
319 | |
320 | vector<const Str> Strs; |
321 | for (int I = 0; I < Strs.size(); ++I) { |
322 | Strs[I].constMember(0); |
323 | constRefArg(Strs[I]); |
324 | } |
325 | // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop |
326 | // CHECK-FIXES: for (auto Str : Strs) |
327 | } |
328 | |
329 | // When we are inside a const-qualified member functions, all the data members |
330 | // are implicitly set as const. As before, there won't be any ImplicitCast to |
331 | // const in their usages. |
332 | class TestInsideConstFunction { |
333 | const static int N = 10; |
334 | int Ints[N]; |
335 | Str Array[N]; |
336 | vector<int> V; |
337 | |
338 | void foo() const { |
339 | for (int I = 0; I < N; ++I) { |
340 | if (Ints[I]) |
341 | copyArg(Ints[I]); |
342 | } |
343 | // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
344 | // CHECK-FIXES: for (int Int : Ints) |
345 | |
346 | for (int I = 0; I < N; ++I) { |
347 | Array[I].constMember(0); |
348 | constRefArg(Array[I]); |
349 | } |
350 | // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
351 | // CHECK-FIXES: for (auto I : Array) |
352 | |
353 | for (int I = 0; I < V.size(); ++I) { |
354 | if (V[I]) |
355 | copyArg(V[I]); |
356 | } |
357 | // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop |
358 | // CHECK-FIXES: for (int I : V) |
359 | } |
360 | }; |
361 | |