146ae26e7SJonas Toth // RUN: %check_clang_tidy %s misc-const-correctness %t -- \
2*1af159e9SPiotr Zegar // RUN:   -config="{CheckOptions: {\
3*1af159e9SPiotr Zegar // RUN:   misc-const-correctness.TransformValues: true,\
4*1af159e9SPiotr Zegar // RUN:   misc-const-correctness.WarnPointersAsValues: false, \
5*1af159e9SPiotr Zegar // RUN:   misc-const-correctness.TransformPointersAsValues: false} \
6*1af159e9SPiotr Zegar // RUN:   }" -- -fno-delayed-template-parsing
746ae26e7SJonas Toth 
846ae26e7SJonas Toth bool global;
946ae26e7SJonas Toth char np_global = 0; // globals can't be known to be const
1046ae26e7SJonas Toth 
1146ae26e7SJonas Toth namespace foo {
1246ae26e7SJonas Toth int scoped;
1346ae26e7SJonas Toth float np_scoped = 1; // namespace variables are like globals
1446ae26e7SJonas Toth } // namespace foo
1546ae26e7SJonas Toth 
1646ae26e7SJonas Toth // Lambdas should be ignored, because they do not follow the normal variable
1746ae26e7SJonas Toth // semantic (e.g. the type is only known to the compiler).
lambdas()1846ae26e7SJonas Toth void lambdas() {
1946ae26e7SJonas Toth   auto Lambda = [](int i) { return i < 0; };
2046ae26e7SJonas Toth }
2146ae26e7SJonas Toth 
2246ae26e7SJonas Toth void some_function(double, wchar_t);
2346ae26e7SJonas Toth 
some_function(double np_arg0,wchar_t np_arg1)2446ae26e7SJonas Toth void some_function(double np_arg0, wchar_t np_arg1) {
2546ae26e7SJonas Toth   int p_local0 = 2;
2646ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
2746ae26e7SJonas Toth   // CHECK-FIXES: int const p_local0 = 2;
2846ae26e7SJonas Toth }
2946ae26e7SJonas Toth 
nested_scopes()3046ae26e7SJonas Toth void nested_scopes() {
3146ae26e7SJonas Toth   {
3246ae26e7SJonas Toth     int p_local1 = 42;
3346ae26e7SJonas Toth     // CHECK-MESSAGES: [[@LINE-1]]:5: warning: variable 'p_local1' of type 'int' can be declared 'const'
3446ae26e7SJonas Toth     // CHECK-FIXES: int const p_local1 = 42;
3546ae26e7SJonas Toth   }
3646ae26e7SJonas Toth }
3746ae26e7SJonas Toth 
3846ae26e7SJonas Toth template <typename T>
define_locals(T np_arg0,T & np_arg1,int np_arg2)3946ae26e7SJonas Toth void define_locals(T np_arg0, T &np_arg1, int np_arg2) {
4046ae26e7SJonas Toth   T np_local0 = 0;
4146ae26e7SJonas Toth   int p_local1 = 42;
4246ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const'
4346ae26e7SJonas Toth   // CHECK-FIXES: int const p_local1 = 42;
4446ae26e7SJonas Toth }
4546ae26e7SJonas Toth 
template_instantiation()4646ae26e7SJonas Toth void template_instantiation() {
4746ae26e7SJonas Toth   const int np_local0 = 42;
4846ae26e7SJonas Toth   int np_local1 = 42;
4946ae26e7SJonas Toth 
5046ae26e7SJonas Toth   define_locals(np_local0, np_local1, np_local0);
5146ae26e7SJonas Toth   define_locals(np_local1, np_local1, np_local1);
5246ae26e7SJonas Toth }
5346ae26e7SJonas Toth 
5446ae26e7SJonas Toth struct ConstNonConstClass {
5546ae26e7SJonas Toth   ConstNonConstClass();
5646ae26e7SJonas Toth   ConstNonConstClass(double &np_local0);
nonConstMethodConstNonConstClass5746ae26e7SJonas Toth   double nonConstMethod() {}
constMethodConstNonConstClass5846ae26e7SJonas Toth   double constMethod() const {}
5946ae26e7SJonas Toth   double modifyingMethod(double &np_arg0) const;
6046ae26e7SJonas Toth 
6146ae26e7SJonas Toth   double NonConstMember;
6246ae26e7SJonas Toth   const double ConstMember;
6346ae26e7SJonas Toth 
6446ae26e7SJonas Toth   double &NonConstMemberRef;
6546ae26e7SJonas Toth   const double &ConstMemberRef;
6646ae26e7SJonas Toth 
6746ae26e7SJonas Toth   double *NonConstMemberPtr;
6846ae26e7SJonas Toth   const double *ConstMemberPtr;
6946ae26e7SJonas Toth };
7046ae26e7SJonas Toth 
direct_class_access()7146ae26e7SJonas Toth void direct_class_access() {
7246ae26e7SJonas Toth   ConstNonConstClass p_local0;
7346ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass' can be declared 'const'
7446ae26e7SJonas Toth   // CHECK-FIXES: ConstNonConstClass const p_local0;
7546ae26e7SJonas Toth   p_local0.constMethod();
7646ae26e7SJonas Toth }
7746ae26e7SJonas Toth 
class_access_array()7846ae26e7SJonas Toth void class_access_array() {
7946ae26e7SJonas Toth   ConstNonConstClass p_local0[2];
8046ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass[2]' can be declared 'const'
8146ae26e7SJonas Toth   // CHECK-FIXES: ConstNonConstClass const p_local0[2];
8246ae26e7SJonas Toth   p_local0[0].constMethod();
8346ae26e7SJonas Toth }
8446ae26e7SJonas Toth 
8546ae26e7SJonas Toth struct MyVector {
8646ae26e7SJonas Toth   double *begin();
8746ae26e7SJonas Toth   const double *begin() const;
8846ae26e7SJonas Toth 
8946ae26e7SJonas Toth   double *end();
9046ae26e7SJonas Toth   const double *end() const;
9146ae26e7SJonas Toth 
9246ae26e7SJonas Toth   double &operator[](int index);
9346ae26e7SJonas Toth   double operator[](int index) const;
9446ae26e7SJonas Toth 
9546ae26e7SJonas Toth   double values[100];
9646ae26e7SJonas Toth };
9746ae26e7SJonas Toth 
vector_usage()9846ae26e7SJonas Toth void vector_usage() {
9946ae26e7SJonas Toth   double p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.};
10046ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double[10]' can be declared 'const'
10146ae26e7SJonas Toth   // CHECK-FIXES: double const p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.};
10246ae26e7SJonas Toth }
10346ae26e7SJonas Toth 
range_for()10446ae26e7SJonas Toth void range_for() {
10546ae26e7SJonas Toth   int np_local0[2] = {1, 2};
10646ae26e7SJonas Toth   // The transformation is not possible because the range-for-loop mutates the array content.
10746ae26e7SJonas Toth   int *const np_local1[2] = {&np_local0[0], &np_local0[1]};
10846ae26e7SJonas Toth   for (int *non_const_ptr : np_local1) {
10946ae26e7SJonas Toth     *non_const_ptr = 45;
11046ae26e7SJonas Toth   }
11146ae26e7SJonas Toth 
11246ae26e7SJonas Toth   int *np_local2[2] = {&np_local0[0], &np_local0[1]};
11346ae26e7SJonas Toth   for (int *non_const_ptr : np_local2) {
11446ae26e7SJonas Toth     *non_const_ptr = 45;
11546ae26e7SJonas Toth   }
11646ae26e7SJonas Toth }
11746ae26e7SJonas Toth 
decltype_declaration()11846ae26e7SJonas Toth void decltype_declaration() {
11946ae26e7SJonas Toth   decltype(sizeof(void *)) p_local0 = 42;
12046ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'decltype(sizeof(void *))'
12146ae26e7SJonas Toth   // CHECK-FIXES: decltype(sizeof(void *)) const p_local0 = 42;
12246ae26e7SJonas Toth }
12346ae26e7SJonas Toth 
12446ae26e7SJonas Toth // Taken from libcxx/include/type_traits and improved readability.
12546ae26e7SJonas Toth template <class Tp, Tp v>
12646ae26e7SJonas Toth struct integral_constant {
12746ae26e7SJonas Toth   static constexpr const Tp value = v;
12846ae26e7SJonas Toth   using value_type = Tp;
12946ae26e7SJonas Toth   using type = integral_constant;
operator value_typeintegral_constant13046ae26e7SJonas Toth   constexpr operator value_type() const noexcept { return value; }
operator ()integral_constant13146ae26e7SJonas Toth   constexpr value_type operator()() const noexcept { return value; }
13246ae26e7SJonas Toth };
13346ae26e7SJonas Toth 
13446ae26e7SJonas Toth template <typename T>
13546ae26e7SJonas Toth struct is_integral : integral_constant<bool, false> {};
13646ae26e7SJonas Toth template <>
13746ae26e7SJonas Toth struct is_integral<int> : integral_constant<bool, true> {};
13846ae26e7SJonas Toth 
13946ae26e7SJonas Toth template <typename T>
14046ae26e7SJonas Toth struct not_integral : integral_constant<bool, false> {};
14146ae26e7SJonas Toth template <>
14246ae26e7SJonas Toth struct not_integral<double> : integral_constant<bool, true> {};
14346ae26e7SJonas Toth 
14446ae26e7SJonas Toth template <bool, typename Tp = void>
14546ae26e7SJonas Toth struct enable_if {};
14646ae26e7SJonas Toth 
14746ae26e7SJonas Toth template <typename Tp>
14846ae26e7SJonas Toth struct enable_if<true, Tp> { using type = Tp; };
14946ae26e7SJonas Toth 
15046ae26e7SJonas Toth template <typename T>
15146ae26e7SJonas Toth struct TMPClass {
alwaysConstTMPClass15246ae26e7SJonas Toth   T alwaysConst() const { return T{}; }
15346ae26e7SJonas Toth 
15446ae26e7SJonas Toth   template <typename T2 = T, typename = typename enable_if<is_integral<T2>::value>::type>
sometimesConstTMPClass15546ae26e7SJonas Toth   T sometimesConst() const { return T{}; }
15646ae26e7SJonas Toth 
15746ae26e7SJonas Toth   template <typename T2 = T, typename = typename enable_if<not_integral<T2>::value>::type>
sometimesConstTMPClass15846ae26e7SJonas Toth   T sometimesConst() { return T{}; }
15946ae26e7SJonas Toth };
16046ae26e7SJonas Toth 
meta_type()16146ae26e7SJonas Toth void meta_type() {
16246ae26e7SJonas Toth   TMPClass<int> p_local0;
16346ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'TMPClass<int>' can be declared 'const'
16446ae26e7SJonas Toth   // CHECK-FIXES: TMPClass<int> const p_local0;
16546ae26e7SJonas Toth   p_local0.alwaysConst();
16646ae26e7SJonas Toth   p_local0.sometimesConst();
16746ae26e7SJonas Toth 
16846ae26e7SJonas Toth   TMPClass<double> p_local1;
16946ae26e7SJonas Toth   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'TMPClass<double>' can be declared 'const'
17046ae26e7SJonas Toth   // CHECK-FIXES: TMPClass<double> const p_local1;
17146ae26e7SJonas Toth   p_local1.alwaysConst();
17246ae26e7SJonas Toth 
17346ae26e7SJonas Toth   TMPClass<double> p_local2; // Don't attempt to make this const
17446ae26e7SJonas Toth   p_local2.sometimesConst();
17546ae26e7SJonas Toth }
176