[clang] [clang-tools-extra] [clang-tidy] Fix false positives about references in `misc-const-correctness` (PR #160971)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 26 19:28:10 PDT 2025
https://github.com/flovent updated https://github.com/llvm/llvm-project/pull/160971
>From fea611f78b31afb861228e0566b02b515bda1d67 Mon Sep 17 00:00:00 2001
From: flovent <flbven at protonmail.com>
Date: Sat, 27 Sep 2025 10:13:09 +0800
Subject: [PATCH 1/2] [clang-tidy] Fix false positives about references in
`misc-const-correctness`
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 +++
.../const-correctness-pointer-as-pointers.cpp | 15 +++++++++++
clang/lib/Analysis/ExprMutationAnalyzer.cpp | 25 ++++++++++---------
.../Analysis/ExprMutationAnalyzerTest.cpp | 23 +++++++++++++++++
4 files changed, 55 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9257dc6b98ba2..a6e4ed2edaebc 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -309,6 +309,10 @@ Changes in existing checks
- ``for`` loops are supported.
+- Improved :doc:`misc-const-correctness
+ <clang-tidy/checks/misc/misc-const-correctness>` check to avoid false
+ positives when pointers is tranferred to non-const references.
+
- Improved :doc:`misc-header-include-cycle
<clang-tidy/checks/misc/header-include-cycle>` check performance.
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..bcd946e7404c1 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,18 @@ void ignore_const_alias() {
p_local0 = &a[1];
}
+void takeNonConstRef(int *&r);
+
+void ignoreNonConstRefOps() {
+ // init with non-const ref
+ int* p0 {nullptr};
+ int*& r1 = p0;
+
+ // non-const ref param
+ int* p1 {nullptr};
+ takeNonConstRef(p1);
+
+ // cast
+ int* p2 {nullptr};
+ int*& r2 = (int*&)p2;
+}
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 3fcd3481c2d6b..1e376da1be83d 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -755,22 +755,23 @@ ExprMutationAnalyzer::Analyzer::findPointeeMemberMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findPointeeToNonConst(const Expr *Exp) {
- const auto NonConstPointerOrDependentType =
- type(anyOf(nonConstPointerType(), isDependentType()));
+ const auto NonConstPointerOrNonConstRefOrDependentType = type(
+ anyOf(nonConstPointerType(), nonConstReferenceType(), isDependentType()));
// assign
const auto InitToNonConst =
- varDecl(hasType(NonConstPointerOrDependentType),
+ varDecl(hasType(NonConstPointerOrNonConstRefOrDependentType),
hasInitializer(expr(canResolveToExprPointee(Exp)).bind("stmt")));
- const auto AssignToNonConst =
- binaryOperation(hasOperatorName("="),
- hasLHS(expr(hasType(NonConstPointerOrDependentType))),
- hasRHS(canResolveToExprPointee(Exp)));
+ const auto AssignToNonConst = binaryOperation(
+ hasOperatorName("="),
+ hasLHS(expr(hasType(NonConstPointerOrNonConstRefOrDependentType))),
+ hasRHS(canResolveToExprPointee(Exp)));
// arguments like
const auto ArgOfInstantiationDependent = allOf(
hasAnyArgument(canResolveToExprPointee(Exp)), isInstantiationDependent());
- const auto ArgOfNonConstParameter = forEachArgumentWithParamType(
- canResolveToExprPointee(Exp), NonConstPointerOrDependentType);
+ const auto ArgOfNonConstParameter =
+ forEachArgumentWithParamType(canResolveToExprPointee(Exp),
+ NonConstPointerOrNonConstRefOrDependentType);
const auto CallLikeMatcher =
anyOf(ArgOfNonConstParameter, ArgOfInstantiationDependent);
const auto PassAsNonConstArg =
@@ -779,9 +780,9 @@ ExprMutationAnalyzer::Analyzer::findPointeeToNonConst(const Expr *Exp) {
parenListExpr(has(canResolveToExprPointee(Exp))),
initListExpr(hasAnyInit(canResolveToExprPointee(Exp)))));
// cast
- const auto CastToNonConst =
- explicitCastExpr(hasSourceExpression(canResolveToExprPointee(Exp)),
- hasDestinationType(NonConstPointerOrDependentType));
+ const auto CastToNonConst = explicitCastExpr(
+ hasSourceExpression(canResolveToExprPointee(Exp)),
+ hasDestinationType(NonConstPointerOrNonConstRefOrDependentType));
// capture
// FIXME: false positive if the pointee does not change in lambda
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index 4e97174c17d95..95f8ae266ae10 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -1749,6 +1749,13 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByInitToNonConst) {
match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
}
+ {
+ const std::string Code = "void f() { int* x = nullptr; int*& b = x; }";
+ auto AST = buildASTFromCodeWithArgs(Code, {});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
+ }
}
TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssignToNonConst) {
@@ -1786,6 +1793,14 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgument) {
match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
}
+ {
+ const std::string Code =
+ "void b(int *&); void f() { int* x = nullptr; b(x); }";
+ auto AST = buildASTFromCodeWithArgs(Code, {});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
+ }
}
TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgumentInConstruct) {
@@ -1884,6 +1899,14 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByExplicitCastToNonConst) {
match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
}
+ {
+ const std::string Code =
+ "void f() { int* x = nullptr; static_cast<int*&>(x); }";
+ auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isPointeeMutated(Results, AST.get()));
+ }
}
TEST(ExprMutationAnalyzerTest, PointeeMutatedByConstCastToNonConst) {
>From 5976ad50784c61e2f47a7f86f6c3b49082973c24 Mon Sep 17 00:00:00 2001
From: flovent <flbven at protonmail.com>
Date: Sat, 27 Sep 2025 10:27:51 +0800
Subject: [PATCH 2/2] [NFC] Fix doc error
---
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a6e4ed2edaebc..34e7ea7f9368b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -310,7 +310,7 @@ Changes in existing checks
- ``for`` loops are supported.
- Improved :doc:`misc-const-correctness
- <clang-tidy/checks/misc/misc-const-correctness>` check to avoid false
+ <clang-tidy/checks/misc/const-correctness>` check to avoid false
positives when pointers is tranferred to non-const references.
- Improved :doc:`misc-header-include-cycle
More information about the cfe-commits
mailing list