[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