Skip to content

Commit df91cde

Browse files
authored
[alpha.webkit.UncountedCallArgsChecker] Ignore methods of WTF String classes. (#90704)
1 parent 1f1a417 commit df91cde

File tree

3 files changed

+134
-6
lines changed

3 files changed

+134
-6
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,17 @@ class UncountedCallArgsChecker
227227
return NamespaceName == "WTF" &&
228228
(MethodName == "find" || MethodName == "findIf" ||
229229
MethodName == "reverseFind" || MethodName == "reverseFindIf" ||
230-
MethodName == "get" || MethodName == "inlineGet" ||
231-
MethodName == "contains" || MethodName == "containsIf") &&
230+
MethodName == "findIgnoringASCIICase" || MethodName == "get" ||
231+
MethodName == "inlineGet" || MethodName == "contains" ||
232+
MethodName == "containsIf" ||
233+
MethodName == "containsIgnoringASCIICase" ||
234+
MethodName == "startsWith" || MethodName == "endsWith" ||
235+
MethodName == "startsWithIgnoringASCIICase" ||
236+
MethodName == "endsWithIgnoringASCIICase" ||
237+
MethodName == "substring") &&
232238
(ClsName.ends_with("Vector") || ClsName.ends_with("Set") ||
233-
ClsName.ends_with("Map"));
239+
ClsName.ends_with("Map") || ClsName == "StringImpl" ||
240+
ClsName.ends_with("String"));
234241
}
235242

236243
void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {

clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,92 @@
44

55
namespace WTF {
66

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) const
81+
{
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+
793
template <typename T>
894
class HashSet {
995
public:
@@ -89,6 +175,9 @@ namespace WTF {
89175

90176
}
91177

178+
using WTF::StringView;
179+
using WTF::StringImpl;
180+
using WTF::String;
92181
using WTF::HashSet;
93182
using WTF::HashMap;
94183
using WTF::WeakHashSet;
@@ -101,8 +190,37 @@ class RefCounted {
101190
};
102191

103192
RefCounted* object();
193+
StringImpl* strImpl();
194+
String* str();
195+
StringView strView();
104196

105197
void 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+
106224
HashSet<RefPtr<RefCounted>> set;
107225
set.find(*object());
108226
set.contains(*object());

clang/test/Analysis/Checkers/WebKit/mock-types.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ template <typename T, typename PtrTraits = RawPtrTraits<T>, typename RefDerefTra
4747
typename PtrTraits::StorageType t;
4848

4949
Ref() : t{} {};
50-
Ref(T &t) : t(RefDerefTraits::refIfNotNull(t)) { }
50+
Ref(T &t) : t(&RefDerefTraits::ref(t)) { }
5151
Ref(const Ref& o) : t(RefDerefTraits::refIfNotNull(PtrTraits::unwrap(o.t))) { }
5252
~Ref() { RefDerefTraits::derefIfNotNull(PtrTraits::exchange(t, nullptr)); }
5353
T &get() { return *PtrTraits::unwrap(t); }
5454
T *ptr() { return PtrTraits::unwrap(t); }
5555
T *operator->() { return PtrTraits::unwrap(t); }
5656
operator const T &() const { return *PtrTraits::unwrap(t); }
5757
operator T &() { return *PtrTraits::unwrap(t); }
58-
T* leakRef() { PtrTraits::exchange(t, nullptr); }
58+
T* leakRef() { return PtrTraits::exchange(t, nullptr); }
5959
};
6060

6161
template <typename T> struct RefPtr {
@@ -67,6 +67,9 @@ template <typename T> struct RefPtr {
6767
if (t)
6868
t->ref();
6969
}
70+
RefPtr(Ref<T>&& o)
71+
: t(o.leakRef())
72+
{ }
7073
~RefPtr() {
7174
if (t)
7275
t->deref();
@@ -76,7 +79,7 @@ template <typename T> struct RefPtr {
7679
const T *operator->() const { return t; }
7780
T &operator*() { return *t; }
7881
RefPtr &operator=(T *) { return *this; }
79-
operator bool() { return t; }
82+
operator bool() const { return t; }
8083
};
8184

8285
template <typename T> bool operator==(const RefPtr<T> &, const RefPtr<T> &) {

0 commit comments

Comments
 (0)