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 elements
22 const E* begin() const; // first element
23 const E* end() const; // one past the last element
24};
25
26// initializer list range access
27template<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 std
57
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 proto2
74
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(val: i);
98 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
99 }
100 {
101 std::vector<int> v1;
102 // CHECK-FIXES: v1.reserve(10);
103 for (int i = 0; i < 10; i++)
104 v1.push_back(val: i);
105 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
106 }
107 {
108 std::vector<int> v2;
109 // CHECK-FIXES: v2.reserve(10);
110 for (int i = 0; i < 10; ++i)
111 v2.push_back(val: 0);
112 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
113 }
114 {
115 std::vector<int> v3;
116 // CHECK-FIXES: v3.reserve(5);
117 for (int i = 0; i < 5; ++i) {
118 v3.push_back(val: i);
119 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
120 }
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(val: i);
125 }
126 }
127 {
128 std::vector<int> v4;
129 std::vector<int> v5;
130 v5.reserve(n: 3);
131 // CHECK-FIXES: v4.reserve(10);
132 for (int i = 0; i < 10; ++i)
133 v4.push_back(val: i);
134 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
135 }
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(val: t[i]);
141 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
142 }
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(val: t[i]);
149 } // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
150 }
151 {
152 std::vector<int> v8;
153 // CHECK-FIXES: v8.reserve(t.size());
154 for (const auto &e : t) {
155 v8.push_back(val: e);
156 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
157 }
158 }
159 {
160 std::vector<int> v9;
161 // CHECK-FIXES: v9.reserve(t.size());
162 for (const auto &e : t) {
163 v9.push_back(val: Op(e));
164 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
165 }
166 }
167 {
168 std::vector<Foo> v10;
169 // CHECK-FIXES: v10.reserve(t.size());
170 for (const auto &e : t) {
171 v10.push_back(val: Foo(e));
172 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
173 }
174 }
175 {
176 std::vector<Bar> v11;
177 // CHECK-FIXES: v11.reserve(t.size());
178 for (const auto &e : t) {
179 v11.push_back(val: e);
180 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
181 }
182 }
183 {
184 std::vector<Foo> v12;
185 // CHECK-FIXES: v12.reserve(t.size());
186 for (const auto &e : t) {
187 v12.emplace_back(args: e);
188 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called
189 }
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(x: i);
197 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'add_x' is called inside a loop; consider pre-allocating the container capacity before the loop
198 }
199 }
200
201 // ---- Non-fixed Cases ----
202 {
203 std::vector<int> z0;
204 z0.reserve(n: 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(val: i);
209 }
210 }
211 {
212 std::vector<int> z1;
213 z1.reserve(n: 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(val: i);
218 }
219 }
220 {
221 std::vector<int> z2;
222 z2.resize(n: 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(val: i);
227 }
228 }
229 {
230 std::vector<int> z3;
231 z3.push_back(val: 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(val: i);
236 }
237 }
238 {
239 std::vector<int> z4;
240 f(t&: 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(val: 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(val: 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(val: 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(val: 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(val: 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(val: 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(val: 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(val: 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 references
307 // container directly.
308 // Complex range init expressions like `*z13` is not supported.
309 for (const auto &e : *z13) {
310 z12.push_back(val: 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(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(x: i);
327 foo.add_x(x: i);
328 }
329 }
330 {
331 FooProto foo;
332 // CHECK-FIXES-NOT: foo.mutable_x()->Reserve(5);
333 foo.add_x(x: -1);
334 for (int i = 0; i < 5; i++) {
335 foo.add_x(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(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(val: Number);
372 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
373 }
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(val: Number);
385 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'push_back' is called
386 }
387 std::vector<int> B;
388 for (auto Number : getStructWithField().Numbers) {
389 B.push_back(val: 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(val: i);
401 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
402 }
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(val: i);
408 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
409 }
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(val: i);
415 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
416 }
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(val: i);
422 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
423 }
424}
425
426} // namespace gh95596
427

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp