xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp (revision 1af159e98c23a293c103e1f548866488126ed6f6)
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 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 
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 
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 
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>
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>
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 
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);
289   double nonConstMethod() {}
290   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 
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 
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 
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 
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 
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 
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 
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 
538 inline void *operator new(decltype(sizeof(void *)), void *p) { return p; }
539 
540 struct Value {
541 };
542 void placement_new() {
543   Value Mem;
544   Value *V = new (&Mem) Value;
545 }
546 
547 struct ModifyingConversion {
548   operator int() { return 15; }
549 };
550 struct NonModifyingConversion {
551   operator int() const { return 15; }
552 };
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 
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 
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;
607   constexpr operator value_type() const noexcept { return value; }
608   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 {
629   T alwaysConst() const { return T{}; }
630 
631   template <typename T2 = T, typename = typename enable_if<is_integral<T2>::value>::type>
632   T sometimesConst() const { return T{}; }
633 
634   template <typename T2 = T, typename = typename enable_if<not_integral<T2>::value>::type>
635   T sometimesConst() { return T{}; }
636 };
637 
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 {
658   to_construct(int &j) {}
659 };
660 template <typename T>
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);
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>
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 
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 {
706   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>
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);
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 };
736 Actuator &test_return_polymorphic() {
737   static AnotherActuator np_local0;
738   return np_local0;
739 }
740 
741 using f_signature = int *(*)(int &);
742 int *my_alloc(int &size) { return new int[size]; }
743 struct A {
744   int f(int &i) { return i + 1; }
745   int (A::*x)(int &);
746 };
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 };
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 
782   int *begin() { return &data[0]; }
783   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.
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 
832   int *begin() { return &data[0]; }
833   int *end() { return &data[2]; }
834   const int *begin() const { return &data[0]; }
835   const int *end() const { return &data[2]; }
836 };
837 
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 
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 }
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 &);
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 
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 
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 };
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 };
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 };
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>
942 void list_init_template() {
943   T np_local0{};
944   ref_pair<T, T> p_local0 = {np_local0, np_local0};
945 }
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);
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>
962 T &return_ref() {
963   static T global;
964   return global;
965 }
966 template <typename T>
967 T *return_ptr() { return &return_ref<T>(); }
968 
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