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
