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
12bool global;
13char 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.
16static int p_static_global = 42;
17
18namespace foo {
19int scoped;
20float 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.
24namespace {
25int np_anonymous_global;
26int 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).
31void lambdas() {
32 auto Lambda = [](int i) { return i < 0; };
33}
34
35void some_function(double, wchar_t);
36
37void 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
59void 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
73void ignore_reference_to_pointers() {
74 int *np_local0 = nullptr;
75 int *&np_local1 = np_local0;
76}
77
78void 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
95void 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
110void function_inout_pointer(int *inout);
111void function_in_pointer(const int *in);
112
113void 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
141void function_inout_ref(int &inout);
142void function_in_ref(const int &in);
143
144void 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
165double *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
174const 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`
185const 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
195void overloaded_arguments(const int &in);
196void overloaded_arguments(int &inout);
197void overloaded_arguments(const int *in);
198void overloaded_arguments(int *inout);
199
200void 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
214template <typename T>
215void 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
234template <typename T>
235void 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
265void 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
274struct 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
291void 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
332void 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
345struct OperatorsAsConstAsPossible {
346 OperatorsAsConstAsPossible &operator+=(const OperatorsAsConstAsPossible &rhs);
347 OperatorsAsConstAsPossible operator+(const OperatorsAsConstAsPossible &rhs) const;
348};
349
350struct NonConstOperators {
351};
352NonConstOperators operator+(NonConstOperators &lhs, NonConstOperators &rhs);
353NonConstOperators operator-(NonConstOperators lhs, NonConstOperators rhs);
354
355void 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
382struct 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
395void 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
426void const_handle(const double &np_local0);
427void const_handle(const double *np_local0);
428
429void non_const_handle(double &np_local0);
430void non_const_handle(double *np_local0);
431
432void 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
477void 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
519void 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
526inline void *operator new(decltype(sizeof(void *)), void *p) { return p; }
527
528struct Value {
529};
530void placement_new() {
531 Value Mem;
532 Value *V = new (&Mem) Value;
533}
534
535struct ModifyingConversion {
536 operator int() { return 15; }
537};
538struct NonModifyingConversion {
539 operator int() const { return 15; }
540};
541void 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
551void 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
570void 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.
590template <class Tp, Tp v>
591struct 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
599template <typename T>
600struct is_integral : integral_constant<bool, false> {};
601template <>
602struct is_integral<int> : integral_constant<bool, true> {};
603
604template <typename T>
605struct not_integral : integral_constant<bool, false> {};
606template <>
607struct not_integral<double> : integral_constant<bool, true> {};
608
609template <bool, typename Tp = void>
610struct enable_if {};
611
612template <typename Tp>
613struct enable_if<true, Tp> { using type = Tp; };
614
615template <typename T>
616struct 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
626void 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
644template <typename T>
645struct to_construct : T {
646 to_construct(int &j) {}
647};
648template <typename T>
649void 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
657struct stream_obj {};
658stream_obj &operator>>(stream_obj &o, unsigned &foo);
659void input_operator() {
660 stream_obj np_local0;
661 unsigned np_local1 = 42;
662 np_local0 >> np_local1;
663}
664
665struct stream_obj_template {};
666template <typename IStream>
667IStream &operator>>(IStream &o, unsigned &foo);
668
669template <typename Stream>
670void input_operator_template() {
671 Stream np_local0;
672 unsigned np_local1 = 42;
673 np_local0 >> np_local1;
674}
675
676// Test bit fields
677struct HardwareRegister {
678 unsigned field : 5;
679 unsigned : 7;
680 unsigned another : 20;
681};
682
683void 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
693struct IntWrapper {
694 IntWrapper &operator=(unsigned value) { return *this; }
695 template <typename Istream>
696 friend Istream &operator>>(Istream &is, IntWrapper &rhs);
697};
698struct IntMaker {
699 friend IntMaker &operator>>(IntMaker &, unsigned &);
700};
701template <typename Istream>
702Istream &operator>>(Istream &is, IntWrapper &rhs) {
703 unsigned np_local0 = 0;
704 is >> np_local0;
705 return is;
706}
707
708struct Actuator {
709 int actuations;
710};
711struct Sensor {
712 int observations;
713};
714struct System : public Actuator, public Sensor {
715};
716int some_computation(int arg);
717int test_inheritance() {
718 System np_sys;
719 np_sys.actuations = 5;
720 return some_computation(arg: np_sys.actuations);
721}
722struct AnotherActuator : Actuator {
723};
724Actuator &test_return_polymorphic() {
725 static AnotherActuator np_local0;
726 return np_local0;
727}
728
729using f_signature = int *(*)(int &);
730int *my_alloc(int &size) { return new int[size]; }
731struct A {
732 int f(int &i) { return i + 1; }
733 int (A::*x)(int &);
734};
735void 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
750struct nested_data {
751 int more_data;
752};
753struct repro_assignment_to_reference {
754 int my_data;
755 nested_data nested;
756};
757void 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
767struct 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.
777void 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
817struct 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
826void 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
852void 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}
860void 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
873void take_ref(int &);
874void 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
880void 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
889void vlas() {
890 int N = 1; // Can't make N 'const' because VLAs make everything awful
891 sizeof(int[++N]);
892}
893
894struct base {
895 int member;
896};
897struct derived : base {};
898struct another_struct {
899 derived member;
900};
901void another_struct_f() {
902 another_struct np_local0{};
903 base &np_local1 = np_local0.member;
904 np_local1.member++;
905}
906struct list_init {
907 int &member;
908};
909void 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}
915struct list_init_derived {
916 base &member;
917};
918void 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}
924template <typename L, typename R>
925struct ref_pair {
926 L &first;
927 R &second;
928};
929template <typename T>
930void list_init_template() {
931 T np_local0{};
932 ref_pair<T, T> p_local0 = {np_local0, np_local0};
933}
934void 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
941void function_ref_target(int);
942using my_function_type = void (&)(int);
943void 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
949template <typename T>
950T &return_ref() {
951 static T global;
952 return global;
953}
954template <typename T>
955T *return_ptr() { return &return_ref<T>(); }
956
957void 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
980using PointerToMemberFunction = int (Value::*)();
981void member_pointer(Value &x, PointerToMemberFunction m) {
982 Value &member_pointer_tmp = x;
983 (member_pointer_tmp.*m)();
984}
985
986using PointerToConstMemberFunction = int (Value::*)() const;
987void 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

source code of clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp