[clang] [clang-tools-extra] [ExprMutation] handle return non-const type (PR #161396)
Congcong Cai via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 30 09:00:24 PDT 2025
https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/161396
>From 9472a9cca3027b43a3b117176ddd3a5063c03f14 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 30 Sep 2025 23:35:57 +0800
Subject: [PATCH 1/2] [ExprMutation] handle return non-const type
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++
.../const-correctness-pointer-as-pointers.cpp | 4 ++
clang/lib/Analysis/ExprMutationAnalyzer.cpp | 20 ++++++----
.../Analysis/ExprMutationAnalyzerTest.cpp | 38 +++++++++++++++++++
4 files changed, 58 insertions(+), 8 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index c3a6d2f9b2890..6991aa4153899 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -312,6 +312,10 @@ Changes in existing checks
- Improved :doc:`misc-header-include-cycle
<clang-tidy/checks/misc/header-include-cycle>` check performance.
+- Improved :doc:`misc-const-correctness
+ <clang-tidy/checks/misc/const-correctness>` check by fixing false positives
+ when return non-const pointer.
+
- Improved :doc:`modernize-avoid-c-arrays
<clang-tidy/checks/modernize/avoid-c-arrays>` to not diagnose array types
which are part of an implicit instantiation of a template.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp
index 2ef47266b02b0..503445c5d3063 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp
@@ -48,3 +48,7 @@ void ignore_const_alias() {
p_local0 = &a[1];
}
+void *return_non_const() {
+ void *const a = nullptr;
+ return a;
+}
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 3fcd3481c2d6b..1524a5369c072 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -140,7 +140,8 @@ class ExprPointeeResolve {
// explicit cast will be checked in `findPointeeToNonConst`
const CastKind kind = ICE->getCastKind();
if (kind == CK_LValueToRValue || kind == CK_DerivedToBase ||
- kind == CK_UncheckedDerivedToBase)
+ kind == CK_UncheckedDerivedToBase ||
+ (kind == CK_NoOp && (ICE->getType() == ICE->getSubExpr()->getType())))
return resolveExpr(ICE->getSubExpr());
return false;
}
@@ -787,13 +788,16 @@ ExprMutationAnalyzer::Analyzer::findPointeeToNonConst(const Expr *Exp) {
// FIXME: false positive if the pointee does not change in lambda
const auto CaptureNoConst = lambdaExpr(hasCaptureInit(Exp));
- const auto Matches =
- match(stmt(anyOf(forEachDescendant(
- stmt(anyOf(AssignToNonConst, PassAsNonConstArg,
- CastToNonConst, CaptureNoConst))
- .bind("stmt")),
- forEachDescendant(InitToNonConst))),
- Stm, Context);
+ const auto ReturnNoCost =
+ returnStmt(hasReturnValue(canResolveToExprPointee(Exp)));
+
+ const auto Matches = match(
+ stmt(anyOf(forEachDescendant(
+ stmt(anyOf(AssignToNonConst, PassAsNonConstArg,
+ CastToNonConst, CaptureNoConst, ReturnNoCost))
+ .bind("stmt")),
+ forEachDescendant(InitToNonConst))),
+ Stm, Context);
return selectFirst<Stmt>("stmt", Matches);
}
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index 4e97174c17d95..8cc89181c61ff 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -2015,4 +2015,42 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByConditionOperator) {
EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
}
+TEST(ExprMutationAnalyzerTest, PointeeMutatedByReturn) {
+ {
+ const std::string Code = R"(
+ int * f() {
+ int *const x = nullptr;
+ return x;
+ })";
+ auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
+ }
+ {
+ const std::string Code = R"(
+ int * f() {
+ int *const x = nullptr;
+ return x;
+ })";
+ // in C++20, AST will have NoOp cast.
+ auto AST =
+ buildASTFromCodeWithArgs(Code, {"-Wno-everything", "-std=c++26"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
+ }
+ {
+ const std::string Code = R"(
+ int const* f() {
+ int *const x = nullptr;
+ return x;
+ })";
+ auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isPointeeMutated(Results, AST.get()));
+ }
+}
+
} // namespace clang
>From 24507746397db0a2998b72f85d33e81f9d1ccd7e Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 1 Oct 2025 00:00:02 +0800
Subject: [PATCH 2/2] fix
---
clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index 8cc89181c61ff..bce3ce5ea0bb1 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -2033,9 +2033,9 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByReturn) {
int *const x = nullptr;
return x;
})";
- // in C++20, AST will have NoOp cast.
+ // in C++23, AST will have NoOp cast.
auto AST =
- buildASTFromCodeWithArgs(Code, {"-Wno-everything", "-std=c++26"});
+ buildASTFromCodeWithArgs(Code, {"-Wno-everything", "-std=c++23"});
auto Results =
match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
More information about the cfe-commits
mailing list