[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