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