[clang] 031f9f3 - [alpha.webkit.UncountedCallArgsChecker] Ignore calls to WTF's container methods (#82156)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 20 17:12:28 PST 2024
Author: Ryosuke Niwa
Date: 2024-02-20T17:12:24-08:00
New Revision: 031f9f331723e6bebc405ffdee4b8a87a5fc0472
URL: https://github.com/llvm/llvm-project/commit/031f9f331723e6bebc405ffdee4b8a87a5fc0472
DIFF: https://github.com/llvm/llvm-project/commit/031f9f331723e6bebc405ffdee4b8a87a5fc0472.diff
LOG: [alpha.webkit.UncountedCallArgsChecker] Ignore calls to WTF's container methods (#82156)
This PR makes the checker ignore / skip calls to methods of Web Template
Platform's container types such as HashMap, HashSet, WeakHashSet,
WeakHashMap, Vector, etc...
Added:
clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp
Modified:
clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index 8d344f9b63961a..8b41a949fd6734 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -170,6 +170,9 @@ class UncountedCallArgsChecker
if (!Callee)
return false;
+ if (isMethodOnWTFContainerType(Callee))
+ return true;
+
auto overloadedOperatorType = Callee->getOverloadedOperator();
if (overloadedOperatorType == OO_EqualEqual ||
overloadedOperatorType == OO_ExclaimEqual ||
@@ -198,6 +201,31 @@ class UncountedCallArgsChecker
return false;
}
+ bool isMethodOnWTFContainerType(const FunctionDecl *Decl) const {
+ if (!isa<CXXMethodDecl>(Decl))
+ return false;
+ auto *ClassDecl = Decl->getParent();
+ if (!ClassDecl || !isa<CXXRecordDecl>(ClassDecl))
+ return false;
+
+ auto *NsDecl = ClassDecl->getParent();
+ if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
+ return false;
+
+ auto MethodName = safeGetName(Decl);
+ auto ClsNameStr = safeGetName(ClassDecl);
+ StringRef ClsName = ClsNameStr; // FIXME: Make safeGetName return StringRef.
+ auto NamespaceName = safeGetName(NsDecl);
+ // FIXME: These should be implemented via attributes.
+ return NamespaceName == "WTF" &&
+ (MethodName == "find" || MethodName == "findIf" ||
+ MethodName == "reverseFind" || MethodName == "reverseFindIf" ||
+ MethodName == "get" || MethodName == "inlineGet" ||
+ MethodName == "contains" || MethodName == "containsIf") &&
+ (ClsName.ends_with("Vector") || ClsName.ends_with("Set") ||
+ ClsName.ends_with("Map"));
+ }
+
void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {
assert(CallArg);
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp
new file mode 100644
index 00000000000000..0a63a789856127
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+namespace WTF {
+
+ 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::HashSet;
+using WTF::HashMap;
+using WTF::WeakHashSet;
+using WTF::Vector;
+
+class RefCounted {
+public:
+ void ref() const;
+ void deref() const;
+};
+
+RefCounted* object();
+
+void test() {
+ HashSet<RefPtr<RefCounted>> set;
+ set.find(*object());
+ set.contains(*object());
+ set.add(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ set.remove(*object());
+ // expected-warning at -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 at -1{{Call argument is uncounted and unsafe}}
+ map.remove(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+
+ WeakHashSet<Ref<RefCounted>> weakSet;
+ weakSet.find(*object());
+ weakSet.contains(*object());
+ weakSet.add(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ weakSet.remove(*object());
+ // expected-warning at -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 at -1{{Call argument is uncounted and unsafe}}
+ vector.remove(*object());
+ // expected-warning at -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; });
+}
\ No newline at end of file
More information about the cfe-commits
mailing list