diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index 2d67ca4a16180a..bb8caf1d84e2ea 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -135,6 +135,23 @@ void RenamerClangTidyCheck::registerPPCallbacks( 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; + while (true) { + Method = *Method->begin_overridden_methods(); + assert(Method && "Overridden method shouldn't be null"); + unsigned NumOverrides = Method->size_overridden_methods(); + if (NumOverrides == 0) + return Method; + if (NumOverrides > 1) + return nullptr; + } +} + void RenamerClangTidyCheck::addUsage( const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, SourceManager *SourceMgr) { @@ -172,6 +189,10 @@ void RenamerClangTidyCheck::addUsage( 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; + } Decl = cast(Decl->getCanonicalDecl()); return addUsage(RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), Decl->getNameAsString()), @@ -412,6 +433,14 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) { } } + // 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/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6e6d46df4933db..595b1c465d5f86 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -125,6 +125,9 @@ Changes in existing checks Added an option `GetConfigPerFile` to support including files which use different naming styles. + Now renames overridden virtual methods if the method they override has a + style violation. + - Removed `google-runtime-references` check because the rule it checks does not exist in the Google Style Guide anymore. 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 index fed362bbecdeca..de53dddc0f92b5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp @@ -266,14 +266,32 @@ class AOverridden { 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: