diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -12,8 +12,10 @@ LoopConvertCheck.cpp LoopConvertUtils.cpp MakeSharedCheck.cpp + MakeSharedForOverwriteCheck.cpp MakeSmartPtrCheck.cpp MakeUniqueCheck.cpp + MakeUniqueForOverwriteCheck.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp RawStringLiteralCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp @@ -18,7 +18,7 @@ namespace modernize { MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_shared") {} + : MakeSmartPtrCheck(Name, Context, "std::make_shared", true) {} MakeSharedCheck::SmartPtrTypeMatcher MakeSharedCheck::getSmartPointerTypeMatcher() const { diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.h @@ -0,0 +1,44 @@ +//===--- MakeSharedForOverwriteCheck.h - clang-tidy -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKESHAREDFOROVERWRITECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKESHAREDFOROVERWRITECHECK_H + +#include "MakeSmartPtrCheck.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Replace the pattern: +/// \code +/// std::shared_ptr(new type) +/// \endcode +/// +/// With the C++20 version: +/// \code +/// std::make_shared_for_overwrite() +/// \endcode +class MakeSharedForOverwriteCheck : public MakeSmartPtrCheck { +public: + MakeSharedForOverwriteCheck(StringRef Name, ClangTidyContext *Context); + +protected: + SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override; + +private: + const bool RequireCPlusPlus20; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKESHAREDFOROVERWRITECHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.cpp copy from clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp copy to clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedForOverwriteCheck.cpp @@ -1,4 +1,4 @@ -//===--- MakeSharedCheck.cpp - clang-tidy----------------------------------===// +//===--- MakeSharedForOverwriteCheck.cpp - clang-tidy ---------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "MakeSharedCheck.h" - -// FixItHint - Hint to check documentation script to mark this check as -// providing a FixIt. +#include "MakeSharedForOverwriteCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -17,11 +16,13 @@ namespace tidy { namespace modernize { -MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_shared") {} +MakeSharedForOverwriteCheck::MakeSharedForOverwriteCheck( + StringRef Name, ClangTidyContext *Context) + : MakeSmartPtrCheck(Name, Context, "std::make_shared_for_overwrite", false), + RequireCPlusPlus20(Options.get("MakeSmartPtrFunction", "").empty()) {} -MakeSharedCheck::SmartPtrTypeMatcher -MakeSharedCheck::getSmartPointerTypeMatcher() const { +MakeSharedForOverwriteCheck::SmartPtrTypeMatcher +MakeSharedForOverwriteCheck::getSmartPointerTypeMatcher() const { return qualType(hasUnqualifiedDesugaredType( recordType(hasDeclaration(classTemplateSpecializationDecl( hasName("::std::shared_ptr"), templateArgumentCountIs(1), @@ -29,6 +30,11 @@ qualType().bind(PointerType))))))))); } +bool MakeSharedForOverwriteCheck::isLanguageVersionSupported( + const LangOptions &LangOpts) const { + return RequireCPlusPlus20 ? LangOpts.CPlusPlus20 : LangOpts.CPlusPlus11; +} + } // namespace modernize } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h --- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h @@ -24,7 +24,7 @@ class MakeSmartPtrCheck : public ClangTidyCheck { public: MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, - StringRef MakeSmartPtrFunctionName); + StringRef MakeSmartPtrFunctionName, bool ValueInitializes); void registerMatchers(ast_matchers::MatchFinder *Finder) final; void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override; @@ -51,6 +51,7 @@ const std::string MakeSmartPtrFunctionName; const bool IgnoreMacros; const bool IgnoreDefaultInitialization; + const bool ValueInitializes; void checkConstruct(SourceManager &SM, ASTContext *Ctx, const CXXConstructExpr *Construct, const QualType *Type, diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -42,7 +42,8 @@ const char MakeSmartPtrCheck::PointerType[] = "pointerType"; MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, - StringRef MakeSmartPtrFunctionName) + StringRef MakeSmartPtrFunctionName, + bool ValueInitializes) : ClangTidyCheck(Name, Context), Inserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM)), @@ -52,7 +53,9 @@ Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)), IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)), IgnoreDefaultInitialization( - Options.get("IgnoreDefaultInitialization", true)) {} + !ValueInitializes || + Options.get("IgnoreDefaultInitialization", true)), + ValueInitializes(ValueInitializes) {} void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IncludeStyle", Inserter.getStyle()); @@ -136,7 +139,7 @@ bool Initializes = New->hasInitializer() || !utils::type_traits::isTriviallyDefaultConstructible( New->getAllocatedType(), *Result.Context); - if (!Initializes && IgnoreDefaultInitialization) + if (Initializes != ValueInitializes && IgnoreDefaultInitialization) return; if (Construct) checkConstruct(SM, Result.Context, Construct, Type, New); diff --git a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp @@ -16,7 +16,7 @@ MakeUniqueCheck::MakeUniqueCheck(StringRef Name, clang::tidy::ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_unique"), + : MakeSmartPtrCheck(Name, Context, "std::make_unique", true), RequireCPlusPlus14(Options.get("MakeSmartPtrFunction", "").empty()) {} MakeUniqueCheck::SmartPtrTypeMatcher diff --git a/clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.h @@ -0,0 +1,44 @@ +//===--- MakeUniqueForOverwriteCheck.h - clang-tidy -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKEUNIQUEFOROVERWRITECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKEUNIQUEFOROVERWRITECHECK_H + +#include "MakeSmartPtrCheck.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Replace the pattern: +/// \code +/// std::unique_ptr(new type) +/// \endcode +/// +/// With the C++20 version: +/// \code +/// std::make_unique_for_overwrite() +/// \endcode +class MakeUniqueForOverwriteCheck : public MakeSmartPtrCheck { +public: + MakeUniqueForOverwriteCheck(StringRef Name, ClangTidyContext *Context); + +protected: + SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override; + +private: + const bool RequireCPlusPlus20; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKEUNIQUEFOROVERWRITECHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.cpp copy from clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp copy to clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeUniqueForOverwriteCheck.cpp @@ -1,4 +1,4 @@ -//===--- MakeUniqueCheck.cpp - clang-tidy----------------------------------===// +//===--- MakeUniqueForOverwriteCheck.cpp - clang-tidy ---------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "MakeUniqueCheck.h" +#include "MakeUniqueForOverwriteCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -14,13 +16,13 @@ namespace tidy { namespace modernize { -MakeUniqueCheck::MakeUniqueCheck(StringRef Name, - clang::tidy::ClangTidyContext *Context) - : MakeSmartPtrCheck(Name, Context, "std::make_unique"), - RequireCPlusPlus14(Options.get("MakeSmartPtrFunction", "").empty()) {} +MakeUniqueForOverwriteCheck::MakeUniqueForOverwriteCheck( + StringRef Name, clang::tidy::ClangTidyContext *Context) + : MakeSmartPtrCheck(Name, Context, "std::make_unique_for_overwrite", false), + RequireCPlusPlus20(Options.get("MakeSmartPtrFunction", "").empty()) {} -MakeUniqueCheck::SmartPtrTypeMatcher -MakeUniqueCheck::getSmartPointerTypeMatcher() const { +MakeUniqueForOverwriteCheck::SmartPtrTypeMatcher +MakeUniqueForOverwriteCheck::getSmartPointerTypeMatcher() const { return qualType(hasUnqualifiedDesugaredType( recordType(hasDeclaration(classTemplateSpecializationDecl( hasName("::std::unique_ptr"), templateArgumentCountIs(2), @@ -36,9 +38,9 @@ equalsBoundNode(PointerType)))))))))))))))); } -bool MakeUniqueCheck::isLanguageVersionSupported( +bool MakeUniqueForOverwriteCheck::isLanguageVersionSupported( const LangOptions &LangOpts) const { - return RequireCPlusPlus14 ? LangOpts.CPlusPlus14 : LangOpts.CPlusPlus11; + return RequireCPlusPlus20 ? LangOpts.CPlusPlus20 : LangOpts.CPlusPlus11; } // FixItHint is done by MakeSmartPtrCheck diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -16,7 +16,9 @@ #include "DeprecatedIosBaseAliasesCheck.h" #include "LoopConvertCheck.h" #include "MakeSharedCheck.h" +#include "MakeSharedForOverwriteCheck.h" #include "MakeUniqueCheck.h" +#include "MakeUniqueForOverwriteCheck.h" #include "PassByValueCheck.h" #include "RawStringLiteralCheck.h" #include "RedundantVoidArgCheck.h" @@ -60,7 +62,11 @@ "modernize-deprecated-ios-base-aliases"); CheckFactories.registerCheck("modernize-loop-convert"); CheckFactories.registerCheck("modernize-make-shared"); + CheckFactories.registerCheck( + "modernize-make-shared-for-overwrite"); CheckFactories.registerCheck("modernize-make-unique"); + CheckFactories.registerCheck( + "modernize-make-unique-for-overwrite"); CheckFactories.registerCheck("modernize-pass-by-value"); CheckFactories.registerCheck( "modernize-raw-string-literal"); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -140,6 +140,18 @@ Diagnoses every integer to pointer cast. +- New :doc:`modernize-make-shared-for-overwrite + ` check. + + Replaces default initialized objects in `new` expressions with a call to + `std::make_shared_for_overwrite` introduced in C++20. + +- New :doc:`modernize-make-unique-for-overwrite + ` check. + + Replaces default initialized objects in `new` expressions with a call to + `std::make_unique_for_overwrite` introduced in C++20. + - New :doc:`readability-function-cognitive-complexity ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -221,7 +221,9 @@ `modernize-deprecated-ios-base-aliases `_, "Yes" `modernize-loop-convert `_, "Yes" `modernize-make-shared `_, "Yes" + `modernize-make-shared-for-overwrite `_, "Yes" `modernize-make-unique `_, "Yes" + `modernize-make-unique-for-overwrite `_, "Yes" `modernize-pass-by-value `_, "Yes" `modernize-raw-string-literal `_, "Yes" `modernize-redundant-void-arg `_, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared-for-overwrite.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared-for-overwrite.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared-for-overwrite.rst @@ -0,0 +1,51 @@ +.. title:: clang-tidy - modernize-make-shared-for-overwrite + +modernize-make-shared-for-overwrite +===================== + +This check finds the creation of ``std::shared_ptr`` objects by explicitly +calling the constructor and a ``new`` expression where default initialization +occurs, and replaces it with a call to ``std::make_shared_for_overwrite``, +introduced in C++20. + +.. code-block:: c++ + + auto my_ptr = std::shared_ptr(new int); + + // becomes + + auto my_ptr = std::make_shared_for_overwrite(); + +This check also finds calls to ``std::shared_ptr::reset()`` with a ``new`` +expression, and replaces it with a call to ``std::make_shared``. + +.. code-block:: c++ + + my_ptr.reset(new int); + + // becomes + + my_ptr = std::make_shared_for_overwrite(); + +Options +------- + +.. option:: MakeSmartPtrFunction + + A string specifying the name of make-shared-ptr-for-overwrite function. Default is + `std::make_shared_for_overwrite`. + +.. option:: MakeSmartPtrFunctionHeader + + A string specifying the corresponding header of make-shared-ptr-for-overwrite function. + Default is ``. + +.. option:: IncludeStyle + + A string specifying which include-style is used, `llvm` or `google`. Default + is `llvm`. + +.. option:: IgnoreMacros + + If set to `true`, the check will not give warnings inside macros. Default + is `true`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique-for-overwrite.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique-for-overwrite.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique-for-overwrite.rst @@ -0,0 +1,51 @@ +.. title:: clang-tidy - modernize-make-unique-for-overwrite + +modernize-make-unique-for-overwrite +===================== + +This check finds the creation of ``std::unique_ptr`` objects by explicitly +calling the constructor and a ``new`` expression where default initialization +occurs, and replaces it with a call to ``std::make_unique_for_overwrite``, +introduced in C++20. + +.. code-block:: c++ + + auto my_ptr = std::unique_ptr(new int); + + // becomes + + auto my_ptr = std::make_unique_for_overwrite(); + +This check also finds calls to ``std::unique_ptr::reset()`` with a ``new`` +expression, and replaces it with a call to ``std::make_unique``. + +.. code-block:: c++ + + my_ptr.reset(new int); + + // becomes + + my_ptr = std::make_unique_for_overwrite(); + +Options +------- + +.. option:: MakeSmartPtrFunction + + A string specifying the name of make-unique-ptr-for-overwrite function. Default is + `std::make_unique_for_overwrite`. + +.. option:: MakeSmartPtrFunctionHeader + + A string specifying the corresponding header of make-unique-ptr-for-overwrite function. + Default is ``. + +.. option:: IncludeStyle + + A string specifying which include-style is used, `llvm` or `google`. Default + is `llvm`. + +.. option:: IgnoreMacros + + If set to `true`, the check will not give warnings inside macros. Default + is `true`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-make-shared-for-overwrite.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-make-shared-for-overwrite.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-make-shared-for-overwrite.cpp @@ -0,0 +1,288 @@ +// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-make-shared-for-overwrite %t -- -- -I %S/Inputs/modernize-smart-ptr + +#include "shared_ptr.h" +// CHECK-FIXES: #include + +struct Base { + Base(); + Base(int, int); +}; + +struct Derived : public Base { + Derived(); + Derived(int, int); +}; + +struct APair { + int a, b; +}; + +struct DPair { + DPair() : a(0), b(0) {} + DPair(int x, int y) : a(y), b(x) {} + int a, b; +}; + +struct Empty {}; + +template +using shared_ptr_ = std::shared_ptr; + +void *operator new(__SIZE_TYPE__ Count, void *Ptr); + +int g(std::shared_ptr P); + +std::shared_ptr getPointer() { + return std::shared_ptr(new Base); +} + +std::shared_ptr getPointerValue() { + return std::shared_ptr(new Base()); +} + +void basic() { + std::shared_ptr P1 = std::shared_ptr(new int()); + std::shared_ptr P2 = std::shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: std::shared_ptr P2 = std::make_shared_for_overwrite(); + + P1.reset(new int()); + P2.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P2 = std::make_shared_for_overwrite(); + + P1 = std::shared_ptr(new int()); + P2 = std::shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P2 = std::make_shared_for_overwrite(); + + P2.reset(new int()); + P2.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P2 = std::make_shared_for_overwrite(); + + P2 = std::shared_ptr(new int()); + P2 = std::shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P2 = std::make_shared_for_overwrite(); + + // With auto. + auto P4 = std::shared_ptr(new int()); + auto P5 = std::shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: auto P5 = std::make_shared_for_overwrite(); + + std::shared_ptr P6 = std::shared_ptr((new int())); + std::shared_ptr P7 = std::shared_ptr((new int)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: std::shared_ptr P7 = std::make_shared_for_overwrite(); + + P4.reset((((new int())))); + P4.reset((((new int)))); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P4 = std::make_shared_for_overwrite(); + + P4 = std::shared_ptr(((new int()))); + P4 = std::shared_ptr(((new int))); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared_for_overwrite instead [modernize-make-shared-for-overwrite] + // CHECK-FIXES: P4 = std::make_shared_for_overwrite(); + + { + // No std. + using namespace std; + shared_ptr Q = shared_ptr(new int()); + shared_ptr P = shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: shared_ptr P = std::make_shared_for_overwrite(); + + Q = shared_ptr(new int()); + Q = shared_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: Q = std::make_shared_for_overwrite(); + } + + std::shared_ptr R(new int()); + std::shared_ptr S(new int); + + // Create the shared_ptr as a parameter to a function. + int T = g(std::shared_ptr(new int())); + T = g(std::shared_ptr(new int)); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: T = g(std::make_shared_for_overwrite()); + + // Only replace if the type in the template is the same as the type returned + // by the new operator. + auto Pderived = std::shared_ptr(new Derived()); + auto PderivedNoparen = std::shared_ptr(new Derived); + + // OK to replace for reset and assign + Pderived.reset(new Derived()); + Pderived.reset(new Derived); + + Pderived = std::shared_ptr(new Derived()); + Pderived = std::shared_ptr(new Derived); + + // FIXME: OK to replace if assigned to shared_ptr + Pderived = std::shared_ptr(new Derived()); + Pderived = std::shared_ptr(new Derived); + + // FIXME: OK to replace when auto is not used + std::shared_ptr PBase = std::shared_ptr(new Derived()); + std::shared_ptr PBase2 = std::shared_ptr(new Derived); + + // The pointer is returned by the function, nothing to do. + std::shared_ptr RetPtr = getPointer(); + std::shared_ptr RetPtr2 = getPointerValue(); + + // This emulates std::move. + std::shared_ptr Move = static_cast &&>(P1); + + // Placement arguments should not be removed. + int *PInt = new int; + std::shared_ptr Placement = std::shared_ptr(new (PInt) int{3}); + Placement.reset(new (PInt) int{3}); + Placement = std::shared_ptr(new (PInt) int{3}); + + std::shared_ptr PlacementNoparen = std::shared_ptr(new (PInt) int); + PlacementNoparen.reset(new (PInt) int); + PlacementNoparen = std::shared_ptr(new (PInt) int); +} + +// 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(new Private); + auto ptr = std::shared_ptr(new Private(42)); + ptr.reset(new Private(42)); + ptr = std::shared_ptr(new Private(42)); + } + + virtual ~Private(); +}; + +class Protected { +protected: + Protected() {} + +public: + Protected(int, int) {} + void create() { + auto callsPublic = std::shared_ptr(new Protected(1, 2)); + auto ptr = std::shared_ptr(new Protected); + ptr.reset(new Protected); + ptr = std::shared_ptr(new Protected); + } +}; + +void initialization(int T, Base b) { + // Test different kinds of initialization of the pointee. + + // Direct initialization with parenthesis. + std::shared_ptr PDir1 = std::shared_ptr(new DPair(1, T)); + PDir1.reset(new DPair(1, T)); + + // Direct initialization with braces. + std::shared_ptr PDir2 = std::shared_ptr(new DPair{2, T}); + PDir2.reset(new DPair{2, T}); + + // Aggregate initialization. + std::shared_ptr PAggr = std::shared_ptr(new APair{T, 1}); + PAggr.reset(new APair{T, 1}); + + // Test different kinds of initialization of the pointee, when the shared_ptr + // is initialized with braces. + + // Direct initialization with parenthesis. + std::shared_ptr PDir3 = std::shared_ptr{new DPair(3, T)}; + + // Direct initialization with braces. + std::shared_ptr PDir4 = std::shared_ptr{new DPair{4, T}}; + + // Aggregate initialization. + std::shared_ptr PAggr2 = std::shared_ptr{new APair{T, 2}}; + + // Direct initialization with parenthesis, without arguments. + std::shared_ptr PDir5 = std::shared_ptr(new DPair()); + + // Direct initialization with braces, without arguments. + std::shared_ptr PDir6 = std::shared_ptr(new DPair{}); + + // Aggregate initialization without arguments. + std::shared_ptr PEmpty = std::shared_ptr(new Empty{}); +} + +void aliases() { + typedef std::shared_ptr IntPtr; + IntPtr Typedef = IntPtr(new int()); + IntPtr Typedef2 = IntPtr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: IntPtr Typedef2 = std::make_shared_for_overwrite(); + + // We use 'bool' instead of '_Bool'. + typedef std::shared_ptr BoolPtr; + BoolPtr BoolType = BoolPtr(new bool()); + BoolPtr BoolType2 = BoolPtr(new bool); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: BoolPtr BoolType2 = std::make_shared_for_overwrite(); + + // We use 'Base' instead of 'struct Base'. + typedef std::shared_ptr BasePtr; + BasePtr StructType = BasePtr(new Base); + +#define PTR shared_ptr + std::shared_ptr Macro = std::PTR(new int()); + std::shared_ptr Macro2 = std::PTR(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: std::shared_ptr Macro2 = std::make_shared_for_overwrite(); +#undef PTR + + std::shared_ptr Using = shared_ptr_(new int()); + std::shared_ptr Using2 = shared_ptr_(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: std::shared_ptr Using2 = std::make_shared_for_overwrite(); +} + +void whitespaces() { + // clang-format off + auto Space = std::shared_ptr (new int()); + auto Space2 = std::shared_ptr (new int); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: auto Space2 = std::make_shared_for_overwrite(); + + auto Spaces = std :: shared_ptr (new int()); + auto Spaces2 = std :: shared_ptr (new int); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: auto Spaces2 = std::make_shared_for_overwrite(); + // clang-format on +} + +void nesting() { + auto Nest = std::shared_ptr>(new std::shared_ptr(new int)); + Nest.reset(new std::shared_ptr(new int)); + Nest->reset(new int()); + Nest->reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: *Nest = std::make_shared_for_overwrite(); +} + +void reset() { + std::shared_ptr P; + P.reset(); + P.reset(nullptr); + P.reset(new int()); + P.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: P = std::make_shared_for_overwrite(); + + auto Q = &P; + Q->reset(new int()); + Q->reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared_for_overwrite instead + // CHECK-FIXES: *Q = std::make_shared_for_overwrite(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-make-unique-for-overwrite.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-make-unique-for-overwrite.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-make-unique-for-overwrite.cpp @@ -0,0 +1,476 @@ +// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-make-unique-for-overwrite %t -- -- -I %S/Inputs/modernize-smart-ptr + +#include "initializer_list.h" +#include "unique_ptr.h" +// CHECK-FIXES: #include + +struct Base { + Base(); + Base(int, int); +}; + +struct Derived : public Base { + Derived(); + Derived(int, int); +}; + +struct APair { + int a, b; +}; + +struct DPair { + DPair() : a(0), b(0) {} + DPair(int x, int y) : a(y), b(x) {} + int a, b; +}; + +template +struct MyVector { + MyVector(std::initializer_list); +}; + +struct Empty {}; + +struct E { + E(std::initializer_list); + E(); +}; + +struct F { + F(std::initializer_list); + F(); + int a; +}; + +struct G { + G(std::initializer_list); + G(int); +}; + +struct H { + H(std::vector); + H(std::vector &, double); + H(MyVector, int); +}; + +struct I { + I(G); +}; + +struct J { + J(E e, int); +}; + +namespace { +class Foo {}; +} // namespace + +namespace bar { +class Bar {}; +} // namespace bar + +template +using unique_ptr_ = std::unique_ptr; + +void *operator new(__SIZE_TYPE__ Count, void *Ptr); + +int g(std::unique_ptr P); + +std::unique_ptr getPointer() { + return std::unique_ptr(new Base); +} + +std::unique_ptr getPointerValue() { + return std::unique_ptr(new Base()); +} + +void basic() { + std::unique_ptr P1 = std::unique_ptr(new int()); + std::unique_ptr P2 = std::unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: std::unique_ptr P2 = std::make_unique_for_overwrite(); + + P1.reset(new int()); + P2.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: P2 = std::make_unique_for_overwrite(); + + P1 = std::unique_ptr(new int()); + P2 = std::unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: P2 = std::make_unique_for_overwrite(); + + P1.reset(new int()); + P2.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: P2 = std::make_unique_for_overwrite(); + + // With auto. + auto P4 = std::unique_ptr(new int()); + auto P5 = std::unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: auto P5 = std::make_unique_for_overwrite(); + + std::unique_ptr P6 = std::unique_ptr((new int())); + std::unique_ptr P7 = std::unique_ptr((new int)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: std::unique_ptr P7 = std::make_unique_for_overwrite(); + + P4.reset((new int())); + P5.reset((new int)); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: P5 = std::make_unique_for_overwrite(); + + std::unique_ptr P8 = std::unique_ptr((((new int())))); + std::unique_ptr P9 = std::unique_ptr((((new int)))); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: std::unique_ptr P9 = std::make_unique_for_overwrite(); + + P5.reset(((((new int()))))); + P6.reset(((((new int))))); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique_for_overwrite instead [modernize-make-unique-for-overwrite] + // CHECK-FIXES: P6 = std::make_unique_for_overwrite(); + + { + // No std. + using namespace std; + unique_ptr Q = unique_ptr(new int()); + unique_ptr P = unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: unique_ptr P = std::make_unique_for_overwrite(); + + Q = unique_ptr(new int()); + P = unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: P = std::make_unique_for_overwrite(); + } + + std::unique_ptr R(new int()); + std::unique_ptr S(new int); + + // Create the unique_ptr as a parameter to a function. + int T = g(std::unique_ptr(new int())); + T = g(std::unique_ptr(new int)); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: T = g(std::make_unique_for_overwrite()); + + // Only replace if the type in the template is the same as the type returned + // by the new operator. + auto Pderived = std::unique_ptr(new Derived()); + auto PderivedNoparen = std::unique_ptr(new Derived); + + // OK to replace for reset and assign + Pderived.reset(new Derived()); + PderivedNoparen.reset(new Derived); + + Pderived = std::unique_ptr(new Derived()); + PderivedNoparen = std::unique_ptr(new Derived); + + // FIXME: OK to replace if assigned to unique_ptr + Pderived = std::unique_ptr(new Derived()); + Pderived = std::unique_ptr(new Derived); + + // FIXME: OK to replace when auto is not used + std::unique_ptr PBase = std::unique_ptr(new Derived()); + std::unique_ptr PBaseNoparen = std::unique_ptr(new Derived); + + // The pointer is returned by the function, nothing to do. + std::unique_ptr RetPtr = getPointer(); + RetPtr = getPointerValue(); + + // This emulates std::move. + std::unique_ptr Move = static_cast &&>(P1); + + // Placement arguments should not be removed. + int *PInt = new int; + std::unique_ptr Placement = std::unique_ptr(new (PInt) int{3}); + Placement.reset(new (PInt) int{3}); + Placement = std::unique_ptr(new (PInt) int{3}); + + std::unique_ptr PlacementNoparen = std::unique_ptr(new (PInt) int); + PlacementNoparen.reset(new (PInt) int); + PlacementNoparen = std::unique_ptr(new (PInt) int); +} + +// 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(new Private); + auto ptr = std::unique_ptr(new Private(42)); + ptr.reset(new Private(42)); + ptr = std::unique_ptr(new Private(42)); + } + + virtual ~Private(); +}; + +class Protected { +protected: + Protected() {} + +public: + Protected(int, int) {} + void create() { + auto callsPublic = std::unique_ptr(new Protected(1, 2)); + auto ptr = std::unique_ptr(new Protected); + ptr.reset(new Protected); + ptr = std::unique_ptr(new Protected); + } +}; + +void initialization(int T, Base b) { + // Test different kinds of initialization of the pointee. + + // Direct initialization with parenthesis. + std::unique_ptr PDir1 = std::unique_ptr(new DPair(1, T)); + PDir1.reset(new DPair(1, T)); + + // Direct initialization with braces. + std::unique_ptr PDir2 = std::unique_ptr(new DPair{2, T}); + PDir2.reset(new DPair{2, T}); + + // Aggregate initialization. + std::unique_ptr PAggr = std::unique_ptr(new APair{T, 1}); + PAggr.reset(new APair{T, 1}); + + // Check aggregate init with intermediate temporaries. + std::unique_ptr PAggrTemp = std::unique_ptr(new APair({T, 1})); + PAggrTemp.reset(new APair({T, 1})); + + // Test different kinds of initialization of the pointee, when the unique_ptr + // is initialized with braces. + + // Direct initialization with parenthesis. + std::unique_ptr PDir3 = std::unique_ptr{new DPair(3, T)}; + + // Direct initialization with braces. + std::unique_ptr PDir4 = std::unique_ptr{new DPair{4, T}}; + + // Aggregate initialization. + std::unique_ptr PAggr2 = std::unique_ptr{new APair{T, 2}}; + + // Direct initialization with parenthesis, without arguments. + std::unique_ptr PDir5 = std::unique_ptr(new DPair()); + + // Direct initialization with braces, without arguments. + std::unique_ptr PDir6 = std::unique_ptr(new DPair{}); + + // Aggregate initialization without arguments. + std::unique_ptr PEmpty = std::unique_ptr(new Empty{}); + + // Initialization with default constructor. + std::unique_ptr PE1 = std::unique_ptr(new E{}); + PE1.reset(new E{}); + + // No warnings for `auto` new expression. + PE1.reset(new auto(E())); + + //============================================================================ + // NOTE: For initializer-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}); + PE2.reset(new E{1, 2}); + + // Initialization with default constructor. + std::unique_ptr PF1 = std::unique_ptr(new F()); + PF1.reset(new F()); + + // Initialization with default constructor. + std::unique_ptr PF2 = std::unique_ptr(new F{}); + PF2.reset(new F()); + + // Initialization with the initializer-list constructor. + std::unique_ptr PF3 = std::unique_ptr(new F{1}); + PF3.reset(new F{1}); + + // Initialization with the initializer-list constructor. + 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})); + + // Initialization with the initializer-list constructor as the default + // constructor is not present. + std::unique_ptr PG1 = std::unique_ptr(new G{}); + PG1.reset(new G{}); + + // Initialization with the initializer-list constructor. + 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}); + + std::unique_ptr PH1 = std::unique_ptr(new H({1, 2, 3})); + PH1.reset(new H({1, 2, 3})); + + std::unique_ptr PH2 = std::unique_ptr(new H({1, 2, 3}, 1)); + PH2.reset(new H({1, 2, 3}, 1)); + + std::unique_ptr PH3 = std::unique_ptr(new H({1, 2, 3}, 1.0)); + PH3.reset(new H({1, 2, 3}, 1.0)); + + std::unique_ptr PI1 = std::unique_ptr(new I(G({1, 2, 3}))); + PI1.reset(new I(G({1, 2, 3}))); + + std::unique_ptr PJ1 = std::unique_ptr(new J({1, 2}, 1)); + PJ1.reset(new J({1, 2}, 1)); + + std::unique_ptr PJ2 = std::unique_ptr(new J(E{1, 2}, 1)); + PJ2.reset(new J(E{1, 2}, 1)); + + std::unique_ptr PJ3 = std::unique_ptr(new J{{1, 2}, 1}); + PJ3.reset(new J{{1, 2}, 1}); + + std::unique_ptr PJ4 = std::unique_ptr(new J{E{1, 2}, 1}); + PJ4.reset(new J{E{1, 2}, 1}); + + std::unique_ptr FF = std::unique_ptr(new Foo()); + FF.reset(new Foo()); + + std::unique_ptr BB = std::unique_ptr(new bar::Bar()); + BB.reset(new bar::Bar()); + + std::unique_ptr FFs; + FFs.reset(new Foo[5]); + FFs.reset(new Foo[5]()); + const int Num = 1; + FFs.reset(new Foo[Num]); + int Num2 = 1; + + // The check doesn't give warnings and fixes for cases where the original new + // expression does value initialization. + std::unique_ptr FI; + FI.reset(new int[5]()); + + FI.reset(new int[5]); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: + // CHECK-FIXES: FI = std::make_unique_for_overwrite(5); + FI.reset(new int[Num]); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: + // CHECK-FIXES: FI = std::make_unique_for_overwrite(Num); + FI.reset(new int[Num2]); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: + // CHECK-FIXES: FI = std::make_unique_for_overwrite(Num2); +} + +void aliases() { + typedef std::unique_ptr IntPtr; + IntPtr Typedef = IntPtr(new int()); + IntPtr Typedef2 = IntPtr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: IntPtr Typedef2 = std::make_unique_for_overwrite(); + + // We use 'bool' instead of '_Bool'. + typedef std::unique_ptr BoolPtr; + BoolPtr BoolType = BoolPtr(new bool()); + BoolPtr BoolType2 = BoolPtr(new bool); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: BoolPtr BoolType2 = std::make_unique_for_overwrite(); + + // We use 'Base' instead of 'struct Base'. + typedef std::unique_ptr BasePtr; + BasePtr StructType = BasePtr(new Base); + +#define PTR unique_ptr + std::unique_ptr Macro = std::PTR(new int()); + std::unique_ptr Macro2 = std::PTR(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: std::unique_ptr Macro2 = std::make_unique_for_overwrite(); +#undef PTR + + std::unique_ptr Using = unique_ptr_(new int()); + std::unique_ptr Using2 = unique_ptr_(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: std::unique_ptr Using2 = std::make_unique_for_overwrite(); +} + +void whitespaces() { + // clang-format off + auto Space = std::unique_ptr (new int()); + auto Space2 = std::unique_ptr (new int); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: auto Space2 = std::make_unique_for_overwrite(); + + auto Spaces = std :: unique_ptr (new int()); + auto Spaces2 = std :: unique_ptr (new int); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: auto Spaces2 = std::make_unique_for_overwrite(); + // clang-format on +} + +void nesting() { + auto Nest = std::unique_ptr>(new std::unique_ptr(new int)); + Nest.reset(new std::unique_ptr(new int)); + Nest->reset(new int()); + Nest->reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: *Nest = std::make_unique_for_overwrite(); +} + +void reset() { + std::unique_ptr P; + P.reset(); + P.reset(nullptr); + P.reset(new int()); + P.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: P = std::make_unique_for_overwrite(); + + auto Q = &P; + Q->reset(new int()); + Q->reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique_for_overwrite instead + // CHECK-FIXES: *Q = std::make_unique_for_overwrite(); +} + +#define DEFINE(...) __VA_ARGS__ +template +void g2(std::unique_ptr *t) { + DEFINE(auto p = std::unique_ptr(new Foo); t->reset(new Foo);); +} +void macro() { + std::unique_ptr *t; + g2(t); +} +#undef DEFINE + +class UniqueFoo : public std::unique_ptr { +public: + void foo() { + reset(new Foo); + this->reset(new Foo); + this->reset(new Foo()); + (*this).reset(new Foo); + (*this).reset(new Foo()); + } +}; + +// Ignore statements inside a template instantiation. +template +void template_fun(T *t) { + std::unique_ptr t2 = std::unique_ptr(new T); + std::unique_ptr t3 = std::unique_ptr(new T()); + t2.reset(new T); + t3.reset(new T()); +} + +void invoke_template() { + Foo *foo; + template_fun(foo); +} + +void no_fix_for_invalid_new_loc() { + // FIXME: Although the code is valid, the end location of `new struct Base` is + // invalid. Correct it once https://bugs.llvm.org/show_bug.cgi?id=35952 is + // fixed. + auto T = std::unique_ptr(new struct Base); +}