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

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