diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -74,8 +74,12 @@ difference_type operator-(const __vector_iterator &rhs); Ref operator*() const { return *ptr; } - Ptr operator->() const { return *ptr; } + Ptr operator->() const { return ptr; } + Ref operator[](difference_type n) { + return *(ptr+n); + } + bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; } bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; } @@ -125,8 +129,12 @@ } Ref operator*() const { return *ptr; } - Ptr operator->() const { return *ptr; } + Ptr operator->() const { return ptr; } + Ref operator[](difference_type n) { + return *(ptr+n); + } + bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; } bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; } @@ -165,7 +173,7 @@ } Ref operator*() const { return item->data; } - Ptr operator->() const { return item->data; } + Ptr operator->() const { return &item->data; } bool operator==(const iterator &rhs) const { return item == rhs->item; } bool operator==(const const_iterator &rhs) const { return item == rhs->item; } @@ -201,7 +209,7 @@ return tmp; } Ref operator*() const { return item->data; } - Ptr operator->() const { return item->data; } + Ptr operator->() const { return &item->data; } bool operator==(const iterator &rhs) const { return item == rhs->item; } bool operator==(const const_iterator &rhs) const { return item == rhs->item; } @@ -255,15 +263,16 @@ template class vector { + T *_start; + T *_finish; + T *_end_of_storage; + + public: typedef T value_type; typedef size_t size_type; typedef __vector_iterator iterator; typedef __vector_iterator const_iterator; - T *_start; - T *_finish; - T *_end_of_storage; - public: vector() : _start(0), _finish(0), _end_of_storage(0) {} template vector(InputIterator first, InputIterator last); @@ -333,6 +342,7 @@ T data; __item *prev, *next; } *_start, *_finish; + public: typedef T value_type; typedef size_t size_type; @@ -399,15 +409,16 @@ template class deque { + T *_start; + T *_finish; + T *_end_of_storage; + + public: typedef T value_type; typedef size_t size_type; typedef __deque_iterator iterator; typedef __deque_iterator const_iterator; - T *_start; - T *_finish; - T *_end_of_storage; - public: deque() : _start(0), _finish(0), _end_of_storage(0) {} template deque(InputIterator first, InputIterator last); @@ -483,6 +494,7 @@ T data; __item *next; } *_start; + public: typedef T value_type; typedef size_t size_type; diff --git a/clang/test/Analysis/diagnostics/explicit-suppression.cpp b/clang/test/Analysis/diagnostics/explicit-suppression.cpp --- a/clang/test/Analysis/diagnostics/explicit-suppression.cpp +++ b/clang/test/Analysis/diagnostics/explicit-suppression.cpp @@ -19,6 +19,6 @@ void testCopyNull(C *I, C *E) { std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:686 {{Called C++ object pointer is null}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:698 {{Called C++ object pointer is null}} #endif } diff --git a/clang/test/Analysis/invalidated-iterator.cpp b/clang/test/Analysis/invalidated-iterator.cpp --- a/clang/test/Analysis/invalidated-iterator.cpp +++ b/clang/test/Analysis/invalidated-iterator.cpp @@ -5,760 +5,119 @@ void clang_analyzer_warnIfReached(); -void bad_copy_assign_operator1_list(std::list &L1, - const std::list &L2) { - auto i0 = L1.cbegin(); - L1 = L2; - *i0; // expected-warning{{Invalidated iterator accessed}} - clang_analyzer_warnIfReached(); +void normal_dereference(std::vector &V) { + auto i = V.cbegin(); + *i; // no-warning } -void bad_copy_assign_operator1_vector(std::vector &V1, - const std::vector &V2) { - auto i0 = V1.cbegin(); - V1 = V2; - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_dereference(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + *i; // expected-warning{{Invalidated iterator accessed}} } -void bad_copy_assign_operator1_deque(std::deque &D1, - const std::deque &D2) { - auto i0 = D1.cbegin(); - D1 = D2; - *i0; // expected-warning{{Invalidated iterator accessed}} +void normal_prefix_increment(std::vector &V) { + auto i = V.cbegin(); + ++i; // no-warning } -void bad_copy_assign_operator1_forward_list(std::forward_list &FL1, - const std::forward_list &FL2) { - auto i0 = FL1.cbegin(); - FL1 = FL2; - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_prefix_increment(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + ++i; // expected-warning{{Invalidated iterator accessed}} } -void bad_assign1_list(std::list &L, int n) { - auto i0 = L.cbegin(); - L.assign(10, n); - *i0; // expected-warning{{Invalidated iterator accessed}} +void normal_prefix_decrement(std::vector &V) { + auto i = ++V.cbegin(); + --i; // no-warning } -void bad_assign1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(); - V.assign(10, n); - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_prefix_decrement(std::vector &V) { + auto i = ++V.cbegin(); + V.erase(i); + --i; // expected-warning{{Invalidated iterator accessed}} } -void bad_assign1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(); - D.assign(10, n); - *i0; // expected-warning{{Invalidated iterator accessed}} +void normal_postfix_increment(std::vector &V) { + auto i = V.cbegin(); + i++; // no-warning } -void bad_assign1_forward_list(std::forward_list &FL, int n) { - auto i0 = FL.cbegin(); - FL.assign(10, n); - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_postfix_increment(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + i++; // expected-warning{{Invalidated iterator accessed}} } -void good_clear1_list(std::list &L) { - auto i0 = L.cend(); - L.clear(); - --i0; // no-warning +void normal_postfix_decrement(std::vector &V) { + auto i = ++V.cbegin(); + i--; // no-warning } -void bad_clear1_list(std::list &L) { - auto i0 = L.cbegin(), i1 = L.cend(); - L.clear(); - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_postfix_decrement(std::vector &V) { + auto i = ++V.cbegin(); + V.erase(i); + i--; // expected-warning{{Invalidated iterator accessed}} } -void bad_clear1_vector(std::vector &V) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.clear(); - *i0; // expected-warning{{Invalidated iterator accessed}} +void normal_increment_by_2(std::vector &V) { + auto i = V.cbegin(); + i += 2; // no-warning } -void bad_clear1_vector_decr(std::vector &V) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.clear(); - --i1; // expected-warning{{Invalidated iterator accessed}} +void invalidated_increment_by_2(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + i += 2; // expected-warning{{Invalidated iterator accessed}} } -void bad_clear1_deque(std::deque &D) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.clear(); - *i0; // expected-warning{{Invalidated iterator accessed}} +void normal_increment_by_2_copy(std::vector &V) { + auto i = V.cbegin(); + auto j = i + 2; // no-warning } -void bad_clear1_deque_decr(std::deque &D) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.clear(); - --i1; // expected-warning{{Invalidated iterator accessed}} +void invalidated_increment_by_2_copy(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + auto j = i + 2; // expected-warning{{Invalidated iterator accessed}} } -void good_push_back1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(); - L.push_back(n); - *i0; // no-warning - --i1; // no-warning +void normal_decrement_by_2(std::vector &V) { + auto i = V.cbegin(); + i -= 2; // no-warning } -void good_push_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.push_back(n); - *i0; // no-warning +void invalidated_decrement_by_2(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + i -= 2; // expected-warning{{Invalidated iterator accessed}} } -void bad_push_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.push_back(n); - --i1; // expected-warning{{Invalidated iterator accessed}} +void normal_decrement_by_2_copy(std::vector &V) { + auto i = V.cbegin(); + auto j = i - 2; // no-warning } -void bad_push_back1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.push_back(n); - *i0; // expected-warning{{Invalidated iterator accessed}} +void invalidated_decrement_by_2_copy(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + auto j = i - 2; // expected-warning{{Invalidated iterator accessed}} } -void bad_push_back1_deque_decr(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.push_back(n); - --i1; // expected-warning{{Invalidated iterator accessed}} +void normal_subscript(std::vector &V) { + auto i = V.cbegin(); + i[1]; // no-warning } -void good_emplace_back1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(); - L.emplace_back(n); - *i0; // no-warning - --i1; // no-warning +void invalidated_subscript(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + i[1]; // expected-warning{{Invalidated iterator accessed}} } -void good_emplace_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.emplace_back(n); - *i0; // no-warning +void assignment(std::vector &V) { + auto i = V.cbegin(); + V.erase(i); + auto j = V.cbegin(); // no-warning } -void bad_emplace_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(); - V.emplace_back(n); - --i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_emplace_back1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.emplace_back(n); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_emplace_back1_deque_decr(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.emplace_back(n); - --i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_pop_back1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(), i2 = i1--; - L.pop_back(); - *i0; // no-warning - *i2; // no-warning -} - -void bad_pop_back1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(), i2 = i1--; - L.pop_back(); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_pop_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(), i2 = i1--; - V.pop_back(); - *i0; // no-warning -} - -void bad_pop_back1_vector(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(), i2 = i1--; - V.pop_back(); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_pop_back1_vector_decr(std::vector &V, int n) { - auto i0 = V.cbegin(), i1 = V.cend(), i2 = i1--; - V.pop_back(); - --i2; // expected-warning{{Invalidated iterator accessed}} -} - -void good_pop_back1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(), i2 = i1--; - D.pop_back(); - *i0; // no-warning -} - -void bad_pop_back1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(), i2 = i1--; - D.pop_back(); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_pop_back1_deque_decr(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(), i2 = i1--; - D.pop_back(); - --i2; // expected-warning{{Invalidated iterator accessed}} -} - -void good_push_front1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(); - L.push_front(n); - *i0; // no-warning - --i1; // no-warning -} - -void bad_push_front1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.push_front(n); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_push_front1_deque_decr(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.push_front(n); - --i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_push_front1_forward_list(std::forward_list &FL, int n) { - auto i0 = FL.cbegin(), i1 = FL.cend(); - FL.push_front(n); - *i0; // no-warning -} - -void good_emplace_front1_list(std::list &L, int n) { - auto i0 = L.cbegin(), i1 = L.cend(); - L.emplace_front(n); - *i0; // no-warning - --i1; // no-warning -} - -void bad_emplace_front1_deque(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.emplace_front(n); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_emplace_front1_deque_decr(std::deque &D, int n) { - auto i0 = D.cbegin(), i1 = D.cend(); - D.emplace_front(n); - --i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_emplace_front1_forward_list(std::forward_list &FL, int n) { - auto i0 = FL.cbegin(), i1 = FL.cend(); - FL.emplace_front(n); - *i0; // no-warning -} - -void good_pop_front1_list(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.pop_front(); - *i1; // no-warning -} - -void bad_pop_front1_list(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.pop_front(); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void good_pop_front1_deque(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.pop_front(); - *i1; // no-warning -} - -void bad_pop_front1_deque(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.pop_front(); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void good_pop_front1_forward_list(std::forward_list &FL, int n) { - auto i1 = FL.cbegin(), i0 = i1++; - FL.pop_front(); - *i1; // no-warning -} - -void bad_pop_front1_forward_list(std::forward_list &FL, int n) { - auto i1 = FL.cbegin(), i0 = i1++; - FL.pop_front(); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert1_list1(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.insert(i1, n); - *i0; // no-warning - *i1; // no-warning -} - -void good_insert1_list2(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - i1 = L.insert(i1, n); - *i1; // no-warning -} - -void good_insert1_vector1(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, n); - *i0; // no-warning -} - -void good_insert1_vector2(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - i1 = V.insert(i1, n); - *i1; // no-warning -} - -void bad_insert1_vector(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, n); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert1_deque(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - i0 = D.insert(i1, n); - *i0; // no-warning -} - -void bad_insert1_deque1(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, n); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_insert1_deque2(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, n); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert2_list1(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.insert(i1, std::move(n)); - *i0; // no-warning - *i1; // no-warning -} - -void good_insert2_list2(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - i1 = L.insert(i1, std::move(n)); - *i1; // no-warning -} - -void good_insert2_vector1(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, std::move(n)); - *i0; // no-warning -} - -void good_insert2_vector2(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - i1 = V.insert(i1, std::move(n)); - *i1; // no-warning -} - -void bad_insert2_vector(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, std::move(n)); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert2_deque(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - i1 = D.insert(i1, std::move(n)); - *i1; // no-warning -} - -void bad_insert2_deque1(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, std::move(n)); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_insert2_deque2(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, std::move(n)); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert3_list1(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.insert(i1, 10, n); - *i0; // no-warning - *i1; // no-warning -} - -void good_insert3_list2(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - i1 = L.insert(i1, 10, n); - *i1; // no-warning -} - -void good_insert3_vector1(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, 10, n); - *i0; // no-warning -} - -void good_insert3_vector2(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - i1 = V.insert(i1, 10, n); - *i1; // no-warning -} - -void bad_insert3_vector(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, 10, n); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert3_deque(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - i1 = D.insert(i1, 10, std::move(n)); - *i1; // no-warning -} - -void bad_insert3_deque1(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, 10, std::move(n)); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_insert3_deque2(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, 10, std::move(n)); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert4_list1(std::list &L1, std::list &L2, int n) { - auto i1 = L1.cbegin(), i0 = i1++; - L1.insert(i1, L2.cbegin(), L2.cend()); - *i0; // no-warning - *i1; // no-warning -} - -void good_insert4_list2(std::list &L1, std::list &L2, int n) { - auto i1 = L1.cbegin(), i0 = i1++; - i1 = L1.insert(i1, L2.cbegin(), L2.cend()); - *i1; // no-warning -} - -void good_insert4_vector1(std::vector &V1, std::vector &V2, int n) { - auto i1 = V1.cbegin(), i0 = i1++; - V1.insert(i1, V2.cbegin(), V2.cend()); - *i0; // no-warning -} - -void good_insert4_vector2(std::vector &V1, std::vector &V2, int n) { - auto i1 = V1.cbegin(), i0 = i1++; - i1 = V1.insert(i1, V2.cbegin(), V2.cend()); - *i1; // no-warning -} - -void bad_insert4_vector(std::vector &V1, std::vector &V2, int n) { - auto i1 = V1.cbegin(), i0 = i1++; - V1.insert(i1, V2.cbegin(), V2.cend()); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert4_deque(std::deque &D1, std::deque &D2, int n) { - auto i1 = D1.cbegin(), i0 = i1++; - i1 = D1.insert(i1, D2.cbegin(), D2.cend()); - *i1; // no-warning -} - -void bad_insert4_deque1(std::deque &D1, std::deque &D2, int n) { - auto i1 = D1.cbegin(), i0 = i1++; - D1.insert(i1, D2.cbegin(), D2.cend()); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_insert4_deque2(std::deque &D1, std::deque &D2, int n) { - auto i1 = D1.cbegin(), i0 = i1++; - D1.insert(i1, D2.cbegin(), D2.cend()); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert5_list1(std::list &L) { - auto i1 = L.cbegin(), i0 = i1++; - L.insert(i1, {1, 2, 3, 4}); - *i0; // no-warning - *i1; // no-warning -} - -void good_insert5_list2(std::list &L) { - auto i1 = L.cbegin(), i0 = i1++; - i1 = L.insert(i1, {1, 2, 3, 4}); - *i1; // no-warning -} - -void good_insert5_vector1(std::vector &V) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, {1, 2, 3, 4}); - *i0; // no-warning -} - -void good_insert5_vector2(std::vector &V) { - auto i1 = V.cbegin(), i0 = i1++; - i1 = V.insert(i1, {1, 2, 3, 4}); - *i1; // no-warning -} - -void bad_insert5_vector(std::vector &V) { - auto i1 = V.cbegin(), i0 = i1++; - V.insert(i1, {1, 2, 3, 4}); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_insert5_deque(std::deque &D) { - auto i1 = D.cbegin(), i0 = i1++; - i1 = D.insert(i1, {1, 2, 3, 4}); - *i1; // no-warning -} - -void bad_insert5_deque1(std::deque &D) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, {1, 2, 3, 4}); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_insert5_deque2(std::deque &D) { - auto i1 = D.cbegin(), i0 = i1++; - D.insert(i1, {1, 2, 3, 4}); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_emplace1_list(std::list &L, int n) { - auto i1 = L.cbegin(), i0 = i1++; - L.emplace(i1, n); - *i0; // no-warning - *i1; // no-warning -} - -void good_emplace1_vector(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.emplace(i1, n); - *i0; // no-warning -} - -void bad_emplace1_vector(std::vector &V, int n) { - auto i1 = V.cbegin(), i0 = i1++; - V.emplace(i1, n); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_emplace1_deque1(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.emplace(i1, n); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_emplace1_deque2(std::deque &D, int n) { - auto i1 = D.cbegin(), i0 = i1++; - D.emplace(i1, n); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase1_list1(std::list &L) { - auto i2 = L.cbegin(), i0 = i2++, i1 = i2++; - L.erase(i1); - *i0; // no-warning - *i2; // no-warning -} - -void good_erase1_list2(std::list &L) { - auto i0 = L.cbegin(); - i0 = L.erase(i0); - *i0; // no-warning -} - -void bad_erase1_list(std::list &L) { - auto i0 = L.cbegin(); - L.erase(i0); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase1_vector1(std::vector &V) { - auto i2 = V.cbegin(), i0 = i2++, i1 = i2++; - V.erase(i1); - *i0; // no-warning -} - -void good_erase1_vector2(std::vector &V) { - auto i0 = V.cbegin(); - i0 = V.erase(i0); - *i0; // no-warning -} - -void bad_erase1_vector1(std::vector &V) { - auto i1 = V.cbegin(), i0 = i1++; - V.erase(i0); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase1_vector2(std::vector &V) { - auto i1 = V.cbegin(), i0 = i1++; - V.erase(i0); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase1_deque(std::deque &D) { - auto i0 = D.cbegin(); - i0 = D.erase(i0); - *i0; // no-warning -} - -void bad_erase1_deque1(std::deque &D) { - auto i2 = D.cbegin(), i0 = i2++, i1 = i2++; - D.erase(i1); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase1_deque2(std::deque &D) { - auto i2 = D.cbegin(), i0 = i2++, i1 = i2++; - D.erase(i1); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase1_deque3(std::deque &D) { - auto i2 = D.cbegin(), i0 = i2++, i1 = i2++; - D.erase(i1); - *i2; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase2_list1(std::list &L) { - auto i3 = L.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - L.erase(i1, i3); - *i0; // no-warning - *i3; // no-warning -} - -void good_erase2_list2(std::list &L) { - auto i2 = L.cbegin(), i0 = i2++, i1 = i2++; - i0 = L.erase(i0, i2); - *i0; // no-warning -} - -void bad_erase2_list1(std::list &L) { - auto i2 = L.cbegin(), i0 = i2++, i1 = i2++; - L.erase(i0, i2); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_list2(std::list &L) { - auto i2 = L.cbegin(), i0 = i2++, i1 = i2++; - L.erase(i0, i2); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase2_vector1(std::vector &V) { - auto i3 = V.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++;; - V.erase(i1, i3); - *i0; // no-warning -} - -void good_erase2_vector2(std::vector &V) { - auto i2 = V.cbegin(), i0 = i2++, i1 = i2++; - i0 = V.erase(i0, i2); - *i0; // no-warning -} - -void bad_erase2_vector1(std::vector &V) { - auto i2 = V.cbegin(), i0 = i2++, i1 = i2++; - V.erase(i0, i2); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_vector2(std::vector &V) { - auto i2 = V.cbegin(), i0 = i2++, i1 = i2++; - V.erase(i0, i2); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_vector3(std::vector &V) { - auto i2 = V.cbegin(), i0 = i2++, i1 = i2++; - V.erase(i0, i2); - *i2; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase2_deque(std::deque &D) { - auto i2 = D.cbegin(), i0 = i2++, i1 = i2++; - i0 = D.erase(i0, i2); - *i0; // no-warning -} - -void bad_erase2_deque1(std::deque &D) { - auto i3 = D.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - D.erase(i1, i3); - *i0; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_deque2(std::deque &D) { - auto i3 = D.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - D.erase(i1, i3); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_deque3(std::deque &D) { - auto i3 = D.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - D.erase(i1, i3); - *i2; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase2_deque4(std::deque &D) { - auto i3 = D.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - D.erase(i1, i3); - *i3; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase_after1_forward_list1(std::forward_list &FL) { - auto i2 = FL.cbegin(), i0 = i2++, i1 = i2++; - FL.erase_after(i0); - *i0; // no-warning - *i2; // no-warning -} - -void good_erase_after1_forward_lis2(std::forward_list &FL) { - auto i1 = FL.cbegin(), i0 = i1++; - i1 = FL.erase_after(i0); - *i1; // no-warning -} - -void bad_erase_after1_forward_list(std::forward_list &FL) { - auto i1 = FL.cbegin(), i0 = i1++; - FL.erase_after(i0); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void good_erase_after2_forward_list1(std::forward_list &FL) { - auto i3 = FL.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - FL.erase_after(i0, i3); - *i0; // no-warning - *i3; // no-warning -} - -void good_erase_after2_forward_list2(std::forward_list &FL) { - auto i3 = FL.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - i2 = FL.erase_after(i0, i3); - *i2; // no-warning -} - -void bad_erase_after2_forward_list1(std::forward_list &FL) { - auto i3 = FL.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - FL.erase_after(i0, i3); - *i1; // expected-warning{{Invalidated iterator accessed}} -} - -void bad_erase_after2_forward_list2(std::forward_list &FL) { - auto i3 = FL.cbegin(), i0 = i3++, i1 = i3++, i2 = i3++; - FL.erase_after(i0, i3); - *i2; // expected-warning{{Invalidated iterator accessed}} -} diff --git a/clang/test/Analysis/iterator-modelling.cpp b/clang/test/Analysis/iterator-modelling.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/iterator-modelling.cpp @@ -0,0 +1,1972 @@ +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify + +#include "Inputs/system-header-simulator-cxx.h" + +template +long clang_analyzer_container_begin(const Container&); +template +long clang_analyzer_container_end(const Container&); +template +long clang_analyzer_iterator_position(const Iterator&); +template +void* clang_analyzer_iterator_container(const Iterator&); +template +bool clang_analyzer_iterator_validity(const Iterator&); + +void clang_analyzer_denote(long, const char*); +void clang_analyzer_express(long); +void clang_analyzer_eval(bool); +void clang_analyzer_warnIfReached(); + +void begin(const std::vector &v) { + auto i = v.begin(); + + clang_analyzer_eval(clang_analyzer_iterator_container(i) == &v); // expected-warning{{TRUE}} + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.begin()}} + + if (i != v.begin()) { + clang_analyzer_warnIfReached(); + } +} + +void end(const std::vector &v) { + auto i = v.end(); + + clang_analyzer_eval(clang_analyzer_iterator_container(i) == &v); // expected-warning{{TRUE}} + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.end()}} + + if (i != v.end()) { + clang_analyzer_warnIfReached(); + } +} + +void prefix_increment(const std::vector &v) { + auto i = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto j = ++i; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(j)); //expected-warning{{$v.begin() + 1}} +} + +void prefix_decrement(const std::vector &v) { + auto i = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto j = --i; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(j)); //expected-warning{{$v.end() - 1}} +} + +void postfix_increment(const std::vector &v) { + auto i = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto j = i++; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(j)); //expected-warning{{$v.begin()}} +} + +void postfix_decrement(const std::vector &v) { + auto i = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto j = i--; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(j)); //expected-warning{{$v.end()}} +} + +void plus_equal(const std::vector &v) { + auto i = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + i += 2; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.begin() + 2}} +} + +void minus_equal(const std::vector &v) { + auto i = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + i -= 2; + + clang_analyzer_express(clang_analyzer_iterator_position(i)); //expected-warning{{$v.end() - 2}} +} + +void copy(const std::vector &v) { + auto i1 = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto i2 = i1; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &v); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.end()}} +} + +void plus(const std::vector &v) { + auto i1 = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto i2 = i1 + 2; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &v); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.begin() + 2}} +} + +void minus(const std::vector &v) { + auto i1 = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto i2 = i1 - 2; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &v); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.end() - 2}} +} + +void copy_and_increment1(const std::vector &v) { + auto i1 = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto i2 = i1; + ++i1; + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); //expected-warning{{$v.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.begin()}} +} + +void copy_and_increment2(const std::vector &v) { + auto i1 = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto i2 = i1; + ++i2; + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); //expected-warning{{$v.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.begin() + 1}} +} + +void copy_and_decrement1(const std::vector &v) { + auto i1 = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto i2 = i1; + --i1; + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); //expected-warning{{$v.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.end()}} +} + +void copy_and_decrement2(const std::vector &v) { + auto i1 = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto i2 = i1; + --i2; + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); //expected-warning{{$v.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); //expected-warning{{$v.end() - 1}} +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// C O N T A I N E R A S S I G N M E N T S +/// +//////////////////////////////////////////////////////////////////////////////// + +// Copy + +void list_copy_assignment(std::list &L1, const std::list &L2) { + auto i0 = L1.cbegin(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + L1 = L2; + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void vector_copy_assignment(std::vector &V1, const std::vector &V2) { + auto i0 = V1.cbegin(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + V1 = V2; + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void deque_copy_assignment(std::deque &D1, const std::deque &D2) { + auto i0 = D1.cbegin(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + D1 = D2; + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void forward_list_copy_assignment(std::forward_list &FL1, + const std::forward_list &FL2) { + auto i0 = FL1.cbegin(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + FL1 = FL2; + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +// Move + +void list_move_assignment(std::list &L1, std::list &L2) { + auto i0 = L1.cbegin(), i1 = L2.cbegin(), i2 = --L2.cend(), i3 = L2.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L2), "$L2.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L2), "$L2.end()"); + + L1 = std::move(L2); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} FIXME: Should be FALSE. + + clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &L1); // expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &L1); // expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L1)); // expected-warning{{$L2.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L2.begin()}} +} + +void vector_move_assignment(std::vector &V1, std::vector &V2) { + auto i0 = V1.cbegin(), i1 = V2.cbegin(), i2 = --V2.cend(), i3 = V2.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()"); + + V1 = std::move(V2); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} FIXME: Should be FALSE. + + clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &V1); // expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &V1); // expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V2.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V2.begin()}} +} + +void deque_move_assignment(std::deque &D1, std::deque &D2) { + auto i0 = D1.cbegin(), i1 = D2.cbegin(), i2 = --D2.cend(), i3 = D2.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D2), "$D2.begin()"); + + D1 = std::move(D2); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} FIXME: Should be FALSE. + + clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &D1); // expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &D1); // expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(D1)); // expected-warning{{$D2.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$D2.begin()}} +} + +void forward_list_move_assignment(std::forward_list &FL1, + std::forward_list &FL2) { + auto i0 = FL1.cbegin(), i1 = FL2.cbegin(), i2 = FL2.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL2), "$FL2.begin()"); + + FL1 = std::move(FL2); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} FIXME: Should be FALSE. + + clang_analyzer_eval(clang_analyzer_iterator_container(i1) == &FL1); // expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL1)); // expected-warning{{$FL2.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL2.begin()}} +} + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// C O N T A I N E R M O D I F I E R S +/// +//////////////////////////////////////////////////////////////////////////////// + +/// assign() +/// +/// - Invalidates all iterators, including the past-the-end iterator for all +/// container types. + +void list_assign(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = L.cend(); + L.assign(10, n); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} +} + +void vector_assign(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = V.cend(); + V.assign(10, n); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} +} + +void deque_assign(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = D.cend(); + D.assign(10, n); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} +} + +void forward_list_assign(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + FL.assign(10, n); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} +} + +/// clear() +/// +/// - Invalidates all iterators, including the past-the-end iterator for all +/// container types. + +void list_clear(std::list &L) { + auto i0 = L.cbegin(), i1 = L.cend(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + L.clear(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void vector_clear(std::vector &V) { + auto i0 = V.cbegin(), i1 = V.cend(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + V.clear(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void deque_clear(std::deque &D) { + auto i0 = D.cbegin(), i1 = D.cend(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + D.clear(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +void forward_list_clear(std::forward_list &FL) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + FL.clear(); + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} +} + +/// push_back() +/// +/// - Design decision: extends containers to the ->RIGHT-> (i.e. the +/// past-the-end position of the container is incremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_push_back(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.push_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() + 1 +} + +/// std::vector-like containers: The past-the-end iterator is invalidated. + +void vector_push_back(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.push_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_push_back(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.push_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} FIXME: Should be $D.end() + 1 (to correctly track the container's size) +} + +/// emplace_back() +/// +/// - Design decision: extends containers to the ->RIGHT-> (i.e. the +/// past-the-end position of the container is incremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_emplace_back(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.emplace_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() + 1 +} + +/// std::vector-like containers: The past-the-end iterator is invalidated. + +void vector_emplace_back(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.emplace_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_emplace_back(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.emplace_back(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} FIXME: Should be $D.end() + 1 (to correctly track the container's size) +} + +/// pop_back() +/// +/// - Design decision: shrinks containers to the <-LEFT<- (i.e. the +/// past-the-end position of the container is decremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: Iterators to the last element are invalidated. + +void list_pop_back(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.pop_back(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} FIXME: Should be $L.end() - 1 +} + +/// std::vector-like containers: Iterators to the last element, as well as the +/// past-the-end iterator, are invalidated. + +void vector_pop_back(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.pop_back(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}} +} + +/// std::deque-like containers: Iterators to the last element are invalidated. +/// The past-the-end iterator is also invalidated. +/// Other iterators are not affected. + +void deque_pop_back(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.pop_back(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$D.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end() - 1}} +} + +/// push_front() +/// +/// - Design decision: extends containers to the <-LEFT<- (i.e. the first +/// position of the container is decremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_push_front(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.push_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_push_front(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.push_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 (to correctly track the container's size) + + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} +} + +/// std::forward_list-like containers: No iterators are invalidated. + +void forward_list_push_front(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + FL.push_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} +} + +/// emplace_front() +/// +/// - Design decision: extends containers to the <-LEFT<- (i.e. the first +/// position of the container is decremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_emplace_front(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.emplace_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_emplace_front(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.emplace_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 (to correctly track the container's size) + + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} +} + +/// std::forward_list-like containers: No iterators are invalidated. + +void forward_list_emplace_front(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + FL.emplace_front(n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} +} + +/// pop_front() +/// +/// - Design decision: shrinks containers to the ->RIGHT-> (i.e. the first +/// position of the container is incremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: Iterators to the first element are invalidated. + +void list_pop_front(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = ++L.cbegin(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.pop_front(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +/// std::deque-like containers: Iterators to the first element are invalidated. +/// Other iterators are not affected. + +void deque_pop_front(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = ++D.cbegin(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + D.pop_front(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$D.begin() + 1}} + + clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$D.end()}} +} + +/// std::forward_list-like containers: Iterators to the first element are +/// invalidated. + +void forward_list_pop_front(std::list &FL, int n) { + auto i0 = FL.cbegin(), i1 = ++FL.cbegin(), i2 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + FL.pop_front(); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin() + 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} +} + +/// insert() +/// +/// - Design decision: shifts positions to the <-LEFT<- (i.e. all iterator +/// ahead of the insertion point are decremented; if the +/// relation between the insertion point and the first +/// position of the container is known, the first position +/// of the container is also decremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_insert_begin(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i2 = L.insert(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $L.begin() - 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} +} + +void list_insert_behind_begin(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = ++L.cbegin(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +template Iter return_any_iterator(const Iter &It); + +void list_insert_unknown(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = return_any_iterator(L.cbegin()), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = L.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i - 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +void list_insert_ahead_of_end(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 2 +} + +void list_insert_end(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.insert(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} FIXME: should be $L.end() - 2 + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 1 +} + +/// std::vector-like containers: Only the iterators before the insertion point +/// remain valid. The past-the-end iterator is also +/// invalidated. + +void vector_insert_begin(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i2 = V.insert(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $V.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() +} + +void vector_insert_behind_begin(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); // FIXME: expect -warning $V.begin() + + // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() +} + +void vector_insert_unknown(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = return_any_iterator(V.cbegin()), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = V.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expecte warning $i1 - 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME expect warning $V.end() +} + +void vector_insert_ahead_of_end(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 2 +} + +void vector_insert_end(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.insert(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} FIXME: Should be $V.end() - 2 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 1 +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_insert_begin(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i2 = D.insert(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $D.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_insert_behind_begin(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = ++D.cbegin(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_insert_unknown(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = return_any_iterator(D.cbegin()), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = D.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_insert_ahead_of_end(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.insert(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 2 +} + +void deque_insert_end(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.insert(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 1 +} + +/// insert_after() [std::forward_list-like containers] +/// +/// - Design decision: shifts positions to the ->RIGHT-> (i.e. all iterator +/// ahead of the insertion point are incremented; if the +/// relation between the insertion point and the past-the-end +/// position of the container is known, the first position of +/// the container is also incremented). +/// +/// - No iterators are invalidated. + +void forward_list_insert_after_begin(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + auto i2 = FL.insert_after(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $FL.begin() + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} +} + +void forward_list_insert_after_behind_begin(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = ++FL.cbegin(), i2 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + auto i3 = FL.insert_after(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $FL.begin() + 2 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} +} + +void forward_list_insert_after_unknown(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = return_any_iterator(FL.cbegin()), i2 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = FL.insert_after(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} +} + +/// emplace() +/// +/// - Design decision: shifts positions to the <-LEFT<- (i.e. all iterator +/// ahead of the emplacement point are decremented; if the +/// relation between the emplacement point and the first +/// position of the container is known, the first position +/// of the container is also decremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: No iterators are invalidated. + +void list_emplace_begin(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i2 = L.emplace(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $L.begin() - 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end()}} +} + +void list_emplace_behind_begin(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = ++L.cbegin(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +template Iter return_any_iterator(const Iter &It); + +void list_emplace_unknown(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = return_any_iterator(L.cbegin()), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = L.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i - 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +void list_emplace_ahead_of_end(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 2 +} + +void list_emplace_end(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.emplace(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.end() - 1}} FIXME: should be $L.end() - 2 + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() - 1 +} + +/// std::vector-like containers: Only the iterators before the emplacement point +/// remain valid. The past-the-end iterator is also +/// invalidated. + +void vector_emplace_begin(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i2 = V.emplace(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $V.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() +} + +void vector_emplace_behind_begin(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); // FIXME: expect -warning $V.begin() + + // clang_analyzer_express(clang_analyzer_container_end(V)); // FIXME: expect warning $V.end() +} + +void vector_emplace_unknown(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = return_any_iterator(V.cbegin()), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = V.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expecte warning $i1 - 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME expect warning $V.end() +} + +void vector_emplace_ahead_of_end(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 2 +} + +void vector_emplace_end(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.emplace(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$V.end() - 1}} FIXME: Should be $V.end() - 2 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() - 1 +} + +/// std::deque-like containers: All iterators, including the past-the-end +/// iterator, are invalidated. + +void deque_emplace_begin(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i2 = D.emplace(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $D.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_emplace_behind_begin(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = ++D.cbegin(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_emplace_unknown(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = return_any_iterator(D.cbegin()), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = D.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 - 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_emplace_ahead_of_end(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.emplace(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 2 +} + +void deque_emplace_end(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.emplace(i2, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() - 1 +} + +/// emplace_after() [std::forward_list-like containers] +/// +/// - Design decision: shifts positions to the ->RIGHT-> (i.e. all iterator +/// ahead of the emplacement point are incremented; if the +/// relation between the emplacement point and the +/// past-the-end position of the container is known, the +/// first position of the container is also incremented). +/// +/// - No iterators are invalidated. + +void forward_list_emplace_after_begin(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + auto i2 = FL.emplace_after(i0, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i2)); FIXME: expect warning $FL.begin() + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.end()}} +} + +void forward_list_emplace_after_behind_begin(std::forward_list &FL, + int n) { + auto i0 = FL.cbegin(), i1 = ++FL.cbegin(), i2 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + auto i3 = FL.emplace_after(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$FL.begin() + 1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $FL.begin() + 2 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} +} + +void forward_list_emplace_after_unknown(std::forward_list &FL, int n) { + auto i0 = FL.cbegin(), i1 = return_any_iterator(FL.cbegin()), i2 = FL.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = FL.emplace_after(i1, n); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.end()}} +} + +/// erase() +/// +/// - Design decision: shifts positions to the ->RIGHT-> (i.e. all iterator +/// ahead of the ereased element are incremented; if the +/// relation between the position of the erased element +/// and the first position of the container is known, the +/// first position of the container is also incremented). +/// +/// - Iterator invalidation rules depend the container type. + +/// std::list-like containers: Iterators to the erased element are invalidated. +/// Other iterators are not affected. + +void list_erase_begin(std::list &L) { + auto i0 = L.cbegin(), i1 = ++L.cbegin(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.erase(i0); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be$L.begin() + 1 + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$L.begin() + 1}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +void list_erase_behind_begin(std::list &L, int n) { + auto i0 = L.cbegin(), i1 = ++L.cbegin(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() + 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} FIXME: Should be $L.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.begin() + 2 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +void list_erase_unknown(std::list &L) { + auto i0 = L.cbegin(), i1 = return_any_iterator(L.cbegin()), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = L.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} +} + +void list_erase_ahead_of_end(std::list &L) { + auto i0 = L.cbegin(), i1 = --L.cend(), i2 = L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + auto i3 = L.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$L.begin()}} + + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$L.end()}} + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $L.end() +} + +/// std::vector-like containers: Invalidates iterators at or after the point of +/// the erase, including the past-the-end iterator. + +void vector_erase_begin(std::vector &V) { + auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.erase(i0); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.begin() + 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() +} + +void vector_erase_behind_begin(std::vector &V, int n) { + auto i0 = V.cbegin(), i1 = ++V.cbegin(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} FIXME: Should be $V.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.begin() + 2 + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() +} + +void vector_erase_unknown(std::vector &V) { + auto i0 = V.cbegin(), i1 = return_any_iterator(V.cbegin()), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = V.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() +} + +void vector_erase_ahead_of_end(std::vector &V) { + auto i0 = V.cbegin(), i1 = --V.cend(), i2 = V.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + auto i3 = V.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$V.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(V)); FIXME: expect warning $V.end() + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $V.end() +} + +/// std::deque-like containers: All iterators are invalidated, unless the erased +/// element is at the end or the beginning of the +/// container, in which case only the iterators to +/// the erased element are invalidated. The +/// past-the-end iterator is also invalidated unless +/// the erased element is at the beginning of the +/// container and the last element is not erased. + +void deque_erase_begin(std::deque &D) { + auto i0 = D.cbegin(), i1 = ++D.cbegin(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.erase(i0); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() + 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning{{$D.end() +} + +void deque_erase_behind_begin(std::deque &D, int n) { + auto i0 = D.cbegin(), i1 = ++D.cbegin(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.begin() + 2 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_erase_unknown(std::deque &D) { + auto i0 = D.cbegin(), i1 = return_any_iterator(D.cbegin()), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i3 = D.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $i1 + 1 + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() +} + +void deque_erase_ahead_of_end(std::deque &D) { + auto i0 = D.cbegin(), i1 = --D.cend(), i2 = D.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + + auto i3 = D.erase(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + + clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} + + // clang_analyzer_express(clang_analyzer_container_end(D)); FIXME: expect warning $D.end() + // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expect warning $D.end() +} + +/// erase_after() [std::forward_list-like containers] +/// +/// - Design decision: shifts positions to the <-LEFT<- (i.e. all iterator +/// begind of the ereased element are decremented; if the +/// relation between the position of the erased element +/// and the past-the-end position of the container is known, +/// the past-the-end position of the container is also +/// decremented). +/// +/// - Iterators to the erased element are invalidated. Other iterators are not +/// affected. + + +void forward_list_erase_after_begin(std::forward_list &FL) { + auto i0 = FL.cbegin(), i1 = ++FL.cbegin(), i2 = i1, i3 = FL.cend(); + ++i2; + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + + auto i4 = FL.erase_after(i0); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$FL.begin() + 2}} FIXME: Should be $FL.begin() + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i4)); FIXME: expect warning $FL.begin() + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i3)); // expected-warning{{$FL.end()}} +} + +void forward_list_erase_after_unknown(std::forward_list &FL) { + auto i0 = FL.cbegin(), i1 = return_any_iterator(FL.cbegin()), i2 = i1, + i3 = i1, i4 = FL.cend(); + ++i2; + ++i3; + ++i3; + + clang_analyzer_denote(clang_analyzer_container_begin(FL), "$FL.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(FL), "$FL.end()"); + clang_analyzer_denote(clang_analyzer_iterator_position(i1), "$i1"); + + auto i5 = FL.erase_after(i1); + + clang_analyzer_eval(clang_analyzer_iterator_validity(i0)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i1)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i2)); //expected-warning{{FALSE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i3)); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_iterator_validity(i4)); //expected-warning{{TRUE}} + + clang_analyzer_express(clang_analyzer_container_begin(FL)); // expected-warning{{$FL.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning{{$FL.begin()}} + + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$i1}} + clang_analyzer_express(clang_analyzer_iterator_position(i3)); // expected-warning{{$i1 + 2}} FIXME: Should be $i1 + 1 + // clang_analyzer_express(clang_analyzer_iterator_position(i5)); FIXME: expect warning $i1 + 1 + + clang_analyzer_express(clang_analyzer_container_end(FL)); // expected-warning{{$FL.end()}} + clang_analyzer_express(clang_analyzer_iterator_position(i4)); // expected-warning{{$FL.end()}} +} + +struct simple_iterator_base { + simple_iterator_base(); + simple_iterator_base(const simple_iterator_base& rhs); + simple_iterator_base &operator=(const simple_iterator_base& rhs); + virtual ~simple_iterator_base(); + bool friend operator==(const simple_iterator_base &lhs, + const simple_iterator_base &rhs); + bool friend operator!=(const simple_iterator_base &lhs, + const simple_iterator_base &rhs); +private: + int *ptr; +}; + +struct simple_derived_iterator: public simple_iterator_base { + int& operator*(); + int* operator->(); + simple_iterator_base &operator++(); + simple_iterator_base operator++(int); + simple_iterator_base &operator--(); + simple_iterator_base operator--(int); +}; + +struct simple_container { + typedef simple_derived_iterator iterator; + + iterator begin(); + iterator end(); +}; + +void good_derived(simple_container c) { + auto i0 = c.end(); + + if (i0 != c.end()) { + clang_analyzer_warnIfReached(); + } +} + +void iter_diff(std::vector &V) { + auto i0 = V.begin(), i1 = V.end(); + ptrdiff_t len = i1 - i0; // no-crash +} + +void deferred_assumption(std::vector &V, int e) { + const auto first = V.begin(); + const auto comp1 = (first != V.end()), comp2 = (first == V.end()); + if (comp1) { + clang_analyzer_eval(clang_analyzer_container_end(V) == + clang_analyzer_iterator_position(first)); // expected-warning@-1{{FALSE}} + } +} + +void loop(std::vector &V, int e) { + auto start = V.begin(); + while (true) { + auto item = std::find(start, V.end(), e); + if (item == V.end()) + break; + + clang_analyzer_eval(clang_analyzer_container_end(V) == + clang_analyzer_iterator_position(item)); // expected-warning@-1{{FALSE}} + } +} + +template +InputIterator nonStdFind(InputIterator first, InputIterator last, + const T &val) { + for (auto i = first; i != last; ++i) { + if (*i == val) { + return i; + } + } + return last; +} + +void non_std_find(std::vector &V, int e) { + auto first = nonStdFind(V.begin(), V.end(), e); + clang_analyzer_eval(clang_analyzer_container_end(V) == + clang_analyzer_iterator_position(first)); // expected-warning@-1{{FALSE}} expected-warning@-1{{TRUE}} + if (V.end() != first) { + clang_analyzer_eval(clang_analyzer_container_end(V) == + clang_analyzer_iterator_position(first)); // expected-warning@-1{{FALSE}} expected-warning@-1 0-1{{TRUE}} FIXME: should only expect FALSE in every case + } +} diff --git a/clang/test/Analysis/iterator-range.cpp b/clang/test/Analysis/iterator-range.cpp --- a/clang/test/Analysis/iterator-range.cpp +++ b/clang/test/Analysis/iterator-range.cpp @@ -5,240 +5,376 @@ void clang_analyzer_warnIfReached(); -void simple_good_end(const std::vector &v) { - auto i = v.end(); - if (i != v.end()) { - clang_analyzer_warnIfReached(); - *i; // no-warning - } +// Dereference - operator*() + +void deref_begin(const std::vector &V) { + auto i = V.begin(); + *i; // no-warning +} + +void deref_begind_begin(const std::vector &V) { + auto i = ++V.begin(); + *i; // no-warning +} + +template Iter return_any_iterator(const Iter &It); + +void deref_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + *i; // no-warning } -void simple_good_end_negated(const std::vector &v) { - auto i = v.end(); - if (!(i == v.end())) { - clang_analyzer_warnIfReached(); - *i; // no-warning - } +void deref_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + *i; // no-warning } -void simple_bad_end(const std::vector &v) { - auto i = v.end(); +void deref_end(const std::vector &V) { + auto i = V.end(); *i; // expected-warning{{Past-the-end iterator dereferenced}} - clang_analyzer_warnIfReached(); } -void copy(const std::vector &v) { - auto i1 = v.end(); - auto i2 = i1; - *i2; // expected-warning{{Past-the-end iterator dereferenced}} +// Prefix increment - operator++() + +void incr_begin(const std::vector &V) { + auto i = V.begin(); + ++i; // no-warning +} + +void incr_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + ++i; // no-warning +} + +void incr_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + ++i; // no-warning +} + +void incr_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + ++i; // no-warning +} + +void incr_end(const std::vector &V) { + auto i = V.end(); + ++i; // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// Postfix increment - operator++(int) + +void begin_incr(const std::vector &V) { + auto i = V.begin(); + i++; // no-warning +} + +void behind_begin_incr(const std::vector &V) { + auto i = ++V.begin(); + i++; // no-warning +} + +void unknown_incr(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + i++; // no-warning +} + +void ahead_of_end_incr(const std::vector &V) { + auto i = --V.end(); + i++; // no-warning +} + +void end_incr(const std::vector &V) { + auto i = V.end(); + i++; // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// Prefix decrement - operator--() + +void decr_begin(const std::vector &V) { + auto i = V.begin(); + --i; // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void decr_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + --i; // no-warning +} + +void decr_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + --i; // no-warning +} + +void decr_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + --i; // no-warning +} + +void decr_end(const std::vector &V) { + auto i = V.end(); + --i; // no-warning +} + +// Postfix decrement - operator--(int) + +void begin_decr(const std::vector &V) { + auto i = V.begin(); + i--; // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void behind_begin_decr(const std::vector &V) { + auto i = ++V.begin(); + i--; // no-warning } -void decrease(const std::vector &v) { - auto i = v.end(); +void unknown_decr(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + i--; // no-warning +} + +void ahead_of_end_decr(const std::vector &V) { + auto i = --V.end(); + i--; // no-warning +} + +void end_decr(const std::vector &V) { + auto i = V.end(); + i--; // no-warning +} + +// Addition assignment - operator+=(int) + +void incr_by_2_begin(const std::vector &V) { + auto i = V.begin(); + i += 2; // no-warning +} + +void incr_by_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + i += 2; // no-warning +} + +void incr_by_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + i += 2; // no-warning +} + +void incr_by_2_ahead_by_2_of_end(const std::vector &V) { + auto i = --V.end(); --i; - *i; // no-warning + i += 2; // no-warning } -void copy_and_decrease1(const std::vector &v) { - auto i1 = v.end(); - auto i2 = i1; - --i1; - *i1; // no-warning +void incr_by_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} } -void copy_and_decrease2(const std::vector &v) { - auto i1 = v.end(); - auto i2 = i1; - --i1; - *i2; // expected-warning{{Past-the-end iterator dereferenced}} +void incr_by_2_end(const std::vector &V) { + auto i = V.end(); + i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} } -void copy_and_increase1(const std::vector &v) { - auto i1 = v.begin(); - auto i2 = i1; - ++i1; - if (i1 == v.end()) - *i2; // no-warning +// Addition - operator+(int) + +void incr_by_2_copy_begin(const std::vector &V) { + auto i = V.begin(); + auto j = i + 2; // no-warning } -void copy_and_increase2(const std::vector &v) { - auto i1 = v.begin(); - auto i2 = i1; - ++i1; - if (i2 == v.end()) - *i2; // expected-warning{{Past-the-end iterator dereferenced}} +void incr_by_2_copy_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = i + 2; // no-warning } -void copy_and_increase3(const std::vector &v) { - auto i1 = v.begin(); - auto i2 = i1; - ++i1; - if (v.end() == i2) - *i2; // expected-warning{{Past-the-end iterator dereferenced}} +void incr_by_2_copy_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = i + 2; // no-warning } -template -InputIterator nonStdFind(InputIterator first, InputIterator last, - const T &val) { - for (auto i = first; i != last; ++i) { - if (*i == val) { - return i; - } - } - return last; +void incr_by_2_copy_ahead_by_2_of_end(const std::vector &V) { + auto i = --V.end(); + --i; + auto j = i + 2; // no-warning } -void good_non_std_find(std::vector &V, int e) { - auto first = nonStdFind(V.begin(), V.end(), e); - if (V.end() != first) - *first; // no-warning +void incr_by_2_copy_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} } -void bad_non_std_find(std::vector &V, int e) { - auto first = nonStdFind(V.begin(), V.end(), e); - *first; // expected-warning{{Past-the-end iterator dereferenced}} +void incr_by_2_copy_end(const std::vector &V) { + auto i = V.end(); + auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} } -void tricky(std::vector &V, int e) { - const auto first = V.begin(); - const auto comp1 = (first != V.end()), comp2 = (first == V.end()); - if (comp1) - *first; // no-warning +// Subtraction assignment - operator-=(int) + +void decr_by_2_begin(const std::vector &V) { + auto i = V.begin(); + i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}} } -void loop(std::vector &V, int e) { - auto start = V.begin(); - while (true) { - auto item = std::find(start, V.end(), e); - if (item == V.end()) - break; - *item; // no-warning - start = ++item; // no-warning - } +void decr_by_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}} } -void good_push_back(std::list &L, int n) { - auto i0 = --L.cend(); - L.push_back(n); - *++i0; // no-warning +void decr_by_2_behind_begin_by_2(const std::vector &V) { + auto i = ++V.begin(); + ++i; + i -= 2; // no-warning } -void bad_push_back(std::list &L, int n) { - auto i0 = --L.cend(); - L.push_back(n); - ++i0; - *++i0; // expected-warning{{Past-the-end iterator dereferenced}} +void decr_by_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + i -= 2; // no-warning } -void good_pop_back(std::list &L, int n) { - auto i0 = --L.cend(); --i0; - L.pop_back(); - *i0; // no-warning +void decr_by_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + i -= 2; // no-warning } -void bad_pop_back(std::list &L, int n) { - auto i0 = --L.cend(); --i0; - L.pop_back(); - *++i0; // expected-warning{{Past-the-end iterator dereferenced}} +void decr_by_2_end(const std::vector &V) { + auto i = V.end(); + i -= 2; // no-warning } -void good_push_front(std::list &L, int n) { - auto i0 = L.cbegin(); - L.push_front(n); - *--i0; // no-warning +// Subtraction - operator-(int) + +void decr_by_2_copy_begin(const std::vector &V) { + auto i = V.begin(); + auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}} } -void bad_push_front(std::list &L, int n) { - auto i0 = L.cbegin(); - L.push_front(n); - --i0; - --i0; // expected-warning{{Iterator decremented ahead of its valid range}} +void decr_by_2_copy_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}} } -void good_pop_front(std::list &L, int n) { - auto i0 = ++L.cbegin(); - L.pop_front(); - *i0; // no-warning +void decr_by_2_copy_behind_begin_by_2(const std::vector &V) { + auto i = ++V.begin(); + ++i; + auto j = i - 2; // no-warning } -void bad_pop_front(std::list &L, int n) { - auto i0 = ++L.cbegin(); - L.pop_front(); - --i0; // expected-warning{{Iterator decremented ahead of its valid range}} +void decr_by_2_copy_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = i - 2; // no-warning } -void bad_move(std::list &L1, std::list &L2) { - auto i0 = --L2.cend(); - L1 = std::move(L2); - *++i0; // expected-warning{{Past-the-end iterator dereferenced}} +void decr_by_2_copy_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = i - 2; // no-warning } -void bad_move_push_back(std::list &L1, std::list &L2, int n) { - auto i0 = --L2.cend(); - L2.push_back(n); - L1 = std::move(L2); - ++i0; - *++i0; // expected-warning{{Past-the-end iterator dereferenced}} +void decr_by_2_copy_end(const std::vector &V) { + auto i = V.end(); + auto j = i - 2; // no-warning } -void good_incr_begin(const std::list &L) { - auto i0 = L.begin(); - ++i0; // no-warning +// +// Subscript - operator[](int) +// + +// By zero + +void subscript_zero_begin(const std::vector &V) { + auto i = V.begin(); + auto j = i[0]; // no-warning } -void bad_decr_begin(const std::list &L) { - auto i0 = L.begin(); - --i0; // expected-warning{{Iterator decremented ahead of its valid range}} +void subscript_zero_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = i[0]; // no-warning } -void good_decr_end(const std::list &L) { - auto i0 = L.end(); - --i0; // no-warning +void subscript_zero_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = i[0]; // no-warning } -void bad_incr_end(const std::list &L) { - auto i0 = L.end(); - ++i0; // expected-warning{{Iterator incremented behind the past-the-end iterator}} +void subscript_zero_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = i[0]; // no-warning } -struct simple_iterator_base { - simple_iterator_base(); - simple_iterator_base(const simple_iterator_base& rhs); - simple_iterator_base &operator=(const simple_iterator_base& rhs); - virtual ~simple_iterator_base(); - bool friend operator==(const simple_iterator_base &lhs, - const simple_iterator_base &rhs); - bool friend operator!=(const simple_iterator_base &lhs, - const simple_iterator_base &rhs); -private: - int *ptr; -}; +void subscript_zero_end(const std::vector &V) { + auto i = V.end(); + auto j = i[0]; // expected-warning{{Past-the-end iterator dereferenced}} +} -struct simple_derived_iterator: public simple_iterator_base { - int& operator*(); - int* operator->(); - simple_iterator_base &operator++(); - simple_iterator_base operator++(int); - simple_iterator_base &operator--(); - simple_iterator_base operator--(int); -}; +// By negative number -struct simple_container { - typedef simple_derived_iterator iterator; +void subscript_negative_begin(const std::vector &V) { + auto i = V.begin(); + auto j = i[-1]; // no-warning FIXME: expect warning Iterator decremented ahead of its valid range +} + +void subscript_negative_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = i[-1]; // no-warning +} + +void subscript_negative_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = i[-1]; // no-warning +} + +void subscript_negative_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = i[-1]; // no-warning +} + +void subscript_negative_end(const std::vector &V) { + auto i = V.end(); + auto j = i[-1]; // // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning +} + +// By positive number + +void subscript_positive_begin(const std::vector &V) { + auto i = V.begin(); + auto j = i[1]; // no-warning +} + +void subscript_positive_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = i[1]; // no-warning +} - iterator begin(); - iterator end(); +void subscript_positive_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = i[1]; // no-warning +} + +void subscript_positive_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = i[1]; // no-warning FIXME: expected warning Past-the-end iterator dereferenced +} + +void subscript_positive_end(const std::vector &V) { + auto i = V.end(); + auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator +} + +// +// Structure member dereference operators +// + +struct S { + int n; }; -void good_derived(simple_container c) { - auto i0 = c.end(); - if (i0 != c.end()) { - clang_analyzer_warnIfReached(); - *i0; // no-warning - } +// Member dereference - operator->() + +void arrow_deref_begin(const std::vector &V) { + auto i = V.begin(); + int n = i->n; // no-warning } -void iter_diff(std::vector &V) { - auto i0 = V.begin(), i1 = V.end(); - ptrdiff_t len = i1 - i0; // no-crash +void arrow_deref_end(const std::vector &V) { + auto i = V.end(); + int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}} } diff --git a/clang/test/Analysis/mismatched-iterator.cpp b/clang/test/Analysis/mismatched-iterator.cpp --- a/clang/test/Analysis/mismatched-iterator.cpp +++ b/clang/test/Analysis/mismatched-iterator.cpp @@ -3,203 +3,118 @@ #include "Inputs/system-header-simulator-cxx.h" -void good_insert1(std::vector &v, int n) { - v.insert(v.cbegin(), n); // no-warning +void good_insert1(std::vector &V, int n) { + V.insert(V.cbegin(), n); // no-warning } - -void good_insert2(std::vector &v, int len, int n) { - v.insert(v.cbegin(), len, n); // no-warning -} - -void good_insert3(std::vector &v1, std::vector &v2) { - v1.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // no-warning -} - -void good_insert4(std::vector &v, int len, int n) { - v.insert(v.cbegin(), {n-1, n, n+1}); // no-warning -} - -void good_insert_find(std::vector &v, int n, int m) { - auto i = std::find(v.cbegin(), v.cend(), n); - v.insert(i, m); // no-warning -} - -void good_erase1(std::vector &v) { - v.erase(v.cbegin()); // no-warning -} - -void good_erase2(std::vector &v) { - v.erase(v.cbegin(), v.cend()); // no-warning -} - -void good_emplace(std::vector &v, int n) { - v.emplace(v.cbegin(), n); // no-warning -} - -void good_ctor(std::vector &v) { - std::vector new_v(v.cbegin(), v.cend()); // no-warning -} - -void good_find(std::vector &v, int n) { - std::find(v.cbegin(), v.cend(), n); // no-warning -} - -void good_find_first_of(std::vector &v1, std::vector &v2) { - std::find_first_of(v1.cbegin(), v1.cend(), v2.cbegin(), v2.cend()); // no-warning -} - -void good_copy(std::vector &v1, std::vector &v2, int n) { - std::copy(v1.cbegin(), v1.cend(), v2.begin()); // no-warning -} - -void good_move_find1(std::vector &v1, std::vector &v2, int n) { - auto i0 = v2.cbegin(); - v1 = std::move(v2); - std::find(i0, v1.cend(), n); // no-warning -} - -void bad_insert1(std::vector &v1, std::vector &v2, int n) { - v2.insert(v1.cbegin(), n); // expected-warning{{Container accessed using foreign iterator argument}} -} - -void bad_insert2(std::vector &v1, std::vector &v2, int len, int n) { - v2.insert(v1.cbegin(), len, n); // expected-warning{{Container accessed using foreign iterator argument}} -} - -void bad_insert3(std::vector &v1, std::vector &v2) { - v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // expected-warning{{Container accessed using foreign iterator argument}} - v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} - v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} +void good_insert2(std::vector &V, int len, int n) { + V.insert(V.cbegin(), len, n); // no-warning } -void bad_insert4(std::vector &v1, std::vector &v2, int len, int n) { - v2.insert(v1.cbegin(), {n-1, n, n+1}); // expected-warning{{Container accessed using foreign iterator argument}} +void good_insert3(std::vector &V1, std::vector &V2) { + V1.insert(V1.cbegin(), V2.cbegin(), V2.cend()); // no-warning } -void bad_erase1(std::vector &v1, std::vector &v2) { - v2.erase(v1.cbegin()); // expected-warning{{Container accessed using foreign iterator argument}} +void good_insert4(std::vector &V, int len, int n) { + V.insert(V.cbegin(), {n-1, n, n+1}); // no-warning } -void bad_erase2(std::vector &v1, std::vector &v2) { - v2.erase(v2.cbegin(), v1.cend()); // expected-warning{{Container accessed using foreign iterator argument}} - v2.erase(v1.cbegin(), v2.cend()); // expected-warning{{Container accessed using foreign iterator argument}} - v2.erase(v1.cbegin(), v1.cend()); // expected-warning{{Container accessed using foreign iterator argument}} +void good_insert_find(std::vector &V, int n, int m) { + auto i = std::find(V.cbegin(), V.cend(), n); + V.insert(i, m); // no-warning } -void bad_emplace(std::vector &v1, std::vector &v2, int n) { - v2.emplace(v1.cbegin(), n); // expected-warning{{Container accessed using foreign iterator argument}} +void good_erase1(std::vector &V) { + V.erase(V.cbegin()); // no-warning } -void good_move_find2(std::vector &v1, std::vector &v2, int n) { - auto i0 = --v2.cend(); - v1 = std::move(v2); - std::find(i0, v1.cend(), n); // no-warning +void good_erase2(std::vector &V) { + V.erase(V.cbegin(), V.cend()); // no-warning } -void good_move_find3(std::vector &v1, std::vector &v2, int n) { - auto i0 = v2.cend(); - v1 = std::move(v2); - v2.push_back(n); // expected-warning{{Method called on moved-from object of type 'std::vector'}} - std::find(v2.cbegin(), i0, n); // no-warning +void good_emplace(std::vector &V, int n) { + V.emplace(V.cbegin(), n); // no-warning } -void good_comparison(std::vector &v) { - if (v.cbegin() == v.cend()) {} // no-warning +void good_ctor(std::vector &V) { + std::vector new_v(V.cbegin(), V.cend()); // no-warning } -void bad_ctor(std::vector &v1, std::vector &v2) { - std::vector new_v(v1.cbegin(), v2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} +void good_find(std::vector &V, int n) { + std::find(V.cbegin(), V.cend(), n); // no-warning } -void bad_find(std::vector &v1, std::vector &v2, int n) { - std::find(v1.cbegin(), v2.cend(), n); // expected-warning{{Iterators of different containers used where the same container is expected}} +void good_find_first_of(std::vector &V1, std::vector &V2) { + std::find_first_of(V1.cbegin(), V1.cend(), V2.cbegin(), V2.cend()); // no-warning } -void bad_find_first_of(std::vector &v1, std::vector &v2) { - std::find_first_of(v1.cbegin(), v2.cend(), v2.cbegin(), v2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} - std::find_first_of(v1.cbegin(), v1.cend(), v2.cbegin(), v1.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} +void good_copy(std::vector &V1, std::vector &V2, int n) { + std::copy(V1.cbegin(), V1.cend(), V2.begin()); // no-warning } -void bad_move_find1(std::vector &v1, std::vector &v2, int n) { - auto i0 = v2.cbegin(); - v1 = std::move(v2); - std::find(i0, v2.cend(), n); // expected-warning{{Iterators of different containers used where the same container is expected}} - // expected-warning@-1{{Method called on moved-from object of type 'std::vector'}} +void bad_insert1(std::vector &V1, std::vector &V2, int n) { + V2.insert(V1.cbegin(), n); // expected-warning{{Container accessed using foreign iterator argument}} } -void bad_insert_find(std::vector &v1, std::vector &v2, int n, int m) { - auto i = std::find(v1.cbegin(), v1.cend(), n); - v2.insert(i, m); // expected-warning{{Container accessed using foreign iterator argument}} +void bad_insert2(std::vector &V1, std::vector &V2, int len, int n) { + V2.insert(V1.cbegin(), len, n); // expected-warning{{Container accessed using foreign iterator argument}} } -void good_overwrite(std::vector &v1, std::vector &v2, int n) { - auto i = v1.cbegin(); - i = v2.cbegin(); - v2.insert(i, n); // no-warning +void bad_insert3(std::vector &V1, std::vector &V2) { + V2.insert(V1.cbegin(), V2.cbegin(), V2.cend()); // expected-warning{{Container accessed using foreign iterator argument}} + V1.insert(V1.cbegin(), V1.cbegin(), V2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} + V1.insert(V1.cbegin(), V2.cbegin(), V1.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} } -void bad_overwrite(std::vector &v1, std::vector &v2, int n) { - auto i = v1.cbegin(); - i = v2.cbegin(); - v1.insert(i, n); // expected-warning{{Container accessed using foreign iterator argument}} +void bad_insert4(std::vector &V1, std::vector &V2, int len, int n) { + V2.insert(V1.cbegin(), {n-1, n, n+1}); // expected-warning{{Container accessed using foreign iterator argument}} } -template -bool is_cend(Container cont, Iterator it) { - return it == cont.cend(); +void bad_erase1(std::vector &V1, std::vector &V2) { + V2.erase(V1.cbegin()); // expected-warning{{Container accessed using foreign iterator argument}} } -void good_empty(std::vector &v) { - is_cend(v, v.cbegin()); // no-warning +void bad_erase2(std::vector &V1, std::vector &V2) { + V2.erase(V2.cbegin(), V1.cend()); // expected-warning{{Container accessed using foreign iterator argument}} + V2.erase(V1.cbegin(), V2.cend()); // expected-warning{{Container accessed using foreign iterator argument}} + V2.erase(V1.cbegin(), V1.cend()); // expected-warning{{Container accessed using foreign iterator argument}} } -void bad_empty(std::vector &v1, std::vector &v2) { - is_cend(v1, v2.cbegin()); // expected-warning@-8{{Iterators of different containers used where the same container is expected}} +void bad_emplace(std::vector &V1, std::vector &V2, int n) { + V2.emplace(V1.cbegin(), n); // expected-warning{{Container accessed using foreign iterator argument}} } -void good_move(std::vector &v1, std::vector &v2) { - const auto i0 = ++v2.cbegin(); - v1 = std::move(v2); - v1.erase(i0); // no-warning +void good_comparison(std::vector &V) { + if (V.cbegin() == V.cend()) {} // no-warning } -void bad_move(std::vector &v1, std::vector &v2) { - const auto i0 = ++v2.cbegin(); - v1 = std::move(v2); - v2.erase(i0); // expected-warning{{Container accessed using foreign iterator argument}} - // expected-warning@-1{{Method called on moved-from object of type 'std::vector'}} +void bad_comparison(std::vector &V1, std::vector &V2) { + if (V1.cbegin() != V2.cend()) {} // expected-warning{{Iterators of different containers used where the same container is expected}} } -void bad_move_find2(std::vector &v1, std::vector &v2, int n) { - auto i0 = --v2.cend(); - v1 = std::move(v2); - std::find(i0, v2.cend(), n); // expected-warning{{Iterators of different containers used where the same container is expected}} - // expected-warning@-1{{Method called on moved-from object of type 'std::vector'}} +void bad_ctor(std::vector &V1, std::vector &V2) { + std::vector new_v(V1.cbegin(), V2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} } -void bad_move_find3(std::vector &v1, std::vector &v2, int n) { - auto i0 = v2.cend(); - v1 = std::move(v2); - std::find(v1.cbegin(), i0, n); // expected-warning{{Iterators of different containers used where the same container is expected}} +void bad_find(std::vector &V1, std::vector &V2, int n) { + std::find(V1.cbegin(), V2.cend(), n); // expected-warning{{Iterators of different containers used where the same container is expected}} } -void bad_comparison(std::vector &v1, std::vector &v2) { - if (v1.cbegin() != v2.cend()) { // expected-warning{{Iterators of different containers used where the same container is expected}} - *v1.cbegin(); - } +void bad_find_first_of(std::vector &V1, std::vector &V2) { + std::find_first_of(V1.cbegin(), V2.cend(), V2.cbegin(), V2.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} + std::find_first_of(V1.cbegin(), V1.cend(), V2.cbegin(), V1.cend()); // expected-warning{{Iterators of different containers used where the same container is expected}} } std::vector &return_vector_ref(); void ignore_conjured1() { - std::vector &v1 = return_vector_ref(), &v2 = return_vector_ref(); + std::vector &V1 = return_vector_ref(), &V2 = return_vector_ref(); - v2.erase(v1.cbegin()); // no-warning + V2.erase(V1.cbegin()); // no-warning } void ignore_conjured2() { - std::vector &v1 = return_vector_ref(), &v2 = return_vector_ref(); + std::vector &V1 = return_vector_ref(), &V2 = return_vector_ref(); - if (v1.cbegin() == v2.cbegin()) {} //no-warning + if (V1.cbegin() == V2.cbegin()) {} //no-warning }