summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp111
1 files changed, 82 insertions, 29 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
index e1f3d022323..f0cb109ef32 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
@@ -22,6 +22,18 @@ namespace clang {
namespace tidy {
namespace cppcoreguidelines {
+SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllowMissingMoveFunctions(Options.get("AllowMissingMoveFunctions", 0)),
+ AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", 0)) {}
+
+void SpecialMemberFunctionsCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "AllowMissingMoveFunctions", AllowMissingMoveFunctions);
+ Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor);
+}
+
void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
@@ -48,6 +60,12 @@ toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K) {
switch (K) {
case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::Destructor:
return "a destructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::
+ DefaultDestructor:
+ return "a default destructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::
+ NonDefaultDestructor:
+ return "a non-default destructor";
case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::CopyConstructor:
return "a copy constructor";
case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::CopyAssignment:
@@ -88,51 +106,86 @@ void SpecialMemberFunctionsCheck::check(
ClassDefId ID(MatchedDecl->getLocation(), MatchedDecl->getName());
+ auto StoreMember = [this, &ID](SpecialMemberFunctionKind Kind) {
+ llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members =
+ ClassWithSpecialMembers[ID];
+ if (!llvm::is_contained(Members, Kind))
+ Members.push_back(Kind);
+ };
+
+ if (const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>("dtor")) {
+ StoreMember(Dtor->isDefaulted()
+ ? SpecialMemberFunctionKind::DefaultDestructor
+ : SpecialMemberFunctionKind::NonDefaultDestructor);
+ }
+
std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
- Matchers = {{"dtor", SpecialMemberFunctionKind::Destructor},
- {"copy-ctor", SpecialMemberFunctionKind::CopyConstructor},
+ Matchers = {{"copy-ctor", SpecialMemberFunctionKind::CopyConstructor},
{"copy-assign", SpecialMemberFunctionKind::CopyAssignment},
{"move-ctor", SpecialMemberFunctionKind::MoveConstructor},
{"move-assign", SpecialMemberFunctionKind::MoveAssignment}};
for (const auto &KV : Matchers)
if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
- SpecialMemberFunctionKind Kind = KV.second;
- llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members =
- ClassWithSpecialMembers[ID];
- if (find(Members, Kind) == Members.end())
- Members.push_back(Kind);
+ StoreMember(KV.second);
}
}
void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() {
- llvm::SmallVector<SpecialMemberFunctionKind, 5> AllSpecialMembers = {
- SpecialMemberFunctionKind::Destructor,
- SpecialMemberFunctionKind::CopyConstructor,
- SpecialMemberFunctionKind::CopyAssignment};
-
- if (getLangOpts().CPlusPlus11) {
- AllSpecialMembers.push_back(SpecialMemberFunctionKind::MoveConstructor);
- AllSpecialMembers.push_back(SpecialMemberFunctionKind::MoveAssignment);
- }
-
for (const auto &C : ClassWithSpecialMembers) {
- const auto &DefinedSpecialMembers = C.second;
-
- if (DefinedSpecialMembers.size() == AllSpecialMembers.size())
- continue;
+ checkForMissingMembers(C.first, C.second);
+ }
+}
- llvm::SmallVector<SpecialMemberFunctionKind, 5> UndefinedSpecialMembers;
- std::set_difference(AllSpecialMembers.begin(), AllSpecialMembers.end(),
- DefinedSpecialMembers.begin(),
- DefinedSpecialMembers.end(),
- std::back_inserter(UndefinedSpecialMembers));
+void SpecialMemberFunctionsCheck::checkForMissingMembers(
+ const ClassDefId &ID,
+ llvm::ArrayRef<SpecialMemberFunctionKind> DefinedMembers) {
+ llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers;
+
+ auto HasMember = [&](SpecialMemberFunctionKind Kind) {
+ return llvm::is_contained(DefinedMembers, Kind);
+ };
+
+ auto RequireMember = [&](SpecialMemberFunctionKind Kind) {
+ if (!HasMember(Kind))
+ MissingMembers.push_back(Kind);
+ };
+
+ bool RequireThree =
+ HasMember(SpecialMemberFunctionKind::NonDefaultDestructor) ||
+ (!AllowSoleDefaultDtor &&
+ HasMember(SpecialMemberFunctionKind::DefaultDestructor)) ||
+ HasMember(SpecialMemberFunctionKind::CopyConstructor) ||
+ HasMember(SpecialMemberFunctionKind::CopyAssignment) ||
+ HasMember(SpecialMemberFunctionKind::MoveConstructor) ||
+ HasMember(SpecialMemberFunctionKind::MoveAssignment);
+
+ bool RequireFive = (!AllowMissingMoveFunctions && RequireThree &&
+ getLangOpts().CPlusPlus11) ||
+ HasMember(SpecialMemberFunctionKind::MoveConstructor) ||
+ HasMember(SpecialMemberFunctionKind::MoveAssignment);
+
+ if (RequireThree) {
+ if (!HasMember(SpecialMemberFunctionKind::DefaultDestructor) &&
+ !HasMember(SpecialMemberFunctionKind::NonDefaultDestructor))
+ MissingMembers.push_back(SpecialMemberFunctionKind::Destructor);
+
+ RequireMember(SpecialMemberFunctionKind::CopyConstructor);
+ RequireMember(SpecialMemberFunctionKind::CopyAssignment);
+ }
- diag(C.first.first, "class '%0' defines %1 but does not define %2")
- << C.first.second << join(DefinedSpecialMembers, " and ")
- << join(UndefinedSpecialMembers, " or ");
+ if (RequireFive) {
+ assert(RequireThree);
+ RequireMember(SpecialMemberFunctionKind::MoveConstructor);
+ RequireMember(SpecialMemberFunctionKind::MoveAssignment);
}
+
+ if (!MissingMembers.empty())
+ diag(ID.first, "class '%0' defines %1 but does not define %2")
+ << ID.second << join(DefinedMembers, " and ")
+ << join(MissingMembers, " or ");
}
+
} // namespace cppcoreguidelines
} // namespace tidy
} // namespace clang
OpenPOWER on IntegriCloud