[clang] [llvm] Introduce a new WebKit checker for a unchecked call arguments (#113708) (PR #114522)

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 1 01:56:16 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)

<details>
<summary>Changes</summary>

This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.

---

Patch is 20.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/114522.diff


8 Files Affected:

- (modified) clang/include/clang/StaticAnalyzer/Checkers/Checkers.td (+4) 
- (modified) clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt (+1-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+11-1) 
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+8) 
- (renamed) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp (+64-14) 
- (added) clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp (+367) 
- (added) clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp (+25) 
- (modified) llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn (+1-1) 


``````````diff
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 86d62b58cac0fb..bc172c7d2fe348 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1760,6 +1760,10 @@ def UncountedCallArgsChecker : Checker<"UncountedCallArgsChecker">,
   HelpText<"Check uncounted call arguments.">,
   Documentation<HasDocumentation>;
 
+def UncheckedCallArgsChecker : Checker<"UncheckedCallArgsChecker">,
+  HelpText<"Check unchecked call arguments.">,
+  Documentation<NotDocumented>;
+
 def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
   HelpText<"Check uncounted local variables.">,
   Documentation<HasDocumentation>;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index c6e5afdc42424c..f40318f46dea1a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -134,7 +134,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   WebKit/ASTUtils.cpp
   WebKit/PtrTypesSemantics.cpp
   WebKit/RefCntblBaseVirtualDtorChecker.cpp
-  WebKit/UncountedCallArgsChecker.cpp
+  WebKit/RawPtrRefCallArgsChecker.cpp
   WebKit/UncountedLambdaCapturesChecker.cpp
   WebKit/RawPtrRefLocalVarsChecker.cpp
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 46819d5ca12058..2c80bd86375431 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -173,6 +173,16 @@ std::optional<bool> isUncounted(const QualType T) {
   return isUncounted(T->getAsCXXRecordDecl());
 }
 
+std::optional<bool> isUnchecked(const QualType T) {
+  if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
+    if (auto *Decl = Subst->getAssociatedDecl()) {
+      if (isCheckedPtr(safeGetName(Decl)))
+        return false;
+    }
+  }
+  return isUnchecked(T->getAsCXXRecordDecl());
+}
+
 std::optional<bool> isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
@@ -187,7 +197,7 @@ std::optional<bool> isUncounted(const CXXRecordDecl* Class)
 }
 
 std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
-  if (isCheckedPtr(Class))
+  if (!Class || isCheckedPtr(Class))
     return false; // Cheaper than below
   return isCheckedPtrCapable(Class);
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 30bdaed706bb53..54c4872ad57d8c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -55,10 +55,18 @@ bool isCheckedPtr(const clang::CXXRecordDecl *Class);
 /// not, std::nullopt if inconclusive.
 std::optional<bool> isUncounted(const clang::QualType T);
 
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::QualType T);
+
 /// \returns true if \p Class is ref-countable AND not ref-counted, false if
 /// not, std::nullopt if inconclusive.
 std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
 
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::CXXRecordDecl* Class);
+
 /// \returns true if \p T is either a raw pointer or reference to an uncounted
 /// class, false if not, std::nullopt if inconclusive.
 std::optional<bool> isUncountedPtr(const clang::QualType T);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
similarity index 82%
rename from clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index 1a5a7309a54f16..f1fbe61c421f88 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -1,4 +1,4 @@
-//=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
+//=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -27,16 +27,20 @@ using namespace ento;
 
 namespace {
 
-class UncountedCallArgsChecker
+class RawPtrRefCallArgsChecker
     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
-  BugType Bug{this,
-            "Uncounted call argument for a raw pointer/reference parameter",
-            "WebKit coding guidelines"};
+  BugType Bug;
   mutable BugReporter *BR;
 
   TrivialFunctionAnalysis TFA;
 
 public:
+  RawPtrRefCallArgsChecker(const char* description)
+      : Bug(this, description, "WebKit coding guidelines") {}
+
+  virtual std::optional<bool> isUnsafeType(QualType) const = 0;
+  virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
+  virtual const char *ptrKind() const = 0;
 
   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
                     BugReporter &BRArg) const {
@@ -48,10 +52,10 @@ class UncountedCallArgsChecker
     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
       using Base = RecursiveASTVisitor<LocalVisitor>;
 
-      const UncountedCallArgsChecker *Checker;
+      const RawPtrRefCallArgsChecker *Checker;
       Decl *DeclWithIssue{nullptr};
 
-      explicit LocalVisitor(const UncountedCallArgsChecker *Checker)
+      explicit LocalVisitor(const RawPtrRefCallArgsChecker *Checker)
           : Checker(Checker) {
         assert(Checker);
       }
@@ -101,8 +105,8 @@ class UncountedCallArgsChecker
         }
         auto *E = MemberCallExpr->getImplicitObjectArgument();
         QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType();
