[clang-tools-extra] [clang-tidy] New bugprone-derived-method-shadowing-base-method (PR #154746)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 5 12:38:09 PDT 2025
================
@@ -0,0 +1,127 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DerivedMethodShadowingBaseMethodCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+namespace {
+
+bool sameBasicType(const ParmVarDecl *Lhs, const ParmVarDecl *Rhs) {
+ return Lhs && Rhs &&
+ Lhs->getType()
+ .getCanonicalType()
+ .getNonReferenceType()
+ .getUnqualifiedType() == Rhs->getType()
+ .getCanonicalType()
+ .getNonReferenceType()
+ .getUnqualifiedType();
+}
+
+bool namesCollide(const CXXMethodDecl &Lhs, const CXXMethodDecl &Rhs) {
+ if (Lhs.getNameAsString() != Rhs.getNameAsString())
+ return false;
+ if (Lhs.isConst() != Rhs.isConst())
+ return false;
+ if (Lhs.getNumParams() != Rhs.getNumParams())
+ return false;
+ for (unsigned int It = 0; It < Lhs.getNumParams(); ++It)
+ if (!sameBasicType(Lhs.getParamDecl(It), Rhs.getParamDecl(It)))
+ return false;
+ return true;
+}
+
+AST_MATCHER(CXXMethodDecl, nameCollidesWithMethodInBase) {
+ const CXXRecordDecl *DerivedClass = Node.getParent();
+ for (const auto &Base : DerivedClass->bases()) {
+ llvm::SmallVector<const CXXBaseSpecifier *, 8> Stack;
+ Stack.push_back(&Base);
+ while (!Stack.empty()) {
+ const CXXBaseSpecifier *CurrentBaseSpec = Stack.back();
+ Stack.pop_back();
+
+ if (CurrentBaseSpec->getAccessSpecifier() ==
+ clang::AccessSpecifier::AS_private)
+ continue;
+
+ const auto *CurrentRecord =
+ CurrentBaseSpec->getType()->getAsCXXRecordDecl();
+ if (!CurrentRecord)
+ continue;
+
+ // For multiple inheritance, we ignore only the bases that come from the
+ // std:: namespace
+ if (CurrentRecord->isInStdNamespace())
+ continue;
+
+ for (const auto &BaseMethod : CurrentRecord->methods()) {
+ if (namesCollide(*BaseMethod, Node)) {
+ ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
+ Builder->setBinding("base_method",
+ clang::DynTypedNode::create(*BaseMethod));
+ return true;
+ }
+ }
+
+ for (const auto &SubBase : CurrentRecord->bases())
+ Stack.push_back(&SubBase);
+ }
+ }
+ return false;
+}
+
+// Same as clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp,
+// similar matchers are used elsewhere in LLVM
+AST_MATCHER(CXXMethodDecl, isOutOfLine) { return Node.isOutOfLine(); }
+
+} // namespace
+
+DerivedMethodShadowingBaseMethodCheck::DerivedMethodShadowingBaseMethodCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+void DerivedMethodShadowingBaseMethodCheck::registerMatchers(
+ MatchFinder *Finder) {
+ Finder->addMatcher(
+ cxxMethodDecl(
+ unless(anyOf(isOutOfLine(), isStaticStorageClass(), isImplicit(),
+ cxxConstructorDecl(), isOverride(), isPrivate(),
+ // isFinal(), //included with isOverride,
+ // Templates are not handled yet
+ ast_matchers::isTemplateInstantiation(),
+ ast_matchers::isExplicitTemplateSpecialization())),
+ ofClass(cxxRecordDecl(isDerivedFrom(cxxRecordDecl()))
+ .bind("derived_class")),
+ nameCollidesWithMethodInBase())
+ .bind("shadowing_method"),
+ this);
+}
+
+void DerivedMethodShadowingBaseMethodCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *ShadowingMethod =
+ Result.Nodes.getNodeAs<CXXMethodDecl>("shadowing_method");
+ const auto *DerivedClass =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("derived_class");
+ const auto *BaseMethod = Result.Nodes.getNodeAs<CXXMethodDecl>("base_method");
+
+ if (!ShadowingMethod || !DerivedClass || !BaseMethod)
+ llvm_unreachable("Required binding not found");
+
+ diag(ShadowingMethod->getBeginLoc(), "'%0' hides same method in %1")
----------------
vbvictor wrote:
```suggestion
diag(ShadowingMethod->getBeginLoc(), "'%0' shadows method with the same name in class %1")
```
https://github.com/llvm/llvm-project/pull/154746
More information about the cfe-commits
mailing list