1 | // RUN: %check_clang_tidy --match-partial-fixes %s modernize-min-max-use-initializer-list %t |
2 | |
3 | // CHECK-FIXES: #include <algorithm> |
4 | namespace utils { |
5 | template <typename T> |
6 | T max(T a, T b) { |
7 | return (a < b) ? b : a; |
8 | } |
9 | } // namespace utils |
10 | |
11 | namespace std { |
12 | template< class T > |
13 | struct initializer_list { |
14 | const T *a, *b; |
15 | initializer_list()=default; |
16 | initializer_list(T*,int){} |
17 | const T* begin() const {return nullptr;} |
18 | const T* end() const {return nullptr;} |
19 | }; |
20 | |
21 | template<class ForwardIt> |
22 | ForwardIt min_element(ForwardIt first, ForwardIt last) |
23 | { |
24 | if (first == last) |
25 | return last; |
26 | |
27 | ForwardIt smallest = first; |
28 | |
29 | while (++first != last) |
30 | if (*first < *smallest) |
31 | smallest = first; |
32 | |
33 | return smallest; |
34 | } |
35 | |
36 | template<class ForwardIt, class Compare> |
37 | ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp) |
38 | { |
39 | if (first == last) |
40 | return last; |
41 | |
42 | ForwardIt smallest = first; |
43 | |
44 | while (++first != last) |
45 | if (comp(*first, *smallest)) |
46 | smallest = first; |
47 | |
48 | return smallest; |
49 | } |
50 | |
51 | template<class ForwardIt> |
52 | ForwardIt max_element(ForwardIt first, ForwardIt last) |
53 | { |
54 | if (first == last) |
55 | return last; |
56 | |
57 | ForwardIt largest = first; |
58 | |
59 | while (++first != last) |
60 | if (*largest < *first) |
61 | largest = first; |
62 | |
63 | return largest; |
64 | } |
65 | |
66 | template<class ForwardIt, class Compare> |
67 | ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp) |
68 | { |
69 | if (first == last) |
70 | return last; |
71 | |
72 | ForwardIt largest = first; |
73 | |
74 | while(++first != last) |
75 | if (comp(*largest, *first)) |
76 | largest = first; |
77 | |
78 | return largest; |
79 | } |
80 | |
81 | template< class T > |
82 | const T& max( const T& a, const T& b ) { |
83 | return (a < b) ? b : a; |
84 | }; |
85 | |
86 | template< class T > |
87 | T max(std::initializer_list<T> ilist) |
88 | { |
89 | return *std::max_element(ilist.begin(), ilist.end()); |
90 | } |
91 | |
92 | template< class T, class Compare > |
93 | const T& max( const T& a, const T& b, Compare comp ) { |
94 | return (comp(a, b)) ? b : a; |
95 | }; |
96 | |
97 | template< class T, class Compare > |
98 | T max(std::initializer_list<T> ilist, Compare comp) { |
99 | return *std::max_element(ilist.begin(), ilist.end(), comp); |
100 | }; |
101 | |
102 | template< class T > |
103 | const T& min( const T& a, const T& b ) { |
104 | return (b < a) ? b : a; |
105 | }; |
106 | |
107 | template< class T > |
108 | T min(std::initializer_list<T> ilist) |
109 | { |
110 | return *std::min_element(ilist.begin(), ilist.end()); |
111 | } |
112 | |
113 | |
114 | template< class T, class Compare > |
115 | const T& min( const T& a, const T& b, Compare comp ) { |
116 | return (comp(b, a)) ? b : a; |
117 | }; |
118 | |
119 | template< class T, class Compare > |
120 | T min(std::initializer_list<T> ilist, Compare comp) { |
121 | return *std::min_element(ilist.begin(), ilist.end(), comp); |
122 | }; |
123 | |
124 | } // namespace std |
125 | |
126 | using namespace std; |
127 | |
128 | namespace { |
129 | bool fless_than(int a, int b) { |
130 | return a < b; |
131 | } |
132 | |
133 | bool fgreater_than(int a, int b) { |
134 | return a > b; |
135 | } |
136 | auto less_than = [](int a, int b) { return a < b; }; |
137 | auto greater_than = [](int a, int b) { return a > b; }; |
138 | |
139 | int max1 = std::max(a: 1, b: std::max(a: 2, b: 3)); |
140 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
141 | // CHECK-FIXES: int max1 = std::max({1, 2, 3}); |
142 | |
143 | int min1 = std::min(a: 1, b: std::min(a: 2, b: 3)); |
144 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
145 | // CHECK-FIXES: int min1 = std::min({1, 2, 3}); |
146 | |
147 | int max2 = std::max(a: 1, b: std::max(a: 2, b: std::max(a: 3, b: 4))); |
148 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
149 | // CHECK-FIXES: int max2 = std::max({1, 2, 3, 4}); |
150 | |
151 | int max2b = std::max(a: std::max(a: std::max(a: 1, b: 2), b: std::max(a: 3, b: 4)), b: std::max(a: std::max(a: 5, b: 6), b: std::max(a: 7, b: 8))); |
152 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
153 | // CHECK-FIXES: int max2b = std::max({1, 2, 3, 4, 5, 6, 7, 8}); |
154 | |
155 | int max2c = std::max(a: std::max(a: 1, b: std::max(a: 2, b: 3)), b: 4); |
156 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
157 | // CHECK-FIXES: int max2c = std::max({1, 2, 3, 4}); |
158 | |
159 | int max2d = std::max(a: std::max(ilist: {1, 2, 3}), b: 4); |
160 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
161 | // CHECK-FIXES: int max2d = std::max({1, 2, 3, 4}); |
162 | |
163 | |
164 | int max2e = std::max(a: 1, b: max(a: 2, b: max(a: 3, b: 4))); |
165 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
166 | // CHECK-FIXES: int max2e = std::max({1, 2, 3, 4}); |
167 | |
168 | int min2 = std::min(a: 1, b: std::min(a: 2, b: std::min(a: 3, b: 4))); |
169 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
170 | // CHECK-FIXES: int min2 = std::min({1, 2, 3, 4}); |
171 | |
172 | int max3 = std::max(a: std::max(a: 4, b: 5), b: std::min(a: 2, b: std::min(a: 3, b: 1))); |
173 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
174 | // CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
175 | // CHECK-FIXES: int max3 = std::max({4, 5, std::min({2, 3, 1})}); |
176 | |
177 | int min3 = std::min(a: std::min(a: 4, b: 5), b: std::max(a: 2, b: std::max(a: 3, b: 1))); |
178 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
179 | // CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
180 | // CHECK-FIXES: int min3 = std::min({4, 5, std::max({2, 3, 1})}); |
181 | |
182 | int max4 = std::max(a: 1, b: std::max(a: 2, b: 3, comp: greater_than), comp: less_than); |
183 | // CHECK-FIXES: int max4 = std::max(1, std::max(2, 3, greater_than), less_than); |
184 | |
185 | int min4 = std::min(a: 1, b: std::min(a: 2, b: 3, comp: greater_than), comp: less_than); |
186 | // CHECK-FIXES: int min4 = std::min(1, std::min(2, 3, greater_than), less_than); |
187 | |
188 | int max5 = std::max(a: 1, b: std::max(a: 2, b: 3), comp: less_than); |
189 | // CHECK-FIXES: int max5 = std::max(1, std::max(2, 3), less_than); |
190 | |
191 | int min5 = std::min(a: 1, b: std::min(a: 2, b: 3), comp: less_than); |
192 | // CHECK-FIXES: int min5 = std::min(1, std::min(2, 3), less_than); |
193 | |
194 | int max6 = std::max(a: 1, b: std::max(a: 2, b: 3, comp: greater_than), comp: greater_than); |
195 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
196 | // CHECK-FIXES: int max6 = std::max({1, 2, 3 }, greater_than); |
197 | |
198 | int min6 = std::min(a: 1, b: std::min(a: 2, b: 3, comp: greater_than), comp: greater_than); |
199 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
200 | // CHECK-FIXES: int min6 = std::min({1, 2, 3 }, greater_than); |
201 | |
202 | int max7 = std::max(a: 1, b: std::max(a: 2, b: 3, comp: fless_than), comp: fgreater_than); |
203 | // CHECK-FIXES: int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than); |
204 | |
205 | int min7 = std::min(a: 1, b: std::min(a: 2, b: 3, comp: fless_than), comp: fgreater_than); |
206 | // CHECK-FIXES: int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than); |
207 | |
208 | int max8 = std::max(a: 1, b: std::max(a: 2, b: 3, comp: fless_than), comp: less_than); |
209 | // CHECK-FIXES: int max8 = std::max(1, std::max(2, 3, fless_than), less_than) |
210 | |
211 | int min8 = std::min(a: 1, b: std::min(a: 2, b: 3, comp: fless_than), comp: less_than); |
212 | // CHECK-FIXES: int min8 = std::min(1, std::min(2, 3, fless_than), less_than); |
213 | |
214 | int max9 = std::max(a: 1, b: std::max(a: 2, b: 3, comp: fless_than), comp: fless_than); |
215 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
216 | // CHECK-FIXES: int max9 = std::max({1, 2, 3 }, fless_than); |
217 | |
218 | int min9 = std::min(a: 1, b: std::min(a: 2, b: 3, comp: fless_than), comp: fless_than); |
219 | // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
220 | // CHECK-FIXES: int min9 = std::min({1, 2, 3 }, fless_than); |
221 | |
222 | int min10 = std::min(a: std::min(a: 4, b: 5), b: std::max(a: 2, b: utils::max(a: 3, b: 1))); |
223 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
224 | // CHECK-FIXES: int min10 = std::min({4, 5, std::max(2, utils::max(3, 1))}); |
225 | |
226 | int max10 = std::max(ilist: {std::max(a: 1, b: 2), std::max(ilist: {5, 6, 1}), 2, std::min(ilist: {1, 2, 4})}); |
227 | // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
228 | // CHECK-FIXES: int max10 = std::max({1, 2, 5, 6, 1, 2, std::min({1, 2, 4})}); |
229 | |
230 | int typecastTest = std::max(a: std::max<int>(a: 0U, b: 0.0f), b: 0); |
231 | // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
232 | // CHECK-FIXES: int typecastTest = std::max({static_cast<int>(0U), static_cast<int>(0.0f), 0}); |
233 | |
234 | int typecastTest1 = std::max(a: std::max<long>(a: 0U, b: 0.0f), b: 0L); |
235 | // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
236 | // CHECK-FIXES: int typecastTest1 = std::max({static_cast<long>(0U), static_cast<long>(0.0f), 0L}); |
237 | |
238 | int typecastTest2 = std::max(a: std::max<int>(a: 10U, b: 20.0f), b: 30); |
239 | // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
240 | // CHECK-FIXES: int typecastTest2 = std::max({static_cast<int>(10U), static_cast<int>(20.0f), 30}); |
241 | |
242 | int typecastTest3 = std::max(a: std::max<int>(a: 0U, b: std::max<int>(a: 0.0f, b: 1.0f)), b: 0); |
243 | // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
244 | // CHECK-FIXES: int typecastTest3 = std::max({static_cast<int>(0U), static_cast<int>(0.0f), static_cast<int>(1.0f), 0}); |
245 | |
246 | #define max3f(a, b, c) std::max(a, std::max(b, c)) |
247 | // CHECK-FIXES: #define max3f(a, b, c) std::max(a, std::max(b, c)) |
248 | |
249 | #define value 4545 |
250 | int macroVarMax = std::max(value, b: std::max(a: 1, b: 2)); |
251 | // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
252 | // CHECK-FIXES: int macroVarMax = std::max({value, 1, 2}); |
253 | |
254 | #define value2 45U |
255 | int macroVarMax2 = std::max(a: 1, b: std::max<int>(value2, b: 2.0f)); |
256 | // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
257 | // CHECK-FIXES: int macroVarMax2 = std::max({1, static_cast<int>(value2), static_cast<int>(2.0f)}); |
258 | |
259 | // True-negative tests |
260 | int maxTN1 = std::max(a: 1, b: 2); |
261 | // CHECK-FIXES: int maxTN1 = std::max(1, 2); |
262 | |
263 | int maxTN2 = std::max(ilist: {1, 2, 3}); |
264 | // CHECK-FIXES: int maxTN2 = std::max({1, 2, 3}); |
265 | |
266 | int maxTN3 = std::max(ilist: {1, 2, 3}, comp: less_than); |
267 | // CHECK-FIXES: int maxTN3 = std::max({1, 2, 3}, less_than); |
268 | |
269 | // non-trivial types |
270 | struct A { |
271 | int a; |
272 | A(int a) : a(a) {} |
273 | bool operator<(const A &rhs) const { return a < rhs.a; } |
274 | }; |
275 | |
276 | A maxNT1 = std::max(a: A(1), b: A(2)); |
277 | // CHECK-FIXES: A maxNT1 = std::max(A(1), A(2)); |
278 | |
279 | A maxNT2 = std::max(a: A(1), b: std::max(a: A(2), b: A(3))); |
280 | // CHECK-FIXES: A maxNT2 = std::max(A(1), std::max(A(2), A(3))); |
281 | |
282 | A maxNT3 = std::max(a: A(1), b: std::max(a: A(2), b: A(3)), comp: [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); |
283 | // CHECK-FIXES: A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); |
284 | |
285 | // Trivial type with size greater than 32 |
286 | struct B { |
287 | // 9*4 = 36 bytes > 32 bytes |
288 | int a[9]; |
289 | |
290 | bool operator<(const B& rhs) const { |
291 | return a[0] < rhs.a[0]; |
292 | } |
293 | }; |
294 | |
295 | B maxTT1 = std::max(a: B(), b: B()); |
296 | // CHECK-FIXES: B maxTT1 = std::max(B(), B()); |
297 | |
298 | B maxTT2 = std::max(a: B(), b: std::max(a: B(), b: B())); |
299 | // CHECK-FIXES: B maxTT2 = std::max(B(), std::max(B(), B())); |
300 | |
301 | B maxTT3 = std::max(a: B(), b: std::max(a: B(), b: B()), comp: [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); |
302 | // CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); |
303 | |
304 | struct GH91982 { |
305 | int fun0Args(); |
306 | int fun1Arg(int a); |
307 | int fun2Args(int a, int b); |
308 | int fun3Args(int a, int b, int c); |
309 | int fun4Args(int a, int b, int c, int d); |
310 | |
311 | int foo() { |
312 | return std::max( |
313 | a: fun0Args(), |
314 | b: std::max(a: fun1Arg(a: 0), |
315 | b: std::max(a: fun2Args(a: 0, b: 1), |
316 | b: std::max(a: fun3Args(a: 0, b: 1, c: 2), b: fun4Args(a: 0, b: 1, c: 2, d: 3))))); |
317 | // CHECK-MESSAGES: :[[@LINE-5]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] |
318 | // CHECK-FIXES: return std::max( |
319 | // CHECK-FIXES-NEXT: {fun0Args(), |
320 | // CHECK-FIXES-NEXT: fun1Arg(0), |
321 | // CHECK-FIXES-NEXT: fun2Args(0, 1), |
322 | // CHECK-FIXES-NEXT: fun3Args(0, 1, 2), fun4Args(0, 1, 2, 3)}); |
323 | } |
324 | }; |
325 | |
326 | struct GH107594 { |
327 | int foo(int a, int b, char c) { |
328 | return std::max<int>(ilist: {a, b, c}); |
329 | } |
330 | }; |
331 | |
332 | } // namespace |
333 | |
334 | |