189a1d03eSRichard // RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t -- \
2*e8a3ddafSNathan James // RUN:     -config='{CheckOptions: {cppcoreguidelines-pro-bounds-constant-array-index.GslHeader: "dir1/gslheader.h"}}'
389a1d03eSRichard // CHECK-FIXES: #include "dir1/gslheader.h"
489a1d03eSRichard 
589a1d03eSRichard typedef __SIZE_TYPE__ size_t;
689a1d03eSRichard 
789a1d03eSRichard namespace std {
889a1d03eSRichard   template<typename T, size_t N>
989a1d03eSRichard   struct array {
1089a1d03eSRichard     T& operator[](size_t n);
1189a1d03eSRichard     T& at(size_t n);
1289a1d03eSRichard   };
1389a1d03eSRichard }
1489a1d03eSRichard 
1589a1d03eSRichard 
1689a1d03eSRichard namespace gsl {
1789a1d03eSRichard   template<class T, size_t N>
1889a1d03eSRichard   T& at( T(&a)[N], size_t index );
1989a1d03eSRichard 
2089a1d03eSRichard   template<class T, size_t N>
2189a1d03eSRichard   T& at( std::array<T, N> &a, size_t index );
2289a1d03eSRichard }
2389a1d03eSRichard 
const_index(int base)2489a1d03eSRichard constexpr int const_index(int base) {
2589a1d03eSRichard   return base + 3;
2689a1d03eSRichard }
2789a1d03eSRichard 
f(std::array<int,10> a,int pos)2889a1d03eSRichard void f(std::array<int, 10> a, int pos) {
2989a1d03eSRichard   a [ pos / 2 /*comment*/] = 1;
3089a1d03eSRichard   // 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]
3189a1d03eSRichard   // CHECK-FIXES: gsl::at(a,  pos / 2 /*comment*/) = 1;
3289a1d03eSRichard   int j = a[pos - 1];
3389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression
3489a1d03eSRichard   // CHECK-FIXES: int j = gsl::at(a, pos - 1);
3589a1d03eSRichard 
3689a1d03eSRichard   a.at(pos-1) = 2; // OK, at() instead of []
3789a1d03eSRichard   gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
3889a1d03eSRichard 
3989a1d03eSRichard   a[-1] = 3;
4089a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
4189a1d03eSRichard   a[10] = 4;
4289a1d03eSRichard   // 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]
4389a1d03eSRichard 
4489a1d03eSRichard   a[const_index(7)] = 3;
4589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
4689a1d03eSRichard 
4789a1d03eSRichard   a[0] = 3; // OK, constant index and inside bounds
4889a1d03eSRichard   a[1] = 3; // OK, constant index and inside bounds
4989a1d03eSRichard   a[9] = 3; // OK, constant index and inside bounds
5089a1d03eSRichard   a[const_index(6)] = 3; // OK, constant index and inside bounds
5189a1d03eSRichard }
5289a1d03eSRichard 
g()5389a1d03eSRichard void g() {
5489a1d03eSRichard   int a[10];
5589a1d03eSRichard   for (int i = 0; i < 10; ++i) {
5689a1d03eSRichard     a[i] = i;
5789a1d03eSRichard     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression
5889a1d03eSRichard     // CHECK-FIXES: gsl::at(a, i) = i;
5989a1d03eSRichard     gsl::at(a, i) = i; // OK, gsl::at() instead of []
6089a1d03eSRichard   }
6189a1d03eSRichard 
6289a1d03eSRichard   a[-1] = 3; // flagged by clang-diagnostic-array-bounds
6389a1d03eSRichard   a[10] = 4; // flagged by clang-diagnostic-array-bounds
6489a1d03eSRichard   a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
6589a1d03eSRichard 
6689a1d03eSRichard   a[0] = 3; // OK, constant index and inside bounds
6789a1d03eSRichard   a[1] = 3; // OK, constant index and inside bounds
6889a1d03eSRichard   a[9] = 3; // OK, constant index and inside bounds
6989a1d03eSRichard   a[const_index(6)] = 3; // OK, constant index and inside bounds
7089a1d03eSRichard }
7189a1d03eSRichard 
7289a1d03eSRichard struct S {
7389a1d03eSRichard   int& operator[](int i);
7489a1d03eSRichard };
7589a1d03eSRichard 
customOperator()7689a1d03eSRichard void customOperator() {
7789a1d03eSRichard   S s;
7889a1d03eSRichard   int i = 0;
7989a1d03eSRichard   s[i] = 3; // OK, custom operator
8089a1d03eSRichard }
81