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