// RUN: %check_clang_tidy %s performance-inefficient-vector-operation %t -- -format-style=llvm -- --std=c++11 namespace std { typedef int size_t; template class initializer_list { public: using value_type = E; using reference = E&; using const_reference = const E&; using size_type = size_t; using iterator = const E*; using const_iterator = const E*; initializer_list(); size_t size() const; // number of elements const E* begin() const; // first element const E* end() const; // one past the last element }; // initializer list range access template const E* begin(initializer_list il); template const E* end(initializer_list il); template class vector { public: typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; explicit vector(); explicit vector(size_type n); void push_back(const T& val); template void emplace_back(Args &&... args); void reserve(size_t n); void resize(size_t n); size_t size(); const_reference operator[] (size_type) const; reference operator[] (size_type); const_iterator begin() const; const_iterator end() const; }; } // namespace std class Foo { public: explicit Foo(int); }; class Bar { public: Bar(int); }; int Op(int); void f(std::vector& t) { { std::vector v0; // CHECK-FIXES: v0.reserve(10); for (int i = 0; i < 10; ++i) v0.push_back(i); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the vector capacity before the loop } { std::vector v1; // CHECK-FIXES: v1.reserve(10); for (int i = 0; i < 10; i++) v1.push_back(i); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } { std::vector v2; // CHECK-FIXES: v2.reserve(10); for (int i = 0; i < 10; ++i) v2.push_back(0); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } { std::vector v3; // CHECK-FIXES: v3.reserve(5); for (int i = 0; i < 5; ++i) { v3.push_back(i); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } // CHECK-FIXES-NOT: v3.reserve(10); for (int i = 0; i < 10; ++i) { // No fix for this loop as we encounter the prior loops. v3.push_back(i); } } { std::vector v4; std::vector v5; v5.reserve(3); // CHECK-FIXES: v4.reserve(10); for (int i = 0; i < 10; ++i) v4.push_back(i); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } { std::vector v6; // CHECK-FIXES: v6.reserve(t.size()); for (std::size_t i = 0; i < t.size(); ++i) { v6.push_back(t[i]); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } { std::vector v7; // CHECK-FIXES: v7.reserve(t.size() - 1); for (std::size_t i = 0; i < t.size() - 1; ++i) { v7.push_back(t[i]); } // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } { std::vector v8; // CHECK-FIXES: v8.reserve(t.size()); for (const auto &e : t) { v8.push_back(e); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } { std::vector v9; // CHECK-FIXES: v9.reserve(t.size()); for (const auto &e : t) { v9.push_back(Op(e)); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } { std::vector v10; // CHECK-FIXES: v10.reserve(t.size()); for (const auto &e : t) { v10.push_back(Foo(e)); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } { std::vector v11; // CHECK-FIXES: v11.reserve(t.size()); for (const auto &e : t) { v11.push_back(e); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } { std::vector v12; // CHECK-FIXES: v12.reserve(t.size()); for (const auto &e : t) { v12.emplace_back(e); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called } } // ---- Non-fixed Cases ---- { std::vector z0; z0.reserve(20); // CHECK-FIXES-NOT: z0.reserve(10); // There is a "reserve" call already. for (int i = 0; i < 10; ++i) { z0.push_back(i); } } { std::vector z1; z1.reserve(5); // CHECK-FIXES-NOT: z1.reserve(10); // There is a "reserve" call already. for (int i = 0; i < 10; ++i) { z1.push_back(i); } } { std::vector z2; z2.resize(5); // CHECK-FIXES-NOT: z2.reserve(10); // There is a ref usage of v before the loop. for (int i = 0; i < 10; ++i) { z2.push_back(i); } } { std::vector z3; z3.push_back(0); // CHECK-FIXES-NOT: z3.reserve(10); // There is a ref usage of v before the loop. for (int i = 0; i < 10; ++i) { z3.push_back(i); } } { std::vector z4; f(z4); // CHECK-FIXES-NOT: z4.reserve(10); // There is a ref usage of z4 before the loop. for (int i = 0; i < 10; ++i) { z4.push_back(i); } } { std::vector z5(20); // CHECK-FIXES-NOT: z5.reserve(10); // z5 is not constructed with default constructor. for (int i = 0; i < 10; ++i) { z5.push_back(i); } } { std::vector z6; // CHECK-FIXES-NOT: z6.reserve(10); // For-loop is not started with 0. for (int i = 1; i < 10; ++i) { z6.push_back(i); } } { std::vector z7; // CHECK-FIXES-NOT: z7.reserve(t.size()); // z7 isn't referenced in for-loop body. for (std::size_t i = 0; i < t.size(); ++i) { t.push_back(i); } } { std::vector z8; int k; // CHECK-FIXES-NOT: z8.reserve(10); // For-loop isn't a fixable loop. for (std::size_t i = 0; k < 10; ++i) { z8.push_back(t[i]); } } { std::vector z9; // CHECK-FIXES-NOT: z9.reserve(i + 1); // The loop end expression refers to the loop variable i. for (int i = 0; i < i + 1; i++) z9.push_back(i); } { std::vector z10; int k; // CHECK-FIXES-NOT: z10.reserve(10); // For-loop isn't a fixable loop. for (std::size_t i = 0; i < 10; ++k) { z10.push_back(t[i]); } } { std::vector z11; // initializer_list should not trigger the check. for (int e : {1, 2, 3, 4, 5}) { z11.push_back(e); } } { std::vector z12; std::vector* z13 = &t; // We only support detecting the range init expression which references // container directly. // Complex range init expressions like `*z13` is not supported. for (const auto &e : *z13) { z12.push_back(e); } } }