jbcoe retitled this revision from "clang-tidy check: rule-of-five" to 
"clang-tidy check: misc-deprecated-special-member-functions".
jbcoe updated the summary for this revision.
jbcoe set the repository for this revision to rL LLVM.
jbcoe updated this revision to Diff 47735.
jbcoe added a comment.

This check now deals only with deprecated special member function generation, 
not move constructors or move assignment operators. I have renamed it and 
modified documentation accordingly.

Code has been updated in line with review comments.


Repository:
  rL LLVM

http://reviews.llvm.org/D16376

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.cpp
  clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.h
  clang-tidy/misc/MiscTidyModule.cpp
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-deprecated-special-member-generation.rst
  test/clang-tidy/misc-deprecated-special-member-generation.cpp

Index: test/clang-tidy/misc-deprecated-special-member-generation.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-deprecated-special-member-generation.cpp
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy %s misc-deprecated-special-member-generation %t
+
+//
+// User defined copy constructors
+//
+class DeclaresCopyConstructor {
+  DeclaresCopyConstructor(const DeclaresCopyConstructor &);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DeclaresCopyConstructor' defines a copy constructor but not a copy assignment operator [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DeclaresCopyConstructor & operator=(const DeclaresCopyConstructor &) = delete;
+
+class DefinesDefaultedCopyConstructor {
+  DefinesDefaultedCopyConstructor(const DefinesDefaultedCopyConstructor &) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DefinesDefaultedCopyConstructor' defines a copy constructor but not a copy assignment operator [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DefinesDefaultedCopyConstructor & operator=(const DefinesDefaultedCopyConstructor &) = default;
+
+class DefinesDeletedCopyConstructor {
+  DefinesDeletedCopyConstructor(const DefinesDeletedCopyConstructor &) = delete;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DefinesDeletedCopyConstructor' defines a copy constructor but not a copy assignment operator [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DefinesDeletedCopyConstructor & operator=(const DefinesDeletedCopyConstructor &) = delete;
+
+
+//
+// User defined copy assignment
+//
+class DeclaresCopyAssignment {
+  DeclaresCopyAssignment & operator=(const DeclaresCopyAssignment &);
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: class 'DeclaresCopyAssignment' defines a copy assignment operator but not a copy constructor [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DeclaresCopyAssignment(const DeclaresCopyAssignment &) = delete;
+
+class DefinesDefaultedCopyAssignment {
+  DefinesDefaultedCopyAssignment & operator=(const DefinesDefaultedCopyAssignment &) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: class 'DefinesDefaultedCopyAssignment' defines a copy assignment operator but not a copy constructor [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DefinesDefaultedCopyAssignment(const DefinesDefaultedCopyAssignment &) = default;
+
+class DefinesDeletedCopyAssignment {
+  DefinesDeletedCopyAssignment & operator=(const DefinesDeletedCopyAssignment &) = delete;
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: class 'DefinesDeletedCopyAssignment' defines a copy assignment operator but not a copy constructor [misc-deprecated-special-member-generation]
+};
+
+// CHECK-FIXES: DefinesDeletedCopyAssignment(const DefinesDeletedCopyAssignment &) = delete;
+
+class DeclaresDestructor {
+  ~DeclaresDestructor();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DeclaresDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: DeclaresDestructor(const DeclaresDestructor &) = delete;
+// CHECK-FIXES: DeclaresDestructor & operator=(const DeclaresDestructor &) = delete;
+
+class DefinesDestructor {
+  ~DefinesDestructor() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DefinesDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: DefinesDestructor(const DefinesDestructor &) = delete;
+// CHECK-FIXES: DefinesDestructor & operator=(const DefinesDestructor &) = delete;
+
+
+class DefinesDefaultedDestructor {
+  ~DefinesDefaultedDestructor() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DefinesDefaultedDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: DefinesDefaultedDestructor(const DefinesDefaultedDestructor &) = delete;
+// CHECK-FIXES: DefinesDefaultedDestructor & operator=(const DefinesDefaultedDestructor &) = delete;
+
+
+class DefinesDeletedDestructor {
+  ~DefinesDeletedDestructor() = delete;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'DefinesDeletedDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: DefinesDeletedDestructor(const DefinesDeletedDestructor &) = delete;
+// CHECK-FIXES: DefinesDeletedDestructor & operator=(const DefinesDeletedDestructor &) = delete;
+
+template <class T>
+class ClassTemplateDeclaresDestructor {
+  ~ClassTemplateDeclaresDestructor();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'ClassTemplateDeclaresDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: ClassTemplateDeclaresDestructor(const ClassTemplateDeclaresDestructor &) = delete;
+// CHECK-FIXES: ClassTemplateDeclaresDestructor & operator=(const ClassTemplateDeclaresDestructor &) = delete;
+
+template <>
+class ClassTemplateDeclaresDestructor<int> {
+  ~ClassTemplateDeclaresDestructor();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'ClassTemplateDeclaresDestructor<int>' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: ClassTemplateDeclaresDestructor(const ClassTemplateDeclaresDestructor &) = delete;
+// CHECK-FIXES: ClassTemplateDeclaresDestructor & operator=(const ClassTemplateDeclaresDestructor &) = delete;
+
+#define DEFAULTED_DESTRUCTOR(X) ~X() = default
+
+class MacroDefaultsDestructor {
+  DEFAULTED_DESTRUCTOR(MacroDefaultsDestructor);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'MacroDefaultsDestructor' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+};
+// CHECK-FIXES: MacroDefaultsDestructor(const MacroDefaultsDestructor &) = delete;
+// CHECK-FIXES: MacroDefaultsDestructor & operator=(const MacroDefaultsDestructor &) = delete;
+
+#define VIRTUAL_BASE_CLASS(X) class X { virtual ~X() = default; }
+
+VIRTUAL_BASE_CLASS(VirtualBase);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: class 'VirtualBase' defines a destructor but not a copy constructor or copy assignment operator [misc-deprecated-special-member-generation]
+
+class DeclaresAllThree {
+  ~DeclaresAllThree();
+  DeclaresAllThree(const DeclaresAllThree&);
+  DeclaresAllThree & operator=(const DeclaresAllThree&);
+};
+
+class DeclaresCopyAndAssignment {
+  DeclaresCopyAndAssignment(const DeclaresCopyAndAssignment&);
+  DeclaresCopyAndAssignment & operator=(const DeclaresCopyAndAssignment&);
+};
+
Index: docs/clang-tidy/checks/misc-deprecated-special-member-generation.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/misc-deprecated-special-member-generation.rst
@@ -0,0 +1,40 @@
+.. title:: clang-tidy - misc-deprecated-special-member-generation
+
+misc-deprecated-special-member-generation
+=========================================
+
+Modern compilers generate copy constructors and copy assignment operators in
+cases where generation of special functions is deprecated by the standard.
+
+C++14 standard [class.copy] paragraph 7:
+
+"If the class definition does not explicitly declare a copy constructor, one is
+declared implicitly. If the class definition declares a move constructor or
+move assignment operator, the implicitly declared copy constructor is defined
+as deleted; otherwise, it is defined as defaulted (8.4). The latter case is
+deprecated if the class has a user-declared copy assignment operator or a
+user-declared destructor."
+
+C++14 standard [class.copy] paragraph 18:
+
+"If the class definition does not explicitly declare a copy assignment
+operator, one is declared implicitly. If the class definition declares a move
+constructor or move assignment operator, the implicitly declared copy
+assignment operator is defined as deleted; otherwise, it is defined as
+defaulted (8.4). The latter case is deprecated if the class has a user-declared
+copy constructor or a user-declared destructor."
+
+This check finds classes where deprecated compiler-generation of special member
+functions may generate a copy constructor or copy assignment operator.
+
+If the destructor is declared, missing copy constructors or copy assignment
+operators are declared '=delete'.
+
+If a copy constructor or assignment operator is declared '=default' and no
+destructor is declared, the missing copy constructor or assignment operator is
+declared '=default'.
+
+Otherwise, if a copy constructor or assignment operator is declared and no
+destructor is declared, the missing copy constructor or assignment operator is
+declared '=delete'.
+
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -46,6 +46,7 @@
    misc-argument-comment
    misc-assert-side-effect
    misc-assign-operator-signature
+   misc-deprecated-special-member-generation
    misc-bool-pointer-implicit-conversion
    misc-definitions-in-headers
    misc-inaccurate-erase
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -34,6 +34,7 @@
 #include "UnusedAliasDeclsCheck.h"
 #include "UnusedParametersCheck.h"
 #include "UnusedRAIICheck.h"
+#include "DeprecatedSpecialMemberGenerationCheck.h"
 #include "VirtualNearMissCheck.h"
 
 namespace clang {
@@ -88,6 +89,8 @@
     CheckFactories.registerCheck<UnusedParametersCheck>(
         "misc-unused-parameters");
     CheckFactories.registerCheck<UnusedRAIICheck>("misc-unused-raii");
+    CheckFactories.registerCheck<DeprecatedSpecialMemberGenerationCheck>(
+        "misc-deprecated-special-member-generation");
     CheckFactories.registerCheck<VirtualNearMissCheck>(
         "misc-virtual-near-miss");
   }
Index: clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.h
@@ -0,0 +1,54 @@
+//===--- DeprecatedSpecialMemberGenerationCheck.h - clang-tidy----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEPRECATED_SPECIAL_MEMBER_GENERATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEPRECATED_SPECIAL_MEMBER_GENERATION_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds classes where deprecated compiler-generation of special member
+/// functions will generate a copy constructor or copy assignment operator.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-deprecated-special-member-generation.html
+class DeprecatedSpecialMemberGenerationCheck : public ClangTidyCheck {
+public:
+  DeprecatedSpecialMemberGenerationCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  enum class SpecialFunctionKind {
+    CopyConstructor,
+    CopyAssignment,
+    Destructor
+  };
+
+  static std::string
+  buildFixIt(const CXXMethodDecl &MatchedDecl, StringRef ClassName,
+             DeprecatedSpecialMemberGenerationCheck::SpecialFunctionKind S);
+  static StringRef getDiagnosticFormat(
+      DeprecatedSpecialMemberGenerationCheck::SpecialFunctionKind S);
+  void
+  addDiagnosticAndFixIt(const ast_matchers::MatchFinder::MatchResult &Result,
+                        const CXXMethodDecl &MatchedDecl,
+                        SpecialFunctionKind S);
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEPRECATED_SPECIAL_MEMBER_GENERATION_H
Index: clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/DeprecatedSpecialMemberGenerationCheck.cpp
@@ -0,0 +1,125 @@
+//===--- DeprecatedSpecialMemberGenerationCheck.cpp - clang-tidy-----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeprecatedSpecialMemberGenerationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void DeprecatedSpecialMemberGenerationCheck::registerMatchers(
+    MatchFinder *Finder) {
+
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  Finder->addMatcher(
+      cxxRecordDecl(isDefinition(),
+                    has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
+                    unless(anyOf(has(cxxConstructorDecl(isCopyConstructor(),
+                                                        unless(isImplicit()))),
+                                 has(cxxMethodDecl(isCopyAssignmentOperator(),
+                                                   unless(isImplicit())))))),
+      this);
+
+  Finder->addMatcher(
+      cxxRecordDecl(isDefinition(), has(cxxConstructorDecl(isCopyConstructor(),
+                                                           unless(isImplicit()))
+                                            .bind("copy-ctor")),
+                    unless(has(cxxMethodDecl(isCopyAssignmentOperator())))),
+      this);
+
+  Finder->addMatcher(
+      cxxRecordDecl(
+          isDefinition(),
+          has(cxxMethodDecl(isCopyAssignmentOperator(), unless(isImplicit()))
+                  .bind("copy assignment")),
+          unless(has(cxxConstructorDecl(isCopyConstructor())))),
+      this);
+}
+
+StringRef DeprecatedSpecialMemberGenerationCheck::getDiagnosticFormat(
+    DeprecatedSpecialMemberGenerationCheck::SpecialFunctionKind S) {
+  switch (S) {
+  case SpecialFunctionKind::Destructor:
+    return "class %0 defines a destructor but not a copy constructor or copy "
+           "assignment operator";
+  case SpecialFunctionKind::CopyConstructor:
+    return "class %0 defines a copy constructor but not a copy assignment "
+           "operator";
+  case SpecialFunctionKind::CopyAssignment:
+    return "class %0 defines a copy assignment operator but not a "
+           "copy constructor";
+  }
+};
+
+std::string DeprecatedSpecialMemberGenerationCheck::buildFixIt(
+    const CXXMethodDecl &MatchedDecl, StringRef ClassName,
+    DeprecatedSpecialMemberGenerationCheck::SpecialFunctionKind S) {
+
+  StringRef DeleteOrDefault =
+      (!dyn_cast<CXXDestructorDecl>(&MatchedDecl) && MatchedDecl.isDefaulted())
+          ? "default"
+          : "delete";
+  switch (S) {
+  case SpecialFunctionKind::Destructor:
+    return (llvm::Twine("\n") + ClassName + "(const " + ClassName + " &) = " +
+            DeleteOrDefault + ";\n" + ClassName + " & operator=(const " +
+            ClassName + " &) = " + DeleteOrDefault + ";\n")
+        .str();
+  case SpecialFunctionKind::CopyConstructor:
+    return (llvm::Twine("\n") + ClassName + " & operator=(const " + ClassName +
+            " &) = " + DeleteOrDefault + ";\n")
+        .str();
+  case SpecialFunctionKind::CopyAssignment:
+    return (llvm::Twine("") + ClassName + "(const " + ClassName + " &) = " +
+            DeleteOrDefault + ";\n")
+        .str();
+  }
+};
+
+void DeprecatedSpecialMemberGenerationCheck::addDiagnosticAndFixIt(
+    const MatchFinder::MatchResult &Result, const CXXMethodDecl &MatchedDecl,
+    SpecialFunctionKind S) {
+  const CXXRecordDecl *Class = MatchedDecl.getParent();
+
+  DiagnosticBuilder Diag =
+      diag(MatchedDecl.getLocation(), getDiagnosticFormat(S)) << Class;
+
+  if (!getLangOpts().CPlusPlus11)
+    return;
+
+  std::string FixIt = buildFixIt(MatchedDecl, Class->getName(), S);
+
+  Diag << FixItHint::CreateInsertion(MatchedDecl.getLocStart(), FixIt);
+}
+
+void DeprecatedSpecialMemberGenerationCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  if (const auto *MatchedDecl =
+          Result.Nodes.getNodeAs<CXXDestructorDecl>("dtor"))
+    addDiagnosticAndFixIt(Result, *MatchedDecl,
+                          SpecialFunctionKind::Destructor);
+  else if (const auto *MatchedDecl =
+               Result.Nodes.getNodeAs<CXXConstructorDecl>("copy-ctor"))
+    addDiagnosticAndFixIt(Result, *MatchedDecl,
+                          SpecialFunctionKind::CopyConstructor);
+  else if (const auto *MatchedDecl =
+               Result.Nodes.getNodeAs<CXXMethodDecl>("copy assignment"))
+    addDiagnosticAndFixIt(Result, *MatchedDecl,
+                          SpecialFunctionKind::CopyAssignment);
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -26,6 +26,7 @@
   UnusedParametersCheck.cpp
   UnusedRAIICheck.cpp
   UniqueptrResetReleaseCheck.cpp
+  DeprecatedSpecialMemberGenerationCheck.cpp
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to