1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// RUN: %check_clang_tidy %s misc-const-correctness %t -- \
// RUN: -config="{CheckOptions: [\
// RUN: {key: 'misc-const-correctness.TransformValues', value: true},\
// RUN: {key: 'misc-const-correctness.WarnPointersAsValues', value: false}, \
// RUN: {key: 'misc-const-correctness.TransformPointersAsValues', value: false}, \
// RUN: ]}" -- -fno-delayed-template-parsing
bool global;
char np_global = 0; // globals can't be known to be const
namespace foo {
int scoped;
float np_scoped = 1; // namespace variables are like globals
} // namespace foo
// Lambdas should be ignored, because they do not follow the normal variable
// semantic (e.g. the type is only known to the compiler).
void lambdas() {
auto Lambda = [](int i) { return i < 0; };
}
void some_function(double, wchar_t);
void some_function(double np_arg0, wchar_t np_arg1) {
int p_local0 = 2;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
// CHECK-FIXES: int const p_local0 = 2;
}
void nested_scopes() {
{
int p_local1 = 42;
// CHECK-MESSAGES: [[@LINE-1]]:5: warning: variable 'p_local1' of type 'int' can be declared 'const'
// CHECK-FIXES: int const p_local1 = 42;
}
}
template <typename T>
void define_locals(T np_arg0, T &np_arg1, int np_arg2) {
T np_local0 = 0;
int p_local1 = 42;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'int' can be declared 'const'
// CHECK-FIXES: int const p_local1 = 42;
}
void template_instantiation() {
const int np_local0 = 42;
int np_local1 = 42;
define_locals(np_local0, np_local1, np_local0);
define_locals(np_local1, np_local1, np_local1);
}
struct ConstNonConstClass {
ConstNonConstClass();
ConstNonConstClass(double &np_local0);
double nonConstMethod() {}
double constMethod() const {}
double modifyingMethod(double &np_arg0) const;
double NonConstMember;
const double ConstMember;
double &NonConstMemberRef;
const double &ConstMemberRef;
double *NonConstMemberPtr;
const double *ConstMemberPtr;
};
void direct_class_access() {
ConstNonConstClass p_local0;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass' can be declared 'const'
// CHECK-FIXES: ConstNonConstClass const p_local0;
p_local0.constMethod();
}
void class_access_array() {
ConstNonConstClass p_local0[2];
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'ConstNonConstClass[2]' can be declared 'const'
// CHECK-FIXES: ConstNonConstClass const p_local0[2];
p_local0[0].constMethod();
}
struct MyVector {
double *begin();
const double *begin() const;
double *end();
const double *end() const;
double &operator[](int index);
double operator[](int index) const;
double values[100];
};
void vector_usage() {
double p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.};
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'double[10]' can be declared 'const'
// CHECK-FIXES: double const p_local0[10] = {0., 1., 2., 3., 4., 5., 6., 7., 8., 9.};
}
void range_for() {
int np_local0[2] = {1, 2};
// The transformation is not possible because the range-for-loop mutates the array content.
int *const np_local1[2] = {&np_local0[0], &np_local0[1]};
for (int *non_const_ptr : np_local1) {
*non_const_ptr = 45;
}
int *np_local2[2] = {&np_local0[0], &np_local0[1]};
for (int *non_const_ptr : np_local2) {
*non_const_ptr = 45;
}
}
void decltype_declaration() {
decltype(sizeof(void *)) p_local0 = 42;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'decltype(sizeof(void *))'
// CHECK-FIXES: decltype(sizeof(void *)) const p_local0 = 42;
}
// Taken from libcxx/include/type_traits and improved readability.
template <class Tp, Tp v>
struct integral_constant {
static constexpr const Tp value = v;
using value_type = Tp;
using type = integral_constant;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
template <typename T>
struct is_integral : integral_constant<bool, false> {};
template <>
struct is_integral<int> : integral_constant<bool, true> {};
template <typename T>
struct not_integral : integral_constant<bool, false> {};
template <>
struct not_integral<double> : integral_constant<bool, true> {};
template <bool, typename Tp = void>
struct enable_if {};
template <typename Tp>
struct enable_if<true, Tp> { using type = Tp; };
template <typename T>
struct TMPClass {
T alwaysConst() const { return T{}; }
template <typename T2 = T, typename = typename enable_if<is_integral<T2>::value>::type>
T sometimesConst() const { return T{}; }
template <typename T2 = T, typename = typename enable_if<not_integral<T2>::value>::type>
T sometimesConst() { return T{}; }
};
void meta_type() {
TMPClass<int> p_local0;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'TMPClass<int>' can be declared 'const'
// CHECK-FIXES: TMPClass<int> const p_local0;
p_local0.alwaysConst();
p_local0.sometimesConst();
TMPClass<double> p_local1;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local1' of type 'TMPClass<double>' can be declared 'const'
// CHECK-FIXES: TMPClass<double> const p_local1;
p_local1.alwaysConst();
TMPClass<double> p_local2; // Don't attempt to make this const
p_local2.sometimesConst();
}
|