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