264 lines
7.6 KiB
C++
264 lines
7.6 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
|
|
|
|
#include "mock-types.h"
|
|
|
|
namespace WTF {
|
|
|
|
constexpr unsigned long notFound = static_cast<unsigned long>(-1);
|
|
|
|
class String;
|
|
class StringImpl;
|
|
|
|
class StringView {
|
|
public:
|
|
StringView(const String&);
|
|
private:
|
|
RefPtr<StringImpl> 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<StringImpl> 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<StringImpl>&& 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<StringImpl> m_impl;
|
|
};
|
|
|
|
template <typename T>
|
|
class HashSet {
|
|
public:
|
|
template <typename U> T* find(U&) const;
|
|
template <typename U> bool contains(U&) const;
|
|
unsigned size() { return m_size; }
|
|
template <typename U> void add(U&) const;
|
|
template <typename U> void remove(U&) const;
|
|
|
|
private:
|
|
T* m_table { nullptr };
|
|
unsigned m_size { 0 };
|
|
};
|
|
|
|
template <typename T, typename S>
|
|
class HashMap {
|
|
public:
|
|
struct Item {
|
|
T key;
|
|
S value;
|
|
};
|
|
|
|
template <typename U> Item* find(U&) const;
|
|
template <typename U> bool contains(U&) const;
|
|
template <typename U> S* get(U&) const;
|
|
template <typename U> S* inlineGet(U&) const;
|
|
template <typename U> void add(U&) const;
|
|
template <typename U> void remove(U&) const;
|
|
|
|
private:
|
|
Item* m_table { nullptr };
|
|
};
|
|
|
|
template <typename T>
|
|
class WeakHashSet {
|
|
public:
|
|
template <typename U> T* find(U&) const;
|
|
template <typename U> bool contains(U&) const;
|
|
template <typename U> void add(U&) const;
|
|
template <typename U> void remove(U&) const;
|
|
};
|
|
|
|
template <typename T>
|
|
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 <typename U> unsigned find(U&);
|
|
template <typename U> unsigned reverseFind(U&);
|
|
template <typename U> bool contains(U&);
|
|
template <typename MatchFunction> unsigned findIf(const MatchFunction& match)
|
|
{
|
|
for (unsigned i = 0; i < m_size; ++i) {
|
|
if (match(at(i)))
|
|
return i;
|
|
}
|
|
return static_cast<unsigned>(-1);
|
|
}
|
|
template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match)
|
|
{
|
|
for (unsigned i = 0; i < m_size; ++i) {
|
|
if (match(at(m_size - i)))
|
|
return i;
|
|
}
|
|
return static_cast<unsigned>(-1);
|
|
}
|
|
template <typename MatchFunction> bool containsIf(const MatchFunction& match)
|
|
{
|
|
for (unsigned i = 0; i < m_size; ++i) {
|
|
if (match(at(m_size - i)))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
template <typename U> void append(U&) const;
|
|
template <typename U> 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<RefPtr<RefCounted>> 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<Ref<RefCounted>, 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<Ref<RefCounted>> 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<Ref<RefCounted>> 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<RefCounted> key) { return key.ptr() == obj; });
|
|
vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
|
|
vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
|
|
} |