[clang] Add nodelete annotation for WebKit checkers (PR #177839)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 26 16:00:37 PST 2026
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/177839
>From b156a8a9e683eda84a64658d0a0af24895613071 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Sat, 24 Jan 2026 22:28:12 -0800
Subject: [PATCH 1/4] Add nodelete annotation for WebKit checkers
This PR adds the support for specifying [[clang::annotate_type("webkit.nodelete")]]
on a function return type, in which case, the whole function is considered "trivial"
or more precisely that it does not trigger any destruction of an object.
---
.../Checkers/WebKit/PtrTypesSemantics.cpp | 11 +++++++++++
.../Analysis/Checkers/WebKit/uncounted-obj-arg.cpp | 6 ++++++
2 files changed, 17 insertions(+)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index e056c35d6cf45..92fd612c11bc3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -508,6 +508,17 @@ class TrivialFunctionAnalysisVisitor
if (auto *FnDecl = dyn_cast<FunctionDecl>(D)) {
if (FnDecl->isVirtualAsWritten())
return false;
+ auto ReturnType = FnDecl->getReturnType();
+ if (auto *Type = ReturnType.getTypePtrOrNull()) {
+ if (auto *AttrType = dyn_cast<AttributedType>(Type)) {
+ if (auto *Attr = AttrType->getAttr()) {
+ if (auto *AnnotateType = dyn_cast<AnnotateTypeAttr>(Attr)) {
+ if (AnnotateType->getAnnotation() == "webkit.nodelete")
+ return true;
+ }
+ }
+ }
+ }
}
return WithCachedResult(D, [&]() {
if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index b83eaedf264e4..14a81aba1adc1 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -389,6 +389,9 @@ class RefCounted {
unsigned trivial71() { return std::bit_cast<unsigned>(nullptr); }
unsigned trivial72() { Number n { 5 }; return WTF::move(n).value(); }
+ unsigned [[clang::annotate_type("webkit.nodelete")]] nodelete1();
+ void [[clang::annotate_type("webkit.nodelete")]] nodelete2();
+
static RefCounted& singleton() {
static RefCounted s_RefCounted;
s_RefCounted.ref();
@@ -581,6 +584,9 @@ class UnrelatedClass {
getFieldTrivial().trivial70(); // no-warning
getFieldTrivial().trivial71(); // no-warning
+ getFieldTrivial().nodelete1(); // no-warning
+ getFieldTrivial().nodelete2(); // no-warning
+
RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
RefCounted::otherSingleton().trivial18(); // no-warning
>From b19f97dc6d1a0f3ed9c4c5d059c91f121d20fca4 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Mon, 26 Jan 2026 15:53:15 -0800
Subject: [PATCH 2/4] Introduce alpha.webkit.NoDeleteChecker
Add alpha.webkit.NoDeleteChecker which validates soundness of webkit.nodelete annotation
by examining the function body.
---
clang/docs/analyzer/checkers.rst | 14 ++
.../clang/StaticAnalyzer/Checkers/Checkers.td | 4 +
.../StaticAnalyzer/Checkers/CMakeLists.txt | 1 +
.../Checkers/WebKit/NoDeleteChecker.cpp | 127 ++++++++++++++++++
.../Checkers/WebKit/PtrTypesSemantics.cpp | 53 +++++---
.../Checkers/WebKit/PtrTypesSemantics.h | 4 +
.../WebKit/RawPtrRefCallArgsChecker.cpp | 2 +-
.../Checkers/WebKit/nodelete-annotation.cpp | 67 +++++++++
.../Checkers/WebKit/uncounted-obj-arg.cpp | 2 +
9 files changed, 251 insertions(+), 23 deletions(-)
create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
create mode 100644 clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index e449593e95d21..9ebd667d4c80e 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3680,6 +3680,20 @@ This applies to:
For types like this, instead of using built in casts, the programmer will use helper functions that internally perform the appropriate type check and disable static analysis.
+alpha.webkit.NoDeleteChecker
+"""""""""""""""""""""""""""""""
+Check that [[clang::annotate_type("webkit.nodelete")]] annotation does not appear on a fucntion which could delete an object
+
+.. code-block:: cpp
+
+ void [[clang::annotate_type("webkit.nodelete")]] someFunction(RefCountable* obj) { // warn
+ delete obj;
+ };
+
+ Foo [[clang::annotate_type("webkit.nodelete")]] trivialFunction(RefCountable* obj) {
+ return obj->anotherTrivialFunction();
+ };
+
alpha.webkit.NoUncheckedPtrMemberChecker
""""""""""""""""""""""""""""""""""""""""
Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed.
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 91738e6a29664..6a409944849e6 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1710,6 +1710,10 @@ def MemoryUnsafeCastChecker : Checker<"MemoryUnsafeCastChecker">,
HelpText<"Check for memory unsafe casts from base type to derived type.">,
Documentation<HasDocumentation>;
+def NoDeleteChecker : Checker<"NoDeleteChecker">,
+ HelpText<"Check for [[clang::annotate_type(\"webkit.nodelete\")]] annotation">,
+ Documentation<HasDocumentation>;
+
def NoUncheckedPtrMemberChecker : Checker<"NoUncheckedPtrMemberChecker">,
HelpText<"Check for no unchecked member variables.">,
Documentation<HasDocumentation>;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 29d2c4512d470..2df36d8e672ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -132,6 +132,7 @@ add_clang_library(clangStaticAnalyzerCheckers
WebKit/ASTUtils.cpp
WebKit/ForwardDeclChecker.cpp
WebKit/MemoryUnsafeCastChecker.cpp
+ WebKit/NoDeleteChecker.cpp
WebKit/PtrTypesSemantics.cpp
WebKit/RefCntblBaseVirtualDtorChecker.cpp
WebKit/RetainPtrCtorAdoptChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
new file mode 100644
index 0000000000000..8c6050a4bb1bd
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
@@ -0,0 +1,127 @@
+//=======- NoDeleteChecker.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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTUtils.h"
+#include "DiagOutputUtils.h"
+#include "PtrTypesSemantics.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class NoDeleteChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
+ BugType Bug;
+ mutable BugReporter *BR = nullptr;
+ mutable TrivialFunctionAnalysis TFA;
+
+public:
+ NoDeleteChecker()
+ : Bug(this, "Incorrect [[clang::annotate_type(\"webkit.nodelete\")]] annotation",
+ "WebKit coding guidelines") {}
+
+ void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
+ BugReporter &BRArg) const {
+ BR = &BRArg;
+
+ // The calls to checkAST* from AnalysisConsumer don't
+ // visit template instantiations or lambda classes. We
+ // want to visit those, so we make our own RecursiveASTVisitor.
+ struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
+ const NoDeleteChecker *Checker;
+ Decl *DeclWithIssue{nullptr};
+
+ explicit LocalVisitor(const NoDeleteChecker *Checker)
+ : Checker(Checker) {
+ assert(Checker);
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const { return false; }
+
+ bool VisitFunctionDecl(FunctionDecl *FD) {
+ Checker->visitFunctionDecl(FD);
+ return true;
+ }
+ };
+
+ LocalVisitor visitor(this);
+ visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
+ }
+
+ void visitFunctionDecl(const FunctionDecl *FD) const {
+ if (!FD->doesThisDeclarationHaveABody())
+ return;
+
+ bool HasNoDeleteAnnotation = isNoDeleteFunction(FD);
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (auto* Cls = MD->getParent(); Cls && MD->isVirtual()) {
+ CXXBasePaths Paths;
+ Paths.setOrigin(Cls);
+
+ Cls->lookupInBases([&](const CXXBaseSpecifier *Base, CXXBasePath &) {
+ const Type *T = Base->getType().getTypePtrOrNull();
+ if (!T)
+ return false;
+
+ const CXXRecordDecl *R = T->getAsCXXRecordDecl();
+ for (const CXXMethodDecl *BaseMD : R->methods()) {
+ if (BaseMD->getCorrespondingMethodInClass(Cls) == MD) {
+ if (isNoDeleteFunction(FD)) {
+ HasNoDeleteAnnotation = true;
+ return false;
+ }
+ }
+ }
+ return true;
+ }, Paths, /*LookupInDependent =*/true);
+ }
+ }
+
+ auto Body = FD->getBody();
+ if (!Body || TFA.isTrivial(Body))
+ return;
+
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+
+ Os << "A function ";
+ printQuotedName(Os, FD);
+ Os << " has [[clang::annotate_type(\"webkit.nodelete\")]] but it contains "
+ "code that could destruct an object";
+
+ const SourceLocation SrcLocToReport = FD->getBeginLoc();
+ PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
+ auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
+ Report->addRange(FD->getSourceRange());
+ Report->setDeclWithIssue(FD);
+ BR->emitReport(std::move(Report));
+ }
+};
+
+} // namespace
+
+void ento::registerNoDeleteChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<NoDeleteChecker>();
+}
+
+bool ento::shouldRegisterNoDeleteChecker(const CheckerManager &) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 92fd612c11bc3..15abfab7734dc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -406,6 +406,28 @@ bool isSmartPtr(const CXXRecordDecl *R) {
return false;
}
+enum class WebKitAnnotation : uint8_t {
+ None,
+ PointerConversion,
+ NoDelete,
+};
+
+static WebKitAnnotation typeAnnotationForReturnType(const FunctionDecl *FD) {
+ auto RetType = FD->getReturnType();
+ auto *Attr = dyn_cast_or_null<AttributedType>(RetType.getTypePtrOrNull());
+ if (!Attr)
+ return WebKitAnnotation::None;
+ auto *AnnotateType = dyn_cast_or_null<AnnotateTypeAttr>(Attr->getAttr());
+ if (!AnnotateType)
+ return WebKitAnnotation::None;
+ auto Annotation = AnnotateType->getAnnotation();
+ if (Annotation == "webkit.pointerconversion")
+ return WebKitAnnotation::PointerConversion;
+ if (Annotation == "webkit.nodelete")
+ return WebKitAnnotation::NoDelete;
+ return WebKitAnnotation::None;
+}
+
bool isPtrConversion(const FunctionDecl *F) {
assert(F);
if (isCtorOfRefCounted(F))
@@ -423,21 +445,17 @@ bool isPtrConversion(const FunctionDecl *F) {
FunctionName == "checked_objc_cast")
return true;
- auto ReturnType = F->getReturnType();
- if (auto *Type = ReturnType.getTypePtrOrNull()) {
- if (auto *AttrType = dyn_cast<AttributedType>(Type)) {
- if (auto *Attr = AttrType->getAttr()) {
- if (auto *AnnotateType = dyn_cast<AnnotateTypeAttr>(Attr)) {
- if (AnnotateType->getAnnotation() == "webkit.pointerconversion")
- return true;
- }
- }
- }
- }
+ if (typeAnnotationForReturnType(F) == WebKitAnnotation::PointerConversion)
+ return true;
return false;
}
+bool isNoDeleteFunction(const FunctionDecl *F)
+{
+ return typeAnnotationForReturnType(F) == WebKitAnnotation::NoDelete;
+}
+
bool isTrivialBuiltinFunction(const FunctionDecl *F) {
if (!F || !F->getDeclName().isIdentifier())
return false;
@@ -506,19 +524,10 @@ class TrivialFunctionAnalysisVisitor
bool IsFunctionTrivial(const Decl *D) {
if (auto *FnDecl = dyn_cast<FunctionDecl>(D)) {
+ if (isNoDeleteFunction(FnDecl))
+ return true;
if (FnDecl->isVirtualAsWritten())
return false;
- auto ReturnType = FnDecl->getReturnType();
- if (auto *Type = ReturnType.getTypePtrOrNull()) {
- if (auto *AttrType = dyn_cast<AttributedType>(Type)) {
- if (auto *Attr = AttrType->getAttr()) {
- if (auto *AnnotateType = dyn_cast<AnnotateTypeAttr>(Attr)) {
- if (AnnotateType->getAnnotation() == "webkit.nodelete")
- return true;
- }
- }
- }
- }
}
return WithCachedResult(D, [&]() {
if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index d5ced4d857241..431357a2150be 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -152,6 +152,10 @@ std::optional<bool> isGetterOfSafePtr(const clang::CXXMethodDecl *Method);
/// pointer types.
bool isPtrConversion(const FunctionDecl *F);
+/// \returns true if \p F's return type is annotated with
+/// [[clang::annotate_type("webkit.nodelete")]].
+bool isNoDeleteFunction(const FunctionDecl *F);
+
/// \returns true if \p F is a builtin function which is considered trivial.
bool isTrivialBuiltinFunction(const FunctionDecl *F);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index dcc14a0aecdf7..b2d87bc267700 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -241,7 +241,7 @@ class RawPtrRefCallArgsChecker
if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
return true;
- if (Callee && TFA.isTrivial(Callee) && !Callee->isVirtualAsWritten())
+ if (Callee && TFA.isTrivial(Callee))
return true;
if (isTrivialBuiltinFunction(Callee))
diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
new file mode 100644
index 0000000000000..70305b7cee69e
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoDeleteChecker -verify %s
+
+void someFunction();
+void [[clang::annotate_type("webkit.nodelete")]] safeFunction();
+
+void [[clang::annotate_type("webkit.nodelete")]] callsUnsafe() {
+ // expected-warning at -1{{A function 'callsUnsafe' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+}
+
+void [[clang::annotate_type("webkit.nodelete")]] callsSafe() {
+ safeFunction();
+}
+
+void [[clang::annotate_type("webkit.nodelete")]] declWithNoDelete();
+void declWithNoDelete() {
+ // expected-warning at -1{{A function 'declWithNoDelete' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+}
+
+void defWithNoDelete();
+void [[clang::annotate_type("webkit.nodelete")]] defWithNoDelete() {
+// expected-warning at -1{{A function 'defWithNoDelete' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+}
+
+class SomeClass {
+ void [[clang::annotate_type("webkit.nodelete")]] someMethod();
+ void [[clang::annotate_type("webkit.nodelete")]] unsafeMethod() {
+ // expected-warning at -1{{A function 'unsafeMethod' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+ }
+ void [[clang::annotate_type("webkit.nodelete")]] safeMethod() {
+ safeFunction();
+ }
+
+ virtual void [[clang::annotate_type("webkit.nodelete")]] someVirtualMethod();
+ virtual void [[clang::annotate_type("webkit.nodelete")]] unsafeVirtualMethod() {
+ // expected-warning at -1{{A function 'unsafeVirtualMethod' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+ }
+ virtual void [[clang::annotate_type("webkit.nodelete")]] safeVirtualMethod() {
+ safeFunction();
+ }
+
+ static void [[clang::annotate_type("webkit.nodelete")]] someStaticMethod();
+ static void [[clang::annotate_type("webkit.nodelete")]] unsafeStaticMethod() {
+ // expected-warning at -1{{A function 'unsafeStaticMethod' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+ }
+ static void [[clang::annotate_type("webkit.nodelete")]] safeStaticMethod() {
+ safeFunction();
+ }
+
+ virtual void [[clang::annotate_type("webkit.nodelete")]] anotherVirtualMethod();
+};
+
+class IntermediateClass : public SomeClass {
+ void anotherVirtualMethod() override;
+};
+
+class DerivedClass : public IntermediateClass {
+ void anotherVirtualMethod() override {
+ // expected-warning at -1{{A function 'anotherVirtualMethod' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ someFunction();
+ }
+};
\ No newline at end of file
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index 14a81aba1adc1..c60126947217d 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -391,6 +391,7 @@ class RefCounted {
unsigned [[clang::annotate_type("webkit.nodelete")]] nodelete1();
void [[clang::annotate_type("webkit.nodelete")]] nodelete2();
+ virtual void [[clang::annotate_type("webkit.nodelete")]] nodelete3();
static RefCounted& singleton() {
static RefCounted s_RefCounted;
@@ -586,6 +587,7 @@ class UnrelatedClass {
getFieldTrivial().nodelete1(); // no-warning
getFieldTrivial().nodelete2(); // no-warning
+ getFieldTrivial().nodelete3(); // no-warning
RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
>From 0e4abd09a68fa3bf62f860b5a5ff330dab15f447 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Mon, 26 Jan 2026 15:57:05 -0800
Subject: [PATCH 3/4] Add a bit more description for the annotation
---
clang/docs/analyzer/checkers.rst | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 9ebd667d4c80e..d157d59e27b94 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3682,7 +3682,7 @@ For types like this, instead of using built in casts, the programmer will use he
alpha.webkit.NoDeleteChecker
"""""""""""""""""""""""""""""""
-Check that [[clang::annotate_type("webkit.nodelete")]] annotation does not appear on a fucntion which could delete an object
+Check that `[[clang::annotate_type("webkit.nodelete")]]` annotation does not appear on a fucntion which could delete an object
.. code-block:: cpp
@@ -3693,6 +3693,9 @@ Check that [[clang::annotate_type("webkit.nodelete")]] annotation does not appea
Foo [[clang::annotate_type("webkit.nodelete")]] trivialFunction(RefCountable* obj) {
return obj->anotherTrivialFunction();
};
+
+`[[clang::annotate_type("webkit.nodelete")]]` annotation makes the function ignored for the purpose of other WebKit smart pointer checkers.
+For example, alpha.webkit.UncountedCallArgsChecker will ignore a function call with this annotation.
alpha.webkit.NoUncheckedPtrMemberChecker
""""""""""""""""""""""""""""""""""""""""
>From 24964796d095e69578292c3239b79fb0fe6f23c6 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Mon, 26 Jan 2026 16:00:21 -0800
Subject: [PATCH 4/4] Fix formatting
---
.../Checkers/WebKit/NoDeleteChecker.cpp | 39 ++++++++++---------
.../Checkers/WebKit/PtrTypesSemantics.cpp | 3 +-
2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
index 8c6050a4bb1bd..c59a55e8310ff 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoDeleteChecker.cpp
@@ -34,7 +34,9 @@ class NoDeleteChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
public:
NoDeleteChecker()
- : Bug(this, "Incorrect [[clang::annotate_type(\"webkit.nodelete\")]] annotation",
+ : Bug(this,
+ "Incorrect [[clang::annotate_type(\"webkit.nodelete\")]] "
+ "annotation",
"WebKit coding guidelines") {}
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
@@ -48,8 +50,7 @@ class NoDeleteChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
const NoDeleteChecker *Checker;
Decl *DeclWithIssue{nullptr};
- explicit LocalVisitor(const NoDeleteChecker *Checker)
- : Checker(Checker) {
+ explicit LocalVisitor(const NoDeleteChecker *Checker) : Checker(Checker) {
assert(Checker);
}
@@ -72,26 +73,28 @@ class NoDeleteChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
bool HasNoDeleteAnnotation = isNoDeleteFunction(FD);
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
- if (auto* Cls = MD->getParent(); Cls && MD->isVirtual()) {
+ if (auto *Cls = MD->getParent(); Cls && MD->isVirtual()) {
CXXBasePaths Paths;
Paths.setOrigin(Cls);
- Cls->lookupInBases([&](const CXXBaseSpecifier *Base, CXXBasePath &) {
- const Type *T = Base->getType().getTypePtrOrNull();
- if (!T)
- return false;
-
- const CXXRecordDecl *R = T->getAsCXXRecordDecl();
- for (const CXXMethodDecl *BaseMD : R->methods()) {
- if (BaseMD->getCorrespondingMethodInClass(Cls) == MD) {
- if (isNoDeleteFunction(FD)) {
- HasNoDeleteAnnotation = true;
+ Cls->lookupInBases(
+ [&](const CXXBaseSpecifier *Base, CXXBasePath &) {
+ const Type *T = Base->getType().getTypePtrOrNull();
+ if (!T)
return false;
+
+ const CXXRecordDecl *R = T->getAsCXXRecordDecl();
+ for (const CXXMethodDecl *BaseMD : R->methods()) {
+ if (BaseMD->getCorrespondingMethodInClass(Cls) == MD) {
+ if (isNoDeleteFunction(FD)) {
+ HasNoDeleteAnnotation = true;
+ return false;
+ }
+ }
}
- }
- }
- return true;
- }, Paths, /*LookupInDependent =*/true);
+ return true;
+ },
+ Paths, /*LookupInDependent =*/true);
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 15abfab7734dc..c47dabf2ec5b0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -451,8 +451,7 @@ bool isPtrConversion(const FunctionDecl *F) {
return false;
}
-bool isNoDeleteFunction(const FunctionDecl *F)
-{
+bool isNoDeleteFunction(const FunctionDecl *F) {
return typeAnnotationForReturnType(F) == WebKitAnnotation::NoDelete;
}
More information about the cfe-commits
mailing list