// RUN: %check_clang_tidy %s modernize-use-emplace %t -- \ // RUN: -config="{CheckOptions: \ // RUN: [{key: modernize-use-emplace.ContainersWithPushBack, \ // RUN: value: '::std::vector; ::std::list; ::std::deque; llvm::LikeASmallVector'}]}" -- -std=c++11 namespace std { template class vector { public: void push_back(const T &) {} void push_back(T &&) {} template void emplace_back(Args &&... args){}; ~vector(); }; template class list { public: void push_back(const T &) {} void push_back(T &&) {} template void emplace_back(Args &&... args){}; ~list(); }; template class deque { public: void push_back(const T &) {} void push_back(T &&) {} template void emplace_back(Args &&... args){}; ~deque(); }; template class pair { public: pair() = default; pair(const pair &) = default; pair(pair &&) = default; pair(const T1 &, const T2 &) {} pair(T1 &&, T2 &&) {} template pair(const pair &p){}; template pair(pair &&p){}; }; template pair make_pair(T1, T2) { return pair(); }; template class unique_ptr { public: explicit unique_ptr(T *) {} ~unique_ptr(); }; } // namespace std namespace llvm { template class LikeASmallVector { public: void push_back(const T &) {} void push_back(T &&) {} template void emplace_back(Args &&... args){}; }; } // llvm void testInts() { std::vector v; v.push_back(42); v.push_back(int(42)); v.push_back(int{42}); v.push_back(42.0); int z; v.push_back(z); } struct Something { Something(int a, int b = 41) {} Something() {} void push_back(Something); int getInt() { return 42; } }; struct Convertable { operator Something() { return Something{}; } }; struct Zoz { Zoz(Something, int = 42) {} }; Zoz getZoz(Something s) { return Zoz(s); } void test_Something() { std::vector v; v.push_back(Something(1, 2)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back instead of push_back [modernize-use-emplace] // CHECK-FIXES: v.emplace_back(1, 2); v.push_back(Something{1, 2}); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, 2); v.push_back(Something()); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(); v.push_back(Something{}); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(); Something Different; v.push_back(Something(Different.getInt(), 42)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(Different.getInt(), 42); v.push_back(Different.getInt()); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(Different.getInt()); v.push_back(42); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(42); Something temporary(42, 42); temporary.push_back(temporary); v.push_back(temporary); v.push_back(Convertable()); v.push_back(Convertable{}); Convertable s; v.push_back(s); } template void dependOnElem() { std::vector v; v.push_back(ElemType(42)); } template void dependOnContainer() { ContainerType v; v.push_back(Something(42)); } void callDependent() { dependOnElem(); dependOnContainer>(); } void test2() { std::vector v; v.push_back(Zoz(Something(21, 37))); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(Something(21, 37)); v.push_back(Zoz(Something(21, 37), 42)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(Something(21, 37), 42); v.push_back(getZoz(Something(1, 2))); } struct GetPair { std::pair getPair(); }; void testPair() { std::vector> v; v.push_back(std::pair(1, 2)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, 2); GetPair g; v.push_back(g.getPair()); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(g.getPair()); std::vector> v2; v2.push_back(std::pair(Something(42, 42), Zoz(Something(21, 37)))); // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back // CHECK-FIXES: v2.emplace_back(Something(42, 42), Zoz(Something(21, 37))); } struct Base { Base(int, int *, int = 42); }; struct Derived : Base { Derived(int *, Something) : Base(42, nullptr) {} }; void testDerived() { std::vector v; v.push_back(Derived(nullptr, Something{})); } void testNewExpr() { std::vector v; v.push_back(Derived(new int, Something{})); } void testSpaces() { std::vector v; // clang-format off v.push_back(Something(1, //arg1 2 // arg2 ) // Something ); // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, //arg1 // CHECK-FIXES: 2 // arg2 // CHECK-FIXES: // Something // CHECK-FIXES: ); v.push_back( Something (1, 2) ); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, 2 ); v.push_back( Something {1, 2} ); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, 2 ); v.push_back( Something {} ); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back( ); v.push_back( Something(1, 2) ); // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(1, 2 ); std::vector v2; v2.push_back( Base(42, nullptr)); // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: use emplace_back // CHECK-FIXES: v2.emplace_back(42, nullptr); // clang-format on } void testPointers() { std::vector v; v.push_back(new int(5)); std::vector> v2; v2.push_back(std::unique_ptr(new int(42))); // This call can't be replaced with emplace_back. // If emplacement will fail (not enough memory to add to vector) // we will have leak of int because unique_ptr won't be constructed // (and destructed) as in push_back case. auto *ptr = new int; v2.push_back(std::unique_ptr(ptr)); // Same here } void testMakePair() { std::vector> v; // FIXME: add functionality to change calls of std::make_pair v.push_back(std::make_pair(1, 2)); // FIXME: This is not a bug, but call of make_pair should be removed in the // future. This one matches because the return type of make_pair is different // than the pair itself. v.push_back(std::make_pair(42LL, 13)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(std::make_pair(42LL, 13)); } void testOtherCointainers() { std::list l; l.push_back(Something(42, 41)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: l.emplace_back(42, 41); std::deque d; d.push_back(Something(42)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: d.emplace_back(42); llvm::LikeASmallVector ls; ls.push_back(Something(42)); // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back // CHECK-FIXES: ls.emplace_back(42); } class IntWrapper { public: IntWrapper(int x) : value(x) {} IntWrapper operator+(const IntWrapper other) const { return IntWrapper(value + other.value); } private: int value; }; void testMultipleOpsInPushBack() { std::vector v; v.push_back(IntWrapper(42) + IntWrapper(27)); } // Macro tests. #define PUSH_BACK_WHOLE(c, x) c.push_back(x) #define PUSH_BACK_NAME push_back #define PUSH_BACK_ARG(x) (x) #define SOME_OBJ Something(10) #define MILLION 3 #define SOME_WEIRD_PUSH(v) v.push_back(Something( #define OPEN ( #define CLOSE ) void macroTest() { std::vector v; Something s; PUSH_BACK_WHOLE(v, Something(5, 6)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use emplace_back v.PUSH_BACK_NAME(Something(5)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back v.push_back PUSH_BACK_ARG(Something(5, 6)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back v.push_back(SOME_OBJ); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back v.push_back(Something(MILLION)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(MILLION); // clang-format off v.push_back( Something OPEN 3 CLOSE ); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // clang-format on PUSH_BACK_WHOLE(s, Something(1)); } struct A { int value1, value2; }; struct B { B(A) {} }; struct C { int value1, value2, value3; }; void testAggregation() { // This should not be noticed or fixed; after the correction, the code won't // compile. std::vector v; v.push_back(A({1, 2})); std::vector vb; vb.push_back(B({10, 42})); } struct Bitfield { unsigned bitfield : 1; unsigned notBitfield; }; void testBitfields() { std::vector v; Bitfield b; v.push_back(Something(42, b.bitfield)); v.push_back(Something(b.bitfield)); v.push_back(Something(42, b.notBitfield)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(42, b.notBitfield); int var; v.push_back(Something(42, var)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(42, var); } class PrivateCtor { PrivateCtor(int z); public: void doStuff() { std::vector v; // This should not change it because emplace back doesn't have permission. // Check currently doesn't support friend delcarations because pretty much // nobody would want to be friend with std::vector :(. v.push_back(PrivateCtor(42)); } }; struct WithDtor { WithDtor(int) {} ~WithDtor(); }; void testWithDtor() { std::vector v; v.push_back(WithDtor(42)); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back // CHECK-FIXES: v.emplace_back(42); }