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 | |
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 | |
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(n: pos-1) = 2; // OK, at() instead of [] |
36 | gsl::at(a, index: 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(base: 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(base: 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(n: pos-1) = 2; // OK, at() instead of [] |
59 | gsl::at(a&: m, index: 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(base: 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(base: 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: |
77 | T& operator[](size_t n){ |
78 | return std::array<T, N>::operator[](static_cast<int>(n)); |
79 | }; |
80 | T& at(size_t n) { |
81 | return std::array<T, N>::at(static_cast<int>(n)); |
82 | }; |
83 | }; |
84 | |
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(n: pos-1) = 2; // OK, at() instead of [] |
92 | gsl::at(a, index: 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(base: 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(base: 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(n: pos-1) = 2; // OK, at() instead of [] |
115 | gsl::at(a&: m, index: 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(base: 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(base: 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(n: pos-1) = 2; // OK, at() instead of [] |
135 | pm[-1] = 3; |
136 | pm[10] = 4; |
137 | |
138 | pm[const_index(base: 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(base: 6)] = 3; // OK, constant index and inside bounds |
144 | } |
145 | |
146 | |
147 | |
148 | |
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, index: 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(base: 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(base: 6)] = 3; // OK, constant index and inside bounds |
166 | } |
167 | |
168 | struct S { |
169 | int& operator[](int i); |
170 | }; |
171 | |
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 | |
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 | |
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 |
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 | |