Index: clang-tidy/modernize/MakeSmartPtrCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -280,7 +280,29 @@ SM, getLangOpts()) .str(); } - + // Returns true if the given constructor expression has any braced-init-list + // argument, e.g. + // Foo({1, 2}, 1) => true + // Foo(Bar{1, 2}) => true + // Foo(1) => false + auto HasListIntializedArgument = [](const CXXConstructExpr *CE) { + for (const auto *Arg : CE->arguments()) { + if (isa(Arg) || isa(Arg)) + return true; + // Check whether we implicitly construct a class from a + // std::initializer_list. + auto IsStdInitListInitConstructExpr = [](const Expr *E) { + assert(E); + if (const auto *ImplicitCE = dyn_cast(E)) { + if (ImplicitCE->isStdInitListInitialization()) + return true; + } + return false; + }; + return IsStdInitListInitConstructExpr(Arg->IgnoreImplicit()); + } + return false; + }; switch (New->getInitializationStyle()) { case CXXNewExpr::NoInit: { if (ArraySizeExpr.empty()) { @@ -300,32 +322,20 @@ // std::make_smart_ptr, we need to specify the type explicitly in the fixes: // struct S { S(std::initializer_list, int); }; // struct S2 { S2(std::vector); }; + // struct S3 { S3(S2, int); }; // smart_ptr(new S({1, 2, 3}, 1)); // C++98 call-style initialization // smart_ptr(new S({}, 1)); // smart_ptr(new S2({1})); // implicit conversion: // // std::initializer_list => std::vector + // smart_ptr(new S3({1, 2}, 3)); // The above samples have to be replaced with: // std::make_smart_ptr(std::initializer_list({1, 2, 3}), 1); // std::make_smart_ptr(std::initializer_list({}), 1); // std::make_smart_ptr(std::vector({1})); + // std::make_smart_ptr(S2{1, 2}, 3); if (const auto *CE = New->getConstructExpr()) { - for (const auto *Arg : CE->arguments()) { - if (isa(Arg)) { - return false; - } - // Check whether we construct a class from a std::initializer_list. - // If so, we won't generate the fixes. - auto IsStdInitListInitConstructExpr = [](const Expr* E) { - assert(E); - if (const auto *ImplicitCE = dyn_cast(E)) { - if (ImplicitCE->isStdInitListInitialization()) - return true; - } - return false; - }; - if (IsStdInitListInitConstructExpr(Arg->IgnoreImplicit())) - return false; - } + if (HasListIntializedArgument(CE)) + return false; } if (ArraySizeExpr.empty()) { SourceRange InitRange = New->getDirectInitRange(); @@ -346,16 +356,20 @@ // Range of the substring that we do not want to remove. SourceRange InitRange; if (const auto *NewConstruct = New->getConstructExpr()) { - if (NewConstruct->isStdInitListInitialization()) { + if (NewConstruct->isStdInitListInitialization() || + HasListIntializedArgument(NewConstruct)) { // FIXME: Add fixes for direct initialization with the initializer-list // constructor. Similar to the above CallInit case, the type has to be // specified explicitly in the fixes. // struct S { S(std::initializer_list); }; + // struct S2 { S2(S, int); }; // smart_ptr(new S{1, 2, 3}); // C++11 direct list-initialization // smart_ptr(new S{}); // use initializer-list consturctor + // smart_ptr()new S2{ {1,2}, 3 }; // have a list-initialized arg // The above cases have to be replaced with: // std::make_smart_ptr(std::initializer_list({1, 2, 3})); // std::make_smart_ptr(std::initializer_list({})); + // std::make_smart_ptr(S{1, 2}, 3); return false; } else { // Direct initialization with ordinary constructors. Index: test/clang-tidy/modernize-make-unique.cpp =================================================================== --- test/clang-tidy/modernize-make-unique.cpp +++ test/clang-tidy/modernize-make-unique.cpp @@ -58,6 +58,10 @@ I(G); }; +struct J { + J(E e, int); +}; + namespace { class Foo {}; } // namespace @@ -372,6 +376,34 @@ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead // CHECK-FIXES: PI1 = std::make_unique(G({1, 2, 3})); + std::unique_ptr PJ1 = std::unique_ptr(new J({1, 2}, 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead + // CHECK-FIXES: std::unique_ptr PJ1 = std::unique_ptr(new J({1, 2}, 1)); + PJ1.reset(new J({1, 2}, 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PJ1.reset(new J({1, 2}, 1)); + + std::unique_ptr PJ2 = std::unique_ptr(new J(E{1, 2}, 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead + // CHECK-FIXES: std::unique_ptr PJ2 = std::make_unique(E{1, 2}, 1); + PJ2.reset(new J(E{1, 2}, 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PJ2 = std::make_unique(E{1, 2}, 1); + + std::unique_ptr PJ3 = std::unique_ptr(new J{ {1, 2}, 1 }); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead + // CHECK-FIXES: std::unique_ptr PJ3 = std::unique_ptr(new J{ {1, 2}, 1 }); + PJ3.reset(new J{ {1, 2}, 1 }); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PJ3.reset(new J{ {1, 2}, 1 }); + + std::unique_ptr PJ4 = std::unique_ptr(new J{E{1, 2}, 1}); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead + // CHECK-FIXES: std::unique_ptr PJ4 = std::make_unique(E{1, 2}, 1); + PJ4.reset(new J{E{1, 2}, 1}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PJ4 = std::make_unique(E{1, 2}, 1); + std::unique_ptr FF = std::unique_ptr(new Foo()); // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: // CHECK-FIXES: std::unique_ptr FF = std::make_unique();