-        std::optional<bool> IsUncounted = isUncounted(ArgType);
-        if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E))
+        std::optional<bool> IsUnsafe = isUnsafeType(ArgType);
+        if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(E))
           reportBugOnThis(E, D);
       }
 
@@ -118,7 +122,7 @@ class UncountedCallArgsChecker
 
         QualType ArgType = (*P)->getType().getCanonicalType();
         // FIXME: more complex types (arrays, references to raw pointers, etc)
-        std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
+        std::optional<bool> IsUncounted = isUnsafePtr(ArgType);
         if (!IsUncounted || !(*IsUncounted))
           continue;
 
@@ -264,7 +268,7 @@ class UncountedCallArgsChecker
       Os << " for parameter ";
       printQuotedQualifiedName(Os, Param);
     }
-    Os << " is uncounted and unsafe.";
+    Os << " is " << ptrKind() << " and unsafe.";
 
     const SourceLocation SrcLocToReport =
         isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc()
@@ -282,15 +286,53 @@ class UncountedCallArgsChecker
 
     const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin();
 
+    SmallString<100> Buf;
+    llvm::raw_svector_ostream Os(Buf);
+    Os << "Call argument for 'this' parameter is " << ptrKind();
+    Os << " and unsafe.";
+
     PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
-    auto Report = std::make_unique<BasicBugReport>(
-        Bug, "Call argument for 'this' parameter is uncounted and unsafe.",
-        BSLoc);
+    auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
     Report->addRange(CallArg->getSourceRange());
     Report->setDeclWithIssue(DeclWithIssue);
     BR->emitReport(std::move(Report));
   }
 };
+
+class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+  UncountedCallArgsChecker()
+      : RawPtrRefCallArgsChecker("Uncounted call argument for a raw "
+                                 "pointer/reference parameter") {}
+
+  std::optional<bool> isUnsafeType(QualType QT) const final {
+    return isUncounted(QT);
+  }
+
+  std::optional<bool> isUnsafePtr(QualType QT) const final {
+    return isUncountedPtr(QT);
+  }
+
+  const char *ptrKind() const final { return "uncounted"; }
+};
+
+class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+  UncheckedCallArgsChecker()
+      : RawPtrRefCallArgsChecker("Unchecked call argument for a raw "
+                                 "pointer/reference parameter") {}
+
+  std::optional<bool> isUnsafeType(QualType QT) const final {
+    return isUnchecked(QT);
+  }
+
+  std::optional<bool> isUnsafePtr(QualType QT) const final {
+    return isUncheckedPtr(QT);
+  }
+
+  const char *ptrKind() const final { return "unchecked"; }
+};
+
 } // namespace
 
 void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
@@ -300,3 +342,11 @@ void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
 bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
   return true;
 }
+
+void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<UncheckedCallArgsChecker>();
+}
+
+bool ento::shouldRegisterUncheckedCallArgsChecker(const CheckerManager &) {
+  return true;
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
new file mode 100644
index 00000000000000..34ff0c70e230ea
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
@@ -0,0 +1,367 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+CheckedObj* provide();
+void consume_refcntbl(CheckedObj*);
+void some_function();
+
+namespace simple {
+  void foo() {
+    consume_refcntbl(provide());
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+  }
+
+  // Test that the checker works with [[clang::suppress]].
+  void foo_suppressed() {
+    [[clang::suppress]]
+    consume_refcntbl(provide()); // no-warning
+  }
+}
+
+namespace multi_arg {
+  void consume_refcntbl(int, CheckedObj* foo, bool);
+  void foo() {
+    consume_refcntbl(42, provide(), true);
+    // expected-warning at -1{{Call argument for parameter 'foo' is unchecked and unsafe}}
+  }
+}
+
+namespace ref_counted {
+  CheckedRef<CheckedObj> provide_ref_counted() { return CheckedRef<CheckedObj>{}; }
+  void consume_ref_counted(CheckedRef<CheckedObj>) {}
+
+  void foo() {
+    consume_refcntbl(provide_ref_counted().ptr());
+    // no warning
+  }
+}
+
+namespace methods {
+  struct Consumer {
+    void consume_ptr(CheckedObj* ptr);
+    void consume_ref(const CheckedObj& ref);
+  };
+
+  void foo() {
+    Consumer c;
+
+    c.consume_ptr(provide());
+    // expected-warning at -1{{Call argument for parameter 'ptr' is unchecked and unsafe}}
+    c.consume_ref(*provide());
+    // expected-warning at -1{{Call argument for parameter 'ref' is unchecked and unsafe}}
+  }
+
+  void foo2() {
+    struct Consumer {
+      void consume(CheckedObj*) { some_function(); }
+      void whatever() {
+        consume(provide());
+        // expected-warning at -1{{Call argument is unchecked and unsafe}}
+      }
+    };
+  }
+
+  void foo3() {
+    struct Consumer {
+      void consume(CheckedObj*) { some_function(); }
+      void whatever() {
+        this->consume(provide());
+        // expected-warning at -1{{Call argument is unchecked and unsafe}}
+      }
+    };
+  }
+}
+
+namespace casts {
+  CheckedObj* downcast(CheckedObj*);
+
+  void foo() {
+    consume_refcntbl(provide());
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(static_cast<CheckedObj*>(provide()));
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(dynamic_cast<CheckedObj*>(provide()));
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(const_cast<CheckedObj*>(provide()));
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(reinterpret_cast<CheckedObj*>(provide()));
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(downcast(provide()));
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+
+    consume_refcntbl(
+      static_cast<CheckedObj*>(
+        downcast(
+          static_cast<CheckedObj*>(
+            provide()
+          )
+        )
+      )
+    );
+    // expected-warning at -8{{Call argument is unchecked and unsafe}}
+  }
+}
+
+namespace null_ptr {
+  void foo_ref() {
+    consume_refcntbl(nullptr);
+    consume_refcntbl(0);
+  }
+}
+
+namespace ref_counted_lookalike {
+  struct Decoy {
+    CheckedObj* get() { return nullptr; }
+  };
+
+  void foo() {
+    Decoy D;
+
+    consume_refcntbl(D.get());
+    // expected-warning at -1{{Call argument is unchecked and unsafe}}
+  }
+}
+
+namespace Ref_to_reference_conversion_operator {
+  template<typename T> struct Ref {
+    Ref() = default;
+    Ref(T*) { }
+    T* get() { return nullptr; }
+    operator T& () { return t; }
+    T t;
+  };
+
+  void consume_ref(CheckedObj&) {}
+
+  void foo() {
+    CheckedRef<CheckedObj> bar;
+    consume_ref(bar);
+  }
+}
+
+namespace param_formarding_function {
+  void consume_ref_countable_ref(CheckedObj&);
+  void consume_ref_countable_ptr(CheckedObj*);
+
+  namespace ptr {
+    void foo(CheckedObj* param) {
+      consume_ref_countable_ptr(param);
+    }
+  }
+
+  namespace ref {
+    void foo(CheckedObj& param) {
+      consume_ref_countable_ref(param);
+    }
+  }
+
+  namespace ref_deref_operators {
+    void foo_ref(CheckedObj& param) {
+      consume_ref_countable_ptr(&param);
+    }
+
+    void foo_ptr(CheckedObj* param) {
+      consume_ref_countable_ref(*param);
+    }
+  }
+
+  namespace casts {
+
+  CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+  template<class T>
+  T* bitwise_cast(T*) { return nullptr; }
+
+    void foo(CheckedObj* param) {
+      consume_ref_countable_ptr(downcast(param));
+      consume_ref_countable_ptr(bitwise_cast(param));
+     }
+  }
+}
+
+namespace param_formarding_lambda {
+  auto consume_ref_countable_ref = [](CheckedObj&) { some_function(); };
+  auto consume_ref_countable_ptr = [](CheckedObj*) { some_function(); };
+
+  namespace ptr {
+    void foo(CheckedObj* param) {
+      consume_ref_countable_ptr(param);
+    }
+  }
+
+  namespace ref {
+    void foo(CheckedObj& param) {
+      consume_ref_countable_ref(param);
+    }
+  }
+
+  namespace ref_deref_operators {
+    void foo_ref(CheckedObj& param) {
+      consume_ref_countable_ptr(&param);
+    }
+
+    void foo_ptr(CheckedObj* param) {
+      consume_ref_countable_ref(*param);
+    }
+  }
+
+  namespace casts {
+
+  CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+  template<class T>
+  T* bitwise_cast(T*) { return nullptr; }
+
+    void foo(CheckedObj* param) {
+      consume_ref_countable_ptr(downcast(param));
+      consume_ref_countable_ptr(bitwise_cast(param));
+    }
+  }
+}
+
+namespace param_forwarding_method {
+  struct methodclass {
+    void consume_ref_countable_ref(CheckedObj&) {};
+    static void consume_ref_countable_ptr(CheckedObj*) {};
+  };
+
+  namespace ptr {
+    void foo(CheckedObj* param) {
+      methodclass::consume_ref_countable_ptr(param);
+     }
+  }
+
+  namespace ref {
+    void foo(CheckedObj& param) {
+      methodclass mc;
+      mc.consume_ref_countable_ref(param);
+     }
+  }
+
+  namespace ref_deref_operators {
+    void foo_ref(CheckedObj& param) {
+      methodclass::consume_ref_countable_ptr(&param);
+     }
+
+    void foo_ptr(CheckedObj* param) {
+      methodclass mc;
+      mc.consume_ref_countable_ref(*param);
+     }
+  }
+
+  namespace casts {
+
+  CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+  template<class T>
+  T* bitwise_cast(T*) { return nullptr; }
+
+    void foo(CheckedObj* param) {
+      methodclass::consume_ref_countable_ptr(downcast(param));
+       methodclass::consume_ref_countable_ptr(bitwise_cast(param));
+     }
+  }
+}
+
+namespace downcast {
+  void consume_ref_countable(CheckedObj*) {}
+  CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+  void foo() {
+    CheckedPtr<CheckedObj> bar;
+    consume_ref_countable( downcast(bar.get()) );
+  }
+}
+
+namespace string_impl {
+  struct String {
+    CheckedObj* impl() { return nullptr; }
+  };
+
+  struct AtomString {
+    CheckedObj rc;
+    CheckedObj& impl() { return rc; }
+  };
+
+  void consume_ptr(CheckedObj*) {}
+  void consume_ref(CheckedObj&) {}
+
+  namespace simple {
+    void foo() {
+      String s;
+      AtomString as;
+      consume_ptr(s.impl());
+      consume_ref(as.impl());
+    }
+  }
+}
+
+namespace default_arg {
+  CheckedObj* global;
+
+  void function_with_default_arg(CheckedObj* param = global);
+  // expected-warning at -1{{Call argument for parameter 'param' is unchecked and unsafe}}
+
+  void foo() {
+    function_with_default_arg();
+  }
+}
+
+namespace cxx_member_func {
+  CheckedRef<CheckedObj> provideProtected();
+  void foo() {
+    provide()->trivial();
+    provide()->method();
+    // expected-warning at -1{{Call argument for 'this' parameter is unchecked and unsafe}}
+    provideProtected()->method();
+    (provideProtected())->method();
+  };
+}
+
+namespace cxx_member_operator_call {
+  // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
+  struct Foo {
+    Foo& operator+(CheckedObj* bad);
+    friend Foo& operator-(Foo& lhs, CheckedObj* bad);
+    void operator()(CheckedObj* bad);
+  };
+
+  CheckedObj* global;
+
+  void foo() {
+    Foo f;
+    f + global;
+    // expected-warning at -1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+    f - global;
+    // expected-warning at -1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+    f(global);
+    // expected-warning at -1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+  }
+}
+
+namespace call_with_ptr_on_ref {
+  CheckedRef<CheckedObj> provideProtected();
+  void bar(CheckedObj* bad);
+  bool baz();
+  void foo(bool v) {
+    bar(v ? nullptr : provideProtected().ptr());
+    bar(baz() ? provideProtected().ptr() : nullptr);
+    bar(v ? provide() : provideProtected().ptr());
+    // expected-warning at -1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+    bar(v ? provideProtected().ptr() : provide());
+    // expected-warning at -1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+  }
+}
+
+namespace call_with_explicit_temporary_obj {
+  void foo() {
+    CheckedRef { *provide() }->method();
+    CheckedPtr { provide() }->method();
+  }
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
new file mode 100644
index 00000000000000..33f7f8272a2560
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class Checkable {
+public:
+  void ref() const;
+  void deref() const;
+};
+
+class Object {
+public:
+  void ref() const;
+  void deref() const;
+  void someFunction(Checkable&);
+};
+
+RefPtr<Object> object();
+RefPtr<Checkable> protectedTargetObject();
+
+void testFunction() {
+  if (RefPtr obj = object())
+    obj->someFunction(*protectedTargetObject());
+}
diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
index 6a4c92390d773b..8579141aa7f99c 100644
--- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
@@ -142,7 +142,7 @@ static_library("Checkers") {
     "WebKit/PtrTypesSemantics.cpp",
     "WebKit/RawPtrRefMemberChecker.cpp",
     "WebKit/RefCntblBaseVirtualDtorChecker.cpp",
-    "WebKit/UncountedCallArgsChecker.cpp",
+    "WebKit/RawPtrRefCallArgsChecker.cpp",
     "WebKit/Unco...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/114522


More information about the cfe-commits mailing list