clang-tools 22.0.0git
MultipleInheritanceCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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//===----------------------------------------------------------------------===//
8
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang;
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::fuchsia {
17
18namespace {
19AST_MATCHER(CXXRecordDecl, hasBases) {
20 return Node.hasDefinition() && Node.getNumBases() > 0;
21}
22} // namespace
23
24bool MultipleInheritanceCheck::isInterface(const CXXBaseSpecifier &Base) {
25 const CXXRecordDecl *const Node = Base.getType()->getAsCXXRecordDecl();
26 if (!Node)
27 return true;
28
29 assert(Node->isCompleteDefinition());
30
31 // Short circuit the lookup if we have analyzed this record before.
32 if (const auto CachedValue = InterfaceMap.find(Node);
33 CachedValue != InterfaceMap.end())
34 return CachedValue->second;
35
36 // To be an interface, a class must have...
37 const bool CurrentClassIsInterface =
38 // ...no bases that aren't interfaces...
39 llvm::none_of(Node->bases(),
40 [&](const CXXBaseSpecifier &I) {
41 return !I.isVirtual() && !isInterface(I);
42 }) &&
43 // ...no fields, and...
44 Node->field_empty() &&
45 // ...no methods that aren't pure virtual.
46 llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
47 return M->isUserProvided() && !M->isPureVirtual() && !M->isStatic();
48 });
49
50 InterfaceMap.try_emplace(Node, CurrentClassIsInterface);
51 return CurrentClassIsInterface;
52}
53
55 Finder->addMatcher(cxxRecordDecl(hasBases(), isDefinition()).bind("decl"),
56 this);
57}
58
59void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
60 const auto &D = *Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
61 // Check to see if the class inherits from multiple concrete classes.
62 unsigned NumConcrete =
63 llvm::count_if(D.bases(), [&](const CXXBaseSpecifier &I) {
64 return !I.isVirtual() && !isInterface(I);
65 });
66
67 // Check virtual bases to see if there is more than one concrete
68 // non-virtual base.
69 NumConcrete += llvm::count_if(
70 D.vbases(), [&](const CXXBaseSpecifier &V) { return !isInterface(V); });
71
72 if (NumConcrete > 1)
73 diag(D.getBeginLoc(), "inheriting multiple classes that aren't "
74 "pure virtual is discouraged");
75}
76
77} // namespace clang::tidy::fuchsia
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER(BinaryOperator, isRelationalOperator)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//