1 // RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t
2 
3 typedef __SIZE_TYPE__ size_t;
4 
5 namespace std {
6   template<typename T, size_t N>
7   struct array {
8     T& operator[](size_t n);
9     T& at(size_t n);
10   };
11 }
12 
13 
14 namespace gsl {
15   template<class T, size_t N>
16   T& at( T(&a)[N], size_t index );
17 
18   template<class T, size_t N>
19   T& at( std::array<T, N> &a, size_t index );
20 }
21 
const_index(int base)22 constexpr int const_index(int base) {
23   return base + 3;
24 }
25 
26 template<class T, size_t N>
27 class DerivedArray : public std::array<T, N> {};
28 
f(std::array<int,10> a,int pos)29 void f(std::array<int, 10> a, int pos) {
30   a [ pos / 2 /*comment*/] = 1;
31   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
32   int j = a[pos - 1];
33   // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression
34 
35   a.at(pos-1) = 2; // OK, at() instead of []
36   gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
37 
38   a[-1] = 3;
39   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
40   a[10] = 4;
41   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
42 
43   a[const_index(7)] = 3;
44   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
45 
46   a[0] = 3; // OK, constant index and inside bounds
47   a[1] = 3; // OK, constant index and inside bounds
48   a[9] = 3; // OK, constant index and inside bounds
49   a[const_index(6)] = 3; // OK, constant index and inside bounds
50 
51   using MyArray = std::array<int, 10>;
52   MyArray m{};
53   m [ pos / 2 /*comment*/] = 1;
54   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
55   int jj = m[pos - 1];
56   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression
57 
58   m.at(pos-1) = 2; // OK, at() instead of []
59   gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []
60   m[-1] = 3;
61   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
62   m[10] = 4;
63   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
64 
65   m[const_index(7)] = 3;
66   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
67 
68   m[0] = 3; // OK, constant index and inside bounds
69   m[1] = 3; // OK, constant index and inside bounds
70   m[9] = 3; // OK, constant index and inside bounds
71   m[const_index(6)] = 3; // OK, constant index and inside bounds
72 }
73 
74 template<class T, size_t N>
75 class PrivateDerivedArray : std::array<T, N> {
76 public:
operator [](size_t n)77   T& operator[](size_t n){
78     return std::array<T, N>::operator[](static_cast<int>(n));
79   };
at(size_t n)80   T& at(size_t n) {
81     return std::array<T, N>::at(static_cast<int>(n));
82   };
83 };
84 
f_derived(DerivedArray<int,10> a,int pos)85 void f_derived(DerivedArray<int, 10> a, int pos) {
86   a [ pos / 2 /*comment*/] = 1;
87   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
88   int j = a[pos - 1];
89   // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression
90 
91   a.at(pos-1) = 2; // OK, at() instead of []
92   gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
93 
94   a[-1] = 3;
95   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
96   a[10] = 4;
97   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
98 
99   a[const_index(7)] = 3;
100   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
101 
102   a[0] = 3; // OK, constant index and inside bounds
103   a[1] = 3; // OK, constant index and inside bounds
104   a[9] = 3; // OK, constant index and inside bounds
105   a[const_index(6)] = 3; // OK, constant index and inside bounds
106 
107   using MyArray = DerivedArray<int, 10>;
108   MyArray m{};
109   m [ pos / 2 /*comment*/] = 1;
110   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression [cppcoreguidelines-pro-bounds-constant-array-index]
111   int jj = m[pos - 1];
112   // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use array subscript when the index is not an integer constant expression
113 
114   m.at(pos-1) = 2; // OK, at() instead of []
115   gsl::at(m, pos-1) = 2; // OK, gsl::at() instead of []
116   m[-1] = 3;
117   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
118   m[10] = 4;
119   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
120 
121   m[const_index(7)] = 3;
122   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
123 
124   m[0] = 3; // OK, constant index and inside bounds
125   m[1] = 3; // OK, constant index and inside bounds
126   m[9] = 3; // OK, constant index and inside bounds
127   m[const_index(6)] = 3; // OK, constant index and inside bounds
128 
129   using MyPrivateArray = PrivateDerivedArray<int, 10>;
130   MyPrivateArray pm{};
131   pm [ pos / 2 /*comment*/] = 1;
132   int jjj = pm[pos - 1];
133 
134   pm.at(pos-1) = 2; // OK, at() instead of []
135   pm[-1] = 3;
136   pm[10] = 4;
137 
138   pm[const_index(7)] = 3;
139 
140   pm[0] = 3; // OK, constant index and inside bounds
141   pm[1] = 3; // OK, constant index and inside bounds
142   pm[9] = 3; // OK, constant index and inside bounds
143   pm[const_index(6)] = 3; // OK, constant index and inside bounds
144 }
145 
146 
147 
148 
g()149 void g() {
150   int a[10];
151   for (int i = 0; i < 10; ++i) {
152     a[i] = i;
153     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression
154     // CHECK-FIXES: gsl::at(a, i) = i;
155     gsl::at(a, i) = i; // OK, gsl::at() instead of []
156   }
157 
158   a[-1] = 3; // flagged by clang-diagnostic-array-bounds
159   a[10] = 4; // flagged by clang-diagnostic-array-bounds
160   a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
161 
162   a[0] = 3; // OK, constant index and inside bounds
163   a[1] = 3; // OK, constant index and inside bounds
164   a[9] = 3; // OK, constant index and inside bounds
165   a[const_index(6)] = 3; // OK, constant index and inside bounds
166 }
167 
168 struct S {
169   int& operator[](int i);
170 };
171 
customOperator()172 void customOperator() {
173   S s;
174   int i = 0;
175   s[i] = 3; // OK, custom operator
176 }
177 
178 namespace ArrayInitIndexExpr {
179 struct A {
180   // The compiler-generated copy constructor uses an ArraySubscriptExpr. Don't warn.
181   int x[3];
182 };
183 
implicitCopyMoveCtor()184 void implicitCopyMoveCtor() {
185   // Force the compiler to generate a copy constructor.
186   A a;
187   A a2(a);
188 
189   // Force the compiler to generate a move constructor.
190   A a3 = (A&&) a;
191 }
192 
lambdaCapture()193 void lambdaCapture() {
194   int arr[3];
195 
196   // Capturing an array by value uses an ArraySubscriptExpr. Don't warn.
197   [arr](){};
198 }
199 
200 #if __cplusplus >= 201703L
structuredBindings()201 void structuredBindings() {
202   int arr[3];
203 
204   // Creating structured bindings by value uses an ArraySubscriptExpr. Don't warn.
205   auto [a,b,c] = arr;
206 }
207 #endif
208 } // namespace ArrayInitIndexExpr
209