From 9dd8caad1f955119c3804029f72bd443986f3dc9 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Mon, 13 Mar 2017 21:39:00 +0000 Subject: Add the 'AllowSoleDefaultDtor' and 'AllowMissingMoveFunctions' options to the cppcoreguidelines-special-member-functions check. Patch by Florian Gross. llvm-svn: 297671 --- .../SpecialMemberFunctionsCheck.cpp | 111 +++++++++++++++------ 1 file changed, 82 insertions(+), 29 deletions(-) (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp') 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 &Members = + ClassWithSpecialMembers[ID]; + if (!llvm::is_contained(Members, Kind)) + Members.push_back(Kind); + }; + + if (const auto *Dtor = Result.Nodes.getNodeAs("dtor")) { + StoreMember(Dtor->isDefaulted() + ? SpecialMemberFunctionKind::DefaultDestructor + : SpecialMemberFunctionKind::NonDefaultDestructor); + } + std::initializer_list> - 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(KV.first)) { - SpecialMemberFunctionKind Kind = KV.second; - llvm::SmallVectorImpl &Members = - ClassWithSpecialMembers[ID]; - if (find(Members, Kind) == Members.end()) - Members.push_back(Kind); + StoreMember(KV.second); } } void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() { - llvm::SmallVector 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 UndefinedSpecialMembers; - std::set_difference(AllSpecialMembers.begin(), AllSpecialMembers.end(), - DefinedSpecialMembers.begin(), - DefinedSpecialMembers.end(), - std::back_inserter(UndefinedSpecialMembers)); +void SpecialMemberFunctionsCheck::checkForMissingMembers( + const ClassDefId &ID, + llvm::ArrayRef DefinedMembers) { + llvm::SmallVector 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 -- cgit v1.2.3