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 Niwavoid 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 }