// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s #include "mock-types.h" namespace WTF { constexpr unsigned long notFound = static_cast(-1); class String; class StringImpl; class StringView { public: StringView(const String&); private: RefPtr m_impl; }; class StringImpl { public: void ref() const { ++m_refCount; } void deref() const { if (!--m_refCount) delete this; } static constexpr unsigned s_flagIs8Bit = 1u << 0; bool is8Bit() const { return m_hashAndFlags & s_flagIs8Bit; } const char* characters8() const { return m_char8; } const short* characters16() const { return m_char16; } unsigned length() const { return m_length; } Ref substring(unsigned position, unsigned length) const; unsigned long find(char) const; unsigned long find(StringView) const; unsigned long contains(StringView) const; unsigned long findIgnoringASCIICase(StringView) const; bool startsWith(StringView) const; bool startsWithIgnoringASCIICase(StringView) const; bool endsWith(StringView) const; bool endsWithIgnoringASCIICase(StringView) const; private: mutable unsigned m_refCount { 0 }; unsigned m_length { 0 }; union { const char* m_char8; const short* m_char16; }; unsigned m_hashAndFlags { 0 }; }; class String { public: String() = default; String(StringImpl& impl) : m_impl(&impl) { } String(StringImpl* impl) : m_impl(impl) { } String(Ref&& impl) : m_impl(impl.get()) { } StringImpl* impl() { return m_impl.get(); } unsigned length() const { return m_impl ? m_impl->length() : 0; } const char* characters8() const { return m_impl ? m_impl->characters8() : nullptr; } const short* characters16() const { return m_impl ? m_impl->characters16() : nullptr; } bool is8Bit() const { return !m_impl || m_impl->is8Bit(); } unsigned long find(char character) const { return m_impl ? m_impl->find(character) : notFound; } unsigned long find(StringView str) const { return m_impl ? m_impl->find(str) : notFound; } unsigned long findIgnoringASCIICase(StringView) const; bool contains(char character) const { return find(character) != notFound; } bool contains(StringView) const; bool containsIgnoringASCIICase(StringView) const; bool startsWith(StringView) const; bool startsWithIgnoringASCIICase(StringView) const; bool endsWith(StringView) const; bool endsWithIgnoringASCIICase(StringView) const; String substring(unsigned position, unsigned length) const { if (!m_impl) return { }; if (!position && length >= m_impl->length()) return *this; return m_impl->substring(position, length); } private: RefPtr m_impl; }; template class HashSet { public: template T* find(U&) const; template bool contains(U&) const; unsigned size() { return m_size; } template void add(U&) const; template void remove(U&) const; private: T* m_table { nullptr }; unsigned m_size { 0 }; }; template class HashMap { public: struct Item { T key; S value; }; template Item* find(U&) const; template bool contains(U&) const; template S* get(U&) const; template S* inlineGet(U&) const; template void add(U&) const; template void remove(U&) const; private: Item* m_table { nullptr }; }; template class WeakHashSet { public: template T* find(U&) const; template bool contains(U&) const; template void add(U&) const; template void remove(U&) const; }; template class Vector { public: unsigned size() { return m_size; } T& at(unsigned i) { return m_buffer[i]; } T& operator[](unsigned i) { return m_buffer[i]; } template unsigned find(U&); template unsigned reverseFind(U&); template bool contains(U&); template unsigned findIf(const MatchFunction& match) { for (unsigned i = 0; i < m_size; ++i) { if (match(at(i))) return i; } return static_cast(-1); } template unsigned reverseFindIf(const MatchFunction& match) { for (unsigned i = 0; i < m_size; ++i) { if (match(at(m_size - i))) return i; } return static_cast(-1); } template bool containsIf(const MatchFunction& match) { for (unsigned i = 0; i < m_size; ++i) { if (match(at(m_size - i))) return true; } return false; } template void append(U&) const; template void remove(U&) const; private: T* m_buffer { nullptr }; unsigned m_size { 0 }; }; } using WTF::StringView; using WTF::StringImpl; using WTF::String; using WTF::HashSet; using WTF::HashMap; using WTF::WeakHashSet; using WTF::Vector; class RefCounted { public: void ref() const; void deref() const; }; RefCounted* object(); StringImpl* strImpl(); String* str(); StringView strView(); void test() { strImpl()->is8Bit(); strImpl()->characters8(); strImpl()->characters16(); strImpl()->length(); strImpl()->substring(2, 4); strImpl()->find(strView()); strImpl()->contains(strView()); strImpl()->findIgnoringASCIICase(strView()); strImpl()->startsWith(strView()); strImpl()->startsWithIgnoringASCIICase(strView()); strImpl()->endsWith(strView()); strImpl()->endsWithIgnoringASCIICase(strView()); str()->is8Bit(); str()->characters8(); str()->characters16(); str()->length(); str()->substring(2, 4); str()->find(strView()); str()->contains(strView()); str()->findIgnoringASCIICase(strView()); str()->startsWith(strView()); str()->startsWithIgnoringASCIICase(strView()); str()->endsWith(strView()); str()->endsWithIgnoringASCIICase(strView()); HashSet> set; set.find(*object()); set.contains(*object()); set.add(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} set.remove(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} HashMap, unsigned> map; map.find(*object()); map.contains(*object()); map.inlineGet(*object()); map.add(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} map.remove(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} WeakHashSet> weakSet; weakSet.find(*object()); weakSet.contains(*object()); weakSet.add(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} weakSet.remove(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} Vector> vector; vector.at(0); vector[0]; vector.find(*object()); vector.reverseFind(*object()); vector.contains(*object()); vector.append(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} vector.remove(*object()); // expected-warning@-1{{Call argument is uncounted and unsafe}} auto* obj = object(); vector.findIf([&](Ref key) { return key.ptr() == obj; }); vector.reverseFindIf([&](Ref key) { return key.ptr() == obj; }); vector.containsIf([&](Ref key) { return key.ptr() == obj; }); }