11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "llvm/ADT/DenseMapInfo.h" 14 #include "llvm/ADT/StringExtras.h" 16 #define DEBUG_TYPE "clang-tidy" 22 namespace cppcoreguidelines {
24 SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
27 AllowMissingMoveFunctions(Options.get(
"AllowMissingMoveFunctions", 0)),
28 AllowSoleDefaultDtor(Options.get(
"AllowSoleDefaultDtor", 0)) {}
32 Options.
store(Opts,
"AllowMissingMoveFunctions", AllowMissingMoveFunctions);
33 Options.
store(Opts,
"AllowSoleDefaultDtor", AllowSoleDefaultDtor);
42 has(cxxDestructorDecl(unless(isImplicit())).bind(
"dtor")),
43 has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
45 has(cxxMethodDecl(isCopyAssignmentOperator(),
47 .bind(
"copy-assign")),
48 has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))
50 has(cxxMethodDecl(isMoveAssignmentOperator(),
52 .bind(
"move-assign"))))
57 static llvm::StringRef
61 return "a destructor";
64 return "a default destructor";
67 return "a non-default destructor";
69 return "a copy constructor";
71 return "a copy assignment operator";
73 return "a move constructor";
75 return "a move assignment operator";
77 llvm_unreachable(
"Unhandled SpecialMemberFunctionKind");
81 join(ArrayRef<SpecialMemberFunctionsCheck::SpecialMemberFunctionKind> SMFS,
82 llvm::StringRef AndOr) {
84 assert(!SMFS.empty() &&
85 "List of defined or undefined members should never be empty.");
87 llvm::raw_string_ostream Stream(Buffer);
90 size_t LastIndex = SMFS.size() - 1;
91 for (
size_t i = 1; i < LastIndex; ++i) {
95 Stream << AndOr <<
toString(SMFS[LastIndex]);
101 const MatchFinder::MatchResult &Result) {
102 const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXRecordDecl>(
"class-def");
106 ClassDefId ID(MatchedDecl->getLocation(), MatchedDecl->getName());
109 llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members =
110 ClassWithSpecialMembers[ID];
111 if (!llvm::is_contained(Members,
Kind))
112 Members.push_back(
Kind);
115 if (
const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>(
"dtor")) {
116 StoreMember(Dtor->isDefaulted()
121 std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
127 for (
const auto &KV : Matchers)
128 if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
129 StoreMember(KV.second);
134 for (
const auto &C : ClassWithSpecialMembers) {
135 checkForMissingMembers(C.first, C.second);
139 void SpecialMemberFunctionsCheck::checkForMissingMembers(
141 llvm::ArrayRef<SpecialMemberFunctionKind> DefinedMembers) {
142 llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers;
145 return llvm::is_contained(DefinedMembers,
Kind);
149 if (!HasMember(
Kind))
150 MissingMembers.push_back(
Kind);
155 (!AllowSoleDefaultDtor &&
162 bool RequireFive = (!AllowMissingMoveFunctions && RequireThree &&
177 assert(RequireThree);
182 if (!MissingMembers.empty())
183 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
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.
const LangOptions & getLangOpts() const
Returns the language options from the context.
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.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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