Index: clang-tidy/modernize/MakeSmartPtrCheck.h =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.h +++ clang-tidy/modernize/MakeSmartPtrCheck.h @@ -57,7 +57,8 @@ void checkReset(SourceManager &SM, const CXXMemberCallExpr *Member, const CXXNewExpr *New); - void replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, + /// Returns true when the fixes for replacing CXXNewExpr are generated. + bool replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, SourceManager &SM); void insertHeader(DiagnosticBuilder &Diag, FileID FD); }; Index: clang-tidy/modernize/MakeSmartPtrCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -147,6 +147,10 @@ return; } + if (!replaceNew(Diag, New, SM)) { + return; + } + // Find the location of the template's left angle. size_t LAngle = ExprStr.find("<"); SourceLocation ConstructCallEnd; @@ -179,7 +183,6 @@ ")"); } - replaceNew(Diag, New, SM); insertHeader(Diag, SM.getFileID(ConstructCallStart)); } @@ -214,6 +217,10 @@ return; } + if (!replaceNew(Diag, New, SM)) { + return; + } + Diag << FixItHint::CreateReplacement( CharSourceRange::getCharRange(OperatorLoc, ExprEnd), (llvm::Twine(" = ") + MakeSmartPtrFunctionName + "<" + @@ -223,11 +230,10 @@ if (Expr->isArrow()) Diag << FixItHint::CreateInsertion(ExprStart, "*"); - replaceNew(Diag, New, SM); insertHeader(Diag, SM.getFileID(OperatorLoc)); } -void MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag, +bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, SourceManager& SM) { SourceLocation NewStart = New->getSourceRange().getBegin(); @@ -254,6 +260,22 @@ break; } case CXXNewExpr::CallInit: { + // FIXME: Add fixes for constructors with initializer-list parameters. + // Unlike ordinal cases, braced list can not be deduced in + // std::make_smart_ptr, we need to specify the type explicitly in the fixes: + // struct S { S(std::initializer_list, int); }; + // smart_ptr(new S({1, 2, 3}, 1)); // C++98 call-style initialization + // smart_ptr(new S({}, 1)); + // 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); + if (const auto *CE = New->getConstructExpr()) { + for (const auto *Arg : CE->arguments()) { + if (llvm::isa(Arg)) { + return false; + } + } + } if (ArraySizeExpr.empty()) { SourceRange InitRange = New->getDirectInitRange(); Diag << FixItHint::CreateRemoval( @@ -274,19 +296,16 @@ SourceRange InitRange; if (const auto *NewConstruct = New->getConstructExpr()) { if (NewConstruct->isStdInitListInitialization()) { - // Direct Initialization with the initializer-list constructor. - // struct S { S(std::initializer_list); }; - // smart_ptr(new S{1, 2, 3}); - // smart_ptr(new S{}); // use initializer-list consturctor - // The brace has to be kept, so this has to be replaced with: - // std::make_smart_ptr({1, 2, 3}); - // std::make_smart_ptr({}); - unsigned NumArgs = NewConstruct->getNumArgs(); - if (NumArgs == 0) { - return; - } - InitRange = SourceRange(NewConstruct->getArg(0)->getLocStart(), - NewConstruct->getArg(NumArgs - 1)->getLocEnd()); + // 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); }; + // smart_ptr(new S{1, 2, 3}); // C++11 direct list-initialization + // smart_ptr(new S{}); // use initializer-list consturctor + // 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({})); + return false; } else { // Direct initialization with ordinary constructors. // struct S { S(int x); S(); }; @@ -316,6 +335,7 @@ break; } } + return true; } void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) { Index: test/clang-tidy/modernize-make-unique.cpp =================================================================== --- test/clang-tidy/modernize-make-unique.cpp +++ test/clang-tidy/modernize-make-unique.cpp @@ -246,52 +246,75 @@ std::unique_ptr PE1 = std::unique_ptr(new E{}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead // CHECK-FIXES: std::unique_ptr PE1 = std::make_unique(); + PE1.reset(new E{}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PE1 = std::make_unique(); + + //============================================================================ + // NOTE: For initlializer-list constructors, the check only gives warnings, + // and no fixes are generated. + //============================================================================ // Initialization with the initializer-list constructor. std::unique_ptr PE2 = std::unique_ptr(new E{1, 2}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PE2 = std::make_unique({1, 2}); + // CHECK-FIXES: std::unique_ptr PE2 = std::unique_ptr(new E{1, 2}); + PE2.reset(new E{1, 2}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PE2.reset(new E{1, 2}); // Initialization with default constructor. std::unique_ptr PF1 = std::unique_ptr(new F()); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead // CHECK-FIXES: std::unique_ptr PF1 = std::make_unique(); + PF1.reset(new F()); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PF1 = std::make_unique(); // Initialization with default constructor. std::unique_ptr PF2 = std::unique_ptr(new F{}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead // CHECK-FIXES: std::unique_ptr PF2 = std::make_unique(); + PF2.reset(new F()); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PF2 = std::make_unique(); // Initialization with the initializer-list constructor. std::unique_ptr PF3 = std::unique_ptr(new F{1}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PF3 = std::make_unique({1}); + // CHECK-FIXES: std::unique_ptr PF3 = std::unique_ptr(new F{1}); + PF3.reset(new F{1}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PF3.reset(new F{1}); // Initialization with the initializer-list constructor. std::unique_ptr PF4 = std::unique_ptr(new F{1, 2}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PF4 = std::make_unique({1, 2}); + // CHECK-FIXES: std::unique_ptr PF4 = std::unique_ptr(new F{1, 2}); // Initialization with the initializer-list constructor. std::unique_ptr PF5 = std::unique_ptr(new F({1, 2})); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PF5 = std::make_unique({1, 2}); + // CHECK-FIXES: std::unique_ptr PF5 = std::unique_ptr(new F({1, 2})); // Initialization with the initializer-list constructor as the default // constructor is not present. std::unique_ptr PG1 = std::unique_ptr(new G{}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PG1 = std::make_unique({}); + // CHECK-FIXES: std::unique_ptr PG1 = std::unique_ptr(new G{}); + PG1.reset(new G{}); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead + // CHECK-FIXES: PG1.reset(new G{}); // Initialization with the initializer-list constructor. std::unique_ptr PG2 = std::unique_ptr(new G{1}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PG2 = std::make_unique({1}); + // CHECK-FIXES: std::unique_ptr PG2 = std::unique_ptr(new G{1}); // Initialization with the initializer-list constructor. std::unique_ptr PG3 = std::unique_ptr(new G{1, 2}); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead - // CHECK-FIXES: std::unique_ptr PG3 = std::make_unique({1, 2}); + // CHECK-FIXES: std::unique_ptr PG3 = std::unique_ptr(new G{1, 2}); std::unique_ptr FF = std::unique_ptr(new Foo()); // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: