Author: Zeyi Xu
Date: 2026-06-13T17:01:34+08:00
New Revision: 76aed382055b0c07a9ce89d9273cc1f70daecf17

URL: 
https://github.com/llvm/llvm-project/commit/76aed382055b0c07a9ce89d9273cc1f70daecf17
DIFF: 
https://github.com/llvm/llvm-project/commit/76aed382055b0c07a9ce89d9273cc1f70daecf17.diff

LOG: [clang-tidy] Avoid non-const-parameter fix-it conflicts with overloads 
(#202490)

`readability-non-const-parameter` can suggest changing `T *` to `const T
*` when that would conflict with an existing overload. Suppress the
diagnostic in that case by comparing the post-fix parameter list against
other declarations with the same name.

Closes https://github.com/llvm/llvm-project/issues/202478

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    
clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
index fa9184a290273..004df8b9af929 100644
--- a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
@@ -23,6 +23,34 @@ AST_MATCHER_P(VarDecl, hasOwnInitializer, 
ast_matchers::internal::Matcher<Expr>,
 }
 } // namespace
 
+static bool wouldConflictWithExistingDecl(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) 
{
+        if (const auto *Using = dyn_cast<UsingShadowDecl>(D))
+          D = Using->getTargetDecl();
+        const FunctionDecl *Overload = D->getAsFunction();
+        if (!Overload ||
+            Overload->getCanonicalDecl() == Function.getCanonicalDecl())
+          return false;
+
+        const 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 +213,9 @@ void NonConstParameterCheck::diagnoseNonConstParameters() {
     if (!Function)
       continue;
     const unsigned Index = Par->getFunctionScopeIndex();
+    if (wouldConflictWithExistingDecl(*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 512aced46fedc..c05d336627356 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -812,6 +812,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..43bd8e72cd568 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,78 @@ struct StaticDepOutOfClassInit {
 
 template <class T>
 const T StaticDepOutOfClassInit<T>::X = 0;
+
+double overloadConflict(double *overloadConflictPtr) {
+  return *overloadConflictPtr;
+}
+
+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; }
+
+namespace UsingOverloadConflict {
+int usingConflict(const int *usingConflictPtr) { return *usingConflictPtr; }
+} // namespace UsingOverloadConflict
+
+using UsingOverloadConflict::usingConflict;
+int usingConflict(int *usingConflictPtr) { return *usingConflictPtr; }
+
+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 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 {
+    // CHECK-FIXES: void withConstQualifier(const int *qualifiedMemberPtr) 
const {
+    (void)*qualifiedMemberPtr;
+  }
+  void withConstQualifier(const int *qualifiedMemberPtr) {}
+};


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to