1// RUN: %check_clang_tidy %s modernize-loop-convert %t
2
3struct 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.
14struct ModifiesRightSide {
15 ModifiesRightSide() = default;
16 ModifiesRightSide(ModifiesRightSide &);
17 bool operator<(ModifiesRightSide &) const;
18 ModifiesRightSide &operator=(ModifiesRightSide &);
19};
20
21template <typename T>
22void copyArg(T);
23
24template <typename T>
25void 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&".
29void constRefArg(const Str &);
30void constRefArg(const ModifiesRightSide &);
31void constRefArg(const int &);
32
33void foo();
34
35const int N = 10;
36Str Array[N], OtherStr;
37ModifiesRightSide Right[N], OtherRight;
38int Ints[N], OtherInt;
39
40void 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
87void 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
148void 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
232void 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
300template <class T>
301struct 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.
312void 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.
332class 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

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-const.cpp