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 | |