forked from OSchip/llvm-project
425 lines
10 KiB
C++
425 lines
10 KiB
C++
// 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);
|
|
}
|