1 // RUN: %check_clang_tidy %s modernize-use-emplace %t -- \
2 // RUN: -config="{CheckOptions: \
3 // RUN: [{key: modernize-use-emplace.ContainersWithPushBack, \
4 // RUN: value: '::std::vector; ::std::list; ::std::deque; llvm::LikeASmallVector'}, \
5 // RUN: {key: modernize-use-emplace.TupleTypes, \
6 // RUN: value: '::std::pair; std::tuple; ::test::Single'}, \
7 // RUN: {key: modernize-use-emplace.TupleMakeFunctions, \
8 // RUN: value: '::std::make_pair; ::std::make_tuple; ::test::MakeSingle'}] \
9 // RUN: }"
10
11 namespace std {
12 template <typename>
13 class initializer_list
14 {
15 public:
initializer_list()16 initializer_list() noexcept {}
17 };
18
19 template <typename T>
20 class vector {
21 public:
22 vector() = default;
vector(initializer_list<T>)23 vector(initializer_list<T>) {}
24
push_back(const T &)25 void push_back(const T &) {}
push_back(T &&)26 void push_back(T &&) {}
27
28 template <typename... Args>
emplace_back(Args &&...args)29 void emplace_back(Args &&... args){};
30 ~vector();
31 };
32 template <typename T>
33 class list {
34 public:
push_back(const T &)35 void push_back(const T &) {}
push_back(T &&)36 void push_back(T &&) {}
37
38 template <typename... Args>
emplace_back(Args &&...args)39 void emplace_back(Args &&... args){};
40 ~list();
41 };
42
43 template <typename T>
44 class deque {
45 public:
push_back(const T &)46 void push_back(const T &) {}
push_back(T &&)47 void push_back(T &&) {}
48
49 template <typename... Args>
emplace_back(Args &&...args)50 void emplace_back(Args &&... args){};
51 ~deque();
52 };
53
54 template <typename T> struct remove_reference { using type = T; };
55 template <typename T> struct remove_reference<T &> { using type = T; };
56 template <typename T> struct remove_reference<T &&> { using type = T; };
57
58 template <typename T1, typename T2> class pair {
59 public:
60 pair() = default;
61 pair(const pair &) = default;
62 pair(pair &&) = default;
63
pair(const T1 &,const T2 &)64 pair(const T1 &, const T2 &) {}
pair(T1 &&,T2 &&)65 pair(T1 &&, T2 &&) {}
66
pair(const pair<U1,U2> &)67 template <typename U1, typename U2> pair(const pair<U1, U2> &){};
pair(pair<U1,U2> &&)68 template <typename U1, typename U2> pair(pair<U1, U2> &&){};
69 };
70
71 template <typename T1, typename T2>
72 pair<typename remove_reference<T1>::type, typename remove_reference<T2>::type>
make_pair(T1 &&,T2 &&)73 make_pair(T1 &&, T2 &&) {
74 return {};
75 };
76
77 template <typename... Ts> class tuple {
78 public:
79 tuple() = default;
80 tuple(const tuple &) = default;
81 tuple(tuple &&) = default;
82
tuple(const Ts &...)83 tuple(const Ts &...) {}
tuple(Ts &&...)84 tuple(Ts &&...) {}
85
tuple(const tuple<Us...> &)86 template <typename... Us> tuple(const tuple<Us...> &){};
tuple(tuple<Us...> &&)87 template <typename... Us> tuple(tuple<Us...> &&) {}
88
tuple(const pair<U1,U2> &)89 template <typename U1, typename U2> tuple(const pair<U1, U2> &) {
90 static_assert(sizeof...(Ts) == 2, "Wrong tuple size");
91 };
tuple(pair<U1,U2> &&)92 template <typename U1, typename U2> tuple(pair<U1, U2> &&) {
93 static_assert(sizeof...(Ts) == 2, "Wrong tuple size");
94 };
95 };
96
97 template <typename... Ts>
make_tuple(Ts &&...)98 tuple<typename remove_reference<Ts>::type...> make_tuple(Ts &&...) {
99 return {};
100 }
101
102 template <typename T>
103 class unique_ptr {
104 public:
unique_ptr(T *)105 explicit unique_ptr(T *) {}
106 ~unique_ptr();
107 };
108 } // namespace std
109
110 namespace llvm {
111 template <typename T>
112 class LikeASmallVector {
113 public:
push_back(const T &)114 void push_back(const T &) {}
push_back(T &&)115 void push_back(T &&) {}
116
117 template <typename... Args>
emplace_back(Args &&...args)118 void emplace_back(Args &&... args){};
119 };
120
121 } // llvm
122
testInts()123 void testInts() {
124 std::vector<int> v;
125 v.push_back(42);
126 v.push_back(int(42));
127 v.push_back(int{42});
128 v.push_back(42.0);
129 int z;
130 v.push_back(z);
131 }
132
133 struct Something {
SomethingSomething134 Something(int a, int b = 41) {}
SomethingSomething135 Something() {}
136 void push_back(Something);
getIntSomething137 int getInt() { return 42; }
138 };
139
140 struct Convertable {
operator SomethingConvertable141 operator Something() { return Something{}; }
142 };
143
144 struct Zoz {
ZozZoz145 Zoz(Something, int = 42) {}
146 };
147
getZoz(Something s)148 Zoz getZoz(Something s) { return Zoz(s); }
149
test_Something()150 void test_Something() {
151 std::vector<Something> v;
152
153 v.push_back(Something(1, 2));
154 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back instead of push_back [modernize-use-emplace]
155 // CHECK-FIXES: v.emplace_back(1, 2);
156
157 v.push_back(Something{1, 2});
158 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
159 // CHECK-FIXES: v.emplace_back(1, 2);
160
161 v.push_back(Something());
162 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
163 // CHECK-FIXES: v.emplace_back();
164
165 v.push_back(Something{});
166 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
167 // CHECK-FIXES: v.emplace_back();
168
169 Something Different;
170 v.push_back(Something(Different.getInt(), 42));
171 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
172 // CHECK-FIXES: v.emplace_back(Different.getInt(), 42);
173
174 v.push_back(Different.getInt());
175 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
176 // CHECK-FIXES: v.emplace_back(Different.getInt());
177
178 v.push_back(42);
179 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
180 // CHECK-FIXES: v.emplace_back(42);
181
182 Something temporary(42, 42);
183 temporary.push_back(temporary);
184 v.push_back(temporary);
185
186 v.push_back(Convertable());
187 v.push_back(Convertable{});
188 Convertable s;
189 v.push_back(s);
190 }
191
192 template <typename ElemType>
dependOnElem()193 void dependOnElem() {
194 std::vector<ElemType> v;
195 v.push_back(ElemType(42));
196 }
197
198 template <typename ContainerType>
dependOnContainer()199 void dependOnContainer() {
200 ContainerType v;
201 v.push_back(Something(42));
202 }
203
callDependent()204 void callDependent() {
205 dependOnElem<Something>();
206 dependOnContainer<std::vector<Something>>();
207 }
208
test2()209 void test2() {
210 std::vector<Zoz> v;
211 v.push_back(Zoz(Something(21, 37)));
212 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
213 // CHECK-FIXES: v.emplace_back(Something(21, 37));
214
215 v.push_back(Zoz(Something(21, 37), 42));
216 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
217 // CHECK-FIXES: v.emplace_back(Something(21, 37), 42);
218
219 v.push_back(getZoz(Something(1, 2)));
220 }
221
222 struct GetPair {
223 std::pair<int, long> getPair();
224 };
testPair()225 void testPair() {
226 std::vector<std::pair<int, int>> v;
227 v.push_back(std::pair<int, int>(1, 2));
228 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
229 // CHECK-FIXES: v.emplace_back(1, 2);
230
231 GetPair g;
232 v.push_back(g.getPair());
233 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
234 // CHECK-FIXES: v.emplace_back(g.getPair());
235
236 std::vector<std::pair<Something, Zoz>> v2;
237 v2.push_back(std::pair<Something, Zoz>(Something(42, 42), Zoz(Something(21, 37))));
238 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back
239 // CHECK-FIXES: v2.emplace_back(Something(42, 42), Zoz(Something(21, 37)));
240 }
241
testTuple()242 void testTuple() {
243 std::vector<std::tuple<bool, char, int>> v;
244 v.push_back(std::tuple<bool, char, int>(false, 'x', 1));
245 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
246 // CHECK-FIXES: v.emplace_back(false, 'x', 1);
247
248 v.push_back(std::tuple<bool, char, int>{false, 'y', 2});
249 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
250 // CHECK-FIXES: v.emplace_back(false, 'y', 2);
251
252 v.push_back({true, 'z', 3});
253 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
254 // CHECK-FIXES: v.emplace_back(true, 'z', 3);
255
256 std::vector<std::tuple<int, bool>> x;
257 x.push_back(std::make_pair(1, false));
258 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
259 // CHECK-FIXES: x.emplace_back(1, false);
260
261 x.push_back(std::make_pair(2LL, 1));
262 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
263 // CHECK-FIXES: x.emplace_back(2LL, 1);
264 }
265
266 struct Base {
267 Base(int, int *, int = 42);
268 };
269
270 struct Derived : Base {
DerivedDerived271 Derived(int *, Something) : Base(42, nullptr) {}
272 };
273
testDerived()274 void testDerived() {
275 std::vector<Base> v;
276 v.push_back(Derived(nullptr, Something{}));
277 }
278
testNewExpr()279 void testNewExpr() {
280 std::vector<Derived> v;
281 v.push_back(Derived(new int, Something{}));
282 }
283
testSpaces()284 void testSpaces() {
285 std::vector<Something> v;
286
287 // clang-format off
288
289 v.push_back(Something(1, //arg1
290 2 // arg2
291 ) // Something
292 );
293 // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use emplace_back
294 // CHECK-FIXES: v.emplace_back(1, //arg1
295 // CHECK-FIXES: 2 // arg2
296 // CHECK-FIXES: // Something
297 // CHECK-FIXES: );
298
299 v.push_back( Something (1, 2) );
300 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
301 // CHECK-FIXES: v.emplace_back(1, 2 );
302
303 v.push_back( Something {1, 2} );
304 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
305 // CHECK-FIXES: v.emplace_back(1, 2 );
306
307 v.push_back( Something {} );
308 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
309 // CHECK-FIXES: v.emplace_back( );
310
311 v.push_back(
312 Something(1, 2) );
313 // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use emplace_back
314 // CHECK-FIXES: v.emplace_back(1, 2 );
315
316 std::vector<Base> v2;
317 v2.push_back(
318 Base(42, nullptr));
319 // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: use emplace_back
320 // CHECK-FIXES: v2.emplace_back(42, nullptr);
321
322 // clang-format on
323 }
324
testPointers()325 void testPointers() {
326 std::vector<int *> v;
327 v.push_back(new int(5));
328
329 std::vector<std::unique_ptr<int>> v2;
330 v2.push_back(std::unique_ptr<int>(new int(42)));
331 // This call can't be replaced with emplace_back.
332 // If emplacement will fail (not enough memory to add to vector)
333 // we will have leak of int because unique_ptr won't be constructed
334 // (and destructed) as in push_back case.
335
336 auto *ptr = new int;
337 v2.push_back(std::unique_ptr<int>(ptr));
338 // Same here
339 }
340
testMakePair()341 void testMakePair() {
342 std::vector<std::pair<int, int>> v;
343 v.push_back(std::make_pair(1, 2));
344 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
345 // CHECK-FIXES: v.emplace_back(1, 2);
346
347 v.push_back(std::make_pair(42LL, 13));
348 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
349 // CHECK-FIXES: v.emplace_back(42LL, 13);
350
351 v.push_back(std::make_pair<char, char>(0, 3));
352 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
353 // CHECK-FIXES: v.emplace_back(std::make_pair<char, char>(0, 3));
354 //
355 // Even though the call above could be turned into v.emplace_back(0, 3),
356 // we don't eliminate the make_pair call here, because of the explicit
357 // template parameters provided. make_pair's arguments can be convertible
358 // to its explicitly provided template parameter, but not to the pair's
359 // element type. The examples below illustrate the problem.
360 struct D {
361 D(...) {}
362 operator char() const { return 0; }
363 };
364 v.push_back(std::make_pair<D, int>(Something(), 2));
365 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
366 // CHECK-FIXES: v.emplace_back(std::make_pair<D, int>(Something(), 2));
367
368 struct X {
369 X(std::pair<int, int>) {}
370 };
371 std::vector<X> x;
372 x.push_back(std::make_pair(1, 2));
373 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
374 // CHECK-FIXES: x.emplace_back(std::make_pair(1, 2));
375 // make_pair cannot be removed here, as X is not constructible with two ints.
376
377 struct Y {
378 Y(std::pair<int, int>&&) {}
379 };
380 std::vector<Y> y;
381 y.push_back(std::make_pair(2, 3));
382 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
383 // CHECK-FIXES: y.emplace_back(std::make_pair(2, 3));
384 // make_pair cannot be removed here, as Y is not constructible with two ints.
385 }
386
testMakeTuple()387 void testMakeTuple() {
388 std::vector<std::tuple<int, bool, char>> v;
389 v.push_back(std::make_tuple(1, true, 'v'));
390 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
391 // CHECK-FIXES: v.emplace_back(1, true, 'v');
392
393 v.push_back(std::make_tuple(2ULL, 1, 0));
394 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
395 // CHECK-FIXES: v.emplace_back(2ULL, 1, 0);
396
397 v.push_back(std::make_tuple<long long, int, int>(3LL, 1, 0));
398 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
399 // CHECK-FIXES: v.emplace_back(std::make_tuple<long long, int, int>(3LL, 1, 0));
400 // make_tuple is not removed when there are explicit template
401 // arguments provided.
402 }
403
404 namespace test {
405 template <typename T> struct Single {
406 Single() = default;
407 Single(const Single &) = default;
408 Single(Single &&) = default;
409
Singletest::Single410 Single(const T &) {}
Singletest::Single411 Single(T &&) {}
412
Singletest::Single413 template <typename U> Single(const Single<U> &) {}
Singletest::Single414 template <typename U> Single(Single<U> &&) {}
415
Singletest::Single416 template <typename U> Single(const std::tuple<U> &) {}
Singletest::Single417 template <typename U> Single(std::tuple<U> &&) {}
418 };
419
420 template <typename T>
MakeSingle(T &&)421 Single<typename std::remove_reference<T>::type> MakeSingle(T &&) {
422 return {};
423 }
424 } // namespace test
425
testOtherTuples()426 void testOtherTuples() {
427 std::vector<test::Single<int>> v;
428 v.push_back(test::Single<int>(1));
429 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
430 // CHECK-FIXES: v.emplace_back(1);
431
432 v.push_back({2});
433 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
434 // CHECK-FIXES: v.emplace_back(2);
435
436 v.push_back(test::MakeSingle(3));
437 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
438 // CHECK-FIXES: v.emplace_back(3);
439
440 v.push_back(test::MakeSingle<long long>(4));
441 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
442 // CHECK-FIXES: v.emplace_back(test::MakeSingle<long long>(4));
443 // We don't remove make functions with explicit template parameters.
444
445 v.push_back(test::MakeSingle(5LL));
446 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
447 // CHECK-FIXES: v.emplace_back(5LL);
448
449 v.push_back(std::make_tuple(6));
450 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
451 // CHECK-FIXES: v.emplace_back(6);
452
453 v.push_back(std::make_tuple(7LL));
454 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
455 // CHECK-FIXES: v.emplace_back(7LL);
456 }
457
testOtherContainers()458 void testOtherContainers() {
459 std::list<Something> l;
460 l.push_back(Something(42, 41));
461 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
462 // CHECK-FIXES: l.emplace_back(42, 41);
463
464 std::deque<Something> d;
465 d.push_back(Something(42));
466 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
467 // CHECK-FIXES: d.emplace_back(42);
468
469 llvm::LikeASmallVector<Something> ls;
470 ls.push_back(Something(42));
471 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back
472 // CHECK-FIXES: ls.emplace_back(42);
473 }
474
475 class IntWrapper {
476 public:
IntWrapper(int x)477 IntWrapper(int x) : value(x) {}
operator +(const IntWrapper other) const478 IntWrapper operator+(const IntWrapper other) const {
479 return IntWrapper(value + other.value);
480 }
481
482 private:
483 int value;
484 };
485
testMultipleOpsInPushBack()486 void testMultipleOpsInPushBack() {
487 std::vector<IntWrapper> v;
488 v.push_back(IntWrapper(42) + IntWrapper(27));
489 }
490
491 // Macro tests.
492 #define PUSH_BACK_WHOLE(c, x) c.push_back(x)
493 #define PUSH_BACK_NAME push_back
494 #define PUSH_BACK_ARG(x) (x)
495 #define SOME_OBJ Something(10)
496 #define MILLION 3
497 #define SOME_WEIRD_PUSH(v) v.push_back(Something(
498 #define OPEN (
499 #define CLOSE )
macroTest()500 void macroTest() {
501 std::vector<Something> v;
502 Something s;
503
504 PUSH_BACK_WHOLE(v, Something(5, 6));
505 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use emplace_back
506
507 v.PUSH_BACK_NAME(Something(5));
508 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
509
510 v.push_back PUSH_BACK_ARG(Something(5, 6));
511 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
512
513 v.push_back(SOME_OBJ);
514 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
515
516 v.push_back(Something(MILLION));
517 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
518 // CHECK-FIXES: v.emplace_back(MILLION);
519
520 // clang-format off
521 v.push_back( Something OPEN 3 CLOSE );
522 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
523 // clang-format on
524 PUSH_BACK_WHOLE(s, Something(1));
525 }
526
527 struct A {
528 int value1, value2;
529 };
530
531 struct B {
BB532 B(A) {}
533 };
534
535 struct C {
536 int value1, value2, value3;
537 };
538
testAggregation()539 void testAggregation() {
540 // This should not be noticed or fixed; after the correction, the code won't
541 // compile.
542
543 std::vector<A> v;
544 v.push_back(A({1, 2}));
545
546 std::vector<B> vb;
547 vb.push_back(B({10, 42}));
548 }
549
550 struct Bitfield {
551 unsigned bitfield : 1;
552 unsigned notBitfield;
553 };
554
testBitfields()555 void testBitfields() {
556 std::vector<Something> v;
557 Bitfield b;
558 v.push_back(Something(42, b.bitfield));
559 v.push_back(Something(b.bitfield));
560
561 v.push_back(Something(42, b.notBitfield));
562 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
563 // CHECK-FIXES: v.emplace_back(42, b.notBitfield);
564 int var;
565 v.push_back(Something(42, var));
566 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
567 // CHECK-FIXES: v.emplace_back(42, var);
568 }
569
570 class PrivateCtor {
571 PrivateCtor(int z);
572
573 public:
doStuff()574 void doStuff() {
575 std::vector<PrivateCtor> v;
576 // This should not change it because emplace back doesn't have permission.
577 // Check currently doesn't support friend declarations because pretty much
578 // nobody would want to be friend with std::vector :(.
579 v.push_back(PrivateCtor(42));
580 }
581 };
582
583 struct WithDtor {
WithDtorWithDtor584 WithDtor(int) {}
585 ~WithDtor();
586 };
587
testWithDtor()588 void testWithDtor() {
589 std::vector<WithDtor> v;
590
591 v.push_back(WithDtor(42));
592 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
593 // CHECK-FIXES: v.emplace_back(42);
594 }
595
testInitializerList()596 void testInitializerList() {
597 std::vector<std::vector<int>> v;
598 v.push_back(std::vector<int>({1}));
599 // Test against the bug reported in PR32896.
600
601 v.push_back({{2}});
602
603 using PairIntVector = std::pair<int, std::vector<int>>;
604 std::vector<PairIntVector> x;
605 x.push_back(PairIntVector(3, {4}));
606 x.push_back({5, {6}});
607 }
608