[clang-tools-extra] [clang-tidy] cppcoreguidelines-owning-memory: support new expressions through implicit casts (PR #189544)
Yukari Kaname via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 31 08:17:48 PDT 2026
https://github.com/yukarikaname updated https://github.com/llvm/llvm-project/pull/189544
>From 4299595400641a1f7101b8749e629d47e6ddc2ba Mon Sep 17 00:00:00 2001
From: Yukari Kaname <yukari at aliciaworks.com>
Date: Tue, 31 Mar 2026 14:01:17 +0800
Subject: [PATCH 1/2] [clang-tidy] cppcoreguidelines-owning-memory: handle new
expressions wrapped in implicit casts and add regression tests for
derived-to-base new returns/assignments
---
.../cppcoreguidelines/OwningMemoryCheck.cpp | 18 ++++++++++--------
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++++
.../cppcoreguidelines/owning-memory.cpp | 18 ++++++++++++++++++
3 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
index f4e89470a80da..5a52605fa6d6a 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -63,7 +63,8 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
CreatesLegacyOwner, LegacyOwnerCast);
- const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
+ const auto CreatesOwnerWithCasts = ignoringImpCasts(CreatesOwner);
+ const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwnerWithCasts);
const auto ScopeDeclaration = anyOf(translationUnitDecl(), namespaceDecl(),
recordDecl(), functionDecl());
@@ -127,14 +128,14 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
// but the LHS is not an owner.
Finder->addMatcher(binaryOperator(isAssignmentOperator(),
hasLHS(unless(IsOwnerType)),
- hasRHS(CreatesOwner))
+ hasRHS(CreatesOwnerWithCasts))
.bind("bad_owner_creation_assignment"),
this);
// Matching on initialization operations where the initial value is a newly
// created owner, but the LHS is not an owner.
Finder->addMatcher(
- traverse(TK_AsIs, namedDecl(varDecl(hasInitializer(CreatesOwner),
+ traverse(TK_AsIs, namedDecl(varDecl(hasInitializer(CreatesOwnerWithCasts),
unless(IsOwnerType))
.bind("bad_owner_creation_variable"))),
this);
@@ -149,11 +150,12 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
// Matching for function calls where one argument is a created owner, but the
// parameter type is not an owner.
- Finder->addMatcher(callExpr(forEachArgumentWithParam(
- expr(CreatesOwner).bind("bad_owner_creation_argument"),
- parmVarDecl(unless(IsOwnerType))
- .bind("bad_owner_creation_parameter"))),
- this);
+ Finder->addMatcher(
+ callExpr(forEachArgumentWithParam(
+ expr(CreatesOwnerWithCasts).bind("bad_owner_creation_argument"),
+ parmVarDecl(unless(IsOwnerType))
+ .bind("bad_owner_creation_parameter"))),
+ this);
auto IsNotInSubLambda = stmt(
hasAncestor(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 69dc5b9633398..1c1233d8164e5 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -283,6 +283,10 @@ Changes in existing checks
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by fixing
a false positive for constrained template parameters.
+- Improved :doc:`cppcoreguidelines-owning-memory
+ <clang-tidy/checks/cppcoreguidelines/owning-memory>` check to detect `new`
+ expressions through implicit casts (e.g., `C* x = new D`).
+
- Improved :doc:`cppcoreguidelines-pro-type-vararg
<clang-tidy/checks/cppcoreguidelines/pro-type-vararg>` check by no longer
warning on builtins with custom type checking (e.g., type-generic builtins
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
index ae61b17ca14d2..2ba8d5ce23749 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
@@ -398,6 +398,24 @@ namespace PR63994 {
}
}
+namespace PR64361 {
+ struct C {
+ virtual ~C() {}
+ };
+
+ struct D : public C {};
+
+ void testDerivedAssignment() {
+ C* x = new D;
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: initializing non-owner 'C *' with a newly created 'gsl::owner<>'
+ }
+
+ C* testDerivedReturn() {
+ return new D;
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'C *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+ }
+}
+
namespace PR59389 {
struct S {
S();
>From e098b2cfa021f8c27433bffc9878602dfa5453e4 Mon Sep 17 00:00:00 2001
From: Yukari Kaname <yukari at aliciaworks.com>
Date: Tue, 31 Mar 2026 23:17:05 +0800
Subject: [PATCH 2/2] [clang-tidy] Replace CreatesOwnerWithCasts with
ignoringImpCasts(CreatesOwner)
---
.../cppcoreguidelines/OwningMemoryCheck.cpp | 25 ++++++++++---------
clang-tools-extra/docs/ReleaseNotes.rst | 4 +--
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
index 5a52605fa6d6a..c8ecc2dc2ea3b 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -63,8 +63,8 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
CreatesLegacyOwner, LegacyOwnerCast);
- const auto CreatesOwnerWithCasts = ignoringImpCasts(CreatesOwner);
- const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwnerWithCasts);
+ const auto ConsideredOwner =
+ eachOf(IsOwnerType, ignoringImpCasts(CreatesOwner));
const auto ScopeDeclaration = anyOf(translationUnitDecl(), namespaceDecl(),
recordDecl(), functionDecl());
@@ -128,16 +128,17 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
// but the LHS is not an owner.
Finder->addMatcher(binaryOperator(isAssignmentOperator(),
hasLHS(unless(IsOwnerType)),
- hasRHS(CreatesOwnerWithCasts))
+ hasRHS(ignoringImpCasts(CreatesOwner)))
.bind("bad_owner_creation_assignment"),
this);
// Matching on initialization operations where the initial value is a newly
// created owner, but the LHS is not an owner.
Finder->addMatcher(
- traverse(TK_AsIs, namedDecl(varDecl(hasInitializer(CreatesOwnerWithCasts),
- unless(IsOwnerType))
- .bind("bad_owner_creation_variable"))),
+ traverse(TK_AsIs,
+ namedDecl(varDecl(hasInitializer(ignoringImpCasts(CreatesOwner)),
+ unless(IsOwnerType))
+ .bind("bad_owner_creation_variable"))),
this);
// Match on all function calls that expect owners as arguments, but didn't
@@ -150,12 +151,12 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
// Matching for function calls where one argument is a created owner, but the
// parameter type is not an owner.
- Finder->addMatcher(
- callExpr(forEachArgumentWithParam(
- expr(CreatesOwnerWithCasts).bind("bad_owner_creation_argument"),
- parmVarDecl(unless(IsOwnerType))
- .bind("bad_owner_creation_parameter"))),
- this);
+ Finder->addMatcher(callExpr(forEachArgumentWithParam(
+ expr(ignoringImpCasts(CreatesOwner))
+ .bind("bad_owner_creation_argument"),
+ parmVarDecl(unless(IsOwnerType))
+ .bind("bad_owner_creation_parameter"))),
+ this);
auto IsNotInSubLambda = stmt(
hasAncestor(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 1c1233d8164e5..b42828b17f1c8 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -284,8 +284,8 @@ Changes in existing checks
a false positive for constrained template parameters.
- Improved :doc:`cppcoreguidelines-owning-memory
- <clang-tidy/checks/cppcoreguidelines/owning-memory>` check to detect `new`
- expressions through implicit casts (e.g., `C* x = new D`).
+ <clang-tidy/checks/cppcoreguidelines/owning-memory>` check to detect ``new``
+ expressions through implicit casts (e.g., ``C* x = new D``).
- Improved :doc:`cppcoreguidelines-pro-type-vararg
<clang-tidy/checks/cppcoreguidelines/pro-type-vararg>` check by no longer
More information about the cfe-commits
mailing list