jbcoe removed rL LLVM as the repository for this revision.
jbcoe updated this revision to Diff 45554.
jbcoe added a comment.

Made requested changes.


http://reviews.llvm.org/D16376

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.cpp
  clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.h
  clang-tidy/modernize/UseDefaultCheck.cpp
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-user-defined-copy-without-assignment.rst
  test/clang-tidy/misc-user-defined-copy-without-assignment.cpp
  test/clang-tidy/modernize-use-default-delayed.cpp

Index: test/clang-tidy/modernize-use-default-delayed.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-default-delayed.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-tidy %s -checks=-*,modernize-use-default -- -std=c++11 -fdelayed-template-parsing -fexceptions | count 0
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+template <typename Ty>
+struct S {
+  S<Ty>& operator=(const S<Ty>&) { return *this; }
+};
Index: test/clang-tidy/misc-user-defined-copy-without-assignment.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-user-defined-copy-without-assignment.cpp
@@ -0,0 +1,38 @@
+// RUN: %check_clang_tidy %s misc-user-defined-copy-without-assignment %t
+class A {
+  A(const A &);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'A' defines a copy-constructor but not an assignment operator [misc-user-defined-copy-without-assignment]
+};
+
+// CHECK-FIXES: class A {
+// CHECK-FIXES-NEXT: A(const A &);
+// CHECK-FIXES-NEXT: A &operator=(const A &) = delete;
+// CHECK-FIXES-NEXT: //
+// CHECK-FIXES-NEXT: };
+
+class B {
+  B(const B &);
+  B &operator=(const B &);
+};
+
+class C {
+  C(const C &) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: class 'C' defines a copy-constructor but not an assignment operator [misc-user-defined-copy-without-assignment]
+};
+
+// CHECK-FIXES: class C {
+// CHECK-FIXES-NEXT: C(const C &) = default;
+// CHECK-FIXES-NEXT: C &operator=(const C &) = delete;
+// CHECK-FIXES-NEXT: //
+// CHECK-FIXES-NEXT: };
+
+class D {
+  D(const D &);
+  D &operator=(const D &) = default;
+};
+
+class E {
+  E(const E &);
+  E &operator=(const E &) = delete;
+};
+
Index: docs/clang-tidy/checks/misc-user-defined-copy-without-assignment.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/misc-user-defined-copy-without-assignment.rst
@@ -0,0 +1,36 @@
+.. title:: clang-tidy - misc-user-defined-copy-without-assignment
+
+misc-user-defined-copy-without-assignment
+=========================================
+
+Compilers will generate an assignment operator even if the user defines a copy
+constructor.  This behaviour is deprecated by the standard (C++ 14 draft
+standard 12.8.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 with a user-defined (including deleted)
+copy-constructor but no assignment operator.
+
+  .. code:: c++
+    class A {
+      A(const A&);
+    };
+
+Will be matched and fixed to delete the assignment operator:
+
+  .. code:: c++
+    class A {
+      A(const A&);
+      A& operator = (const A&) = delete;
+    };
+
+The fix is defensive. Incorrect compiler-generated assignement can cause
+unexpected behaviour. An explicitly deleted assignment operator will cause a
+compiler error if it is used.
+
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -65,6 +65,7 @@
    misc-unused-alias-decls
    misc-unused-parameters
    misc-unused-raii
+   misc-user-defined-copy-without-assignment
    misc-virtual-near-miss
    modernize-loop-convert
    modernize-make-unique
Index: clang-tidy/modernize/UseDefaultCheck.cpp
===================================================================
--- clang-tidy/modernize/UseDefaultCheck.cpp
+++ clang-tidy/modernize/UseDefaultCheck.cpp
@@ -272,6 +272,7 @@
   // that are not user-provided (automatically generated).
   if (SpecialFunctionDecl->isDeleted() ||
       SpecialFunctionDecl->isExplicitlyDefaulted() ||
+      SpecialFunctionDecl->isLateTemplateParsed() ||
       !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
     return;
 
Index: clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.h
@@ -0,0 +1,38 @@
+//===--- UserDefinedCopyWithoutAssignmentCheck.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_USER_DEFINED_COPY_WITHOUT_ASSIGNMENT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USER_DEFINED_COPY_WITHOUT_ASSIGNMENT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds user-defined copy-constructors but no assignement operator.
+///
+/// MSVC 2015 will generate an assignment operator even if the user defines a
+/// copy-constructor. This check finds classes with user-defined
+/// copy-constructors but no assignement operator and (defensively) defines the
+/// assignment operator to be `= delete`.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-user-defined-copy-without-assignment.html
+class UserDefinedCopyWithoutAssignmentCheck : public ClangTidyCheck { public:
+  UserDefinedCopyWithoutAssignmentCheck(StringRef Name, ClangTidyContext
+      *Context) : ClangTidyCheck(Name, Context) {} void
+    registerMatchers(ast_matchers::MatchFinder *Finder) override; void
+    check(const ast_matchers::MatchFinder::MatchResult &Result) override; };
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USER_DEFINED_COPY_WITHOUT_ASSIGNMENT_H
Index: clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/UserDefinedCopyWithoutAssignmentCheck.cpp
@@ -0,0 +1,62 @@
+//===--- UserDefinedCopyWithoutAssignmentCheck.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 "UserDefinedCopyWithoutAssignmentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void UserDefinedCopyWithoutAssignmentCheck::registerMatchers(
+    MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus11)
+    return;
+
+  Finder->addMatcher(
+      cxxRecordDecl(
+          isDefinition(), hasDescendant(cxxConstructorDecl(isCopyConstructor(),
+                                                           unless(isImplicit()))
+                                            .bind("cctor")),
+          unless(hasDescendant(cxxMethodDecl(isCopyAssignmentOperator())))),
+      this);
+}
+
+void UserDefinedCopyWithoutAssignmentCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXConstructorDecl>("cctor");
+
+  StringRef ClassName = MatchedDecl->getParent()->getName();
+
+  DiagnosticBuilder Diag =
+      diag(MatchedDecl->getLocation(), "class '%0' defines a copy-constructor "
+                                       "but not an assignment operator")
+      << ClassName;
+
+  SourceLocation CCtorEnd = Lexer::getLocForEndOfToken(
+      MatchedDecl->getLocEnd(), 0, *Result.SourceManager,
+      Result.Context->getLangOpts());
+  CCtorEnd = CCtorEnd.getLocWithOffset(1);
+  if (CCtorEnd.isInvalid())
+    return;
+
+  auto Insertion = (llvm::Twine("\n") + ClassName + " &operator=(const " +
+                    ClassName + " &) = delete;")
+                       .str();
+
+  Diag << FixItHint::CreateInsertion(CCtorEnd, Insertion);
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
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 "UserDefinedCopyWithoutAssignmentCheck.h"
 #include "VirtualNearMissCheck.h"
 
 namespace clang {
@@ -88,6 +89,8 @@
     CheckFactories.registerCheck<UnusedParametersCheck>(
         "misc-unused-parameters");
     CheckFactories.registerCheck<UnusedRAIICheck>("misc-unused-raii");
+    CheckFactories.registerCheck<UserDefinedCopyWithoutAssignmentCheck>(
+        "misc-user-defined-copy-without-assignment");
     CheckFactories.registerCheck<VirtualNearMissCheck>(
         "misc-virtual-near-miss");
   }
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
+  UserDefinedCopyWithoutAssignmentCheck.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