10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang;
22 if (Node.hasDefinition())
23 return Node.getNumBases() > 0;
30 void MultipleInheritanceCheck::addNodeToInterfaceMap(
const CXXRecordDecl *Node,
32 assert(Node->getIdentifier());
33 StringRef
Name = Node->getIdentifier()->getName();
34 InterfaceMap.insert(std::make_pair(
Name, isInterface));
40 bool MultipleInheritanceCheck::getInterfaceStatus(
const CXXRecordDecl *Node,
41 bool &isInterface)
const {
42 assert(Node->getIdentifier());
43 StringRef
Name = Node->getIdentifier()->getName();
44 llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(
Name);
45 if (Pair == InterfaceMap.end())
47 isInterface = Pair->second;
51 bool MultipleInheritanceCheck::isCurrentClassInterface(
52 const CXXRecordDecl *Node)
const {
54 if (!Node->field_empty())
return false;
57 return llvm::none_of(Node->methods(), [](
const CXXMethodDecl *M) {
58 return M->isUserProvided() && !M->isPure() && !M->isStatic();
62 bool MultipleInheritanceCheck::isInterface(
const CXXRecordDecl *Node) {
63 if (!Node->getIdentifier())
67 bool PreviousIsInterfaceResult;
68 if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
69 return PreviousIsInterfaceResult;
72 for (
const auto &I : Node->bases()) {
73 if (I.isVirtual())
continue;
74 const auto *Ty = I.getType()->getAs<RecordType>();
76 const RecordDecl *D = Ty->getDecl()->getDefinition();
78 const auto *
Base = cast<CXXRecordDecl>(D);
79 if (!isInterface(
Base)) {
80 addNodeToInterfaceMap(Node,
false);
85 bool CurrentClassIsInterface = isCurrentClassInterface(Node);
86 addNodeToInterfaceMap(Node, CurrentClassIsInterface);
87 return CurrentClassIsInterface;
90 void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
93 cxxRecordDecl(allOf(hasBases(), isDefinition())).bind(
"decl"),
this);
96 void MultipleInheritanceCheck::check(
const MatchFinder::MatchResult &Result) {
97 if (
const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>(
"decl")) {
100 unsigned NumConcrete = 0;
101 for (
const auto &I : D->bases()) {
102 if (I.isVirtual())
continue;
103 const auto *Ty = I.getType()->getAs<RecordType>();
105 const auto *
Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
106 if (!isInterface(
Base)) NumConcrete++;
111 for (
const auto &V : D->vbases()) {
112 const auto *Ty = V.getType()->getAs<RecordType>();
114 const auto *
Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
115 if (!isInterface(
Base)) NumConcrete++;
118 if (NumConcrete > 1) {
119 diag(D->getBeginLoc(),
"inheriting multiple classes that aren't "
120 "pure virtual is discouraged");