264 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s2 3#include "mock-types.h"4 5namespace WTF {6 7 constexpr unsigned long notFound = static_cast<unsigned long>(-1);8 9 class String;10 class StringImpl;11 12 class StringView {13 public:14 StringView(const String&);15 private:16 RefPtr<StringImpl> m_impl;17 };18 19 class StringImpl {20 public:21 void ref() const { ++m_refCount; }22 void deref() const {23 if (!--m_refCount)24 delete this;25 }26 27 static constexpr unsigned s_flagIs8Bit = 1u << 0;28 bool is8Bit() const { return m_hashAndFlags & s_flagIs8Bit; }29 const char* characters8() const { return m_char8; }30 const short* characters16() const { return m_char16; }31 unsigned length() const { return m_length; }32 Ref<StringImpl> substring(unsigned position, unsigned length) const;33 34 unsigned long find(char) const;35 unsigned long find(StringView) const;36 unsigned long contains(StringView) const;37 unsigned long findIgnoringASCIICase(StringView) const;38 39 bool startsWith(StringView) const;40 bool startsWithIgnoringASCIICase(StringView) const;41 bool endsWith(StringView) const;42 bool endsWithIgnoringASCIICase(StringView) const;43 44 private:45 mutable unsigned m_refCount { 0 };46 unsigned m_length { 0 };47 union {48 const char* m_char8;49 const short* m_char16;50 };51 unsigned m_hashAndFlags { 0 };52 };53 54 class String {55 public:56 String() = default;57 String(StringImpl& impl) : m_impl(&impl) { }58 String(StringImpl* impl) : m_impl(impl) { }59 String(Ref<StringImpl>&& impl) : m_impl(impl.get()) { }60 StringImpl* impl() { return m_impl.get(); }61 unsigned length() const { return m_impl ? m_impl->length() : 0; }62 const char* characters8() const { return m_impl ? m_impl->characters8() : nullptr; }63 const short* characters16() const { return m_impl ? m_impl->characters16() : nullptr; }64 65 bool is8Bit() const { return !m_impl || m_impl->is8Bit(); }66 67 unsigned long find(char character) const { return m_impl ? m_impl->find(character) : notFound; }68 unsigned long find(StringView str) const { return m_impl ? m_impl->find(str) : notFound; }69 unsigned long findIgnoringASCIICase(StringView) const;70 71 bool contains(char character) const { return find(character) != notFound; }72 bool contains(StringView) const;73 bool containsIgnoringASCIICase(StringView) const;74 75 bool startsWith(StringView) const;76 bool startsWithIgnoringASCIICase(StringView) const;77 bool endsWith(StringView) const;78 bool endsWithIgnoringASCIICase(StringView) const;79 80 String substring(unsigned position, unsigned length) const81 {82 if (!m_impl)83 return { };84 if (!position && length >= m_impl->length())85 return *this;86 return m_impl->substring(position, length);87 }88 89 private:90 RefPtr<StringImpl> m_impl;91 };92 93 template <typename T>94 class HashSet {95 public:96 template <typename U> T* find(U&) const;97 template <typename U> bool contains(U&) const;98 unsigned size() { return m_size; }99 template <typename U> void add(U&) const;100 template <typename U> void remove(U&) const;101 102 private:103 T* m_table { nullptr };104 unsigned m_size { 0 };105 };106 107 template <typename T, typename S>108 class HashMap {109 public:110 struct Item {111 T key;112 S value;113 };114 115 template <typename U> Item* find(U&) const;116 template <typename U> bool contains(U&) const;117 template <typename U> S* get(U&) const;118 template <typename U> S* inlineGet(U&) const;119 template <typename U> void add(U&) const;120 template <typename U> void remove(U&) const;121 122 private:123 Item* m_table { nullptr };124 };125 126 template <typename T>127 class WeakHashSet {128 public:129 template <typename U> T* find(U&) const;130 template <typename U> bool contains(U&) const;131 template <typename U> void add(U&) const;132 template <typename U> void remove(U&) const;133 };134 135 template <typename T>136 class Vector {137 public:138 unsigned size() { return m_size; }139 T& at(unsigned i) { return m_buffer[i]; }140 T& operator[](unsigned i) { return m_buffer[i]; }141 template <typename U> unsigned find(U&);142 template <typename U> unsigned reverseFind(U&);143 template <typename U> bool contains(U&);144 template <typename MatchFunction> unsigned findIf(const MatchFunction& match)145 {146 for (unsigned i = 0; i < m_size; ++i) {147 if (match(at(i)))148 return i;149 }150 return static_cast<unsigned>(-1);151 }152 template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match)153 {154 for (unsigned i = 0; i < m_size; ++i) {155 if (match(at(m_size - i)))156 return i;157 }158 return static_cast<unsigned>(-1);159 }160 template <typename MatchFunction> bool containsIf(const MatchFunction& match)161 {162 for (unsigned i = 0; i < m_size; ++i) {163 if (match(at(m_size - i)))164 return true;165 }166 return false;167 }168 template <typename U> void append(U&) const;169 template <typename U> void remove(U&) const;170 171 private:172 T* m_buffer { nullptr };173 unsigned m_size { 0 };174 };175 176}177 178using WTF::StringView;179using WTF::StringImpl;180using WTF::String;181using WTF::HashSet;182using WTF::HashMap;183using WTF::WeakHashSet;184using WTF::Vector;185 186class RefCounted {187public:188 void ref() const;189 void deref() const;190};191 192RefCounted* object();193StringImpl* strImpl();194String* str();195StringView strView();196 197void test() {198 strImpl()->is8Bit();199 strImpl()->characters8();200 strImpl()->characters16();201 strImpl()->length();202 strImpl()->substring(2, 4);203 strImpl()->find(strView());204 strImpl()->contains(strView());205 strImpl()->findIgnoringASCIICase(strView());206 strImpl()->startsWith(strView());207 strImpl()->startsWithIgnoringASCIICase(strView());208 strImpl()->endsWith(strView());209 strImpl()->endsWithIgnoringASCIICase(strView());210 211 str()->is8Bit();212 str()->characters8();213 str()->characters16();214 str()->length();215 str()->substring(2, 4);216 str()->find(strView());217 str()->contains(strView());218 str()->findIgnoringASCIICase(strView());219 str()->startsWith(strView());220 str()->startsWithIgnoringASCIICase(strView());221 str()->endsWith(strView());222 str()->endsWithIgnoringASCIICase(strView());223 224 HashSet<RefPtr<RefCounted>> set;225 set.find(*object());226 set.contains(*object());227 set.add(*object());228 // expected-warning@-1{{Call argument is uncounted and unsafe}}229 set.remove(*object());230 // expected-warning@-1{{Call argument is uncounted and unsafe}}231 232 HashMap<Ref<RefCounted>, unsigned> map;233 map.find(*object());234 map.contains(*object());235 map.inlineGet(*object());236 map.add(*object());237 // expected-warning@-1{{Call argument is uncounted and unsafe}}238 map.remove(*object());239 // expected-warning@-1{{Call argument is uncounted and unsafe}}240 241 WeakHashSet<Ref<RefCounted>> weakSet;242 weakSet.find(*object());243 weakSet.contains(*object());244 weakSet.add(*object());245 // expected-warning@-1{{Call argument is uncounted and unsafe}}246 weakSet.remove(*object());247 // expected-warning@-1{{Call argument is uncounted and unsafe}}248 249 Vector<Ref<RefCounted>> vector;250 vector.at(0);251 vector[0];252 vector.find(*object());253 vector.reverseFind(*object());254 vector.contains(*object());255 vector.append(*object());256 // expected-warning@-1{{Call argument is uncounted and unsafe}}257 vector.remove(*object());258 // expected-warning@-1{{Call argument is uncounted and unsafe}}259 260 auto* obj = object();261 vector.findIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });262 vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });263 vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });264}