427 lines · cpp
1// RUN: %check_clang_tidy %s performance-inefficient-vector-operation %t -- \2// RUN: -format-style=llvm \3// RUN: -config='{CheckOptions: \4// RUN: {performance-inefficient-vector-operation.EnableProto: true}}'5 6namespace std {7 8typedef decltype(sizeof 0) size_t;9 10template<class E> class initializer_list {11public:12 using value_type = E;13 using reference = E&;14 using const_reference = const E&;15 using size_type = size_t;16 using iterator = const E*;17 using const_iterator = const E*;18 iterator p;19 size_t sz;20 initializer_list();21 size_t size() const; // number of elements22 const E* begin() const; // first element23 const E* end() const; // one past the last element24};25 26// initializer list range access27template<class E> const E* begin(initializer_list<E> il);28template<class E> const E* end(initializer_list<E> il);29 30template <class T>31class vector {32 public:33 typedef T* iterator;34 typedef const T* const_iterator;35 typedef T& reference;36 typedef const T& const_reference;37 typedef size_t size_type;38 39 explicit vector();40 explicit vector(size_type n);41 42 void push_back(const T& val);43 44 template <class... Args> void emplace_back(Args &&... args);45 46 void reserve(size_t n);47 void resize(size_t n);48 49 size_t size() const;50 const_reference operator[] (size_type) const;51 reference operator[] (size_type);52 53 const_iterator begin() const;54 const_iterator end() const;55};56} // namespace std57 58class Foo {59 public:60 explicit Foo(int);61};62 63class Bar {64 public:65 Bar(int);66};67 68int Op(int);69 70namespace proto2 {71class MessageLite {};72class Message : public MessageLite {};73} // namespace proto274 75class FooProto : public proto2::Message {76 public:77 int *add_x(); // repeated int x;78 void add_x(int x);79 void mutable_x();80 void mutable_y();81 int add_z() const; // optional int add_z;82};83 84class BarProto : public proto2::Message {85 public:86 int *add_x();87 void add_x(int x);88 void mutable_x();89 void mutable_y();90};91 92void f(std::vector<int>& t) {93 {94 std::vector<int> v0;95 // CHECK-FIXES: v0.reserve(10);96 for (int i = 0; i < 10; ++i)97 v0.push_back(i);98 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop99 }100 {101 std::vector<int> v1;102 // CHECK-FIXES: v1.reserve(10);103 for (int i = 0; i < 10; i++)104 v1.push_back(i);105 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called106 }107 {108 std::vector<int> v2;109 // CHECK-FIXES: v2.reserve(10);110 for (int i = 0; i < 10; ++i)111 v2.push_back(0);112 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called113 }114 {115 std::vector<int> v3;116 // CHECK-FIXES: v3.reserve(5);117 for (int i = 0; i < 5; ++i) {118 v3.push_back(i);119 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called120 }121 // CHECK-FIXES-NOT: v3.reserve(10);122 for (int i = 0; i < 10; ++i) {123 // No fix for this loop as we encounter the prior loops.124 v3.push_back(i);125 }126 }127 {128 std::vector<int> v4;129 std::vector<int> v5;130 v5.reserve(3);131 // CHECK-FIXES: v4.reserve(10);132 for (int i = 0; i < 10; ++i)133 v4.push_back(i);134 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called135 }136 {137 std::vector<int> v6;138 // CHECK-FIXES: v6.reserve(t.size());139 for (std::size_t i = 0; i < t.size(); ++i) {140 v6.push_back(t[i]);141 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called142 }143 }144 {145 std::vector<int> v7;146 // CHECK-FIXES: v7.reserve(t.size() - 1);147 for (std::size_t i = 0; i < t.size() - 1; ++i) {148 v7.push_back(t[i]);149 } // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called150 }151 {152 std::vector<int> v8;153 // CHECK-FIXES: v8.reserve(t.size());154 for (const auto &e : t) {155 v8.push_back(e);156 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called157 }158 }159 {160 std::vector<int> v9;161 // CHECK-FIXES: v9.reserve(t.size());162 for (const auto &e : t) {163 v9.push_back(Op(e));164 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called165 }166 }167 {168 std::vector<Foo> v10;169 // CHECK-FIXES: v10.reserve(t.size());170 for (const auto &e : t) {171 v10.push_back(Foo(e));172 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called173 }174 }175 {176 std::vector<Bar> v11;177 // CHECK-FIXES: v11.reserve(t.size());178 for (const auto &e : t) {179 v11.push_back(e);180 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called181 }182 }183 {184 std::vector<Foo> v12;185 // CHECK-FIXES: v12.reserve(t.size());186 for (const auto &e : t) {187 v12.emplace_back(e);188 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called189 }190 }191 192 {193 FooProto foo;194 // CHECK-FIXES: foo.mutable_x()->Reserve(5);195 for (int i = 0; i < 5; i++) {196 foo.add_x(i);197 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'add_x' is called inside a loop; consider pre-allocating the container capacity before the loop198 }199 }200 201 // ---- Non-fixed Cases ----202 {203 std::vector<int> z0;204 z0.reserve(20);205 // CHECK-FIXES-NOT: z0.reserve(10);206 // There is a "reserve" call already.207 for (int i = 0; i < 10; ++i) {208 z0.push_back(i);209 }210 }211 {212 std::vector<int> z1;213 z1.reserve(5);214 // CHECK-FIXES-NOT: z1.reserve(10);215 // There is a "reserve" call already.216 for (int i = 0; i < 10; ++i) {217 z1.push_back(i);218 }219 }220 {221 std::vector<int> z2;222 z2.resize(5);223 // CHECK-FIXES-NOT: z2.reserve(10);224 // There is a ref usage of v before the loop.225 for (int i = 0; i < 10; ++i) {226 z2.push_back(i);227 }228 }229 {230 std::vector<int> z3;231 z3.push_back(0);232 // CHECK-FIXES-NOT: z3.reserve(10);233 // There is a ref usage of v before the loop.234 for (int i = 0; i < 10; ++i) {235 z3.push_back(i);236 }237 }238 {239 std::vector<int> z4;240 f(z4);241 // CHECK-FIXES-NOT: z4.reserve(10);242 // There is a ref usage of z4 before the loop.243 for (int i = 0; i < 10; ++i) {244 z4.push_back(i);245 }246 }247 {248 std::vector<int> z5(20);249 // CHECK-FIXES-NOT: z5.reserve(10);250 // z5 is not constructed with default constructor.251 for (int i = 0; i < 10; ++i) {252 z5.push_back(i);253 }254 }255 {256 std::vector<int> z6;257 // CHECK-FIXES-NOT: z6.reserve(10);258 // For-loop is not started with 0.259 for (int i = 1; i < 10; ++i) {260 z6.push_back(i);261 }262 }263 {264 std::vector<int> z7;265 // CHECK-FIXES-NOT: z7.reserve(t.size());266 // z7 isn't referenced in for-loop body.267 for (std::size_t i = 0; i < t.size(); ++i) {268 t.push_back(i);269 }270 }271 {272 std::vector<int> z8;273 int k;274 // CHECK-FIXES-NOT: z8.reserve(10);275 // For-loop isn't a fixable loop.276 for (std::size_t i = 0; k < 10; ++i) {277 z8.push_back(t[i]);278 }279 }280 {281 std::vector<int> z9;282 // CHECK-FIXES-NOT: z9.reserve(i + 1);283 // The loop end expression refers to the loop variable i.284 for (int i = 0; i < i + 1; i++)285 z9.push_back(i);286 }287 {288 std::vector<int> z10;289 int k;290 // CHECK-FIXES-NOT: z10.reserve(10);291 // For-loop isn't a fixable loop.292 for (std::size_t i = 0; i < 10; ++k) {293 z10.push_back(t[i]);294 }295 }296 {297 std::vector<int> z11;298 // initializer_list should not trigger the check.299 for (int e : {1, 2, 3, 4, 5}) {300 z11.push_back(e);301 }302 }303 {304 std::vector<int> z12;305 std::vector<int>* z13 = &t;306 // We only support detecting the range init expression which references307 // container directly.308 // Complex range init expressions like `*z13` is not supported.309 for (const auto &e : *z13) {310 z12.push_back(e);311 }312 }313 314 {315 FooProto foo;316 foo.mutable_x();317 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);318 for (int i = 0; i < 5; i++) {319 foo.add_x(i);320 }321 }322 {323 FooProto foo;324 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);325 for (int i = 0; i < 5; i++) {326 foo.add_x(i);327 foo.add_x(i);328 }329 }330 {331 FooProto foo;332 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);333 foo.add_x(-1);334 for (int i = 0; i < 5; i++) {335 foo.add_x(i);336 }337 }338 {339 FooProto foo;340 BarProto bar;341 bar.mutable_x();342 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);343 for (int i = 0; i < 5; i++) {344 foo.add_x();345 bar.add_x();346 }347 }348 {349 FooProto foo;350 foo.mutable_y();351 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);352 for (int i = 0; i < 5; i++) {353 foo.add_x(i);354 }355 }356 {357 FooProto foo;358 // CHECK-FIXES-NOT: foo.mutable_z()->Reserve(5);359 for (int i = 0; i < 5; i++) {360 foo.add_z();361 }362 }363}364 365struct StructWithFieldContainer {366 std::vector<int> Numbers;367 std::vector<int> getNumbers() const {368 std::vector<int> Result;369 // CHECK-FIXES: Result.reserve(Numbers.size());370 for (auto Number : Numbers) {371 Result.push_back(Number);372 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called373 }374 return Result;375 }376};377 378StructWithFieldContainer getStructWithField();379 380void foo(const StructWithFieldContainer &Src) {381 std::vector<int> A;382 // CHECK-FIXES: A.reserve(Src.Numbers.size());383 for (auto Number : Src.Numbers) {384 A.push_back(Number);385 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'push_back' is called386 }387 std::vector<int> B;388 for (auto Number : getStructWithField().Numbers) {389 B.push_back(Number);390 }391}392 393namespace gh95596 {394 395void f(std::vector<int>& t) {396 {397 std::vector<int> gh95596_0;398 // CHECK-FIXES: gh95596_0.reserve(10);399 for (unsigned i = 0; i < 10; ++i)400 gh95596_0.push_back(i);401 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop402 }403 {404 std::vector<int> gh95596_1;405 // CHECK-FIXES: gh95596_1.reserve(10);406 for (int i = 0U; i < 10; ++i)407 gh95596_1.push_back(i);408 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop409 }410 {411 std::vector<int> gh95596_2;412 // CHECK-FIXES: gh95596_2.reserve(10);413 for (unsigned i = 0U; i < 10; ++i)414 gh95596_2.push_back(i);415 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop416 }417 {418 std::vector<int> gh95596_3;419 // CHECK-FIXES: gh95596_3.reserve(10U);420 for (int i = 0; i < 10U; ++i)421 gh95596_3.push_back(i);422 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop423 }424}425 426} // namespace gh95596427