1// RUN: %check_clang_tidy --match-partial-fixes %s modernize-min-max-use-initializer-list %t
2
3// CHECK-FIXES: #include <algorithm>
4namespace utils {
5template <typename T>
6T max(T a, T b) {
7 return (a < b) ? b : a;
8}
9} // namespace utils
10
11namespace std {
12template< class T >
13struct 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
21template<class ForwardIt>
22ForwardIt 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
36template<class ForwardIt, class Compare>
37ForwardIt 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
51template<class ForwardIt>
52ForwardIt 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
66template<class ForwardIt, class Compare>
67ForwardIt 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
81template< class T >
82const T& max( const T& a, const T& b ) {
83 return (a < b) ? b : a;
84};
85
86template< class T >
87T max(std::initializer_list<T> ilist)
88{
89 return *std::max_element(ilist.begin(), ilist.end());
90}
91
92template< class T, class Compare >
93const T& max( const T& a, const T& b, Compare comp ) {
94 return (comp(a, b)) ? b : a;
95};
96
97template< class T, class Compare >
98T max(std::initializer_list<T> ilist, Compare comp) {
99 return *std::max_element(ilist.begin(), ilist.end(), comp);
100};
101
102template< class T >
103const T& min( const T& a, const T& b ) {
104 return (b < a) ? b : a;
105};
106
107template< class T >
108T min(std::initializer_list<T> ilist)
109{
110 return *std::min_element(ilist.begin(), ilist.end());
111}
112
113
114template< class T, class Compare >
115const T& min( const T& a, const T& b, Compare comp ) {
116 return (comp(b, a)) ? b : a;
117};
118
119template< class T, class Compare >
120T min(std::initializer_list<T> ilist, Compare comp) {
121 return *std::min_element(ilist.begin(), ilist.end(), comp);
122};
123
124} // namespace std
125
126using namespace std;
127
128namespace {
129bool fless_than(int a, int b) {
130return a < b;
131}
132
133bool fgreater_than(int a, int b) {
134return a > b;
135}
136auto less_than = [](int a, int b) { return a < b; };
137auto greater_than = [](int a, int b) { return a > b; };
138
139int 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
143int 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
147int 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
151int 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
155int 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
159int 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
164int 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
168int 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
172int 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
177int 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
182int 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
185int 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
188int 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
191int 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
194int 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
198int 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
202int 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
205int 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
208int 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
211int 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
214int 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
218int 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
222int 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
226int 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
230int 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
234int 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
238int 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
242int 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
250int 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
255int 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
260int maxTN1 = std::max(a: 1, b: 2);
261// CHECK-FIXES: int maxTN1 = std::max(1, 2);
262
263int maxTN2 = std::max(ilist: {1, 2, 3});
264// CHECK-FIXES: int maxTN2 = std::max({1, 2, 3});
265
266int 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
270struct A {
271 int a;
272 A(int a) : a(a) {}
273 bool operator<(const A &rhs) const { return a < rhs.a; }
274};
275
276A maxNT1 = std::max(a: A(1), b: A(2));
277// CHECK-FIXES: A maxNT1 = std::max(A(1), A(2));
278
279A 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
282A 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
286struct 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
295B maxTT1 = std::max(a: B(), b: B());
296// CHECK-FIXES: B maxTT1 = std::max(B(), B());
297
298B 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
301B 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
304struct 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
326struct 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

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp