| 1 | // RUN: %check_clang_tidy %s abseil-cleanup-ctad -std=c++17 %t |
| 2 | |
| 3 | namespace std { |
| 4 | |
| 5 | template <typename, typename> |
| 6 | struct is_same { |
| 7 | static const bool value = false; |
| 8 | }; |
| 9 | |
| 10 | template <typename T> |
| 11 | struct is_same<T, T> { static const bool value = true; }; |
| 12 | |
| 13 | template <typename> |
| 14 | class function { |
| 15 | public: |
| 16 | template <typename T> |
| 17 | function(T) {} |
| 18 | function(const function &) {} |
| 19 | }; |
| 20 | |
| 21 | } // namespace std |
| 22 | |
| 23 | namespace absl { |
| 24 | |
| 25 | namespace cleanup_internal { |
| 26 | |
| 27 | struct Tag {}; |
| 28 | |
| 29 | template <typename Callback> |
| 30 | class Storage { |
| 31 | public: |
| 32 | Storage() = delete; |
| 33 | |
| 34 | explicit Storage(Callback callback) {} |
| 35 | |
| 36 | Storage(Storage &&other) {} |
| 37 | |
| 38 | Storage(const Storage &other) = delete; |
| 39 | |
| 40 | Storage &operator=(Storage &&other) = delete; |
| 41 | |
| 42 | Storage &operator=(const Storage &other) = delete; |
| 43 | |
| 44 | private: |
| 45 | bool is_callback_engaged_; |
| 46 | alignas(Callback) char callback_buffer_[sizeof(Callback)]; |
| 47 | }; |
| 48 | |
| 49 | } // namespace cleanup_internal |
| 50 | |
| 51 | template <typename Arg, typename Callback = void()> |
| 52 | class Cleanup final { |
| 53 | public: |
| 54 | Cleanup(Callback callback) // NOLINT |
| 55 | : storage_(static_cast<Callback &&>(callback)) {} |
| 56 | |
| 57 | Cleanup(Cleanup &&other) = default; |
| 58 | |
| 59 | void Cancel() &&; |
| 60 | |
| 61 | void Invoke() &&; |
| 62 | |
| 63 | ~Cleanup(); |
| 64 | |
| 65 | private: |
| 66 | cleanup_internal::Storage<Callback> storage_; |
| 67 | }; |
| 68 | |
| 69 | template <typename Callback> |
| 70 | Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>; |
| 71 | |
| 72 | template <typename... Args, typename Callback> |
| 73 | absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) { |
| 74 | return {static_cast<Callback &&>(callback)}; |
| 75 | } |
| 76 | |
| 77 | } // namespace absl |
| 78 | |
| 79 | void test() { |
| 80 | auto a = absl::MakeCleanup(callback: [] {}); |
| 81 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer absl::Cleanup's class template argument deduction pattern in C++17 and higher |
| 82 | // CHECK-FIXES: {{^}} absl::Cleanup a = [] {};{{$}} |
| 83 | |
| 84 | auto b = absl::MakeCleanup(callback: std::function<void()>([] {})); |
| 85 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer absl::Cleanup{{.*}}C++17 and higher |
| 86 | // CHECK-FIXES: {{^}} absl::Cleanup b = std::function<void()>([] {});{{$}} |
| 87 | |
| 88 | const auto c = absl::MakeCleanup(callback: [] {}); |
| 89 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: prefer absl::Cleanup{{.*}}C++17 and higher |
| 90 | // CHECK-FIXES: {{^}} const absl::Cleanup c = [] {};{{$}} |
| 91 | |
| 92 | const auto d = absl::MakeCleanup(callback: std::function<void()>([] {})); |
| 93 | // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: prefer absl::Cleanup{{.*}}C++17 and higher |
| 94 | // CHECK-FIXES: {{^}} const absl::Cleanup d = std::function<void()>([] {});{{$}} |
| 95 | |
| 96 | // Preserves extra parens |
| 97 | auto e = absl::MakeCleanup(callback: ([] {})); |
| 98 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer absl::Cleanup{{.*}}C++17 and higher |
| 99 | // CHECK-FIXES: {{^}} absl::Cleanup e = ([] {});{{$}} |
| 100 | |
| 101 | // Preserves comments |
| 102 | auto f = /* a */ absl::MakeCleanup(/* b */ callback: [] { /* c */ } /* d */) /* e */; |
| 103 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer absl::Cleanup{{.*}}C++17 and higher |
| 104 | // CHECK-FIXES: {{^}} absl::Cleanup f = /* a */ /* b */ [] { /* c */ } /* d */ /* e */;{{$}} |
| 105 | } |
| 106 | |