[clang] [alpha.webkit.UncountedLocalVarsChecker] Support obtaining guardian's value via operator* (PR #219647)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 30 19:21:31 PDT 2026
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/219647
>From 6f93383031ab95de11485345e20ee4914cee6498 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Fri, 28 Aug 2026 17:01:32 -0700
Subject: [PATCH 1/3] [alpha.webkit.UncountedLocalVarsChecker] Support
obtaining guardian's value via operator*
This PR fixes a bug in alpha.webkit.UncountedLocalVarsChecker that it wasn't allowing
a guardian variable's getter to be called when initializing a raw pointer/reference.
Also fix a bug that operator* wasn't recognized as a valid getter on a smart pointer.
---
.../Checkers/WebKit/PtrTypesSemantics.cpp | 7 +++++--
.../WebKit/RawPtrRefLocalVarsChecker.cpp | 5 +++++
.../Analysis/Checkers/WebKit/mock-types.h | 3 ++-
.../Checkers/WebKit/uncounted-local-vars.cpp | 19 ++++++++++++++++++-
4 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e8e404c753dcb..eb5960c262c95 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -357,10 +357,13 @@ std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
std::string className = safeGetName(calleeMethodsClass);
std::string method = safeGetName(M);
- if (isCheckedPtr(className) && (method == "get" || method == "ptr"))
+ auto OpType = M->getOverloadedOperator();
+ if (isCheckedPtr(className) &&
+ (method == "get" || method == "ptr" || OpType == OO_Star))
return true;
- if ((isRefType(className) && (method == "get" || method == "ptr")) ||
+ if ((isRefType(className) &&
+ (method == "get" || method == "ptr" || OpType == OO_Star)) ||
((className == "String" || className == "AtomString" ||
className == "AtomStringImpl" || className == "UniqueString" ||
className == "UniqueStringImpl" || className == "Identifier") &&
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index b420ce73ae82e..f3c620436f7a4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -89,6 +89,11 @@ struct GuardianVisitor : DynamicRecursiveASTVisitor {
return false;
if (isPtrConversion(Callee))
return true;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(Callee)) {
+ auto IsGetter = isGetterOfSafePtr(Method);
+ if (IsGetter && *IsGetter)
+ return true;
+ }
unsigned ArgIndex = 0;
unsigned ArgOffset = isa<CXXOperatorCallExpr>(CE);
for (auto *Arg : CE->arguments()) {
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 87b495f526f27..dea16f534ba2b 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -435,7 +435,8 @@ struct RefCountable {
unsigned m_refCount { 0 };
};
-template <typename T> T *downcast(T *t) { return t; }
+template <typename U, typename T> U [[clang::annotate_type("webkit.pointerconversion")]] *downcast(T *t) { return static_cast<U*>(t); }
+template <typename U, typename T> U [[clang::annotate_type("webkit.pointerconversion")]] &downcast(T &t) { return static_cast<U&>(t); }
template <typename T> struct CheckedRef {
private:
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
index d36e78f12453f..31990217525c1 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
@@ -214,6 +214,23 @@ void foo9(RefCountable& o) {
}
}
+RefCountable* provide();
+
+struct Derived : public RefCountable {
+};
+
+void foo10() {
+ RefPtr<RefCountable> obj = provide();
+ if (obj) {
+ auto* ptr = downcast<Derived>(obj.get());
+ ptr->method();
+ }
+ if (obj) {
+ auto& ref = downcast<Derived>(*obj);
+ ref.method();
+ }
+}
+
} // namespace guardian_scopes
namespace auto_keyword {
@@ -705,4 +722,4 @@ namespace binding_raw_ptr {
a->method();
}
-}
\ No newline at end of file
+}
>From f7880a565329860c27102a9ceedb180566f5600a Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <ryosuke.niwa at gmail.com>
Date: Mon, 31 Aug 2026 09:09:34 +0900
Subject: [PATCH 2/3] Address the review comment.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Balázs Benics <benicsbalazs at gmail.com>
---
.../Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index f3c620436f7a4..7f5c82a3437bd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -90,8 +90,7 @@ struct GuardianVisitor : DynamicRecursiveASTVisitor {
if (isPtrConversion(Callee))
return true;
if (auto *Method = dyn_cast<CXXMethodDecl>(Callee)) {
- auto IsGetter = isGetterOfSafePtr(Method);
- if (IsGetter && *IsGetter)
+ if (isGetterOfSafePtr(Method).value_or(false))
return true;
}
unsigned ArgIndex = 0;
>From af008a89ed4f1cdd47cc6af7ce340e23d063194a Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Mon, 31 Aug 2026 11:21:12 +0900
Subject: [PATCH 3/3] Fix tests
---
clang/test/Analysis/Checkers/WebKit/objc-mock-types.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index ee9ac937eb0bf..aad2a6185d0b0 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -273,8 +273,6 @@ template<typename T> RetainPtr<T> adoptNSNullable(T*);
template<typename T> RetainPtr<T> adoptCF(T);
template<typename T> RetainPtr<T> adoptCFNullable(T);
-template <typename T, typename S> T *downcast(S *t) { return static_cast<T*>(t); }
-
template <typename T> struct RemovePointer {
typedef T Type;
};
@@ -713,7 +711,6 @@ using WTF::adoptCFNullable;
using WTF::retainPtr;
using WTF::OSObjectPtr;
using WTF::adoptOSObject;
-using WTF::downcast;
using WTF::bridge_cast;
using WTF::bridge_id_cast;
using WTF::is_objc;
More information about the cfe-commits
mailing list