| // 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 <typename T> |
| class vector { |
| public: |
| void push_back(const T &) {} |
| void push_back(T &&) {} |
| |
| template <typename... Args> |
| void emplace_back(Args &&... args){}; |
| ~vector(); |
| }; |
| template <typename T> |
| class list { |
| public: |
| void push_back(const T &) {} |
| void push_back(T &&) {} |
| |
| template <typename... Args> |
| void emplace_back(Args &&... args){}; |
| ~list(); |
| }; |
| |
| template <typename T> |
| class deque { |
| public: |
| void push_back(const T &) {} |
| void push_back(T &&) {} |
| |
| template <typename... Args> |
| void emplace_back(Args &&... args){}; |
| ~deque(); |
| }; |
| |
| template <typename T1, typename T2> |
| class pair { |
| public: |
| pair() = default; |
| pair(const pair &) = default; |
| pair(pair &&) = default; |
| |
| pair(const T1 &, const T2 &) {} |
| pair(T1 &&, T2 &&) {} |
| |
| template <class U1, class U2> |
| pair(const pair<U1, U2> &p){}; |
| template <class U1, class U2> |
| pair(pair<U1, U2> &&p){}; |
| }; |
| |
| template <typename T1, typename T2> |
| pair<T1, T2> make_pair(T1, T2) { |
| return pair<T1, T2>(); |
| }; |
| |
| template <typename T> |
| class unique_ptr { |
| public: |
| explicit unique_ptr(T *) {} |
| ~unique_ptr(); |
| }; |
| } // namespace std |
| |
| namespace llvm { |
| template <typename T> |
| class LikeASmallVector { |
| public: |
| void push_back(const T &) {} |
| void push_back(T &&) {} |
| |
| template <typename... Args> |
| void emplace_back(Args &&... args){}; |
| }; |
| |
| } // llvm |
| |
| void testInts() { |
| std::vector<int> 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<Something> 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 <typename ElemType> |
| void dependOnElem() { |
| std::vector<ElemType> v; |
| v.push_back(ElemType(42)); |
| } |
| |
| template <typename ContainerType> |
| void dependOnContainer() { |
| ContainerType v; |
| v.push_back(Something(42)); |
| } |
| |
| void callDependent() { |
| dependOnElem<Something>(); |
| dependOnContainer<std::vector<Something>>(); |
| } |
| |
| void test2() { |
| std::vector<Zoz> 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<int, long> getPair(); |
| }; |
| void testPair() { |
| std::vector<std::pair<int, int>> v; |
| v.push_back(std::pair<int, int>(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<std::pair<Something, Zoz>> v2; |
| v2.push_back(std::pair<Something, Zoz>(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<Base> v; |
| v.push_back(Derived(nullptr, Something{})); |
| } |
| |
| void testNewExpr() { |
| std::vector<Derived> v; |
| v.push_back(Derived(new int, Something{})); |
| } |
| |
| void testSpaces() { |
| std::vector<Something> 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<Base> 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<int *> v; |
| v.push_back(new int(5)); |
| |
| std::vector<std::unique_ptr<int>> v2; |
| v2.push_back(std::unique_ptr<int>(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<int>(ptr)); |
| // Same here |
| } |
| |
| void testMakePair() { |
| std::vector<std::pair<int, int>> 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<Something> 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<Something> d; |
| d.push_back(Something(42)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back |
| // CHECK-FIXES: d.emplace_back(42); |
| |
| llvm::LikeASmallVector<Something> 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<IntWrapper> 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<Something> 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<A> v; |
| v.push_back(A({1, 2})); |
| |
| std::vector<B> vb; |
| vb.push_back(B({10, 42})); |
| } |
| |
| struct Bitfield { |
| unsigned bitfield : 1; |
| unsigned notBitfield; |
| }; |
| |
| void testBitfields() { |
| std::vector<Something> 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<PrivateCtor> 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<WithDtor> v; |
| |
| v.push_back(WithDtor(42)); |
| // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back |
| // CHECK-FIXES: v.emplace_back(42); |
| } |