[mlir][ods] Add cppClassName to ConfinedType
[llvm-project.git] / clang-tools-extra / clang-tidy / fuchsia / MultipleInheritanceCheck.cpp
blobae3222a2bd1a40aee156d163510ced8510e778e3
1 //===--- MultipleInheritanceCheck.cpp - clang-tidy-------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "MultipleInheritanceCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang;
14 using namespace clang::ast_matchers;
16 namespace clang {
17 namespace tidy {
18 namespace fuchsia {
20 namespace {
21 AST_MATCHER(CXXRecordDecl, hasBases) {
22 if (Node.hasDefinition())
23 return Node.getNumBases() > 0;
24 return false;
26 } // namespace
28 // Adds a node (by name) to the interface map, if it was not present in the map
29 // previously.
30 void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
31 bool IsInterface) {
32 assert(Node->getIdentifier());
33 StringRef Name = Node->getIdentifier()->getName();
34 InterfaceMap.insert(std::make_pair(Name, IsInterface));
37 // Returns "true" if the boolean "isInterface" has been set to the
38 // interface status of the current Node. Return "false" if the
39 // interface status for the current node is not yet known.
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())
46 return false;
47 IsInterface = Pair->second;
48 return true;
51 bool MultipleInheritanceCheck::isCurrentClassInterface(
52 const CXXRecordDecl *Node) const {
53 // Interfaces should have no fields.
54 if (!Node->field_empty()) return false;
56 // Interfaces should have exclusively pure methods.
57 return llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
58 return M->isUserProvided() && !M->isPure() && !M->isStatic();
59 });
62 bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
63 if (!Node->getIdentifier())
64 return false;
66 // Short circuit the lookup if we have analyzed this record before.
67 bool PreviousIsInterfaceResult;
68 if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
69 return PreviousIsInterfaceResult;
71 // To be an interface, all base classes must be interfaces as well.
72 for (const auto &I : Node->bases()) {
73 if (I.isVirtual()) continue;
74 const auto *Ty = I.getType()->getAs<RecordType>();
75 if (!Ty) continue;
76 const RecordDecl *D = Ty->getDecl()->getDefinition();
77 if (!D) continue;
78 const auto *Base = cast<CXXRecordDecl>(D);
79 if (!isInterface(Base)) {
80 addNodeToInterfaceMap(Node, false);
81 return false;
85 bool CurrentClassIsInterface = isCurrentClassInterface(Node);
86 addNodeToInterfaceMap(Node, CurrentClassIsInterface);
87 return CurrentClassIsInterface;
90 void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
91 // Match declarations which have bases.
92 Finder->addMatcher(
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")) {
98 // Check against map to see if if the class inherits from multiple
99 // concrete classes
100 unsigned NumConcrete = 0;
101 for (const auto &I : D->bases()) {
102 if (I.isVirtual()) continue;
103 const auto *Ty = I.getType()->getAs<RecordType>();
104 if (!Ty) continue;
105 const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
106 if (!isInterface(Base)) NumConcrete++;
109 // Check virtual bases to see if there is more than one concrete
110 // non-virtual base.
111 for (const auto &V : D->vbases()) {
112 const auto *Ty = V.getType()->getAs<RecordType>();
113 if (!Ty) continue;
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");
125 } // namespace fuchsia
126 } // namespace tidy
127 } // namespace clang