xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp (revision df91cde4da62aec22e4d384b1bc800590c7f561a)
1031f9f33SRyosuke Niwa // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2031f9f33SRyosuke Niwa 
3031f9f33SRyosuke Niwa #include "mock-types.h"
4031f9f33SRyosuke Niwa 
5031f9f33SRyosuke Niwa namespace WTF {
6031f9f33SRyosuke Niwa 
7*df91cde4SRyosuke Niwa   constexpr unsigned long notFound = static_cast<unsigned long>(-1);
8*df91cde4SRyosuke Niwa 
9*df91cde4SRyosuke Niwa   class String;
10*df91cde4SRyosuke Niwa   class StringImpl;
11*df91cde4SRyosuke Niwa 
12*df91cde4SRyosuke Niwa   class StringView {
13*df91cde4SRyosuke Niwa   public:
14*df91cde4SRyosuke Niwa     StringView(const String&);
15*df91cde4SRyosuke Niwa   private:
16*df91cde4SRyosuke Niwa     RefPtr<StringImpl> m_impl;
17*df91cde4SRyosuke Niwa   };
18*df91cde4SRyosuke Niwa 
19*df91cde4SRyosuke Niwa   class StringImpl {
20*df91cde4SRyosuke Niwa   public:
ref() const21*df91cde4SRyosuke Niwa     void ref() const { ++m_refCount; }
deref() const22*df91cde4SRyosuke Niwa     void deref() const {
23*df91cde4SRyosuke Niwa       if (!--m_refCount)
24*df91cde4SRyosuke Niwa         delete this;
25*df91cde4SRyosuke Niwa     }
26*df91cde4SRyosuke Niwa 
27*df91cde4SRyosuke Niwa     static constexpr unsigned s_flagIs8Bit = 1u << 0;
is8Bit() const28*df91cde4SRyosuke Niwa     bool is8Bit() const { return m_hashAndFlags & s_flagIs8Bit; }
characters8() const29*df91cde4SRyosuke Niwa     const char* characters8() const { return m_char8; }
characters16() const30*df91cde4SRyosuke Niwa     const short* characters16() const { return m_char16; }
length() const31*df91cde4SRyosuke Niwa     unsigned length() const { return m_length; }
32*df91cde4SRyosuke Niwa     Ref<StringImpl> substring(unsigned position, unsigned length) const;
33*df91cde4SRyosuke Niwa 
34*df91cde4SRyosuke Niwa     unsigned long find(char) const;
35*df91cde4SRyosuke Niwa     unsigned long find(StringView) const;
36*df91cde4SRyosuke Niwa     unsigned long contains(StringView) const;
37*df91cde4SRyosuke Niwa     unsigned long findIgnoringASCIICase(StringView) const;
38*df91cde4SRyosuke Niwa 
39*df91cde4SRyosuke Niwa     bool startsWith(StringView) const;
40*df91cde4SRyosuke Niwa     bool startsWithIgnoringASCIICase(StringView) const;
41*df91cde4SRyosuke Niwa     bool endsWith(StringView) const;
42*df91cde4SRyosuke Niwa     bool endsWithIgnoringASCIICase(StringView) const;
43*df91cde4SRyosuke Niwa 
44*df91cde4SRyosuke Niwa   private:
45*df91cde4SRyosuke Niwa     mutable unsigned m_refCount { 0 };
46*df91cde4SRyosuke Niwa     unsigned m_length { 0 };
47*df91cde4SRyosuke Niwa     union {
48*df91cde4SRyosuke Niwa       const char* m_char8;
49*df91cde4SRyosuke Niwa       const short* m_char16;
50*df91cde4SRyosuke Niwa     };
51*df91cde4SRyosuke Niwa     unsigned m_hashAndFlags { 0 };
52*df91cde4SRyosuke Niwa   };
53*df91cde4SRyosuke Niwa 
54*df91cde4SRyosuke Niwa   class String {
55*df91cde4SRyosuke Niwa   public:
56*df91cde4SRyosuke Niwa     String() = default;
String(StringImpl & impl)57*df91cde4SRyosuke Niwa     String(StringImpl& impl) : m_impl(&impl) { }
String(StringImpl * impl)58*df91cde4SRyosuke Niwa     String(StringImpl* impl) : m_impl(impl) { }
String(Ref<StringImpl> && impl)59*df91cde4SRyosuke Niwa     String(Ref<StringImpl>&& impl) : m_impl(impl.get()) { }
impl()60*df91cde4SRyosuke Niwa     StringImpl* impl() { return m_impl.get(); }
length() const61*df91cde4SRyosuke Niwa     unsigned length() const { return m_impl ? m_impl->length() : 0; }
characters8() const62*df91cde4SRyosuke Niwa     const char* characters8() const { return m_impl ? m_impl->characters8() : nullptr; }
characters16() const63*df91cde4SRyosuke Niwa     const short* characters16() const { return m_impl ? m_impl->characters16() : nullptr; }
64*df91cde4SRyosuke Niwa 
is8Bit() const65*df91cde4SRyosuke Niwa     bool is8Bit() const { return !m_impl || m_impl->is8Bit(); }
66*df91cde4SRyosuke Niwa 
find(char character) const67*df91cde4SRyosuke Niwa     unsigned long find(char character) const { return m_impl ? m_impl->find(character) : notFound; }
find(StringView str) const68*df91cde4SRyosuke Niwa     unsigned long find(StringView str) const { return m_impl ? m_impl->find(str) : notFound; }
69*df91cde4SRyosuke Niwa     unsigned long findIgnoringASCIICase(StringView) const;
70*df91cde4SRyosuke Niwa 
contains(char character) const71*df91cde4SRyosuke Niwa     bool contains(char character) const { return find(character) != notFound; }
72*df91cde4SRyosuke Niwa     bool contains(StringView) const;
73*df91cde4SRyosuke Niwa     bool containsIgnoringASCIICase(StringView) const;
74*df91cde4SRyosuke Niwa 
75*df91cde4SRyosuke Niwa     bool startsWith(StringView) const;
76*df91cde4SRyosuke Niwa     bool startsWithIgnoringASCIICase(StringView) const;
77*df91cde4SRyosuke Niwa     bool endsWith(StringView) const;
78*df91cde4SRyosuke Niwa     bool endsWithIgnoringASCIICase(StringView) const;
79*df91cde4SRyosuke Niwa 
substring(unsigned position,unsigned length) const80*df91cde4SRyosuke Niwa     String substring(unsigned position, unsigned length) const
81*df91cde4SRyosuke Niwa     {
82*df91cde4SRyosuke Niwa       if (!m_impl)
83*df91cde4SRyosuke Niwa         return { };
84*df91cde4SRyosuke Niwa       if (!position && length >= m_impl->length())
85*df91cde4SRyosuke Niwa         return *this;
86*df91cde4SRyosuke Niwa       return m_impl->substring(position, length);
87*df91cde4SRyosuke Niwa     }
88*df91cde4SRyosuke Niwa 
89*df91cde4SRyosuke Niwa   private:
90*df91cde4SRyosuke Niwa     RefPtr<StringImpl> m_impl;
91*df91cde4SRyosuke Niwa   };
92*df91cde4SRyosuke Niwa 
93031f9f33SRyosuke Niwa   template <typename T>
94031f9f33SRyosuke Niwa   class HashSet {
95031f9f33SRyosuke Niwa   public:
96031f9f33SRyosuke Niwa     template <typename U> T* find(U&) const;
97031f9f33SRyosuke Niwa     template <typename U> bool contains(U&) const;
size()98031f9f33SRyosuke Niwa     unsigned size() { return m_size; }
99031f9f33SRyosuke Niwa     template <typename U> void add(U&) const;
100031f9f33SRyosuke Niwa     template <typename U> void remove(U&) const;
101031f9f33SRyosuke Niwa 
102031f9f33SRyosuke Niwa   private:
103031f9f33SRyosuke Niwa     T* m_table { nullptr };
104031f9f33SRyosuke Niwa     unsigned m_size { 0 };
105031f9f33SRyosuke Niwa   };
106031f9f33SRyosuke Niwa 
107031f9f33SRyosuke Niwa   template <typename T, typename S>
108031f9f33SRyosuke Niwa   class HashMap {
109031f9f33SRyosuke Niwa   public:
110031f9f33SRyosuke Niwa     struct Item {
111031f9f33SRyosuke Niwa       T key;
112031f9f33SRyosuke Niwa       S value;
113031f9f33SRyosuke Niwa     };
114031f9f33SRyosuke Niwa 
115031f9f33SRyosuke Niwa     template <typename U> Item* find(U&) const;
116031f9f33SRyosuke Niwa     template <typename U> bool contains(U&) const;
117031f9f33SRyosuke Niwa     template <typename U> S* get(U&) const;
118031f9f33SRyosuke Niwa     template <typename U> S* inlineGet(U&) const;
119031f9f33SRyosuke Niwa     template <typename U> void add(U&) const;
120031f9f33SRyosuke Niwa     template <typename U> void remove(U&) const;
121031f9f33SRyosuke Niwa 
122031f9f33SRyosuke Niwa   private:
123031f9f33SRyosuke Niwa     Item* m_table { nullptr };
124031f9f33SRyosuke Niwa   };
125031f9f33SRyosuke Niwa 
126031f9f33SRyosuke Niwa   template <typename T>
127031f9f33SRyosuke Niwa   class WeakHashSet {
128031f9f33SRyosuke Niwa   public:
129031f9f33SRyosuke Niwa     template <typename U> T* find(U&) const;
130031f9f33SRyosuke Niwa     template <typename U> bool contains(U&) const;
131031f9f33SRyosuke Niwa     template <typename U> void add(U&) const;
132031f9f33SRyosuke Niwa     template <typename U> void remove(U&) const;
133031f9f33SRyosuke Niwa   };
134031f9f33SRyosuke Niwa 
135031f9f33SRyosuke Niwa   template <typename T>
136031f9f33SRyosuke Niwa   class Vector {
137031f9f33SRyosuke Niwa   public:
size()138031f9f33SRyosuke Niwa     unsigned size() { return m_size; }
at(unsigned i)139031f9f33SRyosuke Niwa     T& at(unsigned i) { return m_buffer[i]; }
operator [](unsigned i)140031f9f33SRyosuke Niwa     T& operator[](unsigned i) { return m_buffer[i]; }
141031f9f33SRyosuke Niwa     template <typename U> unsigned find(U&);
142031f9f33SRyosuke Niwa     template <typename U> unsigned reverseFind(U&);
143031f9f33SRyosuke Niwa     template <typename U> bool contains(U&);
findIf(const MatchFunction & match)144031f9f33SRyosuke Niwa     template <typename MatchFunction> unsigned findIf(const MatchFunction& match)
145031f9f33SRyosuke Niwa     {
146031f9f33SRyosuke Niwa       for (unsigned i = 0; i < m_size; ++i) {
147031f9f33SRyosuke Niwa         if (match(at(i)))
148031f9f33SRyosuke Niwa           return i;
149031f9f33SRyosuke Niwa       }
150031f9f33SRyosuke Niwa       return static_cast<unsigned>(-1);
151031f9f33SRyosuke Niwa     }
reverseFindIf(const MatchFunction & match)152031f9f33SRyosuke Niwa     template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match)
153031f9f33SRyosuke Niwa     {
154031f9f33SRyosuke Niwa       for (unsigned i = 0; i < m_size; ++i) {
155031f9f33SRyosuke Niwa         if (match(at(m_size - i)))
156031f9f33SRyosuke Niwa           return i;
157031f9f33SRyosuke Niwa       }
158031f9f33SRyosuke Niwa       return static_cast<unsigned>(-1);
159031f9f33SRyosuke Niwa     }
containsIf(const MatchFunction & match)160031f9f33SRyosuke Niwa     template <typename MatchFunction> bool containsIf(const MatchFunction& match)
161031f9f33SRyosuke Niwa     {
162031f9f33SRyosuke Niwa       for (unsigned i = 0; i < m_size; ++i) {
163031f9f33SRyosuke Niwa         if (match(at(m_size - i)))
164031f9f33SRyosuke Niwa           return true;
165031f9f33SRyosuke Niwa       }
166031f9f33SRyosuke Niwa       return false;
167031f9f33SRyosuke Niwa     }
168031f9f33SRyosuke Niwa     template <typename U> void append(U&) const;
169031f9f33SRyosuke Niwa     template <typename U> void remove(U&) const;
170031f9f33SRyosuke Niwa 
171031f9f33SRyosuke Niwa   private:
172031f9f33SRyosuke Niwa     T* m_buffer { nullptr };
173031f9f33SRyosuke Niwa     unsigned m_size { 0 };
174031f9f33SRyosuke Niwa   };
175031f9f33SRyosuke Niwa 
176031f9f33SRyosuke Niwa }
177031f9f33SRyosuke Niwa 
178*df91cde4SRyosuke Niwa using WTF::StringView;
179*df91cde4SRyosuke Niwa using WTF::StringImpl;
180*df91cde4SRyosuke Niwa using WTF::String;
181031f9f33SRyosuke Niwa using WTF::HashSet;
182031f9f33SRyosuke Niwa using WTF::HashMap;
183031f9f33SRyosuke Niwa using WTF::WeakHashSet;
184031f9f33SRyosuke Niwa using WTF::Vector;
185031f9f33SRyosuke Niwa 
186031f9f33SRyosuke Niwa class RefCounted {
187031f9f33SRyosuke Niwa public:
188031f9f33SRyosuke Niwa   void ref() const;
189031f9f33SRyosuke Niwa   void deref() const;
190031f9f33SRyosuke Niwa };
191031f9f33SRyosuke Niwa 
192031f9f33SRyosuke Niwa RefCounted* object();
193*df91cde4SRyosuke Niwa StringImpl* strImpl();
194*df91cde4SRyosuke Niwa String* str();
195*df91cde4SRyosuke Niwa StringView strView();
196031f9f33SRyosuke Niwa 
test()197031f9f33SRyosuke Niwa void test() {
198*df91cde4SRyosuke Niwa   strImpl()->is8Bit();
199*df91cde4SRyosuke Niwa   strImpl()->characters8();
200*df91cde4SRyosuke Niwa   strImpl()->characters16();
201*df91cde4SRyosuke Niwa   strImpl()->length();
202*df91cde4SRyosuke Niwa   strImpl()->substring(2, 4);
203*df91cde4SRyosuke Niwa   strImpl()->find(strView());
204*df91cde4SRyosuke Niwa   strImpl()->contains(strView());
205*df91cde4SRyosuke Niwa   strImpl()->findIgnoringASCIICase(strView());
206*df91cde4SRyosuke Niwa   strImpl()->startsWith(strView());
207*df91cde4SRyosuke Niwa   strImpl()->startsWithIgnoringASCIICase(strView());
208*df91cde4SRyosuke Niwa   strImpl()->endsWith(strView());
209*df91cde4SRyosuke Niwa   strImpl()->endsWithIgnoringASCIICase(strView());
210*df91cde4SRyosuke Niwa 
211*df91cde4SRyosuke Niwa   str()->is8Bit();
212*df91cde4SRyosuke Niwa   str()->characters8();
213*df91cde4SRyosuke Niwa   str()->characters16();
214*df91cde4SRyosuke Niwa   str()->length();
215*df91cde4SRyosuke Niwa   str()->substring(2, 4);
216*df91cde4SRyosuke Niwa   str()->find(strView());
217*df91cde4SRyosuke Niwa   str()->contains(strView());
218*df91cde4SRyosuke Niwa   str()->findIgnoringASCIICase(strView());
219*df91cde4SRyosuke Niwa   str()->startsWith(strView());
220*df91cde4SRyosuke Niwa   str()->startsWithIgnoringASCIICase(strView());
221*df91cde4SRyosuke Niwa   str()->endsWith(strView());
222*df91cde4SRyosuke Niwa   str()->endsWithIgnoringASCIICase(strView());
223*df91cde4SRyosuke Niwa 
224031f9f33SRyosuke Niwa   HashSet<RefPtr<RefCounted>> set;
225031f9f33SRyosuke Niwa   set.find(*object());
226031f9f33SRyosuke Niwa   set.contains(*object());
227031f9f33SRyosuke Niwa   set.add(*object());
228031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
229031f9f33SRyosuke Niwa   set.remove(*object());
230031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
231031f9f33SRyosuke Niwa 
232031f9f33SRyosuke Niwa   HashMap<Ref<RefCounted>, unsigned> map;
233031f9f33SRyosuke Niwa   map.find(*object());
234031f9f33SRyosuke Niwa   map.contains(*object());
235031f9f33SRyosuke Niwa   map.inlineGet(*object());
236031f9f33SRyosuke Niwa   map.add(*object());
237031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
238031f9f33SRyosuke Niwa   map.remove(*object());
239031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
240031f9f33SRyosuke Niwa 
241031f9f33SRyosuke Niwa   WeakHashSet<Ref<RefCounted>> weakSet;
242031f9f33SRyosuke Niwa   weakSet.find(*object());
243031f9f33SRyosuke Niwa   weakSet.contains(*object());
244031f9f33SRyosuke Niwa   weakSet.add(*object());
245031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
246031f9f33SRyosuke Niwa   weakSet.remove(*object());
247031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
248031f9f33SRyosuke Niwa 
249031f9f33SRyosuke Niwa   Vector<Ref<RefCounted>> vector;
250031f9f33SRyosuke Niwa   vector.at(0);
251031f9f33SRyosuke Niwa   vector[0];
252031f9f33SRyosuke Niwa   vector.find(*object());
253031f9f33SRyosuke Niwa   vector.reverseFind(*object());
254031f9f33SRyosuke Niwa   vector.contains(*object());
255031f9f33SRyosuke Niwa   vector.append(*object());
256031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
257031f9f33SRyosuke Niwa   vector.remove(*object());
258031f9f33SRyosuke Niwa   // expected-warning@-1{{Call argument is uncounted and unsafe}}
259031f9f33SRyosuke Niwa 
260031f9f33SRyosuke Niwa   auto* obj = object();
261031f9f33SRyosuke Niwa   vector.findIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
262031f9f33SRyosuke Niwa   vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
263031f9f33SRyosuke Niwa   vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
264031f9f33SRyosuke Niwa }