Index: clang-tidy/abseil/AbseilTidyModule.cpp =================================================================== --- clang-tidy/abseil/AbseilTidyModule.cpp +++ clang-tidy/abseil/AbseilTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "../modernize/MakeUniqueCheck.h" #include "DurationAdditionCheck.h" #include "DurationComparisonCheck.h" #include "DurationConversionCastCheck.h" @@ -64,6 +65,17 @@ "abseil-time-subtraction"); CheckFactories.registerCheck( "abseil-upgrade-duration-conversions"); + CheckFactories.registerCheck( + "abseil-make-unique"); + } + + ClangTidyOptions getModuleOptions() override { + ClangTidyOptions Options; + ClangTidyOptions::OptionMap &Opts = Options.CheckOptions; + Opts["abseil-make-unique.MakeSmartPtrFunctionHeader"] = "absl/memory/memory.h"; + Opts["abseil-make-unique.MakeSmartPtrFunction"] = "absl::make_unique"; + Opts["abseil-make-unique.UseLegacyFunction"] = true; + return Options; } }; Index: clang-tidy/modernize/MakeSmartPtrCheck.h =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.h +++ clang-tidy/modernize/MakeSmartPtrCheck.h @@ -50,6 +50,7 @@ const std::string MakeSmartPtrFunctionHeader; const std::string MakeSmartPtrFunctionName; const bool IgnoreMacros; + const bool UseLegacyFunction; void checkConstruct(SourceManager &SM, ASTContext *Ctx, const CXXConstructExpr *Construct, const QualType *Type, Index: clang-tidy/modernize/MakeSmartPtrCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -51,13 +51,15 @@ Options.get("MakeSmartPtrFunctionHeader", StdMemoryHeader)), MakeSmartPtrFunctionName( Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)), - IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {} + IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)), + UseLegacyFunction(Options.getLocalOrGlobal("UseLegacyFunction", false)) {} void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IncludeStyle", IncludeStyle); Options.store(Opts, "MakeSmartPtrFunctionHeader", MakeSmartPtrFunctionHeader); Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName); Options.store(Opts, "IgnoreMacros", IgnoreMacros); + Options.store(Opts, "UseLegacyFunction", UseLegacyFunction); } bool MakeSmartPtrCheck::isLanguageVersionSupported( @@ -157,6 +159,11 @@ if (Invalid) return; + // Conservatively disable for list initializations + if (UseLegacyFunction && New->getInitializationStyle() == CXXNewExpr::ListInit) { + return; + } + auto Diag = diag(ConstructCallStart, "use %0 instead") << MakeSmartPtrFunctionName; @@ -227,6 +234,11 @@ return; } + // Conservatively disable for list initializations + if (UseLegacyFunction && New->getInitializationStyle() == CXXNewExpr::ListInit) { + return; + } + auto Diag = diag(ResetCallStart, "use %0 instead") << MakeSmartPtrFunctionName; Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -85,6 +85,11 @@ Finds and fixes cases where ``absl::Duration`` values are being converted to numeric types and back again. +- New alias :doc:`abseil-make-unique + ` to :doc:`modernize-make-unique + ` + added. + - New :doc:`abseil-time-subtraction ` check. Index: docs/clang-tidy/checks/abseil-make-unique.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/abseil-make-unique.rst @@ -0,0 +1,9 @@ +.. title:: clang-tidy - abseil-make-unique +.. meta:: + :http-equiv=refresh: 5;URL=abseil-make-unique.html + +abseil-make-unique +================== + +The abseil-make-unique check is an alias, please see +`modernize-make-unique `_ for more information. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -13,6 +13,7 @@ abseil-duration-subtraction abseil-duration-unnecessary-conversion abseil-faster-strsplit-delimiter + abseil-make-unique (redirects to modernize-make-unique) abseil-no-internal-dependencies abseil-no-namespace abseil-redundant-strcat-calls Index: docs/clang-tidy/checks/modernize-make-unique.rst =================================================================== --- docs/clang-tidy/checks/modernize-make-unique.rst +++ docs/clang-tidy/checks/modernize-make-unique.rst @@ -48,3 +48,8 @@ If set to non-zero, the check will not give warnings inside macros. Default is `1`. + +.. option:: UseLegacyFunction + + If set to non-zero, the check will ignore features from C++11 and later such + as list initialization. Default is `0`. Index: test/clang-tidy/abseil-make-unique.cpp =================================================================== --- /dev/null +++ test/clang-tidy/abseil-make-unique.cpp @@ -0,0 +1,127 @@ +// RUN: %check_clang_tidy %s abseil-make-unique %t -- -- -std=c++11 \ + +namespace std { + +template +class default_delete {}; + +template > +class unique_ptr { +public: + unique_ptr() {} + unique_ptr(type *ptr) {} + unique_ptr(const unique_ptr &t) = delete; + unique_ptr(unique_ptr &&t) {} + ~unique_ptr() {} + type &operator*() { return *ptr; } + type *operator->() { return ptr; } + type *release() { return ptr; } + void reset() {} + void reset(type *pt) {} + void reset(type pt) {} + unique_ptr &operator=(unique_ptr &&) { return *this; } + template + unique_ptr &operator=(unique_ptr &&) { return *this; } + +private: + type *ptr; +}; + +} // namespace std + +class A { + int x; + int y; + + public: + A(int _x, int _y): x(_x), y(_y) {} +}; + +struct Base { + Base(); +}; + +struct Derived : public Base { + Derived(); +}; + +int* returnPointer(); +void expectPointer(std::unique_ptr p); + +std::unique_ptr makeAndReturnPointer() { + return std::unique_ptr(new int(0)); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: return absl::make_unique(0); +} + +void Positives() { + std::unique_ptr P1 = std::unique_ptr(new int(1)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: std::unique_ptr P1 = absl::make_unique(1); + + P1.reset(new int(2)); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: P1 = absl::make_unique(2); + + // Non-primitive paramter + std::unique_ptr P2 = std::unique_ptr(new A(1, 2)); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: std::unique_ptr P2 = absl::make_unique(1, 2); + + P2.reset(new A(3, 4)); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: P2 = absl::make_unique(3, 4); + + // No arguments to new expression + std::unique_ptr P3 = std::unique_ptr(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: std::unique_ptr P3 = absl::make_unique(); + + P3.reset(new int); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: P3 = absl::make_unique(); + + // Nested parentheses + std::unique_ptr P4 = std::unique_ptr((new int(3))); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: std::unique_ptr P4 = absl::make_unique(3); + + P4 = std::unique_ptr(((new int(4)))); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: P4 = absl::make_unique(4); + + P4.reset((new int(5))); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: P4 = absl::make_unique(5); + + // With auto + auto P5 = std::unique_ptr(new int()); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: auto P5 = absl::make_unique(); + + { + // No std + using namespace std; + unique_ptr Q = unique_ptr(new int()); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: unique_ptr Q = absl::make_unique(); + + Q = unique_ptr(new int()); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: Q = absl::make_unique(); + } + + // Create the unique_ptr as a parameter to a function + expectPointer(std::unique_ptr(new int())); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use absl::make_unique instead [abseil-make-unique] + // CHECK-FIXES: expectPointer(absl::make_unique()); +} + +void Negatives() { + // Only warn if explicitly allocating a new object + std::unique_ptr R = std::unique_ptr(returnPointer()); + R.reset(returnPointer()); + + // Only replace if the template type is same as new type + auto Pderived = std::unique_ptr(new Derived()); +}