10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "clang/ASTMatchers/ASTMatchers.h"
17static bool sameBasicType(
const ParmVarDecl *Lhs,
const ParmVarDecl *Rhs) {
21 .getNonReferenceType()
22 .getUnqualifiedType() == Rhs->getType()
24 .getNonReferenceType()
25 .getUnqualifiedType();
28static bool namesCollide(
const CXXMethodDecl &Lhs,
const CXXMethodDecl &Rhs) {
29 if (Lhs.getNameAsString() != Rhs.getNameAsString())
31 if (Lhs.isConst() != Rhs.isConst())
33 if (Lhs.getNumParams() != Rhs.getNumParams())
35 for (
unsigned int It = 0; It < Lhs.getNumParams(); ++It)
36 if (!
sameBasicType(Lhs.getParamDecl(It), Rhs.getParamDecl(It)))
43AST_MATCHER(CXXMethodDecl, nameCollidesWithMethodInBase) {
44 const CXXRecordDecl *DerivedClass = Node.getParent();
45 for (
const auto &Base : DerivedClass->bases()) {
46 llvm::SmallVector<const CXXBaseSpecifier *, 8> Stack;
47 Stack.push_back(&Base);
48 while (!Stack.empty()) {
49 const CXXBaseSpecifier *CurrentBaseSpec = Stack.back();
52 if (CurrentBaseSpec->getAccessSpecifier() ==
53 clang::AccessSpecifier::AS_private)
56 const CXXRecordDecl *CurrentRecord =
57 CurrentBaseSpec->getType()->getAsCXXRecordDecl();
63 if (CurrentRecord->isInStdNamespace())
66 for (
const auto &BaseMethod : CurrentRecord->methods()) {
68 ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
69 Builder->setBinding(
"base_method",
70 clang::DynTypedNode::create(*BaseMethod));
75 for (
const auto &SubBase : CurrentRecord->bases())
76 Stack.push_back(&SubBase);
84AST_MATCHER(CXXMethodDecl, isOutOfLine) {
return Node.isOutOfLine(); }
93 MatchFinder *Finder) {
96 unless(anyOf(isOutOfLine(), isStaticStorageClass(), isImplicit(),
97 cxxConstructorDecl(), isOverride(), isPrivate(),
100 ast_matchers::isTemplateInstantiation(),
101 ast_matchers::isExplicitTemplateSpecialization())),
102 ofClass(cxxRecordDecl(isDerivedFrom(cxxRecordDecl()))
103 .bind(
"derived_class")),
104 nameCollidesWithMethodInBase())
105 .bind(
"shadowing_method"),
110 const MatchFinder::MatchResult &Result) {
111 const auto *ShadowingMethod =
112 Result.Nodes.getNodeAs<CXXMethodDecl>(
"shadowing_method");
113 const auto *DerivedClass =
114 Result.Nodes.getNodeAs<CXXRecordDecl>(
"derived_class");
115 const auto *BaseMethod = Result.Nodes.getNodeAs<CXXMethodDecl>(
"base_method");
117 if (!ShadowingMethod || !DerivedClass || !BaseMethod)
118 llvm_unreachable(
"Required binding not found");
120 diag(ShadowingMethod->getBeginLoc(),
121 "'%0' shadows method with the same name in class %1")
122 << ShadowingMethod->getQualifiedNameAsString() << BaseMethod->getParent();
123 diag(BaseMethod->getBeginLoc(),
"previous definition of %0 is here",
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DerivedMethodShadowingBaseMethodCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static bool namesCollide(const CXXMethodDecl &Lhs, const CXXMethodDecl &Rhs)
static bool sameBasicType(const ParmVarDecl *Lhs, const ParmVarDecl *Rhs)
AST_MATCHER(BinaryOperator, isRelationalOperator)