1 | // RUN: %check_clang_tidy %s misc-const-correctness %t -- \ |
2 | // RUN: -config="{CheckOptions: {\ |
3 | // RUN: misc-const-correctness.TransformValues: true, \ |
4 | // RUN: misc-const-correctness.WarnPointersAsValues: false, \ |
5 | // RUN: misc-const-correctness.TransformPointersAsValues: false \ |
6 | // RUN: }}" -- -fno-delayed-template-parsing |
7 | |
8 | // ------- Provide test samples for primitive builtins --------- |
9 | // - every 'p_*' variable is a 'potential_const_*' variable |
10 | // - every 'np_*' variable is a 'non_potential_const_*' variable |
11 | |
12 | bool global; |
13 | char np_global = 0; // globals can't be known to be const |
14 | |
15 | // FIXME: 'static' globals are not matched right now. They could be analyzed but aren't right now. |
16 | static int p_static_global = 42; |
17 | |
18 | namespace foo { |
19 | int scoped; |
20 | float np_scoped = 1; // namespace variables are like globals |
21 | } // namespace foo |
22 | |
23 | // FIXME: Similary to 'static' globals, anonymous globals are not matched and analyzed. |
24 | namespace { |
25 | int np_anonymous_global; |
26 | int p_anonymous_global = 43; |
27 | } // namespace |
28 | |
29 | // Lambdas should be ignored, because they do not follow the normal variable |
30 | // semantic (e.g. the type is only known to the compiler). |
31 | void lambdas() { |
32 | auto Lambda = [](int i) { return i < 0; }; |
33 | } |
34 | |
35 | void some_function(double, wchar_t); |
36 | |
37 | void some_function(double np_arg0, wchar_t np_arg1) { |
38 | int p_local0 = 2; |
39 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
40 | // CHECK-FIXES: int const p_local0 |
41 | |
42 | int np_local0; |
43 | const int np_local1 = 42; |
44 | |
45 | unsigned int np_local2 = 3; |
46 | np_local2 <<= 4; |
47 | |
48 | int np_local3 = 4; |
49 | ++np_local3; |
50 | int np_local4 = 4; |
51 | np_local4++; |
52 | |
53 | int np_local5 = 4; |
54 | --np_local5; |
55 | int np_local6 = 4; |
56 | np_local6--; |
57 | } |
58 | |
59 | void nested_scopes() { |
60 | int p_local0 = 2; |
61 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
62 | // CHECK-FIXES: int const p_local0 |
63 | int np_local0 = 42; |
64 | |
65 | { |
66 | int p_local1 = 42; |
67 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: variable 'p_local1' of type 'int' can be declared 'const' |
68 | // CHECK-FIXES: int const p_local1 |
69 | np_local0 *= 2; |
70 | } |
71 | } |
72 | |
73 | void ignore_reference_to_pointers() { |
74 | int *np_local0 = nullptr; |
75 | int *&np_local1 = np_local0; |
76 | } |
77 | |
78 | void some_lambda_environment_capture_all_by_reference(double np_arg0) { |
79 | int np_local0 = 0; |
80 | int p_local0 = 1; |
81 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
82 | // CHECK-FIXES: int const p_local0 |
83 | |
84 | int np_local2; |
85 | const int np_local3 = 2; |
86 | |
87 | // Capturing all variables by reference prohibits making them const. |
88 | [&]() { ++np_local0; }; |
89 | |
90 | int p_local1 = 0; |
91 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' |
92 | // CHECK-FIXES: int const p_local1 |
93 | } |
94 | |
95 | void some_lambda_environment_capture_all_by_value(double np_arg0) { |
96 | int np_local0 = 0; |
97 | int p_local0 = 1; |
98 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
99 | // CHECK-FIXES: int const p_local0 |
100 | |
101 | int np_local1; |
102 | const int np_local2 = 2; |
103 | |
104 | // Capturing by value has no influence on them. |
105 | [=]() { (void)p_local0; }; |
106 | |
107 | np_local0 += 10; |
108 | } |
109 | |
110 | void function_inout_pointer(int *inout); |
111 | void function_in_pointer(const int *in); |
112 | |
113 | void some_pointer_taking(int *out) { |
114 | int np_local0 = 42; |
115 | const int *const p0_np_local0 = &np_local0; |
116 | int *const p1_np_local0 = &np_local0; |
117 | |
118 | int np_local1 = 42; |
119 | const int *const p0_np_local1 = &np_local1; |
120 | int *const p1_np_local1 = &np_local1; |
121 | *p1_np_local0 = 43; |
122 | |
123 | int np_local2 = 42; |
124 | function_inout_pointer(inout: &np_local2); |
125 | |
126 | // Prevents const. |
127 | int np_local3 = 42; |
128 | out = &np_local3; // This returns and invalid address, its just about the AST |
129 | |
130 | int p_local1 = 42; |
131 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' |
132 | // CHECK-FIXES: int const p_local1 |
133 | const int *const p0_p_local1 = &p_local1; |
134 | |
135 | int p_local2 = 42; |
136 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'int' can be declared 'const' |
137 | // CHECK-FIXES: int const p_local2 |
138 | function_in_pointer(in: &p_local2); |
139 | } |
140 | |
141 | void function_inout_ref(int &inout); |
142 | void function_in_ref(const int &in); |
143 | |
144 | void some_reference_taking() { |
145 | int np_local0 = 42; |
146 | const int &r0_np_local0 = np_local0; |
147 | int &r1_np_local0 = np_local0; |
148 | r1_np_local0 = 43; |
149 | const int &r2_np_local0 = r1_np_local0; |
150 | |
151 | int np_local1 = 42; |
152 | function_inout_ref(inout&: np_local1); |
153 | |
154 | int p_local0 = 42; |
155 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
156 | // CHECK-FIXES: int const p_local0 |
157 | const int &r0_p_local0 = p_local0; |
158 | |
159 | int p_local1 = 42; |
160 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' |
161 | // CHECK-FIXES: int const p_local1 |
162 | function_in_ref(in: p_local1); |
163 | } |
164 | |
165 | double *non_const_pointer_return() { |
166 | double p_local0 = 0.0; |
167 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' |
168 | // CHECK-FIXES: double const p_local0 |
169 | double np_local0 = 24.4; |
170 | |
171 | return &np_local0; |
172 | } |
173 | |
174 | const double *const_pointer_return() { |
175 | double p_local0 = 0.0; |
176 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' |
177 | // CHECK-FIXES: double const p_local0 |
178 | double p_local1 = 24.4; |
179 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' |
180 | // CHECK-FIXES: double const p_local1 |
181 | return &p_local1; |
182 | } |
183 | |
184 | // Also see const-correctness-values.cpp-before-cxx23.cpp for `non_const_ref_return` and `return_non_const_pointer_ref` |
185 | const double &const_ref_return() { |
186 | double p_local0 = 0.0; |
187 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double' can be declared 'const' |
188 | // CHECK-FIXES: double const p_local0 |
189 | double p_local1 = 24.4; |
190 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' |
191 | // CHECK-FIXES: double const p_local1 |
192 | return p_local1; |
193 | } |
194 | |
195 | void overloaded_arguments(const int &in); |
196 | void overloaded_arguments(int &inout); |
197 | void overloaded_arguments(const int *in); |
198 | void overloaded_arguments(int *inout); |
199 | |
200 | void function_calling() { |
201 | int np_local0 = 42; |
202 | overloaded_arguments(inout&: np_local0); |
203 | |
204 | const int np_local1 = 42; |
205 | overloaded_arguments(in: np_local1); |
206 | |
207 | int np_local2 = 42; |
208 | overloaded_arguments(inout: &np_local2); |
209 | |
210 | const int np_local3 = 42; |
211 | overloaded_arguments(in: &np_local3); |
212 | } |
213 | |
214 | template <typename T> |
215 | void define_locals(T np_arg0, T &np_arg1, int np_arg2) { |
216 | T np_local0 = 0; |
217 | np_local0 += np_arg0 * np_arg1; |
218 | |
219 | T np_local1 = 42; |
220 | np_local0 += np_local1; |
221 | |
222 | // Used as argument to an overloaded function with const and non-const. |
223 | T np_local2 = 42; |
224 | overloaded_arguments(np_local2); |
225 | |
226 | int np_local4 = 42; |
227 | // non-template values are ok still. |
228 | int p_local0 = 42; |
229 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
230 | // CHECK-FIXES: int const p_local0 |
231 | np_local4 += p_local0; |
232 | } |
233 | |
234 | template <typename T> |
235 | void more_template_locals() { |
236 | const T np_local0 = {}; |
237 | auto np_local1 = T{}; |
238 | T &np_local2 = np_local1; |
239 | T *np_local_ptr = &np_local1; |
240 | |
241 | const auto np_local3 = T{}; |
242 | // FIXME: False positive, the reference points to a template type and needs |
243 | // to be excluded from analysis, but somehow isn't (matchers don't work) |
244 | auto &np_local4 = np_local3; |
245 | |
246 | const auto *np_local5 = &np_local3; |
247 | auto *np_local6 = &np_local1; |
248 | |
249 | using TypedefToTemplate = T; |
250 | TypedefToTemplate np_local7{}; |
251 | // FIXME: False positive, the reference points to a template type and needs |
252 | // to be excluded from analysis, but somehow isn't (matchers don't work) |
253 | // auto &np_local8 = np_local7; |
254 | const auto &np_local9 = np_local7; |
255 | auto np_local10 = np_local7; |
256 | auto *np_local11 = &np_local10; |
257 | const auto *const np_local12 = &np_local10; |
258 | |
259 | // FIXME: False positive, the reference points to a template type and needs |
260 | // to be excluded from analysis, but somehow isn't (matchers don't work) |
261 | // TypedefToTemplate &np_local13 = np_local7; |
262 | TypedefToTemplate *np_local14 = &np_local7; |
263 | } |
264 | |
265 | void template_instantiation() { |
266 | const int np_local0 = 42; |
267 | int np_local1 = 42; |
268 | |
269 | define_locals(np_arg0: np_local0, np_arg1&: np_local1, np_arg2: np_local0); |
270 | define_locals(np_arg0: np_local1, np_arg1&: np_local1, np_arg2: np_local1); |
271 | more_template_locals<int>(); |
272 | } |
273 | |
274 | struct ConstNonConstClass { |
275 | ConstNonConstClass(); |
276 | ConstNonConstClass(double &np_local0); |
277 | double nonConstMethod() {} |
278 | double constMethod() const {} |
279 | double modifyingMethod(double &np_arg0) const; |
280 | |
281 | double NonConstMember; |
282 | const double ConstMember; |
283 | |
284 | double &NonConstMemberRef; |
285 | const double &ConstMemberRef; |
286 | |
287 | double *NonConstMemberPtr; |
288 | const double *ConstMemberPtr; |
289 | }; |
290 | |
291 | void direct_class_access() { |
292 | ConstNonConstClass np_local0; |
293 | |
294 | np_local0.constMethod(); |
295 | np_local0.nonConstMethod(); |
296 | |
297 | ConstNonConstClass p_local0; |
298 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass' can be declared 'const' |
299 | // CHECK-FIXES: ConstNonConstClass const p_local0 |
300 | p_local0.constMethod(); |
301 | |
302 | ConstNonConstClass p_local1; |
303 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'ConstNonConstClass' can be declared 'const' |
304 | // CHECK-FIXES: ConstNonConstClass const p_local1 |
305 | double np_local1; |
306 | p_local1.modifyingMethod(np_arg0&: np_local1); |
307 | |
308 | double np_local2; |
309 | ConstNonConstClass p_local2(np_local2); |
310 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'ConstNonConstClass' can be declared 'const' |
311 | // CHECK-FIXES: ConstNonConstClass const p_local2(np_local2) |
312 | |
313 | ConstNonConstClass np_local3; |
314 | np_local3.NonConstMember = 42.; |
315 | |
316 | ConstNonConstClass np_local4; |
317 | np_local4.NonConstMemberRef = 42.; |
318 | |
319 | ConstNonConstClass p_local3; |
320 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'ConstNonConstClass' can be declared 'const' |
321 | // CHECK-FIXES: ConstNonConstClass const p_local3 |
322 | const double val0 = p_local3.NonConstMember; |
323 | const double val1 = p_local3.NonConstMemberRef; |
324 | const double val2 = *p_local3.NonConstMemberPtr; |
325 | |
326 | ConstNonConstClass p_local4; |
327 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'ConstNonConstClass' can be declared 'const' |
328 | // CHECK-FIXES: ConstNonConstClass const p_local4 |
329 | *np_local4.NonConstMemberPtr = 42.; |
330 | } |
331 | |
332 | void class_access_array() { |
333 | ConstNonConstClass np_local0[2]; |
334 | np_local0[0].constMethod(); |
335 | np_local0[1].constMethod(); |
336 | np_local0[1].nonConstMethod(); |
337 | |
338 | ConstNonConstClass p_local0[2]; |
339 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass[2]' can be declared 'const' |
340 | // CHECK-FIXES: ConstNonConstClass const p_local0[2] |
341 | p_local0[0].constMethod(); |
342 | np_local0[1].constMethod(); |
343 | } |
344 | |
345 | struct OperatorsAsConstAsPossible { |
346 | OperatorsAsConstAsPossible &operator+=(const OperatorsAsConstAsPossible &rhs); |
347 | OperatorsAsConstAsPossible operator+(const OperatorsAsConstAsPossible &rhs) const; |
348 | }; |
349 | |
350 | struct NonConstOperators { |
351 | }; |
352 | NonConstOperators (NonConstOperators &lhs, NonConstOperators &rhs); |
353 | NonConstOperators (NonConstOperators lhs, NonConstOperators rhs); |
354 | |
355 | void internal_operator_calls() { |
356 | OperatorsAsConstAsPossible np_local0; |
357 | OperatorsAsConstAsPossible np_local1; |
358 | OperatorsAsConstAsPossible p_local0; |
359 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'OperatorsAsConstAsPossible' can be declared 'const' |
360 | // CHECK-FIXES: OperatorsAsConstAsPossible const p_local0 |
361 | OperatorsAsConstAsPossible p_local1; |
362 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'OperatorsAsConstAsPossible' can be declared 'const' |
363 | // CHECK-FIXES: OperatorsAsConstAsPossible const p_local1 |
364 | |
365 | np_local0 += p_local0; |
366 | np_local1 = p_local0 + p_local1; |
367 | |
368 | NonConstOperators np_local2; |
369 | NonConstOperators np_local3; |
370 | NonConstOperators np_local4; |
371 | |
372 | np_local2 = np_local3 + np_local4; |
373 | |
374 | NonConstOperators p_local2; |
375 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'NonConstOperators' can be declared 'const' |
376 | // CHECK-FIXES: NonConstOperators const p_local2 |
377 | NonConstOperators p_local3 = p_local2 - p_local2; |
378 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'NonConstOperators' can be declared 'const' |
379 | // CHECK-FIXES: NonConstOperators const p_local3 |
380 | } |
381 | |
382 | struct MyVector { |
383 | double *begin(); |
384 | const double *begin() const; |
385 | |
386 | double *end(); |
387 | const double *end() const; |
388 | |
389 | double &operator[](int index); |
390 | double operator[](int index) const; |
391 | |
392 | double values[100]; |
393 | }; |
394 | |
395 | void vector_usage() { |
396 | double np_local0[10]; |
397 | np_local0[5] = 42.; |
398 | |
399 | MyVector np_local1; |
400 | np_local1[5] = 42.; |
401 | |
402 | double p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
403 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double[10]' can be declared 'const' |
404 | // CHECK-FIXES: double const p_local0[10] |
405 | double p_local1 = p_local0[5]; |
406 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double' can be declared 'const' |
407 | // CHECK-FIXES: double const p_local1 |
408 | |
409 | // The following subscript calls suprisingly choose the non-const operator |
410 | // version. |
411 | MyVector np_local2; |
412 | double p_local2 = np_local2[42]; |
413 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'double' can be declared 'const' |
414 | // CHECK-FIXES: double const p_local2 |
415 | |
416 | MyVector np_local3; |
417 | const double np_local4 = np_local3[42]; |
418 | |
419 | // This subscript results in const overloaded operator. |
420 | const MyVector np_local5{}; |
421 | double p_local3 = np_local5[42]; |
422 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double' can be declared 'const' |
423 | // CHECK-FIXES: double const p_local3 |
424 | } |
425 | |
426 | void const_handle(const double &np_local0); |
427 | void const_handle(const double *np_local0); |
428 | |
429 | void non_const_handle(double &np_local0); |
430 | void non_const_handle(double *np_local0); |
431 | |
432 | void handle_from_array() { |
433 | // Non-const handle from non-const array forbids declaring the array as const |
434 | double np_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
435 | double *p_local0 = &np_local0[1]; // Could be `double *const`, but warning deactivated by default |
436 | |
437 | double np_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
438 | double &non_const_ref = np_local1[1]; |
439 | non_const_ref = 42.; |
440 | |
441 | double np_local2[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
442 | double *np_local3; |
443 | np_local3 = &np_local2[5]; |
444 | |
445 | double np_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
446 | non_const_handle(np_local0&: np_local4[2]); |
447 | double np_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
448 | non_const_handle(np_local0: &np_local5[2]); |
449 | |
450 | // Constant handles are ok |
451 | double p_local1[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
452 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'double[10]' can be declared 'const' |
453 | // CHECK-FIXES: double const p_local1[10] |
454 | const double *p_local2 = &p_local1[2]; // Could be `const double *const`, but warning deactivated by default |
455 | |
456 | double p_local3[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
457 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'double[10]' can be declared 'const' |
458 | // CHECK-FIXES: double const p_local3[10] |
459 | const double &const_ref = p_local3[2]; |
460 | |
461 | double p_local4[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
462 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local4' of type 'double[10]' can be declared 'const' |
463 | // CHECK-FIXES: double const p_local4[10] |
464 | const double *const_ptr; |
465 | const_ptr = &p_local4[2]; |
466 | |
467 | double p_local5[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
468 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local5' of type 'double[10]' can be declared 'const' |
469 | // CHECK-FIXES: double const p_local5[10] |
470 | const_handle(np_local0: p_local5[2]); |
471 | double p_local6[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.}; |
472 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local6' of type 'double[10]' can be declared 'const' |
473 | // CHECK-FIXES: double const p_local6[10] |
474 | const_handle(np_local0: &p_local6[2]); |
475 | } |
476 | |
477 | void range_for() { |
478 | int np_local0[2] = {1, 2}; |
479 | for (int &non_const_ref : np_local0) { |
480 | non_const_ref = 42; |
481 | } |
482 | |
483 | int np_local1[2] = {1, 2}; |
484 | for (auto &non_const_ref : np_local1) { |
485 | non_const_ref = 43; |
486 | } |
487 | |
488 | int np_local2[2] = {1, 2}; |
489 | for (auto &&non_const_ref : np_local2) { |
490 | non_const_ref = 44; |
491 | } |
492 | |
493 | int *np_local3[2] = {&np_local0[0], &np_local0[1]}; |
494 | for (int *non_const_ptr : np_local3) { |
495 | *non_const_ptr = 45; |
496 | } |
497 | |
498 | // FIXME same as above, but silenced |
499 | int *const np_local4[2] = {&np_local0[0], &np_local0[1]}; |
500 | for (auto *non_const_ptr : np_local4) { |
501 | *non_const_ptr = 46; |
502 | } |
503 | |
504 | int p_local0[2] = {1, 2}; |
505 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int[2]' can be declared 'const' |
506 | // CHECK-FIXES: int const p_local0[2] |
507 | for (int value : p_local0) { |
508 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'value' of type 'int' can be declared 'const' |
509 | // CHECK-FIXES: int const value |
510 | } |
511 | |
512 | int p_local1[2] = {1, 2}; |
513 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int[2]' can be declared 'const' |
514 | // CHECK-FIXES: int const p_local1[2] |
515 | for (const int &const_ref : p_local1) { |
516 | } |
517 | } |
518 | |
519 | void arrays_of_pointers_are_ignored() { |
520 | int *np_local0[2] = {nullptr, nullptr}; |
521 | |
522 | using intPtr = int*; |
523 | intPtr np_local1[2] = {nullptr, nullptr}; |
524 | } |
525 | |
526 | inline void *operator new(decltype(sizeof(void *)), void *p) { return p; } |
527 | |
528 | struct Value { |
529 | }; |
530 | void placement_new() { |
531 | Value Mem; |
532 | Value *V = new (&Mem) Value; |
533 | } |
534 | |
535 | struct ModifyingConversion { |
536 | operator int() { return 15; } |
537 | }; |
538 | struct NonModifyingConversion { |
539 | operator int() const { return 15; } |
540 | }; |
541 | void conversion_operators() { |
542 | ModifyingConversion np_local0; |
543 | NonModifyingConversion p_local0; |
544 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'NonModifyingConversion' can be declared 'const' |
545 | // CHECK-FIXES: NonModifyingConversion const p_local0 |
546 | |
547 | int np_local1 = np_local0; |
548 | np_local1 = p_local0; |
549 | } |
550 | |
551 | void casts() { |
552 | decltype(sizeof(void *)) p_local0 = 42; |
553 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'decltype(sizeof(void *))' |
554 | // CHECK-FIXES: decltype(sizeof(void *)) const p_local0 |
555 | auto np_local0 = reinterpret_cast<void *>(p_local0); |
556 | np_local0 = nullptr; |
557 | |
558 | int p_local1 = 43; |
559 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const' |
560 | // CHECK-FIXES: int const p_local1 |
561 | short p_local2 = static_cast<short>(p_local1); |
562 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local2' of type 'short' can be declared 'const' |
563 | // CHECK-FIXES: short const p_local2 |
564 | |
565 | int np_local1 = p_local2; |
566 | int &np_local2 = static_cast<int &>(np_local1); |
567 | np_local2 = 5; |
568 | } |
569 | |
570 | void ternary_operator() { |
571 | int np_local0 = 1, np_local1 = 2; |
572 | int &np_local2 = true ? np_local0 : np_local1; |
573 | np_local2 = 2; |
574 | |
575 | int p_local0 = 3, np_local3 = 5; |
576 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
577 | // CHECK-NOT-FIXES: int const p_local0 = 3 |
578 | const int &np_local4 = true ? p_local0 : ++np_local3; |
579 | |
580 | int np_local5[3] = {1, 2, 3}; |
581 | int &np_local6 = np_local5[1] < np_local5[2] ? np_local5[0] : np_local5[2]; |
582 | np_local6 = 42; |
583 | |
584 | int np_local7[3] = {1, 2, 3}; |
585 | int *np_local8 = np_local7[1] < np_local7[2] ? &np_local7[0] : &np_local7[2]; |
586 | *np_local8 = 42; |
587 | } |
588 | |
589 | // Taken from libcxx/include/type_traits and improved readability. |
590 | template <class Tp, Tp v> |
591 | struct integral_constant { |
592 | static constexpr const Tp value = v; |
593 | using value_type = Tp; |
594 | using type = integral_constant; |
595 | constexpr operator value_type() const noexcept { return value; } |
596 | constexpr value_type operator()() const noexcept { return value; } |
597 | }; |
598 | |
599 | template <typename T> |
600 | struct is_integral : integral_constant<bool, false> {}; |
601 | template <> |
602 | struct is_integral<int> : integral_constant<bool, true> {}; |
603 | |
604 | template <typename T> |
605 | struct not_integral : integral_constant<bool, false> {}; |
606 | template <> |
607 | struct not_integral<double> : integral_constant<bool, true> {}; |
608 | |
609 | template <bool, typename Tp = void> |
610 | struct enable_if {}; |
611 | |
612 | template <typename Tp> |
613 | struct enable_if<true, Tp> { using type = Tp; }; |
614 | |
615 | template <typename T> |
616 | struct TMPClass { |
617 | T alwaysConst() const { return T{}; } |
618 | |
619 | template <typename T2 = T, typename = typename enable_if<is_integral<T2>::value>::type> |
620 | T sometimesConst() const { return T{}; } |
621 | |
622 | template <typename T2 = T, typename = typename enable_if<not_integral<T2>::value>::type> |
623 | T sometimesConst() { return T{}; } |
624 | }; |
625 | |
626 | void meta_type() { |
627 | TMPClass<int> p_local0; |
628 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'TMPClass<int>' can be declared 'const' |
629 | // CHECK-FIXES: TMPClass<int> const p_local0 |
630 | p_local0.alwaysConst(); |
631 | p_local0.sometimesConst(); |
632 | |
633 | TMPClass<double> p_local1; |
634 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'TMPClass<double>' can be declared 'const' |
635 | // CHECK-FIXES: TMPClass<double> const p_local1 |
636 | p_local1.alwaysConst(); |
637 | |
638 | TMPClass<double> np_local0; |
639 | np_local0.alwaysConst(); |
640 | np_local0.sometimesConst(); |
641 | } |
642 | |
643 | // This test is the essence from llvm/lib/Support/MemoryBuffer.cpp at line 450 |
644 | template <typename T> |
645 | struct to_construct : T { |
646 | to_construct(int &j) {} |
647 | }; |
648 | template <typename T> |
649 | void placement_new_in_unique_ptr() { |
650 | int p_local0 = 42; |
651 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
652 | // CHECK-FIXES: int const p_local0 |
653 | int np_local0 = p_local0; |
654 | new to_construct<T>(np_local0); |
655 | } |
656 | |
657 | struct stream_obj {}; |
658 | stream_obj &operator>>(stream_obj &o, unsigned &foo); |
659 | void input_operator() { |
660 | stream_obj np_local0; |
661 | unsigned np_local1 = 42; |
662 | np_local0 >> np_local1; |
663 | } |
664 | |
665 | struct stream_obj_template {}; |
666 | template <typename IStream> |
667 | IStream &operator>>(IStream &o, unsigned &foo); |
668 | |
669 | template <typename Stream> |
670 | void input_operator_template() { |
671 | Stream np_local0; |
672 | unsigned np_local1 = 42; |
673 | np_local0 >> np_local1; |
674 | } |
675 | |
676 | // Test bit fields |
677 | struct HardwareRegister { |
678 | unsigned field : 5; |
679 | unsigned : 7; |
680 | unsigned another : 20; |
681 | }; |
682 | |
683 | void TestRegisters() { |
684 | HardwareRegister np_reg0; |
685 | np_reg0.field = 3; |
686 | |
687 | HardwareRegister p_reg1{.field: 3, 22}; |
688 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_reg1' of type 'HardwareRegister' can be declared 'const' |
689 | // CHECK-FIXES: HardwareRegister const p_reg1 |
690 | const unsigned p_val = p_reg1.another; |
691 | } |
692 | |
693 | struct IntWrapper { |
694 | IntWrapper &operator=(unsigned value) { return *this; } |
695 | template <typename Istream> |
696 | friend Istream &operator>>(Istream &is, IntWrapper &rhs); |
697 | }; |
698 | struct IntMaker { |
699 | friend IntMaker &operator>>(IntMaker &, unsigned &); |
700 | }; |
701 | template <typename Istream> |
702 | Istream &operator>>(Istream &is, IntWrapper &rhs) { |
703 | unsigned np_local0 = 0; |
704 | is >> np_local0; |
705 | return is; |
706 | } |
707 | |
708 | struct Actuator { |
709 | int actuations; |
710 | }; |
711 | struct Sensor { |
712 | int observations; |
713 | }; |
714 | struct System : public Actuator, public Sensor { |
715 | }; |
716 | int some_computation(int arg); |
717 | int test_inheritance() { |
718 | System np_sys; |
719 | np_sys.actuations = 5; |
720 | return some_computation(arg: np_sys.actuations); |
721 | } |
722 | struct AnotherActuator : Actuator { |
723 | }; |
724 | Actuator &test_return_polymorphic() { |
725 | static AnotherActuator np_local0; |
726 | return np_local0; |
727 | } |
728 | |
729 | using f_signature = int *(*)(int &); |
730 | int *my_alloc(int &size) { return new int[size]; } |
731 | struct A { |
732 | int f(int &i) { return i + 1; } |
733 | int (A::*x)(int &); |
734 | }; |
735 | void f() { |
736 | int p_local0 = 42; |
737 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
738 | // CHECK-FIXES: int const p_local0 |
739 | int np_local0 = 42; |
740 | f_signature action = my_alloc; |
741 | action(np_local0); |
742 | my_alloc(size&: np_local0); |
743 | |
744 | int np_local1 = 42; |
745 | A a; |
746 | a.x = &A::f; |
747 | (a.*(a.x))(np_local1); |
748 | } |
749 | |
750 | struct nested_data { |
751 | int more_data; |
752 | }; |
753 | struct repro_assignment_to_reference { |
754 | int my_data; |
755 | nested_data nested; |
756 | }; |
757 | void assignment_reference() { |
758 | repro_assignment_to_reference np_local0{.my_data: 42}; |
759 | int &np_local1 = np_local0.my_data; |
760 | np_local1++; |
761 | |
762 | repro_assignment_to_reference np_local2; |
763 | int &np_local3 = np_local2.nested.more_data; |
764 | np_local3++; |
765 | } |
766 | |
767 | struct non_const_iterator { |
768 | int data[42]; |
769 | |
770 | int *begin() { return &data[0]; } |
771 | int *end() { return &data[41]; } |
772 | }; |
773 | |
774 | // The problem is, that 'begin()' and 'end()' are not const overloaded, so |
775 | // they are always a mutation. If 'np_local1' is fixed to const it results in |
776 | // a compilation error. |
777 | void for_bad_iterators() { |
778 | non_const_iterator np_local0; |
779 | non_const_iterator &np_local1 = np_local0; |
780 | |
781 | for (int np_local2 : np_local1) { |
782 | np_local2++; |
783 | } |
784 | |
785 | non_const_iterator np_local3; |
786 | for (int p_local0 : np_local3) |
787 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local0' of type 'int' can be declared 'const' |
788 | // CHECK-FIXES: int const p_local0 |
789 | ; |
790 | |
791 | // Horrible code constructs... |
792 | { |
793 | non_const_iterator np_local4; |
794 | np_local4.data[0]++; |
795 | non_const_iterator np_local5; |
796 | for (int p_local1 : np_local4, np_local5) |
797 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local1' of type 'int' can be declared 'const' |
798 | // CHECK-FIXES: int const p_local1 |
799 | ; |
800 | |
801 | non_const_iterator np_local6; |
802 | non_const_iterator np_local7; |
803 | for (int p_local2 : 1 > 2 ? np_local6 : np_local7) |
804 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local2' of type 'int' can be declared 'const' |
805 | // CHECK-FIXES: int const p_local2 |
806 | ; |
807 | |
808 | non_const_iterator np_local8; |
809 | non_const_iterator np_local9; |
810 | for (int p_local3 : 2 > 1 ? np_local8 : (np_local8, np_local9)) |
811 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: variable 'p_local3' of type 'int' can be declared 'const' |
812 | // CHECK-FIXES: int const p_local3 |
813 | ; |
814 | } |
815 | } |
816 | |
817 | struct good_iterator { |
818 | int data[3] = {1, 2, 3}; |
819 | |
820 | int *begin() { return &data[0]; } |
821 | int *end() { return &data[2]; } |
822 | const int *begin() const { return &data[0]; } |
823 | const int *end() const { return &data[2]; } |
824 | }; |
825 | |
826 | void good_iterators() { |
827 | good_iterator p_local0; |
828 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'good_iterator' can be declared 'const' |
829 | // CHECK-FIXES: good_iterator const p_local0 |
830 | good_iterator &p_local1 = p_local0; |
831 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'good_iterator &' can be declared 'const' |
832 | // CHECK-FIXES: good_iterator const&p_local1 |
833 | |
834 | for (int p_local2 : p_local1) { |
835 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local2' of type 'int' can be declared 'const' |
836 | // CHECK-FIXES: int const p_local2 |
837 | (void)p_local2; |
838 | } |
839 | |
840 | good_iterator p_local3; |
841 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local3' of type 'good_iterator' can be declared 'const' |
842 | // CHECK-FIXES: good_iterator const p_local3 |
843 | for (int p_local4 : p_local3) |
844 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local4' of type 'int' can be declared 'const' |
845 | // CHECK-FIXES: int const p_local4 |
846 | ; |
847 | good_iterator np_local1; |
848 | for (int &np_local2 : np_local1) |
849 | np_local2++; |
850 | } |
851 | |
852 | void for_bad_iterators_array() { |
853 | int np_local0[42]; |
854 | int(&np_local1)[42] = np_local0; |
855 | |
856 | for (int &np_local2 : np_local1) { |
857 | np_local2++; |
858 | } |
859 | } |
860 | void for_ok_iterators_array() { |
861 | int np_local0[42]; |
862 | int(&p_local0)[42] = np_local0; |
863 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int (&)[42]' can be declared 'const' |
864 | // CHECK-FIXES: int const(&p_local0)[42] |
865 | |
866 | for (int p_local1 : p_local0) { |
867 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'p_local1' of type 'int' can be declared 'const' |
868 | // CHECK-FIXES: int const p_local1 |
869 | (void)p_local1; |
870 | } |
871 | } |
872 | |
873 | void take_ref(int &); |
874 | void ternary_reference() { |
875 | int np_local0 = 42; |
876 | int np_local1 = 43; |
877 | take_ref((np_local0 > np_local1 ? np_local0 : (np_local0, np_local1))); |
878 | } |
879 | |
880 | void complex_usage() { |
881 | int np_local0 = 42; |
882 | int p_local0 = 42; |
883 | // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const' |
884 | // CHECK-FIXES: int const p_local0 |
885 | int np_local1 = 42; |
886 | (np_local0 == p_local0 ? np_local0 : (p_local0, np_local1))++; |
887 | } |
888 | |
889 | void vlas() { |
890 | int N = 1; // Can't make N 'const' because VLAs make everything awful |
891 | sizeof(int[++N]); |
892 | } |
893 | |
894 | struct base { |
895 | int member; |
896 | }; |
897 | struct derived : base {}; |
898 | struct another_struct { |
899 | derived member; |
900 | }; |
901 | void another_struct_f() { |
902 | another_struct np_local0{}; |
903 | base &np_local1 = np_local0.member; |
904 | np_local1.member++; |
905 | } |
906 | struct list_init { |
907 | int &member; |
908 | }; |
909 | void create_false_positive() { |
910 | int np_local0 = 42; |
911 | list_init p_local0 = {.member: np_local0}; |
912 | // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init' can be declared 'const' |
913 | // CHECK-FIXES: list_init const p_local0 |
914 | } |
915 | struct list_init_derived { |
916 | base &member; |
917 | }; |
918 | void list_init_derived_func() { |
919 | derived np_local0; |
920 | list_init_derived p_local0 = {.member: np_local0}; |
921 | // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local0' of type 'list_init_derived' can be declared 'const' |
922 | // CHECK-FIXES: list_init_derived const p_local0 |
923 | } |
924 | template <typename L, typename R> |
925 | struct ref_pair { |
926 | L &first; |
927 | R &second; |
928 | }; |
929 | template <typename T> |
930 | void list_init_template() { |
931 | T np_local0{}; |
932 | ref_pair<T, T> p_local0 = {np_local0, np_local0}; |
933 | } |
934 | void cast_in_class_hierarchy() { |
935 | derived np_local0; |
936 | base p_local1 = static_cast<base &>(np_local0); |
937 | // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'p_local1' of type 'base' can be declared 'const' |
938 | // CHECK-FIXES: base const p_local1 |
939 | } |
940 | |
941 | void function_ref_target(int); |
942 | using my_function_type = void (&)(int); |
943 | void func_references() { |
944 | // Could be const, because the reference is not adjusted but adding that |
945 | // has no effect and creates a compiler warning. |
946 | my_function_type ptr = function_ref_target; |
947 | } |
948 | |
949 | template <typename T> |
950 | T &return_ref() { |
951 | static T global; |
952 | return global; |
953 | } |
954 | template <typename T> |
955 | T *return_ptr() { return &return_ref<T>(); } |
956 | |
957 | void auto_usage_variants() { |
958 | auto auto_val0 = int{}; |
959 | // CHECK-FIXES-NOT: auto const auto_val0 |
960 | auto &auto_val1 = auto_val0; |
961 | auto *auto_val2 = &auto_val0; |
962 | |
963 | auto auto_ref0 = return_ref<int>(); |
964 | // CHECK-FIXES-NOT: auto const auto_ref0 |
965 | auto &auto_ref1 = return_ref<int>(); // Bad |
966 | auto *auto_ref2 = return_ptr<int>(); |
967 | |
968 | auto auto_ptr0 = return_ptr<int>(); |
969 | // CHECK-FIXES-NOT: auto const auto_ptr0 |
970 | auto &auto_ptr1 = auto_ptr0; |
971 | auto *auto_ptr2 = return_ptr<int>(); |
972 | |
973 | using MyTypedef = int; |
974 | auto auto_td0 = MyTypedef{}; |
975 | // CHECK-FIXES-NOT: auto const auto_td0 |
976 | auto &auto_td1 = auto_td0; |
977 | auto *auto_td2 = &auto_td0; |
978 | } |
979 | |
980 | using PointerToMemberFunction = int (Value::*)(); |
981 | void member_pointer(Value &x, PointerToMemberFunction m) { |
982 | Value &member_pointer_tmp = x; |
983 | (member_pointer_tmp.*m)(); |
984 | } |
985 | |
986 | using PointerToConstMemberFunction = int (Value::*)() const; |
987 | void member_pointer_const(Value &x, PointerToConstMemberFunction m) { |
988 | Value &member_pointer_tmp = x; |
989 | // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'member_pointer_tmp' of type 'Value &' can be declared 'const' |
990 | (member_pointer_tmp.*m)(); |
991 | } |
992 | |