1 // RUN: %check_clang_tidy %s bugprone-inaccurate-erase %t
2 
3 namespace std {
4 template <typename T> struct vec_iterator {
5   T ptr;
6   vec_iterator operator++(int);
7 
8   template <typename X>
9   vec_iterator(const vec_iterator<X> &); // Omit enable_if<...>.
10 };
11 
12 template <typename T> struct vector {
13   typedef vec_iterator<T*> iterator;
14 
15   iterator begin();
16   iterator end();
17 
18   void erase(iterator);
19   void erase(iterator, iterator);
20 };
21 
22 template <typename T> struct vector_with_const_iterator {
23   typedef vec_iterator<T*> iterator;
24   typedef vec_iterator<const T*> const_iterator;
25 
26   iterator begin();
27   iterator end();
28 
29   void erase(const_iterator);
30   void erase(const_iterator, const_iterator);
31 };
32 
33 template <typename FwIt, typename T>
34 FwIt remove(FwIt begin, FwIt end, const T &val);
35 
36 template <typename FwIt, typename Func>
37 FwIt remove_if(FwIt begin, FwIt end, Func f);
38 
39 template <typename FwIt> FwIt unique(FwIt begin, FwIt end);
40 
41 template <typename T> struct unique_ptr {};
42 } // namespace std
43 
44 struct custom_iter {};
45 struct custom_container {
46   void erase(...);
47   custom_iter begin();
48   custom_iter end();
49 };
50 
g()51 template <typename T> void g() {
52   T t;
53   t.erase(std::remove(t.begin(), t.end(), 10));
54   // CHECK-FIXES: {{^  }}t.erase(std::remove(t.begin(), t.end(), 10));{{$}}
55 
56   std::vector<int> v;
57   v.erase(remove(v.begin(), v.end(), 10));
58   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
59   // CHECK-FIXES: {{^  }}v.erase(remove(v.begin(), v.end(), 10), v.end());{{$}}
60 }
61 
62 #define ERASE(x, y) x.erase(remove(x.begin(), x.end(), y))
63 // CHECK-FIXES: #define ERASE(x, y) x.erase(remove(x.begin(), x.end(), y))
64 
main()65 int main() {
66   std::vector<int> v;
67 
68   v.erase(remove(v.begin(), v.end(), 10));
69   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one item even when multiple items should be removed [bugprone-inaccurate-erase]
70   // CHECK-FIXES: {{^  }}v.erase(remove(v.begin(), v.end(), 10), v.end());{{$}}
71   v.erase(remove(v.begin(), v.end(), 20), v.end());
72 
73   auto *p = &v;
74   p->erase(remove(p->begin(), p->end(), 11));
75   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
76   // CHECK-FIXES: {{^  }}p->erase(remove(p->begin(), p->end(), 11), p->end());{{$}}
77 
78   std::vector_with_const_iterator<int> v2;
79   v2.erase(remove(v2.begin(), v2.end(), 12));
80   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
81   // CHECK-FIXES: {{^  }}v2.erase(remove(v2.begin(), v2.end(), 12), v2.end());{{$}}
82 
83   // Fix is not trivial.
84   auto it = v.end();
85   v.erase(remove(v.begin(), it, 10));
86   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
87   // CHECK-FIXES: {{^  }}v.erase(remove(v.begin(), it, 10));{{$}}
88 
89   g<std::vector<int>>();
90   g<custom_container>();
91 
92   ERASE(v, 15);
93   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: this call will remove at most one
94   // CHECK-FIXES: {{^  }}ERASE(v, 15);{{$}}
95 
96   std::vector<std::unique_ptr<int>> vupi;
97   auto iter = vupi.begin();
98   vupi.erase(iter++);
99   // CHECK-FIXES: {{^  }}vupi.erase(iter++);{{$}}
100 }
101