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