[clang-tidy] modernize-make-{smart_ptr} private ctor bugfix
authorPiotr Padlewski <piotr.padlewski@gmail.com>
Wed, 31 Aug 2016 00:06:55 +0000 (00:06 +0000)
committerPiotr Padlewski <piotr.padlewski@gmail.com>
Wed, 31 Aug 2016 00:06:55 +0000 (00:06 +0000)
Summary:
Bugfix for 27321. When the constructor of stored pointer
type is private then it is invalid to change it to
make_shared or make_unique.

Reviewers: alexfh, aaron.ballman, hokein

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D23343

llvm-svn: 280180

clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/test/clang-tidy/modernize-make-shared.cpp
clang-tools-extra/test/clang-tidy/modernize-make-unique.cpp

index 9b1ea3c..80dd103 100644 (file)
@@ -29,13 +29,19 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus11)
     return;
 
+  // Calling make_smart_ptr from within a member function of a type with a
+  // private or protected constructor would be ill-formed.
+  auto CanCallCtor = unless(has(ignoringImpCasts(cxxConstructExpr(
+      hasDeclaration(decl(unless(isPublic())))))));
+
   Finder->addMatcher(
       cxxBindTemporaryExpr(has(ignoringParenImpCasts(
           cxxConstructExpr(
               hasType(getSmartPointerTypeMatcher()), argumentCountIs(1),
               hasArgument(0,
                           cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
-                                         equalsBoundNode(PointerType))))))
+                                         equalsBoundNode(PointerType))))),
+                                     CanCallCtor)
                               .bind(NewExpression)))
               .bind(ConstructorCall)))),
       this);
index d218ac9..658a8fc 100644 (file)
@@ -97,6 +97,14 @@ Improvements to clang-tidy
   Flags function parameters of a pointer type that could be changed to point to
   a constant type instead.
 
+Fixed bugs:
+- `modernize-make-unique
+  <http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-unique.html>`_
+  and `modernize-make-shared
+  <http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-shared.html>`_
+  Calling ``make_{unique|shared}`` from within a member function of a type
+  with a private or protected constructor would be ill-formed.
+
 Improvements to include-fixer
 -----------------------------
 
index ee4c686..188ef5e 100644 (file)
@@ -100,6 +100,38 @@ void basic() {
   std::shared_ptr<int> Placement = std::shared_ptr<int>(new (PInt) int{3});
 }
 
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+  Private(int z) {}
+
+public:
+  Private() {}
+  void create() {
+    auto callsPublic = std::shared_ptr<Private>(new Private);
+    // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+    // CHECK-FIXES: auto callsPublic = std::make_shared<Private>();
+    auto ptr = std::shared_ptr<Private>(new Private(42));
+  }
+
+  virtual ~Private();
+};
+
+class Protected {
+protected:
+  Protected() {}
+
+public:
+  Protected(int, int) {}
+  void create() {
+    auto callsPublic = std::shared_ptr<Protected>(new Protected(1, 2));
+    // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+    // CHECK-FIXES: auto callsPublic = std::make_shared<Protected>(1, 2);
+    auto ptr = std::shared_ptr<Protected>(new Protected);
+  }
+};
+
 void initialization(int T, Base b) {
   // Test different kinds of initialization of the pointee.
 
index 8429554..3115734 100644 (file)
@@ -103,6 +103,38 @@ void basic() {
   std::unique_ptr<int> Placement = std::unique_ptr<int>(new (PInt) int{3});
 }
 
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+  Private(int z) {}
+
+public:
+  Private() {}
+  void create() {
+    auto callsPublic = std::unique_ptr<Private>(new Private);
+    // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+    // CHECK-FIXES: auto callsPublic = std::make_unique<Private>();
+    auto ptr = std::unique_ptr<Private>(new Private(42));
+  }
+
+  virtual ~Private();
+};
+
+class Protected {
+protected:
+  Protected() {}
+
+public:
+  Protected(int, int) {}
+  void create() {
+    auto callsPublic = std::unique_ptr<Protected>(new Protected(1, 2));
+    // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+    // CHECK-FIXES: auto callsPublic = std::make_unique<Protected>(1, 2);
+    auto ptr = std::unique_ptr<Protected>(new Protected);
+  }
+};
+
 void initialization(int T, Base b) {
   // Test different kinds of initialization of the pointee.