12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "llvm/ADT/DenseMapInfo.h"
15 #include "llvm/ADT/StringExtras.h"
17 #define DEBUG_TYPE "clang-tidy"
19 using namespace clang::ast_matchers;
23 namespace cppcoreguidelines {
25 SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
28 AllowMissingMoveFunctions(Options.get(
"AllowMissingMoveFunctions", 0)),
29 AllowSoleDefaultDtor(Options.get(
"AllowSoleDefaultDtor", 0)) {}
33 Options.
store(Opts,
"AllowMissingMoveFunctions", AllowMissingMoveFunctions);
34 Options.
store(Opts,
"AllowSoleDefaultDtor", AllowSoleDefaultDtor);
43 has(cxxDestructorDecl(unless(isImplicit())).bind(
"dtor")),
44 has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
46 has(cxxMethodDecl(isCopyAssignmentOperator(),
48 .bind(
"copy-assign")),
49 has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))
51 has(cxxMethodDecl(isMoveAssignmentOperator(),
53 .bind(
"move-assign"))))
58 static llvm::StringRef
62 return "a destructor";
65 return "a default destructor";
68 return "a non-default destructor";
70 return "a copy constructor";
72 return "a copy assignment operator";
74 return "a move constructor";
76 return "a move assignment operator";
78 llvm_unreachable(
"Unhandled SpecialMemberFunctionKind");
82 join(ArrayRef<SpecialMemberFunctionsCheck::SpecialMemberFunctionKind> SMFS,
83 llvm::StringRef AndOr) {
85 assert(!SMFS.empty() &&
86 "List of defined or undefined members should never be empty.");
88 llvm::raw_string_ostream Stream(Buffer);
91 size_t LastIndex = SMFS.size() - 1;
92 for (
size_t i = 1; i < LastIndex; ++i) {
96 Stream << AndOr <<
toString(SMFS[LastIndex]);
102 const MatchFinder::MatchResult &Result) {
103 const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXRecordDecl>(
"class-def");
107 ClassDefId ID(MatchedDecl->getLocation(), MatchedDecl->getName());
110 llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members =
111 ClassWithSpecialMembers[ID];
112 if (!llvm::is_contained(Members,
Kind))
113 Members.push_back(
Kind);
116 if (
const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>(
"dtor")) {
117 StoreMember(Dtor->isDefaulted()
122 std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
128 for (
const auto &KV : Matchers)
129 if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
130 StoreMember(KV.second);
135 for (
const auto &C : ClassWithSpecialMembers) {
136 checkForMissingMembers(C.first, C.second);
140 void SpecialMemberFunctionsCheck::checkForMissingMembers(
141 const ClassDefId &ID,
142 llvm::ArrayRef<SpecialMemberFunctionKind> DefinedMembers) {
143 llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers;
146 return llvm::is_contained(DefinedMembers,
Kind);
150 if (!HasMember(
Kind))
151 MissingMembers.push_back(
Kind);
156 (!AllowSoleDefaultDtor &&
163 bool RequireFive = (!AllowMissingMoveFunctions && RequireThree &&
178 assert(RequireThree);
183 if (!MissingMembers.empty())
184 diag(ID.first,
"class '%0' defines %1 but does not define %2")
void onEndOfTranslationUnit() override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
SpecialMemberFunctionKind
LangOptions getLangOpts() const
Returns the language options from the context.
std::unique_ptr< ast_matchers::MatchFinder > Finder
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.
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Base class for all clang-tidy checks.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
std::map< std::string, std::string > OptionMap
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
std::pair< SourceLocation, std::string > ClassDefId