[clang-tools-extra] [clang-tidy] Avoid non-const-parameter fix-it conflicts with overloads (PR #202490)
Zeyi Xu via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 8 23:57:06 PDT 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/202490
>From b28426d8567105b757d4767f418d91aad1530449 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 9 Jun 2026 11:20:49 +0800
Subject: [PATCH 1/3] [clang-tidy] Avoid non-const-parameter fix-it conflicts
with overloads
---
.../readability/NonConstParameterCheck.cpp | 29 +++++++++++++
clang-tools-extra/docs/ReleaseNotes.rst | 3 ++
.../readability/non-const-parameter.cpp | 41 +++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
index fa9184a290273..f5abe02eb2674 100644
--- a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
@@ -23,6 +23,32 @@ AST_MATCHER_P(VarDecl, hasOwnInitializer, ast_matchers::internal::Matcher<Expr>,
}
} // namespace
+static bool wouldConflictWithOverload(const FunctionDecl &Function,
+ unsigned ParamIndex) {
+ ASTContext &Context = Function.getASTContext();
+ const auto *Proto = Function.getType()->getAs<FunctionProtoType>();
+ if (!Proto)
+ return false;
+
+ // Simulate applying the fix-it to compare against existing overloads.
+ SmallVector<QualType> ParamTypes(Proto->getParamTypes());
+ ParamTypes[ParamIndex] = Context.getPointerType(
+ ParamTypes[ParamIndex]->getPointeeType().withConst());
+
+ return llvm::any_of(
+ Function.getParent()->lookup(Function.getDeclName()), [&](const Decl *D) {
+ const FunctionDecl *Overload = D->getAsFunction();
+ if (!Overload ||
+ Overload->getCanonicalDecl() == Function.getCanonicalDecl())
+ return false;
+
+ QualType ConstParamFunctionType = Context.getFunctionType(
+ Overload->getReturnType(), ParamTypes, Proto->getExtProtoInfo());
+ return Context.hasSameFunctionTypeIgnoringExceptionSpec(
+ ConstParamFunctionType, Overload->getType());
+ });
+}
+
void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) {
// Add parameters to Parameters.
Finder->addMatcher(parmVarDecl().bind("Parm"), this);
@@ -185,6 +211,9 @@ void NonConstParameterCheck::diagnoseNonConstParameters() {
if (!Function)
continue;
const unsigned Index = Par->getFunctionScopeIndex();
+ if (wouldConflictWithOverload(*Function, Index))
+ continue;
+
for (FunctionDecl *FnDecl : Function->redecls()) {
if (FnDecl->getNumParams() <= Index)
continue;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9703bb8f17208..8f4e2cf251e94 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -785,6 +785,9 @@ Changes in existing checks
- Fixed a false positive in array subscript expressions where the types are
not yet resolved.
+ - Fixed a false positive when adding ``const`` to a pointer parameter would
+ conflict with an existing overload.
+
- Fixed a crash when analyzing a redeclaration whose initializer is attached
to another declaration.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
index b4918df347e5c..9639b40ae4d16 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
@@ -449,3 +449,44 @@ struct StaticDepOutOfClassInit {
template <class T>
const T StaticDepOutOfClassInit<T>::X = 0;
+
+double overloadConflict(double *overloadConflictPtr) {
+ return *overloadConflictPtr;
+}
+
+double overloadConflict(const double *overloadConflictPtr) {
+ return *overloadConflictPtr;
+}
+
+template <int>
+int templateOverloadConflict(int *templateConflictPtr) {
+ return *templateConflictPtr;
+}
+
+template <int>
+int templateOverloadConflict(const int *templateConflictPtr) {
+ return *templateConflictPtr;
+}
+
+struct ConstructorOverloadConflict {
+ ConstructorOverloadConflict(int *ctorConflictPtr) {
+ (void)*ctorConflictPtr;
+ }
+ ConstructorOverloadConflict(const int *ctorConflictPtr) {}
+};
+
+struct MemberOverloadConflict {
+ void withConflictingOverload(int *memberConflictPtr) {
+ (void)*memberConflictPtr;
+ }
+ void withConflictingOverload(const int *memberConflictPtr) {}
+};
+
+struct QualifiedMemberOverload {
+ // CHECK-MESSAGES: :[[@LINE+1]]:32: warning: pointer parameter 'qualifiedMemberPtr' can be pointer to const
+ void withConstQualifier(int *qualifiedMemberPtr) const {
+ // CHECK-FIXES: void withConstQualifier(const int *qualifiedMemberPtr) const {
+ (void)*qualifiedMemberPtr;
+ }
+ void withConstQualifier(const int *qualifiedMemberPtr) {}
+};
>From aa62fb323c4bbdfbd29f2284ff7d7b3969ce931f Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 9 Jun 2026 11:29:34 +0800
Subject: [PATCH 2/3] make tidy happy
---
.../clang-tidy/readability/NonConstParameterCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
index f5abe02eb2674..5aaf28a22a776 100644
--- a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
@@ -42,7 +42,7 @@ static bool wouldConflictWithOverload(const FunctionDecl &Function,
Overload->getCanonicalDecl() == Function.getCanonicalDecl())
return false;
- QualType ConstParamFunctionType = Context.getFunctionType(
+ const QualType ConstParamFunctionType = Context.getFunctionType(
Overload->getReturnType(), ParamTypes, Proto->getExtProtoInfo());
return Context.hasSameFunctionTypeIgnoringExceptionSpec(
ConstParamFunctionType, Overload->getType());
>From 88eb638083704e28ea33916b9efdf3ad8bfd2d16 Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 9 Jun 2026 14:56:33 +0800
Subject: [PATCH 3/3] add more test cases
---
.../readability/non-const-parameter.cpp | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
index 9639b40ae4d16..2d28ef904282a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp
@@ -458,6 +458,28 @@ double overloadConflict(const double *overloadConflictPtr) {
return *overloadConflictPtr;
}
+double topLevelConstPointerOverload(double *topLevelConstPtr) {
+ return *topLevelConstPtr;
+}
+
+double topLevelConstPointerOverload(const double *const topLevelConstPtr) {
+ return *topLevelConstPtr;
+}
+
+void arrayOverloadConflict(double arrayOut[2],
+ double arrayConflictParam[2]) {
+ arrayOut[0] = arrayConflictParam[0];
+}
+
+void arrayOverloadConflict(double arrayOut[2],
+ const double arrayConflictParam[2]) {
+ arrayOut[0] = arrayConflictParam[0];
+}
+
+int returnTypeConflict(int *returnTypePtr) { return *returnTypePtr; }
+
+long returnTypeConflict(const int *returnTypePtr) { return *returnTypePtr; }
+
template <int>
int templateOverloadConflict(int *templateConflictPtr) {
return *templateConflictPtr;
@@ -482,6 +504,11 @@ struct MemberOverloadConflict {
void withConflictingOverload(const int *memberConflictPtr) {}
};
+struct OperatorCallConflict {
+ int operator()(int *operatorCallPtr) { return *operatorCallPtr; }
+ int operator()(const int *operatorCallPtr) { return *operatorCallPtr; }
+};
+
struct QualifiedMemberOverload {
// CHECK-MESSAGES: :[[@LINE+1]]:32: warning: pointer parameter 'qualifiedMemberPtr' can be pointer to const
void withConstQualifier(int *qualifiedMemberPtr) const {
More information about the cfe-commits
mailing list