Line data Source code
1 : /*
2 : * Cppcheck - A tool for static C/C++ code analysis
3 : * Copyright (C) 2007-2024 Cppcheck team.
4 : *
5 : * This program is free software: you can redistribute it and/or modify
6 : * it under the terms of the GNU General Public License as published by
7 : * the Free Software Foundation, either version 3 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : */
18 :
19 : #include "checkpostfixoperator.h"
20 : #include "errortypes.h"
21 : #include "fixture.h"
22 : #include "helpers.h"
23 : #include "settings.h"
24 :
25 : class TestPostfixOperator : public TestFixture {
26 : public:
27 1 : TestPostfixOperator() : TestFixture("TestPostfixOperator") {}
28 :
29 : private:
30 1 : const Settings settings = settingsBuilder().severity(Severity::performance).build();
31 :
32 : #define check(code) check_(code, __FILE__, __LINE__)
33 30 : void check_(const char code[], const char* file, int line) {
34 : // Tokenize..
35 60 : SimpleTokenizer tokenizer(settings, *this);
36 30 : ASSERT_LOC(tokenizer.tokenize(code), file, line);
37 :
38 : // Check for postfix operators..
39 60 : CheckPostfixOperator checkPostfixOperator(&tokenizer, &settings, this);
40 30 : checkPostfixOperator.postfixOperator();
41 30 : }
42 :
43 1 : void run() override {
44 1 : TEST_CASE(testsimple);
45 1 : TEST_CASE(testfor);
46 1 : TEST_CASE(testvolatile);
47 1 : TEST_CASE(testiterator);
48 1 : TEST_CASE(test2168);
49 1 : TEST_CASE(pointerSimplest);
50 1 : TEST_CASE(pointer); // #2321 - postincrement of pointer is OK
51 1 : TEST_CASE(testtemplate); // #4686
52 1 : TEST_CASE(testmember);
53 1 : TEST_CASE(testcomma);
54 1 : TEST_CASE(testauto); // #8350
55 1 : }
56 :
57 1 : void testsimple() {
58 1 : check("int main()\n"
59 : "{\n"
60 : " unsigned int k(0);\n"
61 : " std::cout << k << std::endl;\n"
62 : " k++;\n"
63 : " std::cout << k << std::endl;\n"
64 : " if(k) {\n"
65 : " k++;\n"
66 : " }\n"
67 : " std::cout << k << std::endl;\n"
68 : " k--;\n"
69 : " std::cout << k << std::endl;\n"
70 : " return 0;\n"
71 : "}");
72 1 : ASSERT_EQUALS("", errout_str());
73 :
74 1 : check("class K {};"
75 : "int main()\n"
76 : "{\n"
77 : " K k(0);\n"
78 : " std::cout << k << std::endl;\n"
79 : " k++;\n"
80 : " std::cout << k << std::endl;\n"
81 : " return 0;\n"
82 : "}");
83 1 : ASSERT_EQUALS("[test.cpp:5]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
84 :
85 1 : check("struct K {};"
86 : "void foo()\n"
87 : "{\n"
88 : " K k(0);\n"
89 : " k++;\n"
90 : "}");
91 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
92 :
93 1 : check("struct K {};\n"
94 : "void foo(K& k)\n"
95 : "{\n"
96 : " k++;\n"
97 : "}");
98 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
99 :
100 1 : check("union K {};"
101 : "void foo()\n"
102 : "{\n"
103 : " K k(0);\n"
104 : " k++;\n"
105 : "}");
106 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
107 :
108 1 : check("class K {};"
109 : "int main()\n"
110 : "{\n"
111 : " K k(1);\n"
112 : " std::cout << k << std::endl;\n"
113 : " if(k) {\n"
114 : " k++;\n"
115 : " }\n"
116 : " std::cout << k << std::endl;\n"
117 : " return 0;\n"
118 : "}");
119 1 : ASSERT_EQUALS("[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
120 :
121 1 : check("class K {};"
122 : "int main()\n"
123 : "{\n"
124 : " K k(1);\n"
125 : " std::cout << k << std::endl;\n"
126 : " if(k) {\n"
127 : " ++k;\n"
128 : " }\n"
129 : " k++;\n"
130 : " std::cout << k << std::endl;\n"
131 : " return 0;\n"
132 : "}");
133 1 : ASSERT_EQUALS("[test.cpp:8]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
134 :
135 :
136 1 : check("class K {};"
137 : "int main()\n"
138 : "{\n"
139 : " K k(0);\n"
140 : " std::cout << k << std::endl;\n"
141 : " k--;\n"
142 : " std::cout << k << std::endl;\n"
143 : " return 0;\n"
144 : "}");
145 1 : ASSERT_EQUALS("[test.cpp:5]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
146 :
147 1 : check("class K {};"
148 : "int main()\n"
149 : "{\n"
150 : " K k(0);\n"
151 : " std::cout << k << std::endl;\n"
152 : " ++k;\n"
153 : " std::cout << k << std::endl;\n"
154 : " return 0;\n"
155 : "}");
156 1 : ASSERT_EQUALS("", errout_str());
157 :
158 1 : check("class K {};"
159 : "int main()\n"
160 : "{\n"
161 : " K k(0);\n"
162 : " std::cout << k << std::endl;\n"
163 : " --k;\n"
164 : " std::cout << k << std::endl;\n"
165 : " return 0;\n"
166 : "}");
167 1 : ASSERT_EQUALS("", errout_str());
168 :
169 : // #9042
170 1 : check("template <class T>\n"
171 : "class c {\n"
172 : " int i = 0;\n"
173 : " c() { i--; }\n"
174 : "};\n"
175 : "template <class T>\n"
176 : "class s {};\n"
177 : "using BOOL = char;");
178 1 : ASSERT_EQUALS("", errout_str());
179 : }
180 :
181 1 : void testfor() {
182 1 : check("int main()\n"
183 : "{\n"
184 : " for ( unsigned int i=0; i <= 10; i++) {\n"
185 : " std::cout << i << std::endl;\n"
186 : " }\n"
187 : " return 0;\n"
188 : "}");
189 1 : ASSERT_EQUALS("", errout_str());
190 :
191 1 : check("class K {};\n"
192 : "int main()\n"
193 : "{\n"
194 : " for ( K i(0); i <= 10; i++) {\n"
195 : " std::cout << i << std::endl;\n"
196 : " }\n"
197 : " return 0;\n"
198 : "}");
199 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
200 :
201 1 : check("class K {};\n"
202 : "int main()\n"
203 : "{\n"
204 : " for ( K i(0); i <= 10; ++i) {\n"
205 : " std::cout << i << std::endl;\n"
206 : " }\n"
207 : " return 0;\n"
208 : "}");
209 1 : ASSERT_EQUALS("", errout_str());
210 :
211 1 : check("class K {};\n"
212 : "int main()\n"
213 : "{\n"
214 : " for ( K i(10); i > 1; i--) {\n"
215 : " std::cout << i << std::endl;\n"
216 : " }\n"
217 : " return 0;\n"
218 : "}");
219 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
220 :
221 1 : check("class K {};\n"
222 : "int main(int argc, char *argv[])\n"
223 : "{\n"
224 : " for ( K i=10; i > 1; --i) {\n"
225 : " std::cout << i << std::endl;\n"
226 : " }\n"
227 : " return 0;\n"
228 : "}");
229 1 : ASSERT_EQUALS("", errout_str());
230 :
231 :
232 : }
233 :
234 1 : void testvolatile() {
235 1 : check("class K {};\n"
236 : "int main()\n"
237 : "{\n"
238 : " volatile K k(0);\n"
239 : " std::cout << k << std::endl;\n"
240 : " k++;\n"
241 : " std::cout << k << std::endl;\n"
242 : " return 0;\n"
243 : "}");
244 1 : ASSERT_EQUALS("[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
245 : }
246 :
247 1 : void testiterator() {
248 1 : check("class Base {};\n"
249 : "int main() {\n"
250 : " std::vector<Base*> v;\n"
251 : " v.push_back(new Base());\n"
252 : " v.push_back(new Base());\n"
253 : " for (std::vector<Base*>::iterator i=v.begin(); i!=v.end(); i++) {\n"
254 : " ;;\n"
255 : " }\n"
256 : " v.clear();\n"
257 : " return 0;\n"
258 : "}");
259 1 : ASSERT_EQUALS("[test.cpp:6]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
260 :
261 1 : check("int main() {\n"
262 : " std::vector<int> v;\n"
263 : " std::vector<int>::iterator it;\n"
264 : " for( int i=0; i < 10; ++i ) v.push_back(i);\n"
265 : " unsigned int total = 0;\n"
266 : " it = v.begin();\n"
267 : " while( it != v.end() ) {\n"
268 : " total += *it;\n"
269 : " it++;\n"
270 : " }\n"
271 : " return 0;\n"
272 : "}");
273 1 : ASSERT_EQUALS("[test.cpp:9]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
274 :
275 1 : check("int main() {\n"
276 : " std::vector<int> v;\n"
277 : " std::vector<int>::const_iterator it;\n"
278 : " for( int i=0; i < 10; ++i ) v.push_back(i);\n"
279 : " unsigned int total = 0;\n"
280 : " it = v.begin();\n"
281 : " while( it != v.end() ) {\n"
282 : " it++;\n"
283 : " }\n"
284 : " return 0;\n"
285 : "}");
286 1 : ASSERT_EQUALS("[test.cpp:8]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
287 :
288 1 : check("int main() {\n"
289 : " std::vector<int> v;\n"
290 : " std::vector<int>::iterator it;\n"
291 : " for( int i=0; i < 10; ++i ) v.push_back(i);\n"
292 : " unsigned int total = 0;\n"
293 : " std::vector<int>::reverse_iterator rit;\n"
294 : " rit= v.rend();\n"
295 : " while( rit != v.rbegin() ) {\n"
296 : " rit--;\n"
297 : " }\n"
298 : " return 0;\n"
299 : "}");
300 1 : ASSERT_EQUALS("[test.cpp:9]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
301 :
302 : }
303 :
304 1 : void test2168() {
305 1 : check("--> declare allocator lock here\n"
306 : "int main(){}");
307 1 : ASSERT_EQUALS("", errout_str());
308 : }
309 :
310 1 : void pointerSimplest() {
311 1 : check("void f(int* p){\n"
312 : " p++;\n"
313 : " std::cout << *p;\n"
314 : "}");
315 1 : ASSERT_EQUALS("", errout_str());
316 : }
317 :
318 1 : void pointer() {
319 1 : check("static struct class * ab;\n"
320 : "int * p;\n"
321 : "\n"
322 : "void f() {\n"
323 : " p++;\n"
324 : "}");
325 1 : ASSERT_EQUALS("", errout_str());
326 : }
327 :
328 1 : void testtemplate() {
329 1 : check("bool foo() {\n"
330 : " std::vector<FilterConfigCacheEntry>::iterator aIter(aImport.begin());\n"
331 : " aIter++;\n"
332 : "}");
333 1 : ASSERT_EQUALS("[test.cpp:3]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
334 : }
335 :
336 1 : void testmember() {
337 1 : check("bool foo() {\n"
338 : " class A {}; class B {A a;};\n"
339 : " B b;\n"
340 : " b.a++;\n"
341 : "}");
342 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
343 :
344 1 : check("bool foo() {\n"
345 : " class A {}; class B {A a;};\n"
346 : " B b;\n"
347 : " foo(b.a++);\n"
348 : "}");
349 1 : ASSERT_EQUALS("", errout_str());
350 : }
351 :
352 1 : void testcomma() {
353 1 : check("bool foo(int i) {\n"
354 : " class A {};\n"
355 : " A a;\n"
356 : " i++, a++;\n"
357 : "}");
358 1 : ASSERT_EQUALS("[test.cpp:4]: (performance) Prefer prefix ++/-- operators for non-primitive types.\n", errout_str());
359 :
360 1 : check("bool foo(int i) {\n"
361 : " class A {};\n"
362 : " A a;\n"
363 : " foo(i, a++);\n"
364 : " foo(a++, i);\n"
365 : "}");
366 1 : ASSERT_EQUALS("", errout_str());
367 : }
368 :
369 1 : void testauto() { // #8350
370 1 : check("enum class Color { Red = 0, Green = 1, };\n"
371 : "int fun(const Color color) {\n"
372 : " auto a = 0;\n"
373 : " for (auto i = static_cast<int>(color); i < 10; i++) {\n"
374 : " a += i;\n"
375 : " }\n"
376 : " return a;\n"
377 : "}");
378 1 : ASSERT_EQUALS("", errout_str());
379 : }
380 : };
381 :
382 : REGISTER_TEST(TestPostfixOperator)
|