diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -23,6 +23,7 @@ ProTypeStaticCastDowncastCheck.cpp ProTypeUnionAccessCheck.cpp ProTypeVarargCheck.cpp + RuleOfFiveAndZeroCheck.cpp SlicingCheck.cpp SpecialMemberFunctionsCheck.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -32,6 +32,7 @@ #include "ProTypeStaticCastDowncastCheck.h" #include "ProTypeUnionAccessCheck.h" #include "ProTypeVarargCheck.h" +#include "RuleOfFiveAndZeroCheck.h" #include "SlicingCheck.h" #include "SpecialMemberFunctionsCheck.h" @@ -86,6 +87,8 @@ "cppcoreguidelines-pro-type-union-access"); CheckFactories.registerCheck( "cppcoreguidelines-pro-type-vararg"); + CheckFactories.registerCheck( + "cppcoreguidelines-rule-of-five-and-zero"); CheckFactories.registerCheck( "cppcoreguidelines-special-member-functions"); CheckFactories.registerCheck("cppcoreguidelines-slicing"); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h @@ -0,0 +1,41 @@ +//===--- RuleOfFiveAndZeroCheck.h - clang-tidy ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_RULE_OF_FIVE_AND_ZERO_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_RULE_OF_FIVE_AND_ZERO_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +/// Rule of five and zero check +/// Checks for classes where some, but not all, of the special member functions +/// are defined. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.html +class RuleOfFiveAndZeroCheck : public ClangTidyCheck { +public: + RuleOfFiveAndZeroCheck(StringRef Name, ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const bool StrictCheck; + void + checkRuleOfFiveViolation(const ast_matchers::MatchFinder::MatchResult &Result, + llvm::StringRef Match, llvm::StringRef FunctionName); +}; + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_RULEOFFIVEANDZEROCHECK_H diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp @@ -0,0 +1,152 @@ +//===--- RuleOfFiveAndZeroCheck.cpp - clang-tidy --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RuleOfFiveAndZeroCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +RuleOfFiveAndZeroCheck::RuleOfFiveAndZeroCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StrictCheck(Options.get("StrictCheck", false)) {} + +void RuleOfFiveAndZeroCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + // Checks for user defined constructors and destructors + auto DefinesDestructor = has(cxxDestructorDecl(unless(isImplicit()))); + auto UserDefinesCopyConstructor = + has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))); + auto UserDefinesCopyAssignment = + has(cxxMethodDecl(isCopyAssignmentOperator(), unless(isImplicit()))); + auto UserDefinesMoveConstructor = + has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))); + auto UserDefinesMoveAssignment = + has(cxxMethodDecl(isMoveAssignmentOperator(), unless(isImplicit()))); + + // Checks for any derived class has deleted special members + auto DerivedFromBaseWithDeletedCopyConstructor = + isDerivedFrom(has(cxxConstructorDecl(isCopyConstructor(), isDeleted()))); + auto DerivedFromBaseWithDeletedCopyAssignment = isDerivedFrom( + has(cxxMethodDecl(isCopyAssignmentOperator(), isDeleted()))); + auto DerivedFromBaseWithDeletedMoveConstructor = + isDerivedFrom(has(cxxConstructorDecl(isMoveConstructor(), isDeleted()))); + auto DerivedFromBaseWithDeletedMoveAssignment = isDerivedFrom( + has(cxxMethodDecl(isMoveAssignmentOperator(), isDeleted()))); + + auto DefinesCopyConstructor = anyOf( + UserDefinesCopyConstructor, DerivedFromBaseWithDeletedCopyConstructor); + auto DefinesCopyAssignment = anyOf(UserDefinesCopyAssignment, + DerivedFromBaseWithDeletedCopyAssignment); + auto DefinesMoveConstructor = anyOf( + UserDefinesMoveConstructor, DerivedFromBaseWithDeletedMoveConstructor); + auto DefinesMoveAssignment = anyOf(UserDefinesMoveAssignment, + DerivedFromBaseWithDeletedMoveAssignment); + auto DefinesAllSpecialMembers = + allOf(DefinesDestructor, DefinesCopyConstructor, DefinesCopyAssignment, + DefinesMoveConstructor, DefinesMoveAssignment); + + // Safe cases + auto DefinesAllExceptMoves = + allOf(DefinesDestructor, DefinesCopyConstructor, DefinesCopyAssignment); + auto DefinesAllExceptMoveAssignment = + allOf(DefinesDestructor, DefinesCopyConstructor, DefinesCopyAssignment, + DefinesMoveConstructor); + auto DefinesAllExceptMoveConstructor = + allOf(DefinesDestructor, DefinesCopyConstructor, DefinesCopyAssignment, + DefinesMoveAssignment); + auto DefinesDestructorAndMoveAssignment = + allOf(DefinesDestructor, DefinesMoveAssignment); + auto DefinesDestructorAndMoveConstructor = + allOf(DefinesDestructor, DefinesMoveConstructor); + + auto SafeSpecialMembers = + anyOf(DefinesAllExceptMoves, DefinesAllExceptMoveConstructor, + DefinesAllExceptMoveAssignment, DefinesDestructorAndMoveConstructor, + DefinesDestructorAndMoveAssignment); + + if (StrictCheck) { + Finder->addMatcher(cxxRecordDecl(allOf(DefinesDestructor, + unless(DefinesAllSpecialMembers))) + .bind("dtor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesCopyConstructor, + unless(DefinesAllSpecialMembers))) + .bind("copy-ctor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesCopyAssignment, + unless(DefinesAllSpecialMembers))) + .bind("copy-assign"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesMoveConstructor, + unless(DefinesAllSpecialMembers))) + .bind("move-ctor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesMoveAssignment, + unless(DefinesAllSpecialMembers))) + .bind("move-assign"), + this); + } else { + Finder->addMatcher( + cxxRecordDecl(allOf(DefinesDestructor, unless(DefinesAllSpecialMembers), + unless(SafeSpecialMembers))) + .bind("dtor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesCopyConstructor, + unless(DefinesAllSpecialMembers), + unless(SafeSpecialMembers))) + .bind("copy-ctor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesCopyAssignment, + unless(DefinesAllSpecialMembers), + unless(SafeSpecialMembers))) + .bind("copy-assign"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesMoveConstructor, + unless(DefinesAllSpecialMembers), + unless(SafeSpecialMembers))) + .bind("move-ctor"), + this); + Finder->addMatcher(cxxRecordDecl(allOf(UserDefinesMoveAssignment, + unless(DefinesAllSpecialMembers), + unless(SafeSpecialMembers))) + .bind("move-assign"), + this); + } +} + +void RuleOfFiveAndZeroCheck::checkRuleOfFiveViolation( + const MatchFinder::MatchResult &Result, llvm::StringRef Match, + llvm::StringRef FunctionName) { + if (const auto *MatchedDecl = Result.Nodes.getNodeAs(Match)) { + diag(MatchedDecl->getLocation(), + "class %0 defines a %1 but does not define all other 5, " + "define all other 5 or delete all other special " + "member functions") + << MatchedDecl << FunctionName; + } +} + +void RuleOfFiveAndZeroCheck::check(const MatchFinder::MatchResult &Result) { + checkRuleOfFiveViolation(Result, "dtor", "destructor"); + checkRuleOfFiveViolation(Result, "copy-ctor", "copy constructor"); + checkRuleOfFiveViolation(Result, "copy-assign", "copy assignment operator"); + checkRuleOfFiveViolation(Result, "move-ctor", "move constructor"); + checkRuleOfFiveViolation(Result, "move-assign", "move assignment operator"); +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -113,6 +113,13 @@ Flags use of the `C` standard library functions ``memset``, ``memcpy`` and ``memcmp`` and similar derivatives on non-trivial types. +- New :doc:`cppcoreguidelines-rule-of-five-and-zero + ` check. + + Check for rule of five and zero violations. + Finds the classes where some but not all of the special member functions + are defined. + - New :doc:`llvmlibc-callee-namespace ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst @@ -0,0 +1,37 @@ +.. title:: clang-tidy - cppcoreguidelines-rule-of-five-and-zero + +cppcoreguidelines-rule-of-five-and-zero +======================================= + +The check finds classes where some but not all of the special member functions +are defined. This rule is known as rule of five and zero. + +By default the compiler defines a copy constructor, copy assignment operator, +move constructor, move assignment operator and destructor. The default can be +suppressed by explicit user-definitions.``=default`` or ``=delete`` are +considered to be a definition and will suppress the implicit declaration. The +relationship between which functions will be suppressed by definitions of +other functions is complicated and it is advised that all five are defaulted +or explicitly defined. + +With ``strict-check`` flag the check has two modes. With the flag the rule +checks whether the all special members or none of the special members are +defined. + +But for some combination, compiler explicitly delete the special members or +does not declare implicitly. In that case don'nt have to define all the special +members. For example, in case of defining all members except move constructor +and move assignment compiler will not implicitly declare the move constructor +and move assignment. + +Without the flag the check will ignore special safe cases: +* Defining all members except move constructor and move assignment +* Defining all except move constructor +* Defining all except move assignment +* Defining only destructor and move constructor +* Defining only destructor and move assignment + +This rule is part of the "Constructors, assignments, and destructors" profile of the C++ Core +Guidelines, corresponding to rule C.21. See + +https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -148,6 +148,7 @@ `cppcoreguidelines-pro-type-static-cast-downcast `_, "Yes" `cppcoreguidelines-pro-type-union-access `_, `cppcoreguidelines-pro-type-vararg `_, + `cppcoreguidelines-rule-of-five-and-zero `_, "Yes" `cppcoreguidelines-slicing `_, `cppcoreguidelines-special-member-functions `_, `darwin-avoid-spinlock `_, @@ -421,4 +422,3 @@ `hicpp-use-override `_, `modernize-use-override `_, "Yes" `hicpp-vararg `_, `cppcoreguidelines-pro-type-vararg `_, `llvm-qualified-auto `_, `readability-qualified-auto `_, "Yes" - diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp @@ -0,0 +1,139 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-rule-of-five-and-zero %t -- \ +// RUN: -config="{CheckOptions: \ +// RUN: [{key: cppcoreguidelines-rule-of-five-and-zero.StrictCheck, \ +// RUN: value: 1}]}" + +class DefinesNothing { +}; + +class DefinesEverything { + DefinesEverything(const DefinesEverything &); + DefinesEverything &operator=(const DefinesEverything &); + DefinesEverything(DefinesEverything &&); + DefinesEverything &operator=(DefinesEverything &&); + ~DefinesEverything(); +}; + +class DeletesEverything { + DeletesEverything(const DeletesEverything &); + DeletesEverything &operator=(const DeletesEverything &); + DeletesEverything(DeletesEverything &&); + DeletesEverything &operator=(DeletesEverything &&); + ~DeletesEverything(); +}; + +// CHECK-MESSAGES: :[[@LINE+3]]:7: warning: class 'DefinesAllExceptMoves' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: class 'DefinesAllExceptMoves' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesAllExceptMoves' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesAllExceptMoves { + ~DefinesAllExceptMoves(); + DefinesAllExceptMoves(const DefinesAllExceptMoves &); + DefinesAllExceptMoves &operator=(const DefinesAllExceptMoves &); +}; + +// CHECK-MESSAGES: :[[@LINE+4]]:7: warning: class 'DefinesAllExceptMoveConstructor' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+3]]:7: warning: class 'DefinesAllExceptMoveConstructor' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: class 'DefinesAllExceptMoveConstructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesAllExceptMoveConstructor' defines a move assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesAllExceptMoveConstructor { + ~DefinesAllExceptMoveConstructor(); + DefinesAllExceptMoveConstructor(const DefinesAllExceptMoveConstructor &); + DefinesAllExceptMoveConstructor &operator=(const DefinesAllExceptMoveConstructor &); + DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &&); +}; + +// CHECK-MESSAGES: :[[@LINE+4]]:7: warning: class 'DefinesAllExceptMoveAssignment' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+3]]:7: warning: class 'DefinesAllExceptMoveAssignment' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: class 'DefinesAllExceptMoveAssignment' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesAllExceptMoveAssignment' defines a move constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesAllExceptMoveAssignment { + ~DefinesAllExceptMoveAssignment(); + DefinesAllExceptMoveAssignment(const DefinesAllExceptMoveAssignment &); + DefinesAllExceptMoveAssignment &operator=(const DefinesAllExceptMoveAssignment &); + DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &&); +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: class 'DefinesDestructorAndMoveConstructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesDestructorAndMoveConstructor' defines a move constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesDestructorAndMoveConstructor { + ~DefinesDestructorAndMoveConstructor(); + DefinesDestructorAndMoveConstructor(DefinesDestructorAndMoveConstructor &&); +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: class 'DefinesDestructorAndMoveAssignment' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesDestructorAndMoveAssignment' defines a move assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesDestructorAndMoveAssignment { + ~DefinesDestructorAndMoveAssignment(); + DefinesDestructorAndMoveAssignment &operator=(DefinesDestructorAndMoveAssignment &&); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyDestructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyDestructor { + ~DefinesOnlyDestructor(); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyConstructor' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyCopyConstructor { + DefinesOnlyCopyConstructor(const DefinesOnlyCopyConstructor &); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveConstructor' defines a move constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyMoveConstructor { + DefinesOnlyMoveConstructor(DefinesOnlyMoveConstructor &&); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyAssignment' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyCopyAssignment { + DefinesOnlyCopyAssignment &operator=(const DefinesOnlyCopyAssignment &); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveAssignment' defines a move assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyMoveAssignment { + DefinesOnlyMoveAssignment &operator=(DefinesOnlyMoveAssignment &&); +}; + +// check inheritance +class NoCopyBase { +public: + ~NoCopyBase(); + NoCopyBase(NoCopyBase &&); + NoCopyBase &operator=(NoCopyBase &&); + +private: + NoCopyBase(const NoCopyBase &) = delete; + NoCopyBase &operator=(const NoCopyBase &) = delete; +}; + +class NoMoveBase { +public: + ~NoMoveBase(); + NoMoveBase(const NoMoveBase &); + NoMoveBase &operator=(const NoMoveBase &); + +private: + NoMoveBase(NoMoveBase &&) = delete; + NoMoveBase &operator=(NoMoveBase &&) = delete; +}; + +class NoCopyNoMove : NoMoveBase, NoCopyBase { +}; + +class NoCopyViaBaseClass : NoCopyBase { + ~NoCopyViaBaseClass(); + NoCopyViaBaseClass(NoCopyViaBaseClass &&); + NoCopyViaBaseClass &operator=(NoCopyViaBaseClass &&); +}; + +class NoMoveViaBaseClass : NoMoveBase { + ~NoMoveViaBaseClass(); + NoMoveViaBaseClass(const NoMoveViaBaseClass &); + NoMoveViaBaseClass &operator=(const NoMoveViaBaseClass &); +}; + +class NoMoveNoCopyViaBaseClasses : NoCopyBase, NoMoveBase { + ~NoMoveNoCopyViaBaseClasses(); +}; + +class NoMoveNoCopyViaBaseClass : NoCopyNoMove { + ~NoMoveNoCopyViaBaseClass(); +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp @@ -0,0 +1,122 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-rule-of-five-and-zero %t + +class DefinesNothing { +}; + +class DefinesEverything { + DefinesEverything(const DefinesEverything &); + DefinesEverything &operator=(const DefinesEverything &); + DefinesEverything(DefinesEverything &&); + DefinesEverything &operator=(DefinesEverything &&); + ~DefinesEverything(); +}; + +class DeletesEverything { + DeletesEverything(const DeletesEverything &); + DeletesEverything &operator=(const DeletesEverything &); + DeletesEverything(DeletesEverything &&); + DeletesEverything &operator=(DeletesEverything &&); + ~DeletesEverything(); +}; + +// Safe cases +class DefinesAllExceptMoves { + ~DefinesAllExceptMoves(); + DefinesAllExceptMoves(DefinesAllExceptMoves &); + DefinesAllExceptMoves &operator=(DefinesAllExceptMoves &); +}; + +class DefinesAllExceptMoveConstructor { + ~DefinesAllExceptMoveConstructor(); + DefinesAllExceptMoveConstructor(DefinesAllExceptMoveConstructor &); + DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &); + DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &&); +}; + +class DefinesAllExceptMoveAssignment { + ~DefinesAllExceptMoveAssignment(); + DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &); + DefinesAllExceptMoveAssignment &operator=(DefinesAllExceptMoveAssignment &); + DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &&); +}; + +class DefinesDestructorAndMoveConstructor { + ~DefinesDestructorAndMoveConstructor(); + DefinesDestructorAndMoveConstructor(DefinesDestructorAndMoveConstructor &&); +}; + +class DefinesDestructorAndMoveAssignment { + ~DefinesDestructorAndMoveAssignment(); + DefinesDestructorAndMoveAssignment &operator=(DefinesDestructorAndMoveAssignment &&); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyDestructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyDestructor { + ~DefinesOnlyDestructor(); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyConstructor' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyCopyConstructor { + DefinesOnlyCopyConstructor(const DefinesOnlyCopyConstructor &); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveConstructor' defines a move constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyMoveConstructor { + DefinesOnlyMoveConstructor(DefinesOnlyMoveConstructor &&); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyAssignment' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyCopyAssignment { + DefinesOnlyCopyAssignment &operator=(const DefinesOnlyCopyAssignment &); +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveAssignment' defines a move assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero] +class DefinesOnlyMoveAssignment { + DefinesOnlyMoveAssignment &operator=(DefinesOnlyMoveAssignment &&); +}; + +// check inheritance +class NoCopyBase { +public: + ~NoCopyBase(); + NoCopyBase(NoCopyBase &&); + NoCopyBase &operator=(NoCopyBase &&); + +private: + NoCopyBase(const NoCopyBase &) = delete; + NoCopyBase &operator=(const NoCopyBase &) = delete; +}; + +class NoMoveBase { +public: + ~NoMoveBase(); + NoMoveBase(const NoMoveBase &); + NoMoveBase &operator=(const NoMoveBase &); + +private: + NoMoveBase(NoMoveBase &&) = delete; + NoMoveBase &operator=(NoMoveBase &&) = delete; +}; + +class NoCopyNoMove : NoMoveBase, NoCopyBase { +}; + +class NoCopyViaBaseClass : NoCopyBase { + ~NoCopyViaBaseClass(); + NoCopyViaBaseClass(NoCopyViaBaseClass &&); + NoCopyViaBaseClass &operator=(NoCopyViaBaseClass &&); +}; + +class NoMoveViaBaseClass : NoMoveBase { + ~NoMoveViaBaseClass(); + NoMoveViaBaseClass(const NoMoveViaBaseClass &); + NoMoveViaBaseClass &operator=(const NoMoveViaBaseClass &); +}; + +class NoMoveNoCopyViaBaseClasses : NoCopyBase, NoMoveBase { + ~NoMoveNoCopyViaBaseClasses(); +}; + +class NoMoveNoCopyViaBaseClass : NoCopyNoMove { + ~NoMoveNoCopyViaBaseClass(); +};