clang-tools 8.0.0

MultipleInheritanceCheck.cpp
Go to the documentation of this file.
1 //===--- MultipleInheritanceCheck.cpp - clang-tidy-------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "MultipleInheritanceCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13
14 using namespace clang;
15 using namespace clang::ast_matchers;
16
17 namespace clang {
18 namespace tidy {
19 namespace fuchsia {
20
21 namespace {
22 AST_MATCHER(CXXRecordDecl, hasBases) {
23 if (Node.hasDefinition())
24 return Node.getNumBases() > 0;
25 return false;
26 }
27 } // namespace
28
29 // Adds a node (by name) to the interface map, if it was not present in the map
30 // previously.
31 void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
32 bool isInterface) {
33 assert(Node->getIdentifier());
34 StringRef Name = Node->getIdentifier()->getName();
35 InterfaceMap.insert(std::make_pair(Name, isInterface));
36 }
37
38 // Returns "true" if the boolean "isInterface" has been set to the
39 // interface status of the current Node. Return "false" if the
40 // interface status for the current node is not yet known.
41 bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
42 bool &isInterface) const {
43 assert(Node->getIdentifier());
44 StringRef Name = Node->getIdentifier()->getName();
45 llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
46 if (Pair == InterfaceMap.end())
47 return false;
48 isInterface = Pair->second;
49 return true;
50 }
51
52 bool MultipleInheritanceCheck::isCurrentClassInterface(
53 const CXXRecordDecl *Node) const {
54 // Interfaces should have no fields.
55 if (!Node->field_empty()) return false;
56
57 // Interfaces should have exclusively pure methods.
58 return llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
59 return M->isUserProvided() && !M->isPure() && !M->isStatic();
60 });
61 }
62
63 bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
64 if (!Node->getIdentifier())
65 return false;
66
67 // Short circuit the lookup if we have analyzed this record before.
68 bool PreviousIsInterfaceResult;
69 if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
70 return PreviousIsInterfaceResult;
71
72 // To be an interface, all base classes must be interfaces as well.
73 for (const auto &I : Node->bases()) {
74 if (I.isVirtual()) continue;
75 const auto *Ty = I.getType()->getAs<RecordType>();
76 if (!Ty) continue;
77 const RecordDecl *D = Ty->getDecl()->getDefinition();
78 if (!D) continue;
79 const auto *Base = cast<CXXRecordDecl>(D);
80 if (!isInterface(Base)) {
81 addNodeToInterfaceMap(Node, false);
82 return false;
83 }
84 }
85
86 bool CurrentClassIsInterface = isCurrentClassInterface(Node);
87 addNodeToInterfaceMap(Node, CurrentClassIsInterface);
88 return CurrentClassIsInterface;
89 }
90
91 void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
92 // Requires C++.
93 if (!getLangOpts().CPlusPlus)
94 return;
95
96 // Match declarations which have bases.
97 Finder->addMatcher(cxxRecordDecl(hasBases()).bind("decl"), this);
98 }
99
100 void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
101 if (const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl")) {
102 // Check against map to see if if the class inherits from multiple
103 // concrete classes
104 unsigned NumConcrete = 0;
105 for (const auto &I : D->bases()) {
106 if (I.isVirtual()) continue;
107 const auto *Ty = I.getType()->getAs<RecordType>();
108 if (!Ty) continue;
109 const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
110 if (!isInterface(Base)) NumConcrete++;
111 }
112
113 // Check virtual bases to see if there is more than one concrete
114 // non-virtual base.
115 for (const auto &V : D->vbases()) {
116 const auto *Ty = V.getType()->getAs<RecordType>();
117 if (!Ty) continue;
118 const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
119 if (!isInterface(Base)) NumConcrete++;
120 }
121
122 if (NumConcrete > 1) {
123 diag(D->getBeginLoc(), "inheriting mulitple classes that aren't "
124 "pure virtual is discouraged");
125 }
126 }
127 }
128
129 } // namespace fuchsia
130 } // namespace tidy
131 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:15
clang::tidy::matchers::AST_MATCHER
AST_MATCHER(BinaryOperator, isAssignmentOperator)
Definition: Matchers.h:20
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
D
const Decl * D
Definition: XRefs.cpp:79
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
MultipleInheritanceCheck.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18