vrnithinkumar created this revision.
vrnithinkumar added reviewers: aaron.ballman, alexfh, jbcoe, dblaikie, rsmith.
Herald added subscribers: cfe-commits, kbarton, mgorny, nemanjai.
Herald added a project: clang.

New check to check if a class defines all special members of none of them. This 
also known as rule of five and zero.
Specified in CppCoreGuidelines: 
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all.
In summary the check will

- Checks class defines all special members of none of them.
- It also see if the base class deletes the special members or not.
- Has two modes with the flag strict-check.
- Strict mode will check all or nothing strictly.

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.
For non strict mode we will consider these combinations as safe.

I found one review https://reviews.llvm.org/D16376 already related to this. 
I modified my changes based on this. But I could not find out why this got 
abandoned.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80490

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp
===================================================================
--- /dev/null
+++ 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();
+};
Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp
===================================================================
--- /dev/null
+++ 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();
+};
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -148,6 +148,7 @@
    `cppcoreguidelines-pro-type-static-cast-downcast <cppcoreguidelines-pro-type-static-cast-downcast.html>`_, "Yes"
    `cppcoreguidelines-pro-type-union-access <cppcoreguidelines-pro-type-union-access.html>`_,
    `cppcoreguidelines-pro-type-vararg <cppcoreguidelines-pro-type-vararg.html>`_,
+   `cppcoreguidelines-rule-of-five-and-zero <cppcoreguidelines-rule-of-five-and-zero.html>`_, "Yes"
    `cppcoreguidelines-slicing <cppcoreguidelines-slicing.html>`_,
    `cppcoreguidelines-special-member-functions <cppcoreguidelines-special-member-functions.html>`_,
    `darwin-avoid-spinlock <darwin-avoid-spinlock.html>`_,
@@ -421,4 +422,3 @@
    `hicpp-use-override <hicpp-use-override.html>`_, `modernize-use-override <modernize-use-override.html>`_, "Yes"
    `hicpp-vararg <hicpp-vararg.html>`_, `cppcoreguidelines-pro-type-vararg <cppcoreguidelines-pro-type-vararg.html>`_,
    `llvm-qualified-auto <llvm-qualified-auto.html>`_, `readability-qualified-auto <readability-qualified-auto.html>`_, "Yes"
-
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst
===================================================================
--- /dev/null
+++ 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
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ 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
+  <clang-tidy/checks/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
   <clang-tidy/checks/llvmlibc-callee-namespace>` check.
 
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h
===================================================================
--- /dev/null
+++ 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_RULEOFFIVEANDZEROCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_RULEOFFIVEANDZEROCHECK_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
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp
===================================================================
--- /dev/null
+++ 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<CXXRecordDecl>(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
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ 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<ProTypeVarargCheck>(
         "cppcoreguidelines-pro-type-vararg");
+    CheckFactories.registerCheck<RuleOfFiveAndZeroCheck>(
+        "cppcoreguidelines-rule-of-five-and-zero");
     CheckFactories.registerCheck<SpecialMemberFunctionsCheck>(
         "cppcoreguidelines-special-member-functions");
     CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing");
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -23,6 +23,7 @@
   ProTypeStaticCastDowncastCheck.cpp
   ProTypeUnionAccessCheck.cpp
   ProTypeVarargCheck.cpp
+  RuleOfFiveAndZeroCheck.cpp
   SlicingCheck.cpp
   SpecialMemberFunctionsCheck.cpp
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to