diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -127,6 +127,26 @@ this)); } +/// Returns the function that \p Method is overridding. If There are none or +/// multiple overrides it returns nullptr. If the overridden function itself is +/// overridding then it will recurse up to find the first decl of the function. +static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) { + if (Method->size_overridden_methods() != 1) + return nullptr; // no overrides + while (true) { + const CXXMethodDecl *Next = *Method->begin_overridden_methods(); + assert(Next && "Overridden method shouldn't be null"); + if (Next->size_overridden_methods() == 0) { + return Next; + } + if (Next->size_overridden_methods() == 1) { + Method = Next; + continue; + } + return nullptr; // Multiple overrides + } +} + void RenamerClangTidyCheck::addUsage( const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, SourceManager *SourceMgr) { @@ -160,7 +180,10 @@ void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range, SourceManager *SourceMgr) { - + if (const auto *Method = dyn_cast(Decl)) { + if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) + Decl = Overridden; + } return addUsage(RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), Decl->getNameAsString()), Range, SourceMgr); @@ -390,6 +413,14 @@ } } + // Fix overridden methods + if (const auto *Method = Result.Nodes.getNodeAs("decl")) { + if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) { + addUsage(Overridden, Method->getLocation()); + return; // Don't try to add the actual decl as a Failure. + } + } + // Ignore ClassTemplateSpecializationDecl which are creating duplicate // replacements with CXXRecordDecl. if (isa(Decl)) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp @@ -267,14 +267,32 @@ virtual ~AOverridden() = default; virtual void BadBaseMethod() = 0; // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for virtual method 'BadBaseMethod' + // CHECK-FIXES: {{^}} virtual void v_Bad_Base_Method() = 0; }; class COverriding : public AOverridden { public: // Overriding a badly-named base isn't a new violation. void BadBaseMethod() override {} + // CHECK-FIXES: {{^}} void v_Bad_Base_Method() override {} + + void foo() { + BadBaseMethod(); + // CHECK-FIXES: {{^}} v_Bad_Base_Method(); + this->BadBaseMethod(); + // CHECK-FIXES: {{^}} this->v_Bad_Base_Method(); + AOverridden::BadBaseMethod(); + // CHECK-FIXES: {{^}} AOverridden::v_Bad_Base_Method(); + COverriding::BadBaseMethod(); + // CHECK-FIXES: {{^}} COverriding::v_Bad_Base_Method(); + } }; +void VirtualCall(AOverridden &a_vItem) { + a_vItem.BadBaseMethod(); + // CHECK-FIXES: {{^}} a_vItem.v_Bad_Base_Method(); +} + template class CRTPBase { public: