11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Tooling/FixIt.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallVector.h" 25 using BasesVector = llvm::SmallVector<const CXXRecordDecl *, 5>;
28 const CXXRecordDecl &ThisClass) {
29 if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl())
31 const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl();
32 return ThisClass.bases_end() !=
33 llvm::find_if(ThisClass.bases(), [=](
const CXXBaseSpecifier &Base) {
34 auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
36 return ParentCanonicalDecl == BaseDecl->getCanonicalDecl();
41 const CXXRecordDecl &ThisClass,
42 const CXXMethodDecl &MemberDecl) {
44 for (
const auto &Base : ThisClass.bases()) {
45 const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
46 const CXXMethodDecl *ActualMemberDecl =
47 MemberDecl.getCorrespondingMethodInClass(BaseDecl);
48 if (!ActualMemberDecl)
53 const Type *TypePtr = ActualMemberDecl->getThisType().getTypePtr();
54 const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl();
55 assert(RecordDeclType &&
"TypePtr is not a pointer to CXXRecordDecl!");
56 if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent))
57 Result.emplace_back(RecordDeclType);
65 llvm::raw_string_ostream OS(QualName);
66 PrintingPolicy PP(Decl->getASTContext().getPrintingPolicy());
67 PP.SuppressUnwrittenScope =
true;
68 Decl->printQualifiedName(OS, PP);
75 clang::ASTContext &AC) {
76 std::string Text = tooling::fixit::getText(E, AC).str();
80 [](
char C) {
return std::isspace(static_cast<unsigned char>(C)); }),
85 void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) {
88 callee(memberExpr(hasDescendant(implicitCastExpr(
89 hasImplicitDestinationType(pointsTo(
90 type(anything()).bind(
"castToType"))),
91 hasSourceExpression(cxxThisExpr(hasType(
92 type(anything()).bind(
"thisType")))))))
94 callee(cxxMethodDecl(isVirtual()))),
98 void ParentVirtualCallCheck::check(
const MatchFinder::MatchResult &
Result) {
99 const auto *Member = Result.Nodes.getNodeAs<MemberExpr>(
"member");
102 if (!Member->getQualifier())
105 const auto *MemberDecl = cast<CXXMethodDecl>(Member->getMemberDecl());
107 const auto *ThisTypePtr = Result.Nodes.getNodeAs<PointerType>(
"thisType");
110 const auto *ThisType = ThisTypePtr->getPointeeCXXRecordDecl();
113 const auto *CastToTypePtr = Result.Nodes.getNodeAs<Type>(
"castToType");
114 assert(CastToTypePtr);
116 const auto *CastToType = CastToTypePtr->getAsCXXRecordDecl();
128 std::string ParentsStr;
129 ParentsStr.reserve(30 * Parents.size());
130 for (
const CXXRecordDecl *Parent : Parents) {
131 if (!ParentsStr.empty())
132 ParentsStr.append(
" or ");
136 assert(Member->getQualifierLoc().getSourceRange().getBegin().isValid());
137 auto Diag = diag(Member->getQualifierLoc().getSourceRange().getBegin(),
138 "qualified name '%0' refers to a member overridden " 139 "in subclass%1; did you mean %2?")
141 << (Parents.size() > 1 ?
"es" :
"") << ParentsStr;
144 if (Parents.size() == 1 &&
146 !isa<ClassTemplateSpecializationDecl>(Parents.front()))
147 Diag << FixItHint::CreateReplacement(
148 Member->getQualifierLoc().getSourceRange(),
static bool isParentOf(const CXXRecordDecl &Parent, const CXXRecordDecl &ThisClass)
llvm::SmallVector< const CXXRecordDecl *, 5 > BasesVector
static std::string getExprAsString(const clang::Expr &E, clang::ASTContext &AC)
static std::string getNameAsString(const NamedDecl *Decl)
static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent, const CXXRecordDecl &ThisClass, const CXXMethodDecl &MemberDecl)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//