10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
20 if (
Node.hasDefinition())
21 return Node.getNumBases() > 0;
28void MultipleInheritanceCheck::addNodeToInterfaceMap(
const CXXRecordDecl *Node,
30 assert(
Node->getIdentifier());
31 StringRef
Name =
Node->getIdentifier()->getName();
32 InterfaceMap.insert(std::make_pair(
Name, IsInterface));
38bool MultipleInheritanceCheck::getInterfaceStatus(
const CXXRecordDecl *Node,
39 bool &IsInterface)
const {
40 assert(
Node->getIdentifier());
41 StringRef
Name =
Node->getIdentifier()->getName();
42 llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(
Name);
43 if (Pair == InterfaceMap.end())
45 IsInterface = Pair->second;
49bool MultipleInheritanceCheck::isCurrentClassInterface(
50 const CXXRecordDecl *Node)
const {
52 if (!
Node->field_empty())
return false;
55 return llvm::none_of(
Node->methods(), [](
const CXXMethodDecl *
M) {
56 return M->isUserProvided() && !M->isPureVirtual() && !M->isStatic();
60bool MultipleInheritanceCheck::isInterface(
const CXXRecordDecl *Node) {
61 if (!
Node->getIdentifier())
65 bool PreviousIsInterfaceResult =
false;
66 if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
67 return PreviousIsInterfaceResult;
70 for (
const auto &I :
Node->bases()) {
71 if (I.isVirtual())
continue;
72 const auto *Ty = I.getType()->getAs<RecordType>();
74 const RecordDecl *D = Ty->getDecl()->getDefinition();
76 const auto *Base = cast<CXXRecordDecl>(D);
77 if (!isInterface(Base)) {
78 addNodeToInterfaceMap(Node,
false);
83 bool CurrentClassIsInterface = isCurrentClassInterface(Node);
84 addNodeToInterfaceMap(Node, CurrentClassIsInterface);
85 return CurrentClassIsInterface;
90 Finder->addMatcher(cxxRecordDecl(hasBases(), isDefinition()).bind(
"decl"),
95 if (
const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>(
"decl")) {
98 unsigned NumConcrete = 0;
99 for (
const auto &I : D->bases()) {
100 if (I.isVirtual())
continue;
101 const auto *Ty = I.getType()->getAs<RecordType>();
103 const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
104 if (!isInterface(Base)) NumConcrete++;
109 for (
const auto &V : D->vbases()) {
110 const auto *Ty = V.getType()->getAs<RecordType>();
112 const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
113 if (!isInterface(Base)) NumConcrete++;
116 if (NumConcrete > 1) {
117 diag(D->getBeginLoc(),
"inheriting multiple classes that aren't "
118 "pure virtual is discouraged");
llvm::SmallString< 256U > Name
::clang::DynTypedNode Node
const google::protobuf::Message & M
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
AST_MATCHER(Decl, declHasNoReturnAttr)
matches a Decl if it has a "no return" attribute of any kind
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//