[clang-tools-extra] Create a new check to look for mis-use in calls that take iterators (PR #99917)
Denis Mikhailov via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 23 06:54:44 PDT 2025
================
@@ -0,0 +1,437 @@
+// RUN: %check_clang_tidy -std=c++14 %s bugprone-incorrect-iterators %t
+
+namespace std {
+
+template <class U, class V> struct pair {};
+
+namespace execution {
+
+class parallel_policy {};
+
+constexpr parallel_policy par;
+
+} // namespace execution
+
+template <typename BiDirIter> class reverse_iterator {
+public:
+ constexpr explicit reverse_iterator(BiDirIter Iter);
+ reverse_iterator operator+(int) const;
+ reverse_iterator operator-(int) const;
+};
+
+template <typename InputIt> InputIt next(InputIt Iter, int n = 1);
+template <typename BidirIt> BidirIt prev(BidirIt Iter, int n = 1);
+
+template <typename BiDirIter>
+reverse_iterator<BiDirIter> make_reverse_iterator(BiDirIter Iter);
+
+template <typename T> class allocator {};
+
+template <typename T, typename Allocator = allocator<T>> class vector {
+public:
+ using iterator = T *;
+ using const_iterator = const T *;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using reverse_const_iterator = std::reverse_iterator<const_iterator>;
+
+ vector() = default;
+ vector(const vector &);
+ vector(vector &&);
+ template <typename InputIt>
+ vector(InputIt first, InputIt last, const Allocator &alloc = Allocator());
+ ~vector();
+
+ constexpr const_iterator begin() const;
+ constexpr const_iterator end() const;
+ constexpr const_iterator cbegin() const;
+ constexpr const_iterator cend() const;
+ constexpr iterator begin();
+ constexpr iterator end();
+ constexpr reverse_const_iterator rbegin() const;
+ constexpr reverse_const_iterator rend() const;
+ constexpr reverse_const_iterator crbegin() const;
+ constexpr reverse_const_iterator crend() const;
+ constexpr reverse_iterator rbegin();
+ constexpr reverse_iterator rend();
+
+ template <class InputIt>
+ iterator insert(const_iterator pos, InputIt first, InputIt last);
+};
+
+template <typename T> struct less {};
+
+template <typename T> class __set_const_iterator {};
+
+template <typename T> class __set_iterator : public __set_const_iterator<T> {};
+
+template <typename Key, typename Compare = less<Key>,
+ typename Allocator = allocator<Key>>
+class set {
+public:
+ using iterator = __set_iterator<Key>;
+ using const_iterator = __set_const_iterator<Key>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using reverse_const_iterator = std::reverse_iterator<const_iterator>;
+ using value_type = Key;
+
+ set();
+ template <class InputIt>
+ set(InputIt first, InputIt last, const Compare &comp = Compare(),
+ const Allocator &alloc = Allocator());
+ ~set();
+
+ constexpr const_iterator begin() const;
+ constexpr const_iterator end() const;
+ constexpr const_iterator cbegin() const;
+ constexpr const_iterator cend() const;
+ constexpr iterator begin();
+ constexpr iterator end();
+ constexpr reverse_const_iterator rbegin() const;
+ constexpr reverse_const_iterator rend() const;
+ constexpr reverse_const_iterator crbegin() const;
+ constexpr reverse_const_iterator crend() const;
+ constexpr reverse_iterator rbegin();
+ constexpr reverse_iterator rend();
+
+ iterator insert(const_iterator pos, value_type &&value);
+ template <class InputIt> void insert(InputIt first, InputIt last);
+};
+
+template <typename Container> constexpr auto begin(const Container &Cont) {
+ return Cont.begin();
+}
+
+template <typename Container> constexpr auto begin(Container &Cont) {
+ return Cont.begin();
+}
+
+template <typename Container> constexpr auto end(const Container &Cont) {
+ return Cont.end();
+}
+
+template <typename Container> constexpr auto end(Container &Cont) {
+ return Cont.end();
+}
+
+template <typename Container> constexpr auto cbegin(const Container &Cont) {
+ return Cont.cbegin();
+}
+
+template <typename Container> constexpr auto cend(const Container &Cont) {
+ return Cont.cend();
+}
+
+template <typename Container> constexpr auto rbegin(const Container &Cont) {
+ return Cont.rbegin();
+}
+
+template <typename Container> constexpr auto rbegin(Container &Cont) {
+ return Cont.rbegin();
+}
+
+template <typename Container> constexpr auto rend(const Container &Cont) {
+ return Cont.rend();
+}
+
+template <typename Container> constexpr auto rend(Container &Cont) {
+ return Cont.rend();
+}
+
+template <typename Container> constexpr auto crbegin(const Container &Cont) {
+ return Cont.crbegin();
+}
+
+template <typename Container> constexpr auto crend(const Container &Cont) {
+ return Cont.crend();
+}
+// Find
+template <class InputIt, class T>
+InputIt find(InputIt first, InputIt last, const T &value);
+
+template <class Policy, class InputIt, class T>
+InputIt find(Policy &&policy, InputIt first, InputIt last, const T &value);
+
+template <class InputIt1, class InputIt2, class OutputIt>
+OutputIt set_union(InputIt1 first1, InputIt1 last1, InputIt2 first2,
+ InputIt2 last2, OutputIt d_first);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+ class ForwardIt3>
+ForwardIt3 set_union(ExecutionPolicy &&policy, ForwardIt1 first1,
+ ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2,
+ ForwardIt3 d_first);
+
+template <class RandomIt> void push_heap(RandomIt first, RandomIt last);
+
+template <class BidirIt1, class BidirIt2>
+BidirIt2 copy_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last);
+
+template <class ForwardIt1, class ForwardIt2>
+ForwardIt1 find_end(ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first,
+ ForwardIt2 s_last);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+ForwardIt1 find_end(ExecutionPolicy &&policy, ForwardIt1 first, ForwardIt1 last,
+ ForwardIt2 s_first, ForwardIt2 s_last);
+
+template <class InputIt1, class InputIt2>
+bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1,
+ ForwardIt2 first2);
+
+template <class InputIt1, class InputIt2>
+bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+bool equal(ExecutionPolicy &&policy, ForwardIt1 first1, ForwardIt1 last1,
+ ForwardIt2 first2, ForwardIt2 last2);
+
+template <class ForwardIt1, class ForwardIt2>
+bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2);
+
+template <class ForwardIt1, class ForwardIt2>
+bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
+ ForwardIt2 last2);
+
+template <class InputIt, class NoThrowForwardIt>
+NoThrowForwardIt uninitialized_copy(InputIt first, InputIt last,
+ NoThrowForwardIt d_first);
+
+template <class ExecutionPolicy, class ForwardIt, class NoThrowForwardIt>
+NoThrowForwardIt uninitialized_copy(ExecutionPolicy &&policy, ForwardIt first,
+ ForwardIt last, NoThrowForwardIt d_first);
+
+template <class InputIt1, class InputIt2, class T>
+T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init);
+
+template <class InputIt, class OutputIt>
+OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first);
+
+template <class InputIt, class OutputIt1, class OutputIt2, class UnaryPred>
+pair<OutputIt1, OutputIt2> partition_copy(InputIt first, InputIt last,
+ OutputIt1 d_first_true,
+ OutputIt2 d_first_false, UnaryPred p);
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+ class ForwardIt3, class UnaryPred>
+pair<ForwardIt2, ForwardIt3>
+partition_copy(ExecutionPolicy &&policy, ForwardIt1 first, ForwardIt1 last,
+ ForwardIt2 d_first_true, ForwardIt3 d_first_false, UnaryPred p);
+
+template <class InputIt, class OutputIt, class UnaryOp>
+OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first,
+ UnaryOp unary_op);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+ class UnaryOp>
+ForwardIt2 transform(ExecutionPolicy &&policy, ForwardIt1 first1,
+ ForwardIt1 last1, ForwardIt2 d_first, UnaryOp unary_op);
+
+template <class InputIt1, class InputIt2, class OutputIt, class BinaryOp>
+OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
+ OutputIt d_first, BinaryOp binary_op);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
+ class ForwardIt3, class BinaryOp>
+ForwardIt3 transform(ExecutionPolicy &&policy, ForwardIt1 first1,
+ ForwardIt1 last1, ForwardIt2 first2, ForwardIt3 d_first,
+ BinaryOp binary_op);
+
+template <class ForwardIt, class OutputIt>
+OutputIt rotate_copy(ForwardIt first, ForwardIt n_first, ForwardIt last,
+ OutputIt d_first);
+
+template <class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
+ForwardIt2 rotate_copy(ExecutionPolicy &&policy, ForwardIt1 first,
+ ForwardIt1 n_first, ForwardIt1 last, ForwardIt2 d_first);
+
+} // namespace std
+
+template <typename T = int> static bool dummyUnary(const T &);
+template <typename T = int, typename U = T>
+static bool dummyBinary(const T &, const U &);
+
+void Test() {
+ std::vector<int> I;
+ std::vector<int> J{I.begin(), I.begin()};
+ // CHECK-NOTES: :[[@LINE-1]]:33: warning: 'begin' iterator supplied where an 'end' iterator is expected
+ std::vector<int> K{I.begin(), J.end()};
+ // CHECK-NOTES: [[@LINE-1]]:20: warning: mismatched ranges supplied to 'std::vector<int>::vector'
+ // CHECK-NOTES: :[[@LINE-2]]:22: note: range passed as the begin iterator
+ // CHECK-NOTES: :[[@LINE-3]]:33: note: different range passed as the end iterator
+ delete (new std::vector<int>(I.end(), I.end()));
+ // CHECK-NOTES: :[[@LINE-1]]:32: warning: 'end' iterator supplied where a 'begin' iterator is expected
+ auto RandomIIter = std::find(I.end(), I.begin(), 0);
+ // CHECK-NOTES: :[[@LINE-1]]:32: warning: 'end' iterator supplied where a 'begin' iterator is expected
+ // CHECK-NOTES: :[[@LINE-2]]:41: warning: 'begin' iterator supplied where an 'end' iterator is expected
+ std::find(std::execution::par, I.begin(), J.end(), 0);
+ // CHECK-NOTES: :[[@LINE-1]]:3: warning: mismatched ranges supplied to 'std::find'
+ // CHECK-NOTES: :[[@LINE-2]]:34: note: range passed as the begin iterator
+ // CHECK-NOTES: :[[@LINE-3]]:45: note: different range passed as the end iterator
+ std::find(std::make_reverse_iterator(I.end()),
+ std::make_reverse_iterator(I.end()), 0);
+ // CHECK-NOTES: :[[@LINE-1]]:40: warning: 'begin' iterator supplied where an 'end' iterator is expected
+ // CHECK-NOTES: :[[@LINE-2]]:13: note: 'make_reverse_iterator<int *>' changes 'end' into a 'begin' iterator
+ std::find(I.rbegin(), std::make_reverse_iterator(J.begin()), 0);
+ // CHECK-NOTES: :[[@LINE-1]]:3: warning: mismatched ranges supplied to 'std::find'
+ // CHECK-NOTES: :[[@LINE-2]]:13: note: range passed as the begin iterator
+ // CHECK-NOTES: :[[@LINE-3]]:52: note: different range passed as the end iterator
+
+ I.insert(J.begin(), J.end(), J.begin());
+ // CHECK-NOTES: :[[@LINE-1]]:12: warning: 'insert<int *>' called with an iterator for a different container
+ // CHECK-NOTES: :[[@LINE-2]]:3: note: container is specified here
+ // CHECK-NOTES: :[[@LINE-3]]:12: note: different container provided here
+ // CHECK-NOTES: :[[@LINE-4]]:23: warning: 'end' iterator supplied where a 'begin' iterator is expected
+ // CHECK-NOTES: :[[@LINE-5]]:32: warning: 'begin' iterator supplied where an 'end' iterator is expected
+
+ std::set_union(I.begin(), I.begin(), J.end(), J.end(), K.end());
+ // CHECK-NOTES: :[[@LINE-1]]:29: warning: 'begin' iterator supplied where an 'end' iterator is expected
+ // CHECK-NOTES: :[[@LINE-2]]:40: warning: 'end' iterator supplied where a 'begin' iterator is expected
+ // CHECK-NOTES: :[[@LINE-3]]:58: warning: 'end' iterator supplied where an output iterator is expected
+ std::set_union(std::execution::par, I.begin(), I.begin(), J.end(), J.end(),
+ K.end());
+ // CHECK-NOTES: :[[@LINE-2]]:50: warning: 'begin' iterator supplied where an 'end' iterator is expected
+ // CHECK-NOTES: :[[@LINE-3]]:61: warning: 'end' iterator supplied where a 'begin' iterator is expected
+ // CHECK-NOTES: :[[@LINE-3]]:18: warning: 'end' iterator supplied where an output iterator is expected
+
+ std::push_heap(std::begin(I), std::end(J));
----------------
denzor200 wrote:
Please add test case:
```
std::vector<int> get_data() {
return std::vector<int>{1,2,3,4};
}
void test() {
std::push_heap(std::begin(get_data()), std::end(get_data()));
}
```
There should also be a warning here "mismatched ranges supplied to 'std::push_heap'"
https://github.com/llvm/llvm-project/pull/99917
More information about the cfe-commits
mailing list