189a1d03eSRichard // RUN: %check_clang_tidy %s performance-inefficient-vector-operation %t -- \ 289a1d03eSRichard // RUN: -format-style=llvm \ 389a1d03eSRichard // RUN: -config='{CheckOptions: \ 4e8a3ddafSNathan James // RUN: {performance-inefficient-vector-operation.EnableProto: true}}' 589a1d03eSRichard 689a1d03eSRichard namespace std { 789a1d03eSRichard 8*482c41e9SMital Ashok typedef decltype(sizeof 0) size_t; 989a1d03eSRichard 1089a1d03eSRichard template<class E> class initializer_list { 1189a1d03eSRichard public: 1289a1d03eSRichard using value_type = E; 1389a1d03eSRichard using reference = E&; 1489a1d03eSRichard using const_reference = const E&; 1589a1d03eSRichard using size_type = size_t; 1689a1d03eSRichard using iterator = const E*; 1789a1d03eSRichard using const_iterator = const E*; 18*482c41e9SMital Ashok iterator p; 19*482c41e9SMital Ashok size_t sz; 2089a1d03eSRichard initializer_list(); 2189a1d03eSRichard size_t size() const; // number of elements 2289a1d03eSRichard const E* begin() const; // first element 2389a1d03eSRichard const E* end() const; // one past the last element 2489a1d03eSRichard }; 2589a1d03eSRichard 2689a1d03eSRichard // initializer list range access 2789a1d03eSRichard template<class E> const E* begin(initializer_list<E> il); 2889a1d03eSRichard template<class E> const E* end(initializer_list<E> il); 2989a1d03eSRichard 3089a1d03eSRichard template <class T> 3189a1d03eSRichard class vector { 3289a1d03eSRichard public: 3389a1d03eSRichard typedef T* iterator; 3489a1d03eSRichard typedef const T* const_iterator; 3589a1d03eSRichard typedef T& reference; 3689a1d03eSRichard typedef const T& const_reference; 3789a1d03eSRichard typedef size_t size_type; 3889a1d03eSRichard 3989a1d03eSRichard explicit vector(); 4089a1d03eSRichard explicit vector(size_type n); 4189a1d03eSRichard 4289a1d03eSRichard void push_back(const T& val); 4389a1d03eSRichard 4489a1d03eSRichard template <class... Args> void emplace_back(Args &&... args); 4589a1d03eSRichard 4689a1d03eSRichard void reserve(size_t n); 4789a1d03eSRichard void resize(size_t n); 4889a1d03eSRichard 4989a1d03eSRichard size_t size() const; 5089a1d03eSRichard const_reference operator[] (size_type) const; 5189a1d03eSRichard reference operator[] (size_type); 5289a1d03eSRichard 5389a1d03eSRichard const_iterator begin() const; 5489a1d03eSRichard const_iterator end() const; 5589a1d03eSRichard }; 5689a1d03eSRichard } // namespace std 5789a1d03eSRichard 5889a1d03eSRichard class Foo { 5989a1d03eSRichard public: 6089a1d03eSRichard explicit Foo(int); 6189a1d03eSRichard }; 6289a1d03eSRichard 6389a1d03eSRichard class Bar { 6489a1d03eSRichard public: 6589a1d03eSRichard Bar(int); 6689a1d03eSRichard }; 6789a1d03eSRichard 6889a1d03eSRichard int Op(int); 6989a1d03eSRichard 7089a1d03eSRichard namespace proto2 { 7189a1d03eSRichard class MessageLite {}; 7289a1d03eSRichard class Message : public MessageLite {}; 7389a1d03eSRichard } // namespace proto2 7489a1d03eSRichard 7589a1d03eSRichard class FooProto : public proto2::Message { 7689a1d03eSRichard public: 7789a1d03eSRichard int *add_x(); // repeated int x; 7889a1d03eSRichard void add_x(int x); 7989a1d03eSRichard void mutable_x(); 8089a1d03eSRichard void mutable_y(); 8189a1d03eSRichard int add_z() const; // optional int add_z; 8289a1d03eSRichard }; 8389a1d03eSRichard 8489a1d03eSRichard class BarProto : public proto2::Message { 8589a1d03eSRichard public: 8689a1d03eSRichard int *add_x(); 8789a1d03eSRichard void add_x(int x); 8889a1d03eSRichard void mutable_x(); 8989a1d03eSRichard void mutable_y(); 9089a1d03eSRichard }; 9189a1d03eSRichard f(std::vector<int> & t)9289a1d03eSRichardvoid f(std::vector<int>& t) { 9389a1d03eSRichard { 9489a1d03eSRichard std::vector<int> v0; 9589a1d03eSRichard // CHECK-FIXES: v0.reserve(10); 9689a1d03eSRichard for (int i = 0; i < 10; ++i) 9789a1d03eSRichard v0.push_back(i); 9889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop 9989a1d03eSRichard } 10089a1d03eSRichard { 10189a1d03eSRichard std::vector<int> v1; 10289a1d03eSRichard // CHECK-FIXES: v1.reserve(10); 10389a1d03eSRichard for (int i = 0; i < 10; i++) 10489a1d03eSRichard v1.push_back(i); 10589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 10689a1d03eSRichard } 10789a1d03eSRichard { 10889a1d03eSRichard std::vector<int> v2; 10989a1d03eSRichard // CHECK-FIXES: v2.reserve(10); 11089a1d03eSRichard for (int i = 0; i < 10; ++i) 11189a1d03eSRichard v2.push_back(0); 11289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 11389a1d03eSRichard } 11489a1d03eSRichard { 11589a1d03eSRichard std::vector<int> v3; 11689a1d03eSRichard // CHECK-FIXES: v3.reserve(5); 11789a1d03eSRichard for (int i = 0; i < 5; ++i) { 11889a1d03eSRichard v3.push_back(i); 11989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 12089a1d03eSRichard } 12189a1d03eSRichard // CHECK-FIXES-NOT: v3.reserve(10); 12289a1d03eSRichard for (int i = 0; i < 10; ++i) { 12389a1d03eSRichard // No fix for this loop as we encounter the prior loops. 12489a1d03eSRichard v3.push_back(i); 12589a1d03eSRichard } 12689a1d03eSRichard } 12789a1d03eSRichard { 12889a1d03eSRichard std::vector<int> v4; 12989a1d03eSRichard std::vector<int> v5; 13089a1d03eSRichard v5.reserve(3); 13189a1d03eSRichard // CHECK-FIXES: v4.reserve(10); 13289a1d03eSRichard for (int i = 0; i < 10; ++i) 13389a1d03eSRichard v4.push_back(i); 13489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 13589a1d03eSRichard } 13689a1d03eSRichard { 13789a1d03eSRichard std::vector<int> v6; 13889a1d03eSRichard // CHECK-FIXES: v6.reserve(t.size()); 13989a1d03eSRichard for (std::size_t i = 0; i < t.size(); ++i) { 14089a1d03eSRichard v6.push_back(t[i]); 14189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 14289a1d03eSRichard } 14389a1d03eSRichard } 14489a1d03eSRichard { 14589a1d03eSRichard std::vector<int> v7; 14689a1d03eSRichard // CHECK-FIXES: v7.reserve(t.size() - 1); 14789a1d03eSRichard for (std::size_t i = 0; i < t.size() - 1; ++i) { 14889a1d03eSRichard v7.push_back(t[i]); 14989a1d03eSRichard } // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 15089a1d03eSRichard } 15189a1d03eSRichard { 15289a1d03eSRichard std::vector<int> v8; 15389a1d03eSRichard // CHECK-FIXES: v8.reserve(t.size()); 15489a1d03eSRichard for (const auto &e : t) { 15589a1d03eSRichard v8.push_back(e); 15689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 15789a1d03eSRichard } 15889a1d03eSRichard } 15989a1d03eSRichard { 16089a1d03eSRichard std::vector<int> v9; 16189a1d03eSRichard // CHECK-FIXES: v9.reserve(t.size()); 16289a1d03eSRichard for (const auto &e : t) { 16389a1d03eSRichard v9.push_back(Op(e)); 16489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 16589a1d03eSRichard } 16689a1d03eSRichard } 16789a1d03eSRichard { 16889a1d03eSRichard std::vector<Foo> v10; 16989a1d03eSRichard // CHECK-FIXES: v10.reserve(t.size()); 17089a1d03eSRichard for (const auto &e : t) { 17189a1d03eSRichard v10.push_back(Foo(e)); 17289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 17389a1d03eSRichard } 17489a1d03eSRichard } 17589a1d03eSRichard { 17689a1d03eSRichard std::vector<Bar> v11; 17789a1d03eSRichard // CHECK-FIXES: v11.reserve(t.size()); 17889a1d03eSRichard for (const auto &e : t) { 17989a1d03eSRichard v11.push_back(e); 18089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 18189a1d03eSRichard } 18289a1d03eSRichard } 18389a1d03eSRichard { 18489a1d03eSRichard std::vector<Foo> v12; 18589a1d03eSRichard // CHECK-FIXES: v12.reserve(t.size()); 18689a1d03eSRichard for (const auto &e : t) { 18789a1d03eSRichard v12.emplace_back(e); 18889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called 18989a1d03eSRichard } 19089a1d03eSRichard } 19189a1d03eSRichard 19289a1d03eSRichard { 19389a1d03eSRichard FooProto foo; 19489a1d03eSRichard // CHECK-FIXES: foo.mutable_x()->Reserve(5); 19589a1d03eSRichard for (int i = 0; i < 5; i++) { 19689a1d03eSRichard foo.add_x(i); 19789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'add_x' is called inside a loop; consider pre-allocating the container capacity before the loop 19889a1d03eSRichard } 19989a1d03eSRichard } 20089a1d03eSRichard 20189a1d03eSRichard // ---- Non-fixed Cases ---- 20289a1d03eSRichard { 20389a1d03eSRichard std::vector<int> z0; 20489a1d03eSRichard z0.reserve(20); 20589a1d03eSRichard // CHECK-FIXES-NOT: z0.reserve(10); 20689a1d03eSRichard // There is a "reserve" call already. 20789a1d03eSRichard for (int i = 0; i < 10; ++i) { 20889a1d03eSRichard z0.push_back(i); 20989a1d03eSRichard } 21089a1d03eSRichard } 21189a1d03eSRichard { 21289a1d03eSRichard std::vector<int> z1; 21389a1d03eSRichard z1.reserve(5); 21489a1d03eSRichard // CHECK-FIXES-NOT: z1.reserve(10); 21589a1d03eSRichard // There is a "reserve" call already. 21689a1d03eSRichard for (int i = 0; i < 10; ++i) { 21789a1d03eSRichard z1.push_back(i); 21889a1d03eSRichard } 21989a1d03eSRichard } 22089a1d03eSRichard { 22189a1d03eSRichard std::vector<int> z2; 22289a1d03eSRichard z2.resize(5); 22389a1d03eSRichard // CHECK-FIXES-NOT: z2.reserve(10); 22489a1d03eSRichard // There is a ref usage of v before the loop. 22589a1d03eSRichard for (int i = 0; i < 10; ++i) { 22689a1d03eSRichard z2.push_back(i); 22789a1d03eSRichard } 22889a1d03eSRichard } 22989a1d03eSRichard { 23089a1d03eSRichard std::vector<int> z3; 23189a1d03eSRichard z3.push_back(0); 23289a1d03eSRichard // CHECK-FIXES-NOT: z3.reserve(10); 23389a1d03eSRichard // There is a ref usage of v before the loop. 23489a1d03eSRichard for (int i = 0; i < 10; ++i) { 23589a1d03eSRichard z3.push_back(i); 23689a1d03eSRichard } 23789a1d03eSRichard } 23889a1d03eSRichard { 23989a1d03eSRichard std::vector<int> z4; 24089a1d03eSRichard f(z4); 24189a1d03eSRichard // CHECK-FIXES-NOT: z4.reserve(10); 24289a1d03eSRichard // There is a ref usage of z4 before the loop. 24389a1d03eSRichard for (int i = 0; i < 10; ++i) { 24489a1d03eSRichard z4.push_back(i); 24589a1d03eSRichard } 24689a1d03eSRichard } 24789a1d03eSRichard { 24889a1d03eSRichard std::vector<int> z5(20); 24989a1d03eSRichard // CHECK-FIXES-NOT: z5.reserve(10); 25089a1d03eSRichard // z5 is not constructed with default constructor. 25189a1d03eSRichard for (int i = 0; i < 10; ++i) { 25289a1d03eSRichard z5.push_back(i); 25389a1d03eSRichard } 25489a1d03eSRichard } 25589a1d03eSRichard { 25689a1d03eSRichard std::vector<int> z6; 25789a1d03eSRichard // CHECK-FIXES-NOT: z6.reserve(10); 25889a1d03eSRichard // For-loop is not started with 0. 25989a1d03eSRichard for (int i = 1; i < 10; ++i) { 26089a1d03eSRichard z6.push_back(i); 26189a1d03eSRichard } 26289a1d03eSRichard } 26389a1d03eSRichard { 26489a1d03eSRichard std::vector<int> z7; 26589a1d03eSRichard // CHECK-FIXES-NOT: z7.reserve(t.size()); 26689a1d03eSRichard // z7 isn't referenced in for-loop body. 26789a1d03eSRichard for (std::size_t i = 0; i < t.size(); ++i) { 26889a1d03eSRichard t.push_back(i); 26989a1d03eSRichard } 27089a1d03eSRichard } 27189a1d03eSRichard { 27289a1d03eSRichard std::vector<int> z8; 27389a1d03eSRichard int k; 27489a1d03eSRichard // CHECK-FIXES-NOT: z8.reserve(10); 27589a1d03eSRichard // For-loop isn't a fixable loop. 27689a1d03eSRichard for (std::size_t i = 0; k < 10; ++i) { 27789a1d03eSRichard z8.push_back(t[i]); 27889a1d03eSRichard } 27989a1d03eSRichard } 28089a1d03eSRichard { 28189a1d03eSRichard std::vector<int> z9; 28289a1d03eSRichard // CHECK-FIXES-NOT: z9.reserve(i + 1); 28389a1d03eSRichard // The loop end expression refers to the loop variable i. 28489a1d03eSRichard for (int i = 0; i < i + 1; i++) 28589a1d03eSRichard z9.push_back(i); 28689a1d03eSRichard } 28789a1d03eSRichard { 28889a1d03eSRichard std::vector<int> z10; 28989a1d03eSRichard int k; 29089a1d03eSRichard // CHECK-FIXES-NOT: z10.reserve(10); 29189a1d03eSRichard // For-loop isn't a fixable loop. 29289a1d03eSRichard for (std::size_t i = 0; i < 10; ++k) { 29389a1d03eSRichard z10.push_back(t[i]); 29489a1d03eSRichard } 29589a1d03eSRichard } 29689a1d03eSRichard { 29789a1d03eSRichard std::vector<int> z11; 29889a1d03eSRichard // initializer_list should not trigger the check. 29989a1d03eSRichard for (int e : {1, 2, 3, 4, 5}) { 30089a1d03eSRichard z11.push_back(e); 30189a1d03eSRichard } 30289a1d03eSRichard } 30389a1d03eSRichard { 30489a1d03eSRichard std::vector<int> z12; 30589a1d03eSRichard std::vector<int>* z13 = &t; 30689a1d03eSRichard // We only support detecting the range init expression which references 30789a1d03eSRichard // container directly. 30889a1d03eSRichard // Complex range init expressions like `*z13` is not supported. 30989a1d03eSRichard for (const auto &e : *z13) { 31089a1d03eSRichard z12.push_back(e); 31189a1d03eSRichard } 31289a1d03eSRichard } 31389a1d03eSRichard 31489a1d03eSRichard { 31589a1d03eSRichard FooProto foo; 31689a1d03eSRichard foo.mutable_x(); 31789a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5); 31889a1d03eSRichard for (int i = 0; i < 5; i++) { 31989a1d03eSRichard foo.add_x(i); 32089a1d03eSRichard } 32189a1d03eSRichard } 32289a1d03eSRichard { 32389a1d03eSRichard FooProto foo; 32489a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5); 32589a1d03eSRichard for (int i = 0; i < 5; i++) { 32689a1d03eSRichard foo.add_x(i); 32789a1d03eSRichard foo.add_x(i); 32889a1d03eSRichard } 32989a1d03eSRichard } 33089a1d03eSRichard { 33189a1d03eSRichard FooProto foo; 33289a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5); 33389a1d03eSRichard foo.add_x(-1); 33489a1d03eSRichard for (int i = 0; i < 5; i++) { 33589a1d03eSRichard foo.add_x(i); 33689a1d03eSRichard } 33789a1d03eSRichard } 33889a1d03eSRichard { 33989a1d03eSRichard FooProto foo; 34089a1d03eSRichard BarProto bar; 34189a1d03eSRichard bar.mutable_x(); 34289a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5); 34389a1d03eSRichard for (int i = 0; i < 5; i++) { 34489a1d03eSRichard foo.add_x(); 34589a1d03eSRichard bar.add_x(); 34689a1d03eSRichard } 34789a1d03eSRichard } 34889a1d03eSRichard { 34989a1d03eSRichard FooProto foo; 35089a1d03eSRichard foo.mutable_y(); 35189a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5); 35289a1d03eSRichard for (int i = 0; i < 5; i++) { 35389a1d03eSRichard foo.add_x(i); 35489a1d03eSRichard } 35589a1d03eSRichard } 35689a1d03eSRichard { 35789a1d03eSRichard FooProto foo; 35889a1d03eSRichard // CHECK-FIXES-NOT: foo.mutable_z()->Reserve(5); 35989a1d03eSRichard for (int i = 0; i < 5; i++) { 36089a1d03eSRichard foo.add_z(); 36189a1d03eSRichard } 36289a1d03eSRichard } 36389a1d03eSRichard } 36489a1d03eSRichard 36589a1d03eSRichard struct StructWithFieldContainer { 36689a1d03eSRichard std::vector<int> Numbers; getNumbersStructWithFieldContainer36789a1d03eSRichard std::vector<int> getNumbers() const { 36889a1d03eSRichard std::vector<int> Result; 36989a1d03eSRichard // CHECK-FIXES: Result.reserve(Numbers.size()); 37089a1d03eSRichard for (auto Number : Numbers) { 37189a1d03eSRichard Result.push_back(Number); 37289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called 37389a1d03eSRichard } 37489a1d03eSRichard return Result; 37589a1d03eSRichard } 37689a1d03eSRichard }; 37789a1d03eSRichard 37889a1d03eSRichard StructWithFieldContainer getStructWithField(); 37989a1d03eSRichard foo(const StructWithFieldContainer & Src)38089a1d03eSRichardvoid foo(const StructWithFieldContainer &Src) { 38189a1d03eSRichard std::vector<int> A; 38289a1d03eSRichard // CHECK-FIXES: A.reserve(Src.Numbers.size()); 38389a1d03eSRichard for (auto Number : Src.Numbers) { 38489a1d03eSRichard A.push_back(Number); 38589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'push_back' is called 38689a1d03eSRichard } 38789a1d03eSRichard std::vector<int> B; 38889a1d03eSRichard for (auto Number : getStructWithField().Numbers) { 38989a1d03eSRichard B.push_back(Number); 39089a1d03eSRichard } 39189a1d03eSRichard } 392dcbe0d43SCongcong Cai 393dcbe0d43SCongcong Cai namespace gh95596 { 394dcbe0d43SCongcong Cai f(std::vector<int> & t)395dcbe0d43SCongcong Caivoid f(std::vector<int>& t) { 396dcbe0d43SCongcong Cai { 397dcbe0d43SCongcong Cai std::vector<int> gh95596_0; 398dcbe0d43SCongcong Cai // CHECK-FIXES: gh95596_0.reserve(10); 399dcbe0d43SCongcong Cai for (unsigned i = 0; i < 10; ++i) 400dcbe0d43SCongcong Cai gh95596_0.push_back(i); 401dcbe0d43SCongcong Cai // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop 402dcbe0d43SCongcong Cai } 403dcbe0d43SCongcong Cai { 404dcbe0d43SCongcong Cai std::vector<int> gh95596_1; 405dcbe0d43SCongcong Cai // CHECK-FIXES: gh95596_1.reserve(10); 406dcbe0d43SCongcong Cai for (int i = 0U; i < 10; ++i) 407dcbe0d43SCongcong Cai gh95596_1.push_back(i); 408dcbe0d43SCongcong Cai // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop 409dcbe0d43SCongcong Cai } 410dcbe0d43SCongcong Cai { 411dcbe0d43SCongcong Cai std::vector<int> gh95596_2; 412dcbe0d43SCongcong Cai // CHECK-FIXES: gh95596_2.reserve(10); 413dcbe0d43SCongcong Cai for (unsigned i = 0U; i < 10; ++i) 414dcbe0d43SCongcong Cai gh95596_2.push_back(i); 415dcbe0d43SCongcong Cai // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop 416dcbe0d43SCongcong Cai } 417dcbe0d43SCongcong Cai { 418dcbe0d43SCongcong Cai std::vector<int> gh95596_3; 419dcbe0d43SCongcong Cai // CHECK-FIXES: gh95596_3.reserve(10U); 420dcbe0d43SCongcong Cai for (int i = 0; i < 10U; ++i) 421dcbe0d43SCongcong Cai gh95596_3.push_back(i); 422dcbe0d43SCongcong Cai // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop 423dcbe0d43SCongcong Cai } 424dcbe0d43SCongcong Cai } 425dcbe0d43SCongcong Cai 426dcbe0d43SCongcong Cai } // namespace gh95596 427