Coverage Report

Created: 2025-02-17 06:38

/src/cppcheck/oss-fuzz/build/checkother.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "matchcompiler.h"
2
#include <string>
3
#include <cstring>
4
#include "errorlogger.h"
5
#include "token.h"
6
// pattern: %var%|EOF %comp%|=
7
21.5k
static inline bool match1(const Token* tok) {
8
21.5k
    if (!tok || !((tok->varId() != 0) || (tok->str() == MatchCompiler::makeConstString("EOF"))))
9
17.5k
        return false;
10
4.05k
    tok = tok->next();
11
4.05k
    if (!tok || !(tok->isComparisonOp() || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))))
12
3.16k
        return false;
13
889
    return true;
14
4.05k
}
15
// pattern: %var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (
16
889
static inline bool match2(const Token* tok) {
17
889
    if (!tok || !(tok->varId() != 0))
18
0
        return false;
19
889
    tok = tok->next();
20
889
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
21
629
        return false;
22
260
    tok = tok->next();
23
260
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("fclose")) || (tok->str() == MatchCompiler::makeConstString("fflush")) || (tok->str() == MatchCompiler::makeConstString("fputc")) || (tok->str() == MatchCompiler::makeConstString("fputs")) || (tok->str() == MatchCompiler::makeConstString("fscanf")) || (tok->str() == MatchCompiler::makeConstString("getchar")) || (tok->str() == MatchCompiler::makeConstString("getc")) || (tok->str() == MatchCompiler::makeConstString("fgetc")) || (tok->str() == MatchCompiler::makeConstString("putchar")) || (tok->str() == MatchCompiler::makeConstString("putc")) || (tok->str() == MatchCompiler::makeConstString("puts")) || (tok->str() == MatchCompiler::makeConstString("scanf")) || (tok->str() == MatchCompiler::makeConstString("sscanf")) || (tok->str() == MatchCompiler::makeConstString("ungetc"))))
24
260
        return false;
25
0
    tok = tok->next();
26
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
27
0
        return false;
28
0
    return true;
29
0
}
30
// pattern: EOF %comp% ( %var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (
31
889
static inline bool match3(const Token* tok) {
32
889
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("EOF")))
33
889
        return false;
34
0
    tok = tok->next();
35
0
    if (!tok || !tok->isComparisonOp())
36
0
        return false;
37
0
    tok = tok->next();
38
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
39
0
        return false;
40
0
    tok = tok->next();
41
0
    if (!tok || !(tok->varId() != 0))
42
0
        return false;
43
0
    tok = tok->next();
44
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
45
0
        return false;
46
0
    tok = tok->next();
47
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("fclose")) || (tok->str() == MatchCompiler::makeConstString("fflush")) || (tok->str() == MatchCompiler::makeConstString("fputc")) || (tok->str() == MatchCompiler::makeConstString("fputs")) || (tok->str() == MatchCompiler::makeConstString("fscanf")) || (tok->str() == MatchCompiler::makeConstString("getchar")) || (tok->str() == MatchCompiler::makeConstString("getc")) || (tok->str() == MatchCompiler::makeConstString("fgetc")) || (tok->str() == MatchCompiler::makeConstString("putchar")) || (tok->str() == MatchCompiler::makeConstString("putc")) || (tok->str() == MatchCompiler::makeConstString("puts")) || (tok->str() == MatchCompiler::makeConstString("scanf")) || (tok->str() == MatchCompiler::makeConstString("sscanf")) || (tok->str() == MatchCompiler::makeConstString("ungetc"))))
48
0
        return false;
49
0
    tok = tok->next();
50
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
51
0
        return false;
52
0
    return true;
53
0
}
54
// pattern: EOF %comp% ( %var% = std :: cin . get (
55
889
static inline bool match4(const Token* tok) {
56
889
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("EOF")))
57
889
        return false;
58
0
    tok = tok->next();
59
0
    if (!tok || !tok->isComparisonOp())
60
0
        return false;
61
0
    tok = tok->next();
62
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
63
0
        return false;
64
0
    tok = tok->next();
65
0
    if (!tok || !(tok->varId() != 0))
66
0
        return false;
67
0
    tok = tok->next();
68
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
69
0
        return false;
70
0
    tok = tok->next();
71
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
72
0
        return false;
73
0
    tok = tok->next();
74
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
75
0
        return false;
76
0
    tok = tok->next();
77
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("cin")))
78
0
        return false;
79
0
    tok = tok->next();
80
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
81
0
        return false;
82
0
    tok = tok->next();
83
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("get")))
84
0
        return false;
85
0
    tok = tok->next();
86
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
87
0
        return false;
88
0
    return true;
89
0
}
90
// pattern: EOF %comp% ( %var% = cin . get (
91
889
static inline bool match5(const Token* tok) {
92
889
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("EOF")))
93
889
        return false;
94
0
    tok = tok->next();
95
0
    if (!tok || !tok->isComparisonOp())
96
0
        return false;
97
0
    tok = tok->next();
98
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
99
0
        return false;
100
0
    tok = tok->next();
101
0
    if (!tok || !(tok->varId() != 0))
102
0
        return false;
103
0
    tok = tok->next();
104
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
105
0
        return false;
106
0
    tok = tok->next();
107
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("cin")))
108
0
        return false;
109
0
    tok = tok->next();
110
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
111
0
        return false;
112
0
    tok = tok->next();
113
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("get")))
114
0
        return false;
115
0
    tok = tok->next();
116
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
117
0
        return false;
118
0
    return true;
119
0
}
120
// pattern: %var% = std :: cin . get (
121
889
static inline bool match6(const Token* tok) {
122
889
    if (!tok || !(tok->varId() != 0))
123
0
        return false;
124
889
    tok = tok->next();
125
889
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
126
629
        return false;
127
260
    tok = tok->next();
128
260
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
129
260
        return false;
130
0
    tok = tok->next();
131
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
132
0
        return false;
133
0
    tok = tok->next();
134
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("cin")))
135
0
        return false;
136
0
    tok = tok->next();
137
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
138
0
        return false;
139
0
    tok = tok->next();
140
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("get")))
141
0
        return false;
142
0
    tok = tok->next();
143
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
144
0
        return false;
145
0
    return true;
146
0
}
147
// pattern: %var% = cin . get (
148
889
static inline bool match7(const Token* tok) {
149
889
    if (!tok || !(tok->varId() != 0))
150
0
        return false;
151
889
    tok = tok->next();
152
889
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
153
629
        return false;
154
260
    tok = tok->next();
155
260
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("cin")))
156
260
        return false;
157
0
    tok = tok->next();
158
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
159
0
        return false;
160
0
    tok = tok->next();
161
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("get")))
162
0
        return false;
163
0
    tok = tok->next();
164
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
165
0
        return false;
166
0
    return true;
167
0
}
168
// pattern: %var% %comp% EOF
169
889
static inline bool match8(const Token* tok) {
170
889
    if (!tok || !(tok->varId() != 0))
171
0
        return false;
172
889
    tok = tok->next();
173
889
    if (!tok || !tok->isComparisonOp())
174
260
        return false;
175
629
    tok = tok->next();
176
629
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("EOF")))
177
629
        return false;
178
0
    return true;
179
629
}
180
// pattern: EOF %comp% %var%
181
889
static inline bool match9(const Token* tok) {
182
889
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("EOF")))
183
889
        return false;
184
0
    tok = tok->next();
185
0
    if (!tok || !tok->isComparisonOp())
186
0
        return false;
187
0
    tok = tok->next();
188
0
    if (!tok || !(tok->varId() != 0))
189
0
        return false;
190
0
    return true;
191
0
}
192
// pattern: %or%|&|%|*|/
193
0
static inline bool match10(const Token* tok) {
194
0
    if (!tok || !((tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") ) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/"))))
195
0
        return false;
196
0
    return true;
197
0
}
198
// pattern: %char%
199
0
static inline bool match11(const Token* tok) {
200
0
    if (!tok || !(tok->tokType() == Token::eChar))
201
0
        return false;
202
0
    return true;
203
0
}
204
// pattern: * %name%
205
6.52k
static inline bool match12(const Token* tok) {
206
6.52k
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
207
6.41k
        return false;
208
115
    tok = tok->next();
209
115
    if (!tok || !tok->isName())
210
25
        return false;
211
90
    return true;
212
115
}
213
// pattern: [{};]
214
18
static inline bool match13(const Token* tok) {
215
18
    if (!tok || tok->str().size() != 1U || !strchr("{};", tok->str()[0]))
216
18
        return false;
217
0
    return true;
218
18
}
219
// pattern: ++|-- [;,]
220
0
static inline bool match14(const Token* tok) {
221
0
    if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--"))))
222
0
        return false;
223
0
    tok = tok->next();
224
0
    if (!tok || tok->str().size() != 1U || !strchr(";,", tok->str()[0]))
225
0
        return false;
226
0
    return true;
227
0
}
228
// pattern: { ; } {
229
931
static inline bool match15(const Token* tok) {
230
931
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
231
0
        return false;
232
931
    tok = tok->next();
233
931
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
234
931
        return false;
235
0
    tok = tok->next();
236
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
237
0
        return false;
238
0
    tok = tok->next();
239
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
240
0
        return false;
241
0
    return true;
242
0
}
243
// pattern: const|volatile|class|struct|union|%type%|::
244
1.22k
static inline bool match16(const Token* tok) {
245
1.22k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("class")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("struct")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union")) || (tok->isName() && tok->varId() == 0U) || (tok->str() == MatchCompiler::makeConstString("::"))))
246
990
        return false;
247
237
    return true;
248
1.22k
}
249
// pattern: <
250
237
static inline bool match17(const Token* tok) {
251
237
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
252
207
        return false;
253
30
    return true;
254
237
}
255
// pattern: *|const|&
256
251
static inline bool match18(const Token* tok) {
257
251
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))))
258
237
        return false;
259
14
    return true;
260
251
}
261
// pattern: ) (| %name%|%num%|%bool%|%char%|%str%|&
262
14
static inline bool match19(const Token* tok) {
263
14
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
264
14
        return false;
265
0
    tok = tok->next();
266
0
    if (tok && (((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
267
0
        tok = tok->next();
268
0
    if (!tok || !(tok->isName() || tok->isNumber() || tok->isBoolean() || (tok->tokType() == Token::eChar) || (tok->tokType() == Token::eString) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))))
269
0
        return false;
270
0
    return true;
271
0
}
272
// pattern: %type%
273
0
static inline bool match20(const Token* tok) {
274
0
    if (!tok || !(tok->isName() && tok->varId() == 0U))
275
0
        return false;
276
0
    return true;
277
0
}
278
// pattern: const|volatile|class|struct|union
279
0
static inline bool match21(const Token* tok) {
280
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("class")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("struct")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union"))))
281
0
        return false;
282
0
    return true;
283
0
}
284
// pattern: ( const|volatile| const|volatile| %type% %type%| const| * )
285
21.5k
static inline bool match22(const Token* tok) {
286
21.5k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
287
20.5k
        return false;
288
990
    tok = tok->next();
289
990
    if (tok && (((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile"))))
290
0
        tok = tok->next();
291
990
    if (tok && (((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile"))))
292
0
        tok = tok->next();
293
990
    if (!tok || !(tok->isName() && tok->varId() == 0U))
294
753
        return false;
295
237
    tok = tok->next();
296
237
    if (tok && ((tok->isName() && tok->varId() == 0U)))
297
0
        tok = tok->next();
298
237
    if (tok && (((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const"))))
299
0
        tok = tok->next();
300
237
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
301
233
        return false;
302
4
    tok = tok->next();
303
4
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
304
4
        return false;
305
0
    return true;
306
4
}
307
// pattern: reinterpret_cast <
308
21.5k
static inline bool match23(const Token* tok) {
309
21.5k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("reinterpret_cast")))
310
21.5k
        return false;
311
0
    tok = tok->next();
312
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
313
0
        return false;
314
0
    return true;
315
0
}
316
// pattern: ] (
317
21.5k
static inline bool match24(const Token* tok) {
318
21.5k
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
319
21.5k
        return false;
320
0
    tok = tok->next();
321
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
322
0
        return false;
323
0
    return true;
324
0
}
325
// pattern: try {
326
21.5k
static inline bool match25(const Token* tok) {
327
21.5k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("try")))
328
21.5k
        return false;
329
0
    tok = tok->next();
330
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
331
0
        return false;
332
0
    return true;
333
0
}
334
// pattern: ; %var% =
335
1.99k
static inline bool match26(const Token* tok) {
336
1.99k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
337
688
        return false;
338
1.31k
    tok = tok->next();
339
1.31k
    if (!tok || !(tok->varId() != 0))
340
1.29k
        return false;
341
14
    tok = tok->next();
342
14
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
343
0
        return false;
344
14
    return true;
345
14
}
346
// pattern: { 0 }
347
0
static inline bool match27(const Token* tok) {
348
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
349
0
        return false;
350
0
    tok = tok->next();
351
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0")))
352
0
        return false;
353
0
    tok = tok->next();
354
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
355
0
        return false;
356
0
    return true;
357
0
}
358
// pattern: %str%|%num%|%name%
359
0
static inline bool match28(const Token* tok) {
360
0
    if (!tok || !((tok->tokType() == Token::eString) || tok->isNumber() || tok->isName()))
361
0
        return false;
362
0
    return true;
363
0
}
364
// pattern: :: %name%
365
0
static inline bool match29(const Token* tok) {
366
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
367
0
        return false;
368
0
    tok = tok->next();
369
0
    if (!tok || !tok->isName())
370
0
        return false;
371
0
    return true;
372
0
}
373
// pattern: .
374
7.42k
static inline bool match30(const Token* tok) {
375
7.42k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
376
7.42k
        return false;
377
0
    return true;
378
7.42k
}
379
// pattern: =
380
2.16k
static inline bool match31(const Token* tok) {
381
2.16k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
382
2.11k
        return false;
383
53
    return true;
384
2.16k
}
385
// pattern: %name% (
386
53.3k
static inline bool match32(const Token* tok) {
387
53.3k
    if (!tok || !tok->isName())
388
30.4k
        return false;
389
22.9k
    tok = tok->next();
390
22.9k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
391
20.8k
        return false;
392
2.09k
    return true;
393
22.9k
}
394
// pattern: break|continue|return|exit|goto|throw
395
0
static inline bool match33(const Token* tok) {
396
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || (tok->str() == MatchCompiler::makeConstString("exit")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")) || (tok->str() == MatchCompiler::makeConstString("throw"))))
397
0
        return false;
398
0
    return true;
399
0
}
400
// pattern: )|else {
401
0
static inline bool match34(const Token* tok) {
402
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else"))))
403
0
        return false;
404
0
    tok = tok->next();
405
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
406
0
        return false;
407
0
    return true;
408
0
}
409
// pattern: ;|{|}|: %var% = %any% ;
410
0
static inline bool match35(const Token* tok) {
411
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))))
412
0
        return false;
413
0
    tok = tok->next();
414
0
    if (!tok || !(tok->varId() != 0))
415
0
        return false;
416
0
    tok = tok->next();
417
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
418
0
        return false;
419
0
    tok = tok->next();
420
0
    if (!tok || false)
421
0
        return false;
422
0
    tok = tok->next();
423
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
424
0
        return false;
425
0
    return true;
426
0
}
427
// pattern: ;|{|}|: %var% %assign% %num% ;
428
0
static inline bool match36(const Token* tok) {
429
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))))
430
0
        return false;
431
0
    tok = tok->next();
432
0
    if (!tok || !(tok->varId() != 0))
433
0
        return false;
434
0
    tok = tok->next();
435
0
    if (!tok || !tok->isAssignmentOp())
436
0
        return false;
437
0
    tok = tok->next();
438
0
    if (!tok || !tok->isNumber())
439
0
        return false;
440
0
    tok = tok->next();
441
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
442
0
        return false;
443
0
    return true;
444
0
}
445
// pattern: %num%
446
0
static inline bool match37(const Token* tok) {
447
0
    if (!tok || !tok->isNumber())
448
0
        return false;
449
0
    return true;
450
0
}
451
// pattern: ;|{|}|: %var% = %name% %or%|& %num% ;
452
0
static inline bool match38(const Token* tok) {
453
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))))
454
0
        return false;
455
0
    tok = tok->next();
456
0
    if (!tok || !(tok->varId() != 0))
457
0
        return false;
458
0
    tok = tok->next();
459
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
460
0
        return false;
461
0
    tok = tok->next();
462
0
    if (!tok || !tok->isName())
463
0
        return false;
464
0
    tok = tok->next();
465
0
    if (!tok || !((tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") ) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))))
466
0
        return false;
467
0
    tok = tok->next();
468
0
    if (!tok || !tok->isNumber())
469
0
        return false;
470
0
    tok = tok->next();
471
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
472
0
        return false;
473
0
    return true;
474
0
}
475
// pattern: [;}{]
476
0
static inline bool match39(const Token* tok) {
477
0
    if (!tok || tok->str().size() != 1U || !strchr(";}{", tok->str()[0]))
478
0
        return false;
479
0
    return true;
480
0
}
481
// pattern: &&|%oror%
482
3.18k
static inline bool match40(const Token* tok) {
483
3.18k
    if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||"))))
484
3.18k
        return false;
485
0
    return true;
486
3.18k
}
487
// pattern: ;
488
240
template<class T> static inline T * findmatch41(T * start_tok) {
489
2.37k
    for (; start_tok; start_tok = start_tok->next()) {
490
491
2.37k
    T * tok = start_tok;
492
2.37k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
493
2.13k
        continue;
494
240
    return start_tok;
495
2.37k
    }
496
0
    return nullptr;
497
240
}
498
// pattern: (|[|<
499
3.69k
static inline bool match42(const Token* tok) {
500
3.69k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))))
501
2.96k
        return false;
502
727
    return true;
503
3.69k
}
504
// pattern: break|continue ;
505
12.8k
static inline bool match43(const Token* tok) {
506
12.8k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue"))))
507
12.8k
        return false;
508
0
    tok = tok->next();
509
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
510
0
        return false;
511
0
    return true;
512
0
}
513
// pattern: [;{}:] return|throw
514
12.8k
static inline bool match44(const Token* tok) {
515
12.8k
    if (!tok || tok->str().size() != 1U || !strchr(";{}:", tok->str()[0]))
516
7.86k
        return false;
517
4.96k
    tok = tok->next();
518
4.96k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || (tok->str() == MatchCompiler::makeConstString("throw"))))
519
3.77k
        return false;
520
1.19k
    return true;
521
4.96k
}
522
// pattern: ?
523
4.37k
static inline bool match45(const Token* tok) {
524
4.37k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")))
525
4.37k
        return false;
526
0
    return true;
527
4.37k
}
528
// pattern: goto %any% ;
529
11.6k
static inline bool match46(const Token* tok) {
530
11.6k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")))
531
11.6k
        return false;
532
0
    tok = tok->next();
533
0
    if (!tok || false)
534
0
        return false;
535
0
    tok = tok->next();
536
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
537
0
        return false;
538
0
    return true;
539
0
}
540
// pattern: ?|:
541
0
static inline bool match47(const Token* tok) {
542
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))))
543
0
        return false;
544
0
    return true;
545
0
}
546
// pattern: return
547
0
static inline bool match48(const Token* tok) {
548
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
549
0
        return false;
550
0
    return true;
551
0
}
552
// pattern: }
553
13.5k
static inline bool match49(const Token* tok) {
554
13.5k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
555
12.3k
        return false;
556
1.19k
    return true;
557
13.5k
}
558
// pattern: {
559
0
static inline bool match50(const Token* tok) {
560
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
561
0
        return false;
562
0
    return true;
563
0
}
564
// pattern: ;
565
50.0k
static inline bool match51(const Token* tok) {
566
50.0k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
567
46.8k
        return false;
568
3.18k
    return true;
569
50.0k
}
570
// pattern: continue|goto|throw|return
571
1.19k
static inline bool match52(const Token* tok) {
572
1.19k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")) || (tok->str() == MatchCompiler::makeConstString("throw")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return"))))
573
1.19k
        return false;
574
0
    return true;
575
1.19k
}
576
// pattern: [}:]
577
0
template<class T> static inline T * findmatch53(T * start_tok) {
578
0
    for (; start_tok; start_tok = start_tok->next()) {
579
580
0
    T * tok = start_tok;
581
0
    if (!tok || tok->str().size() != 1U || !strchr("}:", tok->str()[0]))
582
0
        continue;
583
0
    return start_tok;
584
0
    }
585
0
    return nullptr;
586
0
}
587
// pattern: return|}|case|default
588
1.19k
static inline bool match54(const Token* tok) {
589
1.19k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("default"))))
590
0
        return false;
591
1.19k
    return true;
592
1.19k
}
593
// pattern: while|do|for
594
0
static inline bool match55(const Token* tok) {
595
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("do")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for"))))
596
0
        return false;
597
0
    return true;
598
0
}
599
// pattern: {
600
0
template<class T> static inline T * findmatch56(T * start_tok) {
601
0
    for (; start_tok; start_tok = start_tok->next()) {
602
603
0
    T * tok = start_tok;
604
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
605
0
        continue;
606
0
    return start_tok;
607
0
    }
608
0
    return nullptr;
609
0
}
610
// pattern: [;{}] %any% :
611
0
static inline bool match57(const Token* tok) {
612
0
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
613
0
        return false;
614
0
    tok = tok->next();
615
0
    if (!tok || false)
616
0
        return false;
617
0
    tok = tok->next();
618
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
619
0
        return false;
620
0
    return true;
621
0
}
622
// pattern: ( void ) %name% ;
623
0
static inline bool match58(const Token* tok) {
624
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
625
0
        return false;
626
0
    tok = tok->next();
627
0
    if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("void")))
628
0
        return false;
629
0
    tok = tok->next();
630
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
631
0
        return false;
632
0
    tok = tok->next();
633
0
    if (!tok || !tok->isName())
634
0
        return false;
635
0
    tok = tok->next();
636
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
637
0
        return false;
638
0
    return true;
639
0
}
640
// pattern: & %var% = %var% .
641
0
static inline bool match59(const Token* tok) {
642
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
643
0
        return false;
644
0
    tok = tok->next();
645
0
    if (!tok || !(tok->varId() != 0))
646
0
        return false;
647
0
    tok = tok->next();
648
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
649
0
        return false;
650
0
    tok = tok->next();
651
0
    if (!tok || !(tok->varId() != 0))
652
0
        return false;
653
0
    tok = tok->next();
654
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
655
0
        return false;
656
0
    return true;
657
0
}
658
// pattern: %var% :
659
0
static inline bool match60(const Token* tok) {
660
0
    if (!tok || !(tok->varId() != 0))
661
0
        return false;
662
0
    tok = tok->next();
663
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
664
0
        return false;
665
0
    return true;
666
0
}
667
// pattern: for (
668
9.52k
static inline bool match61(const Token* tok) {
669
9.52k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")))
670
9.52k
        return false;
671
0
    tok = tok->next();
672
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
673
0
        return false;
674
0
    return true;
675
0
}
676
// pattern: [;{}]
677
0
static inline bool match62(const Token* tok) {
678
0
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
679
0
        return false;
680
0
    return true;
681
0
}
682
// pattern: ; %varid% =
683
0
static inline bool match63(const Token* tok, const int varid) {
684
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
685
0
        return false;
686
0
    tok = tok->next();
687
0
    if (varid==0U)
688
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
689
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
690
0
        return false;
691
0
    tok = tok->next();
692
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
693
0
        return false;
694
0
    return true;
695
0
}
696
// pattern: {|(
697
0
static inline bool match64(const Token* tok) {
698
0
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
699
0
        return false;
700
0
    return true;
701
0
}
702
// pattern: ,
703
7.68k
static inline bool match65(const Token* tok) {
704
7.68k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
705
7.67k
        return false;
706
4
    return true;
707
7.68k
}
708
// pattern: [(=]
709
0
static inline bool match66(const Token* tok) {
710
0
    if (!tok || tok->str().size() != 1U || !strchr("(=", tok->str()[0]))
711
0
        return false;
712
0
    return true;
713
0
}
714
// pattern: (
715
2.24k
static inline bool match67(const Token* tok) {
716
2.24k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
717
2.24k
        return false;
718
0
    return true;
719
2.24k
}
720
// pattern: else { if (
721
0
static inline bool match68(const Token* tok) {
722
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else")))
723
0
        return false;
724
0
    tok = tok->next();
725
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
726
0
        return false;
727
0
    tok = tok->next();
728
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")))
729
0
        return false;
730
0
    tok = tok->next();
731
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
732
0
        return false;
733
0
    return true;
734
0
}
735
// pattern: ) {
736
0
static inline bool match69(const Token* tok) {
737
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
738
0
        return false;
739
0
    tok = tok->next();
740
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
741
0
        return false;
742
0
    return true;
743
0
}
744
// pattern: %varid% =
745
0
static inline bool match70(const Token* tok, const int varid) {
746
0
    if (varid==0U)
747
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
748
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
749
0
        return false;
750
0
    tok = tok->next();
751
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
752
0
        return false;
753
0
    return true;
754
0
}
755
// pattern: %varid% !!=
756
0
static inline bool match71(const Token* tok, const int varid) {
757
0
    if (varid==0U)
758
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
759
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
760
0
        return false;
761
0
    tok = tok->next();
762
0
    if (tok && tok->str() == MatchCompiler::makeConstString("="))
763
0
        return false;
764
0
    return true;
765
0
}
766
// pattern: & %varid%
767
0
static inline bool match72(const Token* tok, const int varid) {
768
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
769
0
        return false;
770
0
    tok = tok->next();
771
0
    if (varid==0U)
772
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
773
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
774
0
        return false;
775
0
    return true;
776
0
}
777
// pattern: %varid%
778
0
template<class T> static inline T * findmatch73(T * start_tok, const Token * end, int varid) {
779
0
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
780
781
0
    T * tok = start_tok;
782
0
    if (varid==0U)
783
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
784
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
785
0
        continue;
786
0
    return start_tok;
787
0
    }
788
0
    return nullptr;
789
0
}
790
// pattern: * %varid%
791
0
static inline bool match74(const Token* tok, const int varid) {
792
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
793
0
        return false;
794
0
    tok = tok->next();
795
0
    if (varid==0U)
796
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
797
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
798
0
        return false;
799
0
    return true;
800
0
}
801
// pattern: = %varid%
802
0
static inline bool match75(const Token* tok, const int varid) {
803
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
804
0
        return false;
805
0
    tok = tok->next();
806
0
    if (varid==0U)
807
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
808
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
809
0
        return false;
810
0
    return true;
811
0
}
812
// pattern: [([{<]
813
0
static inline bool match76(const Token* tok) {
814
0
    if (!tok || tok->str().size() != 1U || !strchr("([{<", tok->str()[0]))
815
0
        return false;
816
0
    return true;
817
0
}
818
// pattern: [
819
14.2k
static inline bool match77(const Token* tok) {
820
14.2k
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
821
14.2k
        return false;
822
0
    return true;
823
14.2k
}
824
// pattern: %var% (
825
0
static inline bool match78(const Token* tok) {
826
0
    if (!tok || !(tok->varId() != 0))
827
0
        return false;
828
0
    tok = tok->next();
829
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
830
0
        return false;
831
0
    return true;
832
0
}
833
// pattern: &
834
0
static inline bool match79(const Token* tok) {
835
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
836
0
        return false;
837
0
    return true;
838
0
}
839
// pattern: & %var% = %varid%
840
0
static inline bool match80(const Token* tok, const int varid) {
841
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
842
0
        return false;
843
0
    tok = tok->next();
844
0
    if (!tok || !(tok->varId() != 0))
845
0
        return false;
846
0
    tok = tok->next();
847
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
848
0
        return false;
849
0
    tok = tok->next();
850
0
    if (varid==0U)
851
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
852
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
853
0
        return false;
854
0
    return true;
855
0
}
856
// pattern: %varid%
857
0
static inline bool match81(const Token* tok, const int varid) {
858
0
    if (varid==0U)
859
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
860
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
861
0
        return false;
862
0
    return true;
863
0
}
864
// pattern: %name% ) (
865
0
static inline bool match82(const Token* tok) {
866
0
    if (!tok || !tok->isName())
867
0
        return false;
868
0
    tok = tok->next();
869
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
870
0
        return false;
871
0
    tok = tok->next();
872
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
873
0
        return false;
874
0
    return true;
875
0
}
876
// pattern: %op%
877
0
static inline bool match83(const Token* tok) {
878
0
    if (!tok || !tok->isOp())
879
0
        return false;
880
0
    return true;
881
0
}
882
// pattern: %cop%
883
0
static inline bool match84(const Token* tok) {
884
0
    if (!tok || !tok->isConstOp())
885
0
        return false;
886
0
    return true;
887
0
}
888
// pattern: %assign%
889
0
static inline bool match85(const Token* tok) {
890
0
    if (!tok || !tok->isAssignmentOp())
891
0
        return false;
892
0
    return true;
893
0
}
894
// pattern: %oror%|%comp%|&&|?|!|-|<<
895
0
static inline bool match86(const Token* tok) {
896
0
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || tok->isComparisonOp() || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<"))))
897
0
        return false;
898
0
    return true;
899
0
}
900
// pattern: if|while
901
0
static inline bool match87(const Token* tok) {
902
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
903
0
        return false;
904
0
    return true;
905
0
}
906
// pattern: *
907
0
static inline bool match88(const Token* tok) {
908
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
909
0
        return false;
910
0
    return true;
911
0
}
912
// pattern: %var% [
913
32.1k
static inline bool match89(const Token* tok) {
914
32.1k
    if (!tok || !(tok->varId() != 0))
915
25.3k
        return false;
916
6.81k
    tok = tok->next();
917
6.81k
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
918
6.81k
        return false;
919
0
    return true;
920
6.81k
}
921
// pattern: [&|^]
922
22.6k
static inline bool match90(const Token* tok) {
923
22.6k
    if (!tok || tok->str().size() != 1U || !strchr("&|^", tok->str()[0]))
924
22.4k
        return false;
925
261
    return true;
926
22.6k
}
927
// pattern: ::
928
0
static inline bool match91(const Token* tok) {
929
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
930
0
        return false;
931
0
    return true;
932
0
}
933
// pattern: %name% !!(
934
0
static inline bool match92(const Token* tok) {
935
0
    if (!tok || !tok->isName())
936
0
        return false;
937
0
    tok = tok->next();
938
0
    if (tok && tok->str() == MatchCompiler::makeConstString("("))
939
0
        return false;
940
0
    return true;
941
0
}
942
// pattern: %bool%|%num%|%str%|%char%|nullptr|NULL
943
3.18k
static inline bool match93(const Token* tok) {
944
3.18k
    if (!tok || !(tok->isBoolean() || tok->isNumber() || (tok->tokType() == Token::eString) || (tok->tokType() == Token::eChar) || (tok->str() == MatchCompiler::makeConstString("nullptr")) || (tok->str() == MatchCompiler::makeConstString("NULL"))))
945
3.18k
        return false;
946
0
    return true;
947
3.18k
}
948
// pattern: *|&|&&
949
3.18k
static inline bool match94(const Token* tok) {
950
3.18k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
951
3.18k
        return false;
952
0
    return true;
953
3.18k
}
954
// pattern: ::|.|const|volatile|restrict
955
0
static inline bool match95(const Token* tok) {
956
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString(".")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("restrict"))))
957
0
        return false;
958
0
    return true;
959
0
}
960
// pattern: <<|>>
961
3.18k
static inline bool match96(const Token* tok) {
962
3.18k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>"))))
963
3.18k
        return false;
964
0
    return true;
965
3.18k
}
966
// pattern: delete
967
3.18k
static inline bool match97(const Token* tok) {
968
3.18k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("delete")))
969
3.18k
        return false;
970
0
    return true;
971
3.18k
}
972
// pattern: !|~|%cop%
973
3.18k
static inline bool match98(const Token* tok) {
974
3.18k
    if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("~")) || tok->isConstOp()))
975
3.18k
        return false;
976
0
    return true;
977
3.18k
}
978
// pattern: sizeof (
979
3.18k
static inline bool match99(const Token* tok) {
980
3.18k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof")))
981
3.18k
        return false;
982
0
    tok = tok->next();
983
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
984
0
        return false;
985
0
    return true;
986
0
}
987
// pattern: dynamic_cast
988
0
static inline bool match100(const Token* tok) {
989
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("dynamic_cast")))
990
0
        return false;
991
0
    return true;
992
0
}
993
// pattern: & >
994
0
static inline bool match101(const Token* tok) {
995
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
996
0
        return false;
997
0
    tok = tok->next();
998
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))
999
0
        return false;
1000
0
    return true;
1001
0
}
1002
// pattern: .|[|(|*
1003
0
static inline bool match102(const Token* tok) {
1004
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*"))))
1005
0
        return false;
1006
0
    return true;
1007
0
}
1008
// pattern: :
1009
0
static inline bool match103(const Token* tok) {
1010
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
1011
0
        return false;
1012
0
    return true;
1013
0
}
1014
// pattern: ( void
1015
0
static inline bool match104(const Token* tok) {
1016
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1017
0
        return false;
1018
0
    tok = tok->next();
1019
0
    if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("void")))
1020
0
        return false;
1021
0
    return true;
1022
0
}
1023
// pattern: < void *| >
1024
0
static inline bool match105(const Token* tok) {
1025
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
1026
0
        return false;
1027
0
    tok = tok->next();
1028
0
    if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("void")))
1029
0
        return false;
1030
0
    tok = tok->next();
1031
0
    if (tok && (((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*"))))
1032
0
        tok = tok->next();
1033
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))
1034
0
        return false;
1035
0
    return true;
1036
0
}
1037
// pattern: )
1038
0
static inline bool match106(const Token* tok) {
1039
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1040
0
        return false;
1041
0
    return true;
1042
0
}
1043
// pattern: delete|throw|return
1044
0
static inline bool match107(const Token* tok) {
1045
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("delete")) || (tok->str() == MatchCompiler::makeConstString("throw")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return"))))
1046
0
        return false;
1047
0
    return true;
1048
0
}
1049
// pattern: for|if (
1050
0
static inline bool match108(const Token* tok) {
1051
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if"))))
1052
0
        return false;
1053
0
    tok = tok->next();
1054
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1055
0
        return false;
1056
0
    return true;
1057
0
}
1058
// pattern: %oror%|&&
1059
12.7k
static inline bool match109(const Token* tok) {
1060
12.7k
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
1061
12.7k
        return false;
1062
0
    return true;
1063
12.7k
}
1064
// pattern: ;|}|{ %any% ;
1065
9.52k
static inline bool match110(const Token* tok) {
1066
9.52k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
1067
7.20k
        return false;
1068
2.31k
    tok = tok->next();
1069
2.31k
    if (!tok || false)
1070
0
        return false;
1071
2.31k
    tok = tok->next();
1072
2.31k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1073
2.31k
        return false;
1074
6
    return true;
1075
2.31k
}
1076
// pattern: ; } )
1077
3.18k
static inline bool match111(const Token* tok) {
1078
3.18k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1079
6
        return false;
1080
3.18k
    tok = tok->next();
1081
3.18k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1082
1.83k
        return false;
1083
1.35k
    tok = tok->next();
1084
1.35k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1085
1.35k
        return false;
1086
0
    return true;
1087
1.35k
}
1088
// pattern: ==
1089
0
static inline bool match112(const Token* tok) {
1090
0
    if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")))
1091
0
        return false;
1092
0
    return true;
1093
0
}
1094
// pattern: ,|!|~|%cop%
1095
0
static inline bool match113(const Token* tok) {
1096
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("~")) || tok->isConstOp()))
1097
0
        return false;
1098
0
    return true;
1099
0
}
1100
// pattern: %var%
1101
2.24k
static inline bool match114(const Token* tok) {
1102
2.24k
    if (!tok || !(tok->varId() != 0))
1103
2.00k
        return false;
1104
240
    return true;
1105
2.24k
}
1106
// pattern: [+-]
1107
69
static inline bool match115(const Token* tok) {
1108
69
    if (!tok || tok->str().size() != 1U || !strchr("+-", tok->str()[0]))
1109
65
        return false;
1110
4
    return true;
1111
69
}
1112
// pattern: 0.0
1113
4
static inline bool match116(const Token* tok) {
1114
4
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0.0")))
1115
4
        return false;
1116
0
    return true;
1117
4
}
1118
// pattern: [;{}] %name%
1119
22.6k
static inline bool match117(const Token* tok) {
1120
22.6k
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
1121
16.5k
        return false;
1122
6.15k
    tok = tok->next();
1123
6.15k
    if (!tok || !tok->isName())
1124
2.03k
        return false;
1125
4.12k
    return true;
1126
6.15k
}
1127
// pattern: %name% ::
1128
2.00k
static inline bool match118(const Token* tok) {
1129
2.00k
    if (!tok || !tok->isName())
1130
0
        return false;
1131
2.00k
    tok = tok->next();
1132
2.00k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
1133
2.00k
        return false;
1134
0
    return true;
1135
2.00k
}
1136
// pattern: %name% <
1137
2.00k
static inline bool match119(const Token* tok) {
1138
2.00k
    if (!tok || !tok->isName())
1139
0
        return false;
1140
2.00k
    tok = tok->next();
1141
2.00k
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
1142
2.00k
        return false;
1143
0
    return true;
1144
2.00k
}
1145
// pattern: %name%|> (|{
1146
2.00k
static inline bool match120(const Token* tok) {
1147
2.00k
    if (!tok || !(tok->isName() || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">"))))
1148
0
        return false;
1149
2.00k
    tok = tok->next();
1150
2.00k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
1151
2.00k
        return false;
1152
0
    return true;
1153
2.00k
}
1154
// pattern: )|} ;
1155
0
static inline bool match121(const Token* tok) {
1156
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
1157
0
        return false;
1158
0
    tok = tok->next();
1159
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1160
0
        return false;
1161
0
    return true;
1162
0
}
1163
// pattern: class|struct|union
1164
0
static inline bool match122(const Token* tok) {
1165
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("struct")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union"))))
1166
0
        return false;
1167
0
    return true;
1168
0
}
1169
// pattern: ; }
1170
212
static inline bool match123(const Token* tok) {
1171
212
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1172
98
        return false;
1173
114
    tok = tok->next();
1174
114
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1175
59
        return false;
1176
55
    return true;
1177
114
}
1178
// pattern: } else {
1179
501
static inline bool match124(const Token* tok) {
1180
501
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1181
0
        return false;
1182
501
    tok = tok->next();
1183
501
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else")))
1184
222
        return false;
1185
279
    tok = tok->next();
1186
279
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
1187
0
        return false;
1188
279
    return true;
1189
279
}
1190
// pattern: %var% = new
1191
21.5k
static inline bool match125(const Token* tok) {
1192
21.5k
    if (!tok || !(tok->varId() != 0))
1193
17.5k
        return false;
1194
4.05k
    tok = tok->next();
1195
4.05k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1196
3.79k
        return false;
1197
260
    tok = tok->next();
1198
260
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("new")))
1199
260
        return false;
1200
0
    return true;
1201
260
}
1202
// pattern: %var% = %name% (
1203
21.5k
static inline bool match126(const Token* tok) {
1204
21.5k
    if (!tok || !(tok->varId() != 0))
1205
17.5k
        return false;
1206
4.05k
    tok = tok->next();
1207
4.05k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1208
3.79k
        return false;
1209
260
    tok = tok->next();
1210
260
    if (!tok || !tok->isName())
1211
43
        return false;
1212
217
    tok = tok->next();
1213
217
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1214
217
        return false;
1215
0
    return true;
1216
217
}
1217
// pattern: %var% = %name% +|-
1218
21.5k
static inline bool match127(const Token* tok) {
1219
21.5k
    if (!tok || !(tok->varId() != 0))
1220
17.5k
        return false;
1221
4.05k
    tok = tok->next();
1222
4.05k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1223
3.79k
        return false;
1224
260
    tok = tok->next();
1225
260
    if (!tok || !tok->isName())
1226
43
        return false;
1227
217
    tok = tok->next();
1228
217
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1229
206
        return false;
1230
11
    return true;
1231
217
}
1232
// pattern: %var% =
1233
21.5k
static inline bool match128(const Token* tok) {
1234
21.5k
    if (!tok || !(tok->varId() != 0))
1235
17.5k
        return false;
1236
4.05k
    tok = tok->next();
1237
4.05k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1238
3.79k
        return false;
1239
260
    return true;
1240
4.05k
}
1241
// pattern: %name% ( %any% +|-
1242
21.3k
static inline bool match129(const Token* tok) {
1243
21.3k
    if (!tok || !tok->isName())
1244
12.5k
        return false;
1245
8.74k
    tok = tok->next();
1246
8.74k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1247
8.02k
        return false;
1248
722
    tok = tok->next();
1249
722
    if (!tok || false)
1250
0
        return false;
1251
722
    tok = tok->next();
1252
722
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1253
707
        return false;
1254
15
    return true;
1255
722
}
1256
// pattern: delete [ ] ( %any% +|-
1257
21.3k
static inline bool match130(const Token* tok) {
1258
21.3k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("delete")))
1259
21.3k
        return false;
1260
0
    tok = tok->next();
1261
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
1262
0
        return false;
1263
0
    tok = tok->next();
1264
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
1265
0
        return false;
1266
0
    tok = tok->next();
1267
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1268
0
        return false;
1269
0
    tok = tok->next();
1270
0
    if (!tok || false)
1271
0
        return false;
1272
0
    tok = tok->next();
1273
0
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1274
0
        return false;
1275
0
    return true;
1276
0
}
1277
// pattern: delete %any% +|- %any%
1278
21.3k
static inline bool match131(const Token* tok) {
1279
21.3k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("delete")))
1280
21.3k
        return false;
1281
0
    tok = tok->next();
1282
0
    if (!tok || false)
1283
0
        return false;
1284
0
    tok = tok->next();
1285
0
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1286
0
        return false;
1287
0
    tok = tok->next();
1288
0
    if (!tok || false)
1289
0
        return false;
1290
0
    return true;
1291
0
}
1292
// pattern: %var%
1293
2.24k
template<class T> static inline T * findmatch132(T * start_tok, const Token * end) {
1294
5.39k
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
1295
1296
4.67k
    T * tok = start_tok;
1297
4.67k
    if (!tok || !(tok->varId() != 0))
1298
3.14k
        continue;
1299
1.52k
    return start_tok;
1300
4.67k
    }
1301
722
    return nullptr;
1302
2.24k
}
1303
// pattern: static_assert
1304
82
static inline bool match133(const Token* tok) {
1305
82
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("static_assert")))
1306
82
        return false;
1307
0
    return true;
1308
82
}
1309
// pattern: _Static_assert
1310
0
static inline bool match134(const Token* tok) {
1311
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("_Static_assert")))
1312
0
        return false;
1313
0
    return true;
1314
0
}
1315
// pattern: ; %type% %var% ;
1316
240
static inline bool match135(const Token* tok) {
1317
240
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1318
0
        return false;
1319
240
    tok = tok->next();
1320
240
    if (!tok || !(tok->isName() && tok->varId() == 0U))
1321
135
        return false;
1322
105
    tok = tok->next();
1323
105
    if (!tok || !(tok->varId() != 0))
1324
102
        return false;
1325
3
    tok = tok->next();
1326
3
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1327
1
        return false;
1328
2
    return true;
1329
3
}
1330
// pattern: %var% %assign%
1331
240
static inline bool match136(const Token* tok) {
1332
240
    if (!tok || !(tok->varId() != 0))
1333
240
        return false;
1334
0
    tok = tok->next();
1335
0
    if (!tok || !tok->isAssignmentOp())
1336
0
        return false;
1337
0
    return true;
1338
0
}
1339
// pattern: ;|{|} %var%
1340
0
static inline bool match137(const Token* tok) {
1341
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
1342
0
        return false;
1343
0
    tok = tok->next();
1344
0
    if (!tok || !(tok->varId() != 0))
1345
0
        return false;
1346
0
    return true;
1347
0
}
1348
// pattern: %assign%|%comp%
1349
0
static inline bool match138(const Token* tok) {
1350
0
    if (!tok || !(tok->isAssignmentOp() || tok->isComparisonOp()))
1351
0
        return false;
1352
0
    return true;
1353
0
}
1354
// pattern: +|*|<<|>>|+=|*=|<<=|>>=
1355
4.68k
static inline bool match139(const Token* tok) {
1356
4.68k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("+=")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("*=")) || (tok->str() == MatchCompiler::makeConstString("<<=")) || (tok->str() == MatchCompiler::makeConstString(">>="))))
1357
4.48k
        return false;
1358
200
    return true;
1359
4.68k
}
1360
// pattern: ==|!=|-
1361
4.48k
static inline bool match140(const Token* tok) {
1362
4.48k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1363
4.09k
        return false;
1364
397
    return true;
1365
4.48k
}
1366
// pattern: %comp%|%oror%|&&
1367
9
static inline bool match141(const Token* tok) {
1368
9
    if (!tok || !(tok->isComparisonOp() || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
1369
9
        return false;
1370
0
    return true;
1371
9
}
1372
// pattern: =|-|-=|/|/=
1373
1
static inline bool match142(const Token* tok) {
1374
1
    if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("-=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("/="))))
1375
1
        return false;
1376
0
    return true;
1377
1
}
1378
// pattern: [-/%]
1379
4.00k
static inline bool match143(const Token* tok) {
1380
4.00k
    if (!tok || tok->str().size() != 1U || !strchr("-/%", tok->str()[0]))
1381
3.83k
        return false;
1382
174
    return true;
1383
4.00k
}
1384
// pattern: %oror%|%comp%|&&|?|!
1385
0
static inline bool match144(const Token* tok) {
1386
0
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || tok->isComparisonOp() || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!"))))
1387
0
        return false;
1388
0
    return true;
1389
0
}
1390
// pattern: ==|>=|<=
1391
0
static inline bool match145(const Token* tok) {
1392
0
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<="))))
1393
0
        return false;
1394
0
    return true;
1395
0
}
1396
// pattern: !=|>|<
1397
0
static inline bool match146(const Token* tok) {
1398
0
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))))
1399
0
        return false;
1400
0
    return true;
1401
0
}
1402
// pattern: %num%|NULL|nullptr
1403
0
static inline bool match147(const Token* tok) {
1404
0
    if (!tok || !(tok->isNumber() || (tok->str() == MatchCompiler::makeConstString("NULL")) || (tok->str() == MatchCompiler::makeConstString("nullptr"))))
1405
0
        return false;
1406
0
    return true;
1407
0
}
1408
// pattern: isgreater|isless|islessgreater|isgreaterequal|islessequal ( %var% , %var% )
1409
9.00k
static inline bool match148(const Token* tok) {
1410
9.00k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("isgreater")) || (tok->str() == MatchCompiler::makeConstString("isless")) || (tok->str() == MatchCompiler::makeConstString("islessgreater")) || (tok->str() == MatchCompiler::makeConstString("isgreaterequal")) || (tok->str() == MatchCompiler::makeConstString("islessequal"))))
1411
9.00k
        return false;
1412
0
    tok = tok->next();
1413
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1414
0
        return false;
1415
0
    tok = tok->next();
1416
0
    if (!tok || !(tok->varId() != 0))
1417
0
        return false;
1418
0
    tok = tok->next();
1419
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
1420
0
        return false;
1421
0
    tok = tok->next();
1422
0
    if (!tok || !(tok->varId() != 0))
1423
0
        return false;
1424
0
    tok = tok->next();
1425
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1426
0
        return false;
1427
0
    return true;
1428
0
}
1429
// pattern: <|<=
1430
934
static inline bool match149(const Token* tok) {
1431
934
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<="))))
1432
615
        return false;
1433
319
    return true;
1434
934
}
1435
// pattern: >|>=
1436
930
static inline bool match150(const Token* tok) {
1437
930
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">="))))
1438
620
        return false;
1439
310
    return true;
1440
930
}
1441
// pattern: >=
1442
934
static inline bool match151(const Token* tok) {
1443
934
    if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")))
1444
874
        return false;
1445
60
    return true;
1446
934
}
1447
// pattern: <=
1448
933
static inline bool match152(const Token* tok) {
1449
933
    if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")))
1450
874
        return false;
1451
59
    return true;
1452
933
}
1453
// pattern: (|{
1454
0
static inline bool match153(const Token* tok) {
1455
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
1456
0
        return false;
1457
0
    return true;
1458
0
}
1459
// pattern: ) )|}| ;
1460
0
static inline bool match154(const Token* tok) {
1461
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1462
0
        return false;
1463
0
    tok = tok->next();
1464
0
    if (tok && (((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
1465
0
        tok = tok->next();
1466
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1467
0
        return false;
1468
0
    return true;
1469
0
}
1470
// pattern: return %var% ;
1471
0
static inline bool match155(const Token* tok) {
1472
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
1473
0
        return false;
1474
0
    tok = tok->next();
1475
0
    if (!tok || !(tok->varId() != 0))
1476
0
        return false;
1477
0
    tok = tok->next();
1478
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1479
0
        return false;
1480
0
    return true;
1481
0
}
1482
// pattern: <<|>>|<<=|>>=
1483
8.26k
static inline bool match156(const Token* tok) {
1484
8.26k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || (tok->str() == MatchCompiler::makeConstString("<<=")) || (tok->str() == MatchCompiler::makeConstString(">>="))))
1485
8.26k
        return false;
1486
1
    return true;
1487
8.26k
}
1488
// pattern: memset|memcpy|memmove (
1489
21.5k
static inline bool match157(const Token* tok) {
1490
21.5k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("memset")) || (tok->str() == MatchCompiler::makeConstString("memcpy")) || (tok->str() == MatchCompiler::makeConstString("memmove"))))
1491
21.5k
        return false;
1492
0
    tok = tok->next();
1493
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1494
0
        return false;
1495
0
    return true;
1496
0
}
1497
// pattern: %name% ::|.
1498
0
static inline bool match158(const Token* tok) {
1499
0
    if (!tok || !tok->isName())
1500
0
        return false;
1501
0
    tok = tok->next();
1502
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("."))))
1503
0
        return false;
1504
0
    return true;
1505
0
}
1506
// pattern: %var% ,
1507
0
static inline bool match159(const Token* tok) {
1508
0
    if (!tok || !(tok->varId() != 0))
1509
0
        return false;
1510
0
    tok = tok->next();
1511
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
1512
0
        return false;
1513
0
    return true;
1514
0
}
1515
// pattern: [(,] NULL [,)]
1516
22.6k
static inline bool match160(const Token* tok) {
1517
22.6k
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
1518
21.6k
        return false;
1519
996
    tok = tok->next();
1520
996
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("NULL")))
1521
996
        return false;
1522
0
    tok = tok->next();
1523
0
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
1524
0
        return false;
1525
0
    return true;
1526
0
}
1527
// pattern: ...
1528
0
static inline bool match161(const Token* tok) {
1529
0
    if (!tok || !((tok->tokType() == Token::eEllipsis) && tok->str() == MatchCompiler::makeConstString("...")))
1530
0
        return false;
1531
0
    return true;
1532
0
}
1533
// pattern: InterlockedDecrement ( & %name% ) ; if ( %name%|!|0
1534
0
static inline bool match162(const Token* tok) {
1535
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("InterlockedDecrement")))
1536
0
        return false;
1537
0
    tok = tok->next();
1538
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1539
0
        return false;
1540
0
    tok = tok->next();
1541
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
1542
0
        return false;
1543
0
    tok = tok->next();
1544
0
    if (!tok || !tok->isName())
1545
0
        return false;
1546
0
    tok = tok->next();
1547
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1548
0
        return false;
1549
0
    tok = tok->next();
1550
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1551
0
        return false;
1552
0
    tok = tok->next();
1553
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")))
1554
0
        return false;
1555
0
    tok = tok->next();
1556
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1557
0
        return false;
1558
0
    tok = tok->next();
1559
0
    if (!tok || !(tok->isName() || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || (tok->str() == MatchCompiler::makeConstString("0"))))
1560
0
        return false;
1561
0
    return true;
1562
0
}
1563
// pattern: 0 %comp% %name% )
1564
0
static inline bool match163(const Token* tok) {
1565
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0")))
1566
0
        return false;
1567
0
    tok = tok->next();
1568
0
    if (!tok || !tok->isComparisonOp())
1569
0
        return false;
1570
0
    tok = tok->next();
1571
0
    if (!tok || !tok->isName())
1572
0
        return false;
1573
0
    tok = tok->next();
1574
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1575
0
        return false;
1576
0
    return true;
1577
0
}
1578
// pattern: ! %name% )
1579
0
static inline bool match164(const Token* tok) {
1580
0
    if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))
1581
0
        return false;
1582
0
    tok = tok->next();
1583
0
    if (!tok || !tok->isName())
1584
0
        return false;
1585
0
    tok = tok->next();
1586
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1587
0
        return false;
1588
0
    return true;
1589
0
}
1590
// pattern: %name% )
1591
0
static inline bool match165(const Token* tok) {
1592
0
    if (!tok || !tok->isName())
1593
0
        return false;
1594
0
    tok = tok->next();
1595
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1596
0
        return false;
1597
0
    return true;
1598
0
}
1599
// pattern: %name% %comp% 0 )
1600
0
static inline bool match166(const Token* tok) {
1601
0
    if (!tok || !tok->isName())
1602
0
        return false;
1603
0
    tok = tok->next();
1604
0
    if (!tok || !tok->isComparisonOp())
1605
0
        return false;
1606
0
    tok = tok->next();
1607
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0")))
1608
0
        return false;
1609
0
    tok = tok->next();
1610
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1611
0
        return false;
1612
0
    return true;
1613
0
}
1614
// pattern: if ( ::| InterlockedDecrement ( & %name%
1615
0
static inline bool match167(const Token* tok) {
1616
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")))
1617
0
        return false;
1618
0
    tok = tok->next();
1619
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1620
0
        return false;
1621
0
    tok = tok->next();
1622
0
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
1623
0
        tok = tok->next();
1624
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("InterlockedDecrement")))
1625
0
        return false;
1626
0
    tok = tok->next();
1627
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1628
0
        return false;
1629
0
    tok = tok->next();
1630
0
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
1631
0
        return false;
1632
0
    tok = tok->next();
1633
0
    if (!tok || !tok->isName())
1634
0
        return false;
1635
0
    return true;
1636
0
}
1637
// pattern: } return %name%
1638
0
static inline bool match168(const Token* tok) {
1639
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1640
0
        return false;
1641
0
    tok = tok->next();
1642
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
1643
0
        return false;
1644
0
    tok = tok->next();
1645
0
    if (!tok || !tok->isName())
1646
0
        return false;
1647
0
    return true;
1648
0
}
1649
// pattern: } else { return %name%
1650
0
static inline bool match169(const Token* tok) {
1651
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1652
0
        return false;
1653
0
    tok = tok->next();
1654
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else")))
1655
0
        return false;
1656
0
    tok = tok->next();
1657
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
1658
0
        return false;
1659
0
    tok = tok->next();
1660
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
1661
0
        return false;
1662
0
    tok = tok->next();
1663
0
    if (!tok || !tok->isName())
1664
0
        return false;
1665
0
    return true;
1666
0
}
1667
// pattern: {|}|; %name% :
1668
22.6k
static inline bool match170(const Token* tok) {
1669
22.6k
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString(";"))))
1670
16.5k
        return false;
1671
6.15k
    tok = tok->next();
1672
6.15k
    if (!tok || !tok->isName())
1673
2.03k
        return false;
1674
4.12k
    tok = tok->next();
1675
4.12k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
1676
4.12k
        return false;
1677
0
    return true;
1678
4.12k
}
1679
// pattern: sizeof
1680
0
static inline bool match171(const Token* tok) {
1681
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof")))
1682
0
        return false;
1683
0
    return true;
1684
0
}
1685
// pattern: %oror%|&&|?|:|;
1686
1.64k
static inline bool match172(const Token* tok) {
1687
1.64k
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString(";"))))
1688
1.64k
        return false;
1689
0
    return true;
1690
1.64k
}
1691
// pattern: ,|)|;
1692
0
static inline bool match173(const Token* tok) {
1693
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString(";"))))
1694
0
        return false;
1695
0
    return true;
1696
0
}
1697
// pattern: 0
1698
0
static inline bool match174(const Token* tok) {
1699
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0")))
1700
0
        return false;
1701
0
    return true;
1702
0
}
1703
// pattern: &&
1704
0
static inline bool match175(const Token* tok) {
1705
0
    if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")))
1706
0
        return false;
1707
0
    return true;
1708
0
}
1709
// pattern: false
1710
0
static inline bool match176(const Token* tok) {
1711
0
    if (!tok || !((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false")))
1712
0
        return false;
1713
0
    return true;
1714
0
}
1715
// pattern: ||
1716
0
static inline bool match177(const Token* tok) {
1717
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("||")))
1718
0
        return false;
1719
0
    return true;
1720
0
}
1721
// pattern: true
1722
0
static inline bool match178(const Token* tok) {
1723
0
    if (!tok || !((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("true")))
1724
0
        return false;
1725
0
    return true;
1726
0
}
1727
// pattern: ++|--|%assign%
1728
1.22k
static inline bool match179(const Token* tok) {
1729
1.22k
    if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")) || tok->isAssignmentOp()))
1730
1.12k
        return false;
1731
100
    return true;
1732
1.22k
}
1733
// pattern: (|{|,
1734
1.12k
static inline bool match180(const Token* tok) {
1735
1.12k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(","))))
1736
1.02k
        return false;
1737
107
    return true;
1738
1.12k
}
1739
// pattern: if|while|switch|sizeof
1740
107
static inline bool match181(const Token* tok) {
1741
107
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("switch")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof"))))
1742
0
        return false;
1743
107
    return true;
1744
107
}
1745
// pattern: %var%|.|[
1746
0
static inline bool match182(const Token* tok) {
1747
0
    if (!tok || !((tok->varId() != 0) || (tok->str() == MatchCompiler::makeConstString(".")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))))
1748
0
        return false;
1749
0
    return true;
1750
0
}
1751
// pattern: ?|!|&&|%oror%|%comp%
1752
0
static inline bool match183(const Token* tok) {
1753
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || tok->isComparisonOp()))
1754
0
        return false;
1755
0
    return true;
1756
0
}
1757
// pattern: if|while|switch|sizeof (
1758
0
static inline bool match184(const Token* tok) {
1759
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("switch")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof"))))
1760
0
        return false;
1761
0
    tok = tok->next();
1762
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1763
0
        return false;
1764
0
    return true;
1765
0
}
1766
// pattern: <|>|<=|>=|-
1767
22.6k
static inline bool match185(const Token* tok) {
1768
22.6k
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1769
21.9k
        return false;
1770
720
    return true;
1771
22.6k
}
1772
// pattern: -
1773
0
static inline bool match186(const Token* tok) {
1774
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))
1775
0
        return false;
1776
0
    return true;
1777
0
}
1778
// pattern: +|-
1779
0
static inline bool match187(const Token* tok) {
1780
0
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1781
0
        return false;
1782
0
    return true;
1783
0
}
1784
/*
1785
 * Cppcheck - A tool for static C/C++ code analysis
1786
 * Copyright (C) 2007-2024 Cppcheck team.
1787
 *
1788
 * This program is free software: you can redistribute it and/or modify
1789
 * it under the terms of the GNU General Public License as published by
1790
 * the Free Software Foundation, either version 3 of the License, or
1791
 * (at your option) any later version.
1792
 *
1793
 * This program is distributed in the hope that it will be useful,
1794
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1795
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1796
 * GNU General Public License for more details.
1797
 *
1798
 * You should have received a copy of the GNU General Public License
1799
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1800
 */
1801
1802
1803
//---------------------------------------------------------------------------
1804
#include "checkother.h"
1805
1806
#include "astutils.h"
1807
#include "fwdanalysis.h"
1808
#include "library.h"
1809
#include "mathlib.h"
1810
#include "platform.h"
1811
#include "settings.h"
1812
#include "standards.h"
1813
#include "symboldatabase.h"
1814
#include "token.h"
1815
#include "tokenize.h"
1816
#include "tokenlist.h"
1817
#include "utils.h"
1818
#include "valueflow.h"
1819
#include "vfvalue.h"
1820
1821
#include <algorithm> // find_if()
1822
#include <cctype>
1823
#include <cstddef>
1824
#include <cstdint>
1825
#include <list>
1826
#include <map>
1827
#include <set>
1828
#include <sstream>
1829
#include <utility>
1830
1831
//---------------------------------------------------------------------------
1832
1833
// Register this check class (by creating a static instance of it)
1834
namespace {
1835
    CheckOther instance;
1836
}
1837
1838
static const CWE CWE128(128U);   // Wrap-around Error
1839
static const CWE CWE131(131U);   // Incorrect Calculation of Buffer Size
1840
static const CWE CWE197(197U);   // Numeric Truncation Error
1841
static const CWE CWE362(362U);   // Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
1842
static const CWE CWE369(369U);   // Divide By Zero
1843
static const CWE CWE398(398U);   // Indicator of Poor Code Quality
1844
static const CWE CWE475(475U);   // Undefined Behavior for Input to API
1845
static const CWE CWE561(561U);   // Dead Code
1846
static const CWE CWE563(563U);   // Assignment to Variable without Use ('Unused Variable')
1847
static const CWE CWE570(570U);   // Expression is Always False
1848
static const CWE CWE571(571U);   // Expression is Always True
1849
static const CWE CWE672(672U);   // Operation on a Resource after Expiration or Release
1850
static const CWE CWE628(628U);   // Function Call with Incorrectly Specified Arguments
1851
static const CWE CWE683(683U);   // Function Call With Incorrect Order of Arguments
1852
static const CWE CWE704(704U);   // Incorrect Type Conversion or Cast
1853
static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
1854
static const CWE CWE768(768U);   // Incorrect Short Circuit Evaluation
1855
static const CWE CWE783(783U);   // Operator Precedence Logic Error
1856
1857
//----------------------------------------------------------------------------------
1858
// The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value.
1859
// If this return value is stored in a character variable and then compared
1860
// to EOF, which is an integer, the comparison maybe be false.
1861
//
1862
// Reference:
1863
// - Ticket #160
1864
// - http://www.cplusplus.com/reference/cstdio/fgetc/
1865
// - http://www.cplusplus.com/reference/cstdio/getc/
1866
// - http://www.cplusplus.com/reference/cstdio/getchar/
1867
// - http://www.cplusplus.com/reference/cstdio/ungetc/ ...
1868
//----------------------------------------------------------------------------------
1869
void CheckOther::checkCastIntToCharAndBack()
1870
763
{
1871
763
    if (!mSettings->severity.isEnabled(Severity::warning))
1872
0
        return;
1873
1874
763
    logChecker("CheckOther::checkCastIntToCharAndBack"); // warning
1875
1876
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
1877
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
1878
1.10k
        std::map<int, std::string> vars;
1879
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
1880
            // Quick check to see if any of the matches below have any chances
1881
21.5k
            if (!match1(tok))
1882
20.6k
                continue;
1883
889
            if (match2(tok)) {
1884
0
                const Variable *var = tok->variable();
1885
0
                if (var && var->typeEndToken()->str() == MatchCompiler::makeConstString("char") && !var->typeEndToken()->isSigned()) {
1886
0
                    vars[tok->varId()] = tok->strAt(2);
1887
0
                }
1888
889
            } else if (match3(tok)) {
1889
0
                tok = tok->tokAt(3);
1890
0
                const Variable *var = tok->variable();
1891
0
                if (var && var->typeEndToken()->str() == MatchCompiler::makeConstString("char") && !var->typeEndToken()->isSigned()) {
1892
0
                    checkCastIntToCharAndBackError(tok, tok->strAt(2));
1893
0
                }
1894
889
            } else if (tok->isCpp() && (match4(tok) || match5(tok))) {
1895
0
                tok = tok->tokAt(3);
1896
0
                const Variable *var = tok->variable();
1897
0
                if (var && var->typeEndToken()->str() == MatchCompiler::makeConstString("char") && !var->typeEndToken()->isSigned()) {
1898
0
                    checkCastIntToCharAndBackError(tok, "cin.get");
1899
0
                }
1900
889
            } else if (tok->isCpp() && (match6(tok) || match7(tok))) {
1901
0
                const Variable *var = tok->variable();
1902
0
                if (var && var->typeEndToken()->str() == MatchCompiler::makeConstString("char") && !var->typeEndToken()->isSigned()) {
1903
0
                    vars[tok->varId()] = "cin.get";
1904
0
                }
1905
889
            } else if (match8(tok)) {
1906
0
                if (vars.find(tok->varId()) != vars.end()) {
1907
0
                    checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
1908
0
                }
1909
889
            } else if (match9(tok)) {
1910
0
                tok = tok->tokAt(2);
1911
0
                if (vars.find(tok->varId()) != vars.end()) {
1912
0
                    checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
1913
0
                }
1914
0
            }
1915
889
        }
1916
1.10k
    }
1917
763
}
1918
1919
void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName)
1920
0
{
1921
0
    reportError(
1922
0
        tok,
1923
0
        Severity::warning,
1924
0
        "checkCastIntToCharAndBack",
1925
0
        "$symbol:" + strFunctionName + "\n"
1926
0
        "Storing $symbol() return value in char variable and then comparing with EOF.\n"
1927
0
        "When saving $symbol() return value in char variable there is loss of precision. "
1928
0
        " When $symbol() returns EOF this value is truncated. Comparing the char "
1929
0
        "variable with EOF can have unexpected results. For instance a loop \"while (EOF != (c = $symbol());\" "
1930
0
        "loops forever on some compilers/platforms and on other compilers/platforms it will stop "
1931
0
        "when the file contains a matching character.", CWE197, Certainty::normal
1932
0
        );
1933
0
}
1934
1935
1936
//---------------------------------------------------------------------------
1937
// Clarify calculation precedence for ternary operators.
1938
//---------------------------------------------------------------------------
1939
void CheckOther::clarifyCalculation()
1940
763
{
1941
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCalculation"))
1942
0
        return;
1943
1944
763
    logChecker("CheckOther::clarifyCalculation"); // style
1945
1946
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
1947
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
1948
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
1949
            // ? operator where lhs is arithmetical expression
1950
21.5k
            if (tok->str() != MatchCompiler::makeConstString("?") || !tok->astOperand1() || !tok->astOperand1()->isCalculation())
1951
21.5k
                continue;
1952
0
            if (!tok->astOperand1()->isArithmeticalOp() && tok->astOperand1()->tokType() != Token::eBitOp)
1953
0
                continue;
1954
1955
            // non-pointer calculation in lhs and pointer in rhs => no clarification is needed
1956
0
            if (tok->astOperand1()->isBinaryOp() && match10(tok->astOperand1()) && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->pointer > 0)
1957
0
                continue;
1958
1959
            // bit operation in lhs and char literals in rhs => probably no mistake
1960
0
            if (tok->astOperand1()->tokType() == Token::eBitOp && match11(tok->astOperand2()->astOperand1()) && match11(tok->astOperand2()->astOperand2()))
1961
0
                continue;
1962
1963
            // 2nd operand in lhs has known integer value => probably no mistake
1964
0
            if (tok->astOperand1()->isBinaryOp() && tok->astOperand1()->astOperand2()->hasKnownIntValue()) {
1965
0
                const Token *op = tok->astOperand1()->astOperand2();
1966
0
                if (op->isNumber())
1967
0
                    continue;
1968
0
                if (op->valueType() && op->valueType()->isEnum())
1969
0
                    continue;
1970
0
            }
1971
1972
            // Is code clarified by parentheses already?
1973
0
            const Token *tok2 = tok->astOperand1();
1974
0
            for (; tok2; tok2 = tok2->next()) {
1975
0
                if (tok2->str() == MatchCompiler::makeConstString("("))
1976
0
                    tok2 = tok2->link();
1977
0
                else if (tok2->str() == MatchCompiler::makeConstString(")"))
1978
0
                    break;
1979
0
                else if (tok2->str() == MatchCompiler::makeConstString("?")) {
1980
0
                    clarifyCalculationError(tok, tok->astOperand1()->str());
1981
0
                    break;
1982
0
                }
1983
0
            }
1984
0
        }
1985
1.10k
    }
1986
763
}
1987
1988
void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op)
1989
0
{
1990
    // suspicious calculation
1991
0
    const std::string calc("'a" + op + "b?c:d'");
1992
1993
    // recommended calculation #1
1994
0
    const std::string s1("'(a" + op + "b)?c:d'");
1995
1996
    // recommended calculation #2
1997
0
    const std::string s2("'a" + op + "(b?c:d)'");
1998
1999
0
    reportError(tok,
2000
0
                Severity::style,
2001
0
                "clarifyCalculation",
2002
0
                "Clarify calculation precedence for '" + op + "' and '?'.\n"
2003
0
                "Suspicious calculation. Please use parentheses to clarify the code. "
2004
0
                "The code '" + calc + "' should be written as either '" + s1 + "' or '" + s2 + "'.", CWE783, Certainty::normal);
2005
0
}
2006
2007
//---------------------------------------------------------------------------
2008
// Clarify (meaningless) statements like *foo++; with parentheses.
2009
//---------------------------------------------------------------------------
2010
void CheckOther::clarifyStatement()
2011
763
{
2012
763
    if (!mSettings->severity.isEnabled(Severity::warning))
2013
0
        return;
2014
2015
763
    logChecker("CheckOther::clarifyStatement"); // warning
2016
2017
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2018
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
2019
23.7k
        for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
2020
22.6k
            if (tok->astOperand1() && match12(tok)) {
2021
90
                const Token *tok2 = tok->previous();
2022
2023
90
                while (tok2 && tok2->str() == MatchCompiler::makeConstString("*"))
2024
0
                    tok2 = tok2->previous();
2025
2026
90
                if (tok2 && !tok2->astParent() && match13(tok2)) {
2027
0
                    tok2 = tok->astOperand1();
2028
0
                    if (match14(tok2))
2029
0
                        clarifyStatementError(tok2);
2030
0
                }
2031
90
            }
2032
22.6k
        }
2033
1.10k
    }
2034
763
}
2035
2036
void CheckOther::clarifyStatementError(const Token *tok)
2037
0
{
2038
0
    reportError(tok, Severity::warning, "clarifyStatement", "In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'?\n"
2039
0
                "A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. "
2040
0
                "Thus, the dereference is meaningless. Did you intend to write '(*A)++;'?", CWE783, Certainty::normal);
2041
0
}
2042
2043
//---------------------------------------------------------------------------
2044
// Check for suspicious occurrences of 'if(); {}'.
2045
//---------------------------------------------------------------------------
2046
void CheckOther::checkSuspiciousSemicolon()
2047
763
{
2048
763
    if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
2049
0
        return;
2050
2051
763
    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
2052
2053
763
    logChecker("CheckOther::checkSuspiciousSemicolon"); // warning,inconclusive
2054
2055
    // Look for "if(); {}", "for(); {}" or "while(); {}"
2056
2.79k
    for (const Scope &scope : symbolDatabase->scopeList) {
2057
2.79k
        if (scope.type == Scope::eIf || scope.type == Scope::eElse || scope.type == Scope::eWhile || scope.type == Scope::eFor) {
2058
            // Ensure the semicolon is at the same line number as the if/for/while statement
2059
            // and the {..} block follows it without an extra empty line.
2060
931
            if (match15(scope.bodyStart) &&
2061
931
                scope.bodyStart->previous()->linenr() == scope.bodyStart->tokAt(2)->linenr() &&
2062
931
                scope.bodyStart->linenr()+1 >= scope.bodyStart->tokAt(3)->linenr() &&
2063
931
                !scope.bodyStart->tokAt(3)->isExpandedMacro()) {
2064
0
                suspiciousSemicolonError(scope.classDef);
2065
0
            }
2066
931
        }
2067
2.79k
    }
2068
763
}
2069
2070
void CheckOther::suspiciousSemicolonError(const Token* tok)
2071
0
{
2072
0
    reportError(tok, Severity::warning, "suspiciousSemicolon",
2073
0
                "Suspicious use of ; at the end of '" + (tok ? tok->str() : std::string()) + "' statement.", CWE398, Certainty::normal);
2074
0
}
2075
2076
2077
//---------------------------------------------------------------------------
2078
// For C++ code, warn if C-style casts are used on pointer types
2079
//---------------------------------------------------------------------------
2080
void CheckOther::warningOldStylePointerCast()
2081
763
{
2082
    // Only valid on C++ code
2083
763
    if (!mTokenizer->isCPP())
2084
0
        return;
2085
2086
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("cstyleCast"))
2087
0
        return;
2088
2089
763
    logChecker("CheckOther::warningOldStylePointerCast"); // style,c++
2090
2091
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2092
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
2093
1.10k
        const Token* tok;
2094
1.10k
        if (scope->function && scope->function->isConstructor())
2095
0
            tok = scope->classDef;
2096
1.10k
        else
2097
1.10k
            tok = scope->bodyStart;
2098
23.7k
        for (; tok && tok != scope->bodyEnd; tok = tok->next()) {
2099
            // Old style pointer casting..
2100
22.6k
            if (tok->str() != MatchCompiler::makeConstString("("))
2101
21.6k
                continue;
2102
990
            const Token* castTok = tok->next();
2103
1.22k
            while (match16(castTok)) {
2104
237
                castTok = castTok->next();
2105
237
                if (match17(castTok) && castTok->link())
2106
0
                    castTok = castTok->link()->next();
2107
237
            }
2108
990
            if (castTok == tok->next())
2109
753
                continue;
2110
237
            bool isPtr = false, isRef = false;
2111
251
            while (match18(castTok)) {
2112
14
                if (castTok->str() == MatchCompiler::makeConstString("*"))
2113
4
                    isPtr = true;
2114
10
                else if (castTok->str() == MatchCompiler::makeConstString("&"))
2115
10
                    isRef = true;
2116
14
                castTok = castTok->next();
2117
14
            }
2118
237
            if ((!isPtr && !isRef) || !match19(castTok))
2119
237
                continue;
2120
2121
0
            if (match20(tok->previous()))
2122
0
                continue;
2123
2124
            // skip first "const" in "const Type* const"
2125
0
            while (match21(tok->next()))
2126
0
                tok = tok->next();
2127
0
            const Token* typeTok = tok->next();
2128
            // skip second "const" in "const Type* const"
2129
0
            if (tok->strAt(3) == MatchCompiler::makeConstString("const"))
2130
0
                tok = tok->next();
2131
2132
0
            const Token *p = tok->tokAt(4);
2133
0
            if (p->hasKnownIntValue() && p->values().front().intvalue==0) // Casting nullpointers is safe
2134
0
                continue;
2135
2136
0
            if (typeTok->tokType() == Token::eType || typeTok->tokType() == Token::eName)
2137
0
                cstyleCastError(tok, isPtr);
2138
0
        }
2139
1.10k
    }
2140
763
}
2141
2142
void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
2143
0
{
2144
0
    const std::string type = isPtr ? "pointer" : "reference";
2145
0
    reportError(tok, Severity::style, "cstyleCast",
2146
0
                "C-style " + type + " casting\n"
2147
0
                "C-style " + type + " casting detected. C++ offers four different kinds of casts as replacements: "
2148
0
                "static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to "
2149
0
                "any of those automatically, thus it is considered safer if the programmer explicitly states "
2150
0
                "which kind of cast is expected.", CWE398, Certainty::normal);
2151
0
}
2152
2153
void CheckOther::suspiciousFloatingPointCast()
2154
763
{
2155
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("suspiciousFloatingPointCast"))
2156
0
        return;
2157
2158
763
    logChecker("CheckOther::suspiciousFloatingPointCast"); // style
2159
2160
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2161
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
2162
1.10k
        const Token* tok = scope->bodyStart;
2163
1.10k
        if (scope->function && scope->function->isConstructor())
2164
0
            tok = scope->classDef;
2165
23.7k
        for (; tok && tok != scope->bodyEnd; tok = tok->next()) {
2166
2167
22.6k
            if (!tok->isCast())
2168
22.6k
                continue;
2169
2170
1
            const ValueType* vt = tok->valueType();
2171
1
            if (!vt || vt->pointer || vt->reference != Reference::None || (vt->type != ValueType::FLOAT && vt->type != ValueType::DOUBLE))
2172
1
                continue;
2173
2174
0
            using VTT = std::vector<ValueType::Type>;
2175
0
            const VTT sourceTypes = vt->type == ValueType::FLOAT ? VTT{ ValueType::DOUBLE, ValueType::LONGDOUBLE } : VTT{ ValueType::LONGDOUBLE };
2176
2177
0
            const Token* source = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
2178
0
            if (!source || !source->valueType() || std::find(sourceTypes.begin(), sourceTypes.end(), source->valueType()->type) == sourceTypes.end())
2179
0
                continue;
2180
2181
0
            const Token* parent = tok->astParent();
2182
0
            if (!parent)
2183
0
                continue;
2184
2185
0
            const ValueType* parentVt = parent->valueType();
2186
0
            if (!parentVt || parent->str() == MatchCompiler::makeConstString("(")) {
2187
0
                int argn{};
2188
0
                if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
2189
0
                    if (ftok->function()) {
2190
0
                        if (const Variable* argVar = ftok->function()->getArgumentVar(argn))
2191
0
                            parentVt = argVar->valueType();
2192
0
                    }
2193
0
                }
2194
0
            }
2195
0
            if (!parentVt || std::find(sourceTypes.begin(), sourceTypes.end(), parentVt->type) == sourceTypes.end())
2196
0
                continue;
2197
2198
0
            suspiciousFloatingPointCastError(tok);
2199
0
        }
2200
1.10k
    }
2201
763
}
2202
2203
void CheckOther::suspiciousFloatingPointCastError(const Token* tok)
2204
0
{
2205
0
    reportError(tok, Severity::style, "suspiciousFloatingPointCast",
2206
0
                "Floating-point cast causes loss of precision.\n"
2207
0
                "If this cast is not intentional, remove it to avoid loss of precision", CWE398, Certainty::normal);
2208
0
}
2209
2210
//---------------------------------------------------------------------------
2211
// float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
2212
//---------------------------------------------------------------------------
2213
2214
void CheckOther::invalidPointerCast()
2215
763
{
2216
763
    if (!mSettings->severity.isEnabled(Severity::portability))
2217
0
        return;
2218
2219
763
    logChecker("CheckOther::invalidPointerCast"); // portability
2220
2221
763
    const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
2222
763
    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
2223
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
2224
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
2225
21.5k
            const Token* toTok = nullptr;
2226
21.5k
            const Token* fromTok = nullptr;
2227
            // Find cast
2228
21.5k
            if (match22(tok)) {
2229
0
                toTok = tok;
2230
0
                fromTok = tok->astOperand1();
2231
21.5k
            } else if (match23(tok) && tok->linkAt(1)) {
2232
0
                toTok = tok->linkAt(1)->next();
2233
0
                fromTok = toTok->astOperand2();
2234
0
            }
2235
21.5k
            if (!fromTok)
2236
21.5k
                continue;
2237
2238
0
            const ValueType* fromType = fromTok->valueType();
2239
0
            const ValueType* toType = toTok->valueType();
2240
0
            if (!fromType || !toType || !fromType->pointer || !toType->pointer)
2241
0
                continue;
2242
2243
0
            if (fromType->type != toType->type && fromType->type >= ValueType::Type::BOOL && toType->type >= ValueType::Type::BOOL && (toType->type != ValueType::Type::CHAR || printInconclusive)) {
2244
0
                if (toType->isIntegral() && fromType->isIntegral())
2245
0
                    continue;
2246
2247
0
                invalidPointerCastError(tok, fromType->str(), toType->str(), toType->type == ValueType::Type::CHAR, toType->isIntegral());
2248
0
            }
2249
0
        }
2250
1.10k
    }
2251
763
}
2252
2253
2254
void CheckOther::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt)
2255
0
{
2256
0
    if (toIsInt) { // If we cast something to int*, this can be useful to play with its binary data representation
2257
0
        reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + " to " + to + " is not portable due to different binary data representations on different platforms.", CWE704, inconclusive ? Certainty::inconclusive : Certainty::normal);
2258
0
    } else
2259
0
        reportError(tok, Severity::portability, "invalidPointerCast", "Casting between " + from + " and " + to + " which have an incompatible binary data representation.", CWE704, Certainty::normal);
2260
0
}
2261
2262
2263
//---------------------------------------------------------------------------
2264
// Detect redundant assignments: x = 0; x = 4;
2265
//---------------------------------------------------------------------------
2266
2267
void CheckOther::checkRedundantAssignment()
2268
763
{
2269
763
    if (!mSettings->severity.isEnabled(Severity::style) &&
2270
763
        !mSettings->isPremiumEnabled("redundantAssignment") &&
2271
763
        !mSettings->isPremiumEnabled("redundantAssignInSwitch"))
2272
0
        return;
2273
2274
763
    logChecker("CheckOther::checkRedundantAssignment"); // style
2275
2276
763
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
2277
1.10k
    for (const Scope *scope : symbolDatabase->functionScopes) {
2278
1.10k
        if (!scope->bodyStart)
2279
0
            continue;
2280
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
2281
21.5k
            if (match24(tok))
2282
                // todo: handle lambdas
2283
0
                break;
2284
21.5k
            if (match25(tok))
2285
                // todo: check try blocks
2286
0
                tok = tok->linkAt(1);
2287
21.5k
            if ((tok->isAssignmentOp() || tok->tokType() == Token::eIncDecOp) && tok->astOperand1()) {
2288
2.87k
                if (tok->astParent())
2289
881
                    continue;
2290
2291
                // Do not warn about redundant initialization when rhs is trivial
2292
                // TODO : do not simplify the variable declarations
2293
1.99k
                bool isInitialization = false;
2294
1.99k
                if (match26(tok->tokAt(-2)) && tok->tokAt(-2)->isSplittedVarDeclEq()) {
2295
0
                    isInitialization = true;
2296
0
                    bool trivial = true;
2297
0
                    visitAstNodes(tok->astOperand2(),
2298
0
                                  [&](const Token *rhs) {
2299
0
                        if (match27(rhs))
2300
0
                            return ChildrenToVisit::none;
2301
0
                        if (match28(rhs) && !rhs->varId())
2302
0
                            return ChildrenToVisit::none;
2303
0
                        if (match29(rhs) && rhs->hasKnownIntValue())
2304
0
                            return ChildrenToVisit::none;
2305
0
                        if (rhs->isCast())
2306
0
                            return ChildrenToVisit::op2;
2307
0
                        trivial = false;
2308
0
                        return ChildrenToVisit::done;
2309
0
                    });
2310
0
                    if (trivial)
2311
0
                        continue;
2312
0
                }
2313
2314
1.99k
                const Token* rhs = tok->astOperand2();
2315
                // Do not warn about assignment with 0 / NULL
2316
1.99k
                if ((rhs && MathLib::isNullValue(rhs->str())) || isNullOperand(rhs))
2317
3
                    continue;
2318
2319
1.99k
                if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference())
2320
                    // todo: check references
2321
0
                    continue;
2322
2323
1.99k
                if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isStatic())
2324
                    // todo: check static variables
2325
0
                    continue;
2326
2327
1.99k
                bool inconclusive = false;
2328
1.99k
                if (tok->isCpp() && tok->astOperand1()->valueType()) {
2329
                    // If there is a custom assignment operator => this is inconclusive
2330
14
                    if (tok->astOperand1()->valueType()->typeScope) {
2331
0
                        const std::string op = "operator" + tok->str();
2332
0
                        const std::list<Function>& fList = tok->astOperand1()->valueType()->typeScope->functionList;
2333
0
                        inconclusive = std::any_of(fList.cbegin(), fList.cend(), [&](const Function& f) {
2334
0
                            return f.name() == op;
2335
0
                        });
2336
0
                    }
2337
                    // assigning a smart pointer has side effects
2338
14
                    if (tok->astOperand1()->valueType()->type == ValueType::SMART_POINTER)
2339
0
                        break;
2340
14
                }
2341
1.99k
                if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive))
2342
0
                    continue;
2343
2344
1.99k
                FwdAnalysis fwdAnalysis(*mSettings);
2345
1.99k
                if (fwdAnalysis.hasOperand(tok->astOperand2(), tok->astOperand1()))
2346
8
                    continue;
2347
2348
                // Is there a redundant assignment?
2349
1.98k
                const Token *start;
2350
1.98k
                if (tok->isAssignmentOp())
2351
1.98k
                    start = tok->next();
2352
0
                else
2353
0
                    start = tok->findExpressionStartEndTokens().second->next();
2354
2355
1.98k
                const Token * tokenToCheck = tok->astOperand1();
2356
2357
                // Check if we are working with union
2358
1.98k
                for (const Token* tempToken = tokenToCheck; match30(tempToken);) {
2359
0
                    tempToken = tempToken->astOperand1();
2360
0
                    if (tempToken && tempToken->variable() && tempToken->variable()->type() && tempToken->variable()->type()->isUnionType())
2361
0
                        tokenToCheck = tempToken;
2362
0
                }
2363
2364
1.98k
                if (start->hasKnownSymbolicValue(tokenToCheck) && match31(start->astParent()) && !diag(tok)) {
2365
0
                    const ValueFlow::Value* val = start->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC);
2366
0
                    if (val->intvalue == 0) // no offset
2367
0
                        redundantAssignmentSameValueError(tokenToCheck, val, tok->astOperand1()->expressionString());
2368
0
                }
2369
2370
                // Get next assignment..
2371
1.98k
                const Token *nextAssign = fwdAnalysis.reassign(tokenToCheck, start, scope->bodyEnd);
2372
                // extra check for union
2373
1.98k
                if (nextAssign && tokenToCheck != tok->astOperand1())
2374
0
                    nextAssign = fwdAnalysis.reassign(tok->astOperand1(), start, scope->bodyEnd);
2375
2376
1.98k
                if (!nextAssign)
2377
1.98k
                    continue;
2378
2379
                // there is redundant assignment. Is there a case between the assignments?
2380
0
                bool hasCase = false;
2381
0
                for (const Token *tok2 = tok; tok2 != nextAssign; tok2 = tok2->next()) {
2382
0
                    if (tok2->str() == MatchCompiler::makeConstString("break") || tok2->str() == MatchCompiler::makeConstString("return"))
2383
0
                        break;
2384
0
                    if (tok2->str() == MatchCompiler::makeConstString("case")) {
2385
0
                        hasCase = true;
2386
0
                        break;
2387
0
                    }
2388
0
                }
2389
2390
                // warn
2391
0
                if (hasCase)
2392
0
                    redundantAssignmentInSwitchError(tok, nextAssign, tok->astOperand1()->expressionString());
2393
0
                else if (isInitialization)
2394
0
                    redundantInitializationError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
2395
0
                else {
2396
0
                    diag(nextAssign);
2397
0
                    redundantAssignmentError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
2398
0
                }
2399
0
            }
2400
21.5k
        }
2401
1.10k
    }
2402
763
}
2403
2404
void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var)
2405
0
{
2406
0
    const std::list<const Token *> callstack = { tok1, tok2 };
2407
0
    reportError(callstack, Severity::performance, "redundantCopy",
2408
0
                "$symbol:" + var + "\n"
2409
0
                "Buffer '$symbol' is being written before its old content has been used.", CWE563, Certainty::normal);
2410
0
}
2411
2412
void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
2413
0
{
2414
0
    const ErrorPath errorPath = { ErrorPathItem(tok1, var + " is assigned"), ErrorPathItem(tok2, var + " is overwritten") };
2415
0
    if (inconclusive)
2416
0
        reportError(errorPath, Severity::style, "redundantAssignment",
2417
0
                    "$symbol:" + var + "\n"
2418
0
                    "Variable '$symbol' is reassigned a value before the old one has been used if variable is no semaphore variable.\n"
2419
0
                    "Variable '$symbol' is reassigned a value before the old one has been used. Make sure that this variable is not used like a semaphore in a threading environment before simplifying this code.", CWE563, Certainty::inconclusive);
2420
0
    else
2421
0
        reportError(errorPath, Severity::style, "redundantAssignment",
2422
0
                    "$symbol:" + var + "\n"
2423
0
                    "Variable '$symbol' is reassigned a value before the old one has been used.", CWE563, Certainty::normal);
2424
0
}
2425
2426
void CheckOther::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
2427
0
{
2428
0
    const ErrorPath errorPath = { ErrorPathItem(tok1, var + " is initialized"), ErrorPathItem(tok2, var + " is overwritten") };
2429
0
    reportError(errorPath, Severity::style, "redundantInitialization",
2430
0
                "$symbol:" + var + "\nRedundant initialization for '$symbol'. The initialized value is overwritten before it is read.",
2431
0
                CWE563,
2432
0
                inconclusive ? Certainty::inconclusive : Certainty::normal);
2433
0
}
2434
2435
void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
2436
0
{
2437
0
    const ErrorPath errorPath = { ErrorPathItem(tok1, "$symbol is assigned"), ErrorPathItem(tok2, "$symbol is overwritten") };
2438
0
    reportError(errorPath, Severity::style, "redundantAssignInSwitch",
2439
0
                "$symbol:" + var + "\n"
2440
0
                "Variable '$symbol' is reassigned a value before the old one has been used. 'break;' missing?", CWE563, Certainty::normal);
2441
0
}
2442
2443
void CheckOther::redundantAssignmentSameValueError(const Token *tok, const ValueFlow::Value* val, const std::string &var)
2444
0
{
2445
0
    auto errorPath = val->errorPath;
2446
0
    errorPath.emplace_back(tok, "");
2447
0
    reportError(errorPath, Severity::style, "redundantAssignment",
2448
0
                "$symbol:" + var + "\n"
2449
0
                "Variable '$symbol' is assigned an expression that holds the same value.", CWE563, Certainty::normal);
2450
0
}
2451
2452
2453
//---------------------------------------------------------------------------
2454
//    switch (x)
2455
//    {
2456
//        case 2:
2457
//            y = a;        // <- this assignment is redundant
2458
//        case 3:
2459
//            y = b;        // <- case 2 falls through and sets y twice
2460
//    }
2461
//---------------------------------------------------------------------------
2462
static inline bool isFunctionOrBreakPattern(const Token *tok)
2463
0
{
2464
0
    return match32(tok) || match33(tok);
2465
0
}
2466
2467
void CheckOther::redundantBitwiseOperationInSwitchError()
2468
763
{
2469
763
    if (!mSettings->severity.isEnabled(Severity::warning))
2470
0
        return;
2471
2472
763
    logChecker("CheckOther::redundantBitwiseOperationInSwitch"); // warning
2473
2474
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2475
2476
    // Find the beginning of a switch. E.g.:
2477
    //   switch (var) { ...
2478
2.79k
    for (const Scope &switchScope : symbolDatabase->scopeList) {
2479
2.79k
        if (switchScope.type != Scope::eSwitch || !switchScope.bodyStart)
2480
2.79k
            continue;
2481
2482
        // Check the contents of the switch statement
2483
0
        std::map<int, const Token*> varsWithBitsSet;
2484
0
        std::map<int, std::string> bitOperations;
2485
2486
0
        for (const Token *tok2 = switchScope.bodyStart->next(); tok2 != switchScope.bodyEnd; tok2 = tok2->next()) {
2487
0
            if (tok2->str() == MatchCompiler::makeConstString("{")) {
2488
                // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
2489
                //   case 3: b = 1;
2490
                //   case 4: if (a) { b = 2; }    // Doesn't make the b=1 redundant because it's conditional
2491
0
                if (match34(tok2->previous()) && tok2->link()) {
2492
0
                    const Token* endOfConditional = tok2->link();
2493
0
                    for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) {
2494
0
                        if (tok3->varId() != 0) {
2495
0
                            varsWithBitsSet.erase(tok3->varId());
2496
0
                            bitOperations.erase(tok3->varId());
2497
0
                        } else if (isFunctionOrBreakPattern(tok3)) {
2498
0
                            varsWithBitsSet.clear();
2499
0
                            bitOperations.clear();
2500
0
                        }
2501
0
                    }
2502
0
                    tok2 = endOfConditional;
2503
0
                }
2504
0
            }
2505
2506
            // Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
2507
            //    case 3: b = 1;    // <== redundant
2508
            //    case 4: b = 2;
2509
2510
0
            if (match35(tok2->previous())) {
2511
0
                varsWithBitsSet.erase(tok2->varId());
2512
0
                bitOperations.erase(tok2->varId());
2513
0
            }
2514
2515
            // Bitwise operation. Report an error if it's performed twice before a break. E.g.:
2516
            //    case 3: b |= 1;    // <== redundant
2517
            //    case 4: b |= 1;
2518
0
            else if (match36(tok2->previous()) &&
2519
0
                     (tok2->strAt(1) == MatchCompiler::makeConstString("|=") || tok2->strAt(1) == MatchCompiler::makeConstString("&=")) &&
2520
0
                     match37(tok2->next()->astOperand2())) {
2521
0
                const std::string bitOp = tok2->strAt(1)[0] + tok2->strAt(2);
2522
0
                const auto i2 = utils::as_const(varsWithBitsSet).find(tok2->varId());
2523
2524
                // This variable has not had a bit operation performed on it yet, so just make a note of it
2525
0
                if (i2 == varsWithBitsSet.end()) {
2526
0
                    varsWithBitsSet[tok2->varId()] = tok2;
2527
0
                    bitOperations[tok2->varId()] = bitOp;
2528
0
                }
2529
2530
                // The same bit operation has been performed on the same variable twice, so report an error
2531
0
                else if (bitOperations[tok2->varId()] == bitOp)
2532
0
                    redundantBitwiseOperationInSwitchError(i2->second, i2->second->str());
2533
2534
                // A different bit operation was performed on the variable, so clear it
2535
0
                else {
2536
0
                    varsWithBitsSet.erase(tok2->varId());
2537
0
                    bitOperations.erase(tok2->varId());
2538
0
                }
2539
0
            }
2540
2541
            // Bitwise operation. Report an error if it's performed twice before a break. E.g.:
2542
            //    case 3: b = b | 1;    // <== redundant
2543
            //    case 4: b = b | 1;
2544
0
            else if (match38(tok2->previous()) &&
2545
0
                     tok2->varId() == tok2->tokAt(2)->varId()) {
2546
0
                const std::string bitOp = tok2->strAt(3) + tok2->strAt(4);
2547
0
                const auto i2 = utils::as_const(varsWithBitsSet).find(tok2->varId());
2548
2549
                // This variable has not had a bit operation performed on it yet, so just make a note of it
2550
0
                if (i2 == varsWithBitsSet.end()) {
2551
0
                    varsWithBitsSet[tok2->varId()] = tok2;
2552
0
                    bitOperations[tok2->varId()] = bitOp;
2553
0
                }
2554
2555
                // The same bit operation has been performed on the same variable twice, so report an error
2556
0
                else if (bitOperations[tok2->varId()] == bitOp)
2557
0
                    redundantBitwiseOperationInSwitchError(i2->second, i2->second->str());
2558
2559
                // A different bit operation was performed on the variable, so clear it
2560
0
                else {
2561
0
                    varsWithBitsSet.erase(tok2->varId());
2562
0
                    bitOperations.erase(tok2->varId());
2563
0
                }
2564
0
            }
2565
2566
            // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
2567
            //    case 3: b = 1;
2568
            //    case 4: b++;
2569
0
            else if (tok2->varId() != 0 && tok2->strAt(1) != MatchCompiler::makeConstString("|") && tok2->strAt(1) != MatchCompiler::makeConstString("&")) {
2570
0
                varsWithBitsSet.erase(tok2->varId());
2571
0
                bitOperations.erase(tok2->varId());
2572
0
            }
2573
2574
            // Reset our record of assignments if there is a break or function call. E.g.:
2575
            //    case 3: b = 1; break;
2576
0
            if (isFunctionOrBreakPattern(tok2)) {
2577
0
                varsWithBitsSet.clear();
2578
0
                bitOperations.clear();
2579
0
            }
2580
0
        }
2581
0
    }
2582
763
}
2583
2584
void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname)
2585
0
{
2586
0
    reportError(tok, Severity::style,
2587
0
                "redundantBitwiseOperationInSwitch",
2588
0
                "$symbol:" + varname + "\n"
2589
0
                "Redundant bitwise operation on '$symbol' in 'switch' statement. 'break;' missing?");
2590
0
}
2591
2592
2593
//---------------------------------------------------------------------------
2594
// Check for statements like case A||B: in switch()
2595
//---------------------------------------------------------------------------
2596
void CheckOther::checkSuspiciousCaseInSwitch()
2597
763
{
2598
763
    if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
2599
0
        return;
2600
2601
763
    logChecker("CheckOther::checkSuspiciousCaseInSwitch"); // warning,inconclusive
2602
2603
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2604
2605
2.79k
    for (const Scope & scope : symbolDatabase->scopeList) {
2606
2.79k
        if (scope.type != Scope::eSwitch)
2607
2.79k
            continue;
2608
2609
0
        for (const Token* tok = scope.bodyStart->next(); tok != scope.bodyEnd; tok = tok->next()) {
2610
0
            if (tok->str() == MatchCompiler::makeConstString("case")) {
2611
0
                const Token* finding = nullptr;
2612
0
                for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
2613
0
                    if (tok2->str() == MatchCompiler::makeConstString(":"))
2614
0
                        break;
2615
0
                    if (match39(tok2))
2616
0
                        break;
2617
2618
0
                    if (tok2->str() == MatchCompiler::makeConstString("?"))
2619
0
                        finding = nullptr;
2620
0
                    else if (match40(tok2))
2621
0
                        finding = tok2;
2622
0
                }
2623
0
                if (finding)
2624
0
                    suspiciousCaseInSwitchError(finding, finding->str());
2625
0
            }
2626
0
        }
2627
0
    }
2628
763
}
2629
2630
void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
2631
0
{
2632
0
    reportError(tok, Severity::warning, "suspiciousCase",
2633
0
                "Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n"
2634
0
                "Using an operator like '" + operatorString + "' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead?", CWE398, Certainty::inconclusive);
2635
0
}
2636
2637
static bool isNestedInSwitch(const Scope* scope)
2638
0
{
2639
0
    while (scope) {
2640
0
        if (scope->type == Scope::ScopeType::eSwitch)
2641
0
            return true;
2642
0
        if (scope->type == Scope::ScopeType::eUnconditional) {
2643
0
            scope = scope->nestedIn;
2644
0
            continue;
2645
0
        }
2646
0
        break;
2647
0
    }
2648
0
    return false;
2649
0
}
2650
2651
static bool isVardeclInSwitch(const Token* tok)
2652
0
{
2653
0
    if (!tok)
2654
0
        return false;
2655
0
    if (!isNestedInSwitch(tok->scope()))
2656
0
        return false;
2657
0
    if (const Token* end = findmatch41(tok) ) {
2658
0
        for (const Token* tok2 = tok; tok2 != end; tok2 = tok2->next()) {
2659
0
            if (tok2->isKeyword() && tok2->str() == MatchCompiler::makeConstString("case"))
2660
0
                return false;
2661
0
            if (tok2->variable() && tok2->variable()->nameToken() == tok2) {
2662
0
                end = tok2->scope()->bodyEnd;
2663
0
                for (const Token* tok3 = tok2; tok3 != end; tok3 = tok3->next()) {
2664
0
                    if (tok3->isKeyword())
2665
0
                        return tok3->str() == MatchCompiler::makeConstString("case");
2666
0
                }
2667
0
                return false;
2668
0
            }
2669
0
        }
2670
0
    }
2671
0
    return false;
2672
0
}
2673
2674
//---------------------------------------------------------------------------
2675
//    Find consecutive return, break, continue, goto or throw statements. e.g.:
2676
//        break; break;
2677
//    Detect dead code, that follows such a statement. e.g.:
2678
//        return(0); foo();
2679
//---------------------------------------------------------------------------
2680
void CheckOther::checkUnreachableCode()
2681
763
{
2682
    // misra-c-2012-2.1
2683
    // misra-c-2023-2.1
2684
    // misra-cpp-2008-0-1-1
2685
    // autosar
2686
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateBreak") && !mSettings->isPremiumEnabled("unreachableCode"))
2687
0
        return;
2688
2689
763
    logChecker("CheckOther::checkUnreachableCode"); // style
2690
2691
763
    const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
2692
763
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
2693
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
2694
1.10k
        if (scope->hasInlineOrLambdaFunction(nullptr, /*onlyInline*/ true))
2695
0
            continue;
2696
14.6k
        for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
2697
13.5k
            const Token* secondBreak = nullptr;
2698
13.5k
            const Token* labelName = nullptr;
2699
13.5k
            if (tok->link() && match42(tok))
2700
727
                tok = tok->link();
2701
12.8k
            else if (match43(tok))
2702
0
                secondBreak = tok->tokAt(2);
2703
12.8k
            else if (match44(tok) && tok->next()->isKeyword()) {
2704
1.19k
                if (match45(tok->astParent()))
2705
0
                    continue;
2706
1.19k
                tok = tok->next(); // tok should point to return or throw
2707
2.95k
                for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
2708
2.95k
                    if (tok2->str() == MatchCompiler::makeConstString("(") || tok2->str() == MatchCompiler::makeConstString("{"))
2709
83
                        tok2 = tok2->link();
2710
2.95k
                    if (tok2->str() == MatchCompiler::makeConstString(";")) {
2711
1.19k
                        secondBreak = tok2->next();
2712
1.19k
                        break;
2713
1.19k
                    }
2714
2.95k
                }
2715
11.6k
            } else if (match46(tok)) {
2716
0
                secondBreak = tok->tokAt(3);
2717
0
                labelName = tok->next();
2718
11.6k
            } else if (match32(tok) && mSettings->library.isnoreturn(tok) && !match47(tok->next()->astParent())) {
2719
0
                if ((!tok->function() || (tok->function()->token != tok && tok->function()->tokenDef != tok)) && tok->linkAt(1)->strAt(1) != MatchCompiler::makeConstString("{"))
2720
0
                    secondBreak = tok->linkAt(1)->tokAt(2);
2721
0
                if (match48(secondBreak)) {
2722
                    // clarification for tools that function returns
2723
0
                    continue;
2724
0
                }
2725
0
            }
2726
13.5k
            while (match49(secondBreak) && secondBreak->scope()->type == Scope::ScopeType::eUnconditional)
2727
0
                secondBreak = secondBreak->next();
2728
13.5k
            if (secondBreak && secondBreak->scope()->nestedIn && secondBreak->scope()->nestedIn->type == Scope::ScopeType::eSwitch &&
2729
13.5k
                tok->str() == MatchCompiler::makeConstString("break")) {
2730
0
                while (match50(secondBreak) && secondBreak->scope()->type == Scope::ScopeType::eUnconditional)
2731
0
                    secondBreak = secondBreak->next();
2732
0
            }
2733
13.5k
            while (match51(secondBreak))
2734
0
                secondBreak = secondBreak->next();
2735
2736
            // Statements follow directly, no line between them. (#3383)
2737
            // TODO: Try to find a better way to avoid false positives due to preprocessor configurations.
2738
13.5k
            const bool inconclusive = secondBreak && (secondBreak->linenr() - 1 > secondBreak->previous()->linenr());
2739
2740
13.5k
            if (secondBreak && (printInconclusive || !inconclusive)) {
2741
1.19k
                if (match52(secondBreak) && secondBreak->isKeyword()) {
2742
0
                    duplicateBreakError(secondBreak, inconclusive);
2743
0
                    tok = findmatch53(secondBreak) ;
2744
1.19k
                } else if (secondBreak->str() == MatchCompiler::makeConstString("break")) { // break inside switch as second break statement should not issue a warning
2745
0
                    if (tok->str() == MatchCompiler::makeConstString("break")) // If the previous was a break, too: Issue warning
2746
0
                        duplicateBreakError(secondBreak, inconclusive);
2747
0
                    else {
2748
0
                        if (tok->scope()->type != Scope::eSwitch) // Check, if the enclosing scope is a switch
2749
0
                            duplicateBreakError(secondBreak, inconclusive);
2750
0
                    }
2751
0
                    tok = findmatch53(secondBreak) ;
2752
1.19k
                } else if (!match54(secondBreak) && secondBreak->strAt(1) != MatchCompiler::makeConstString(":")) { // TODO: No bailout for unconditional scopes
2753
                    // If the goto label is followed by a loop construct in which the label is defined it's quite likely
2754
                    // that the goto jump was intended to skip some code on the first loop iteration.
2755
0
                    bool labelInFollowingLoop = false;
2756
0
                    if (labelName && match55(secondBreak)) {
2757
0
                        const Token *scope2 = findmatch56(secondBreak) ;
2758
0
                        if (scope2) {
2759
0
                            for (const Token *tokIter = scope2; tokIter != scope2->link() && tokIter; tokIter = tokIter->next()) {
2760
0
                                if (match57(tokIter) && labelName->str() == tokIter->strAt(1)) {
2761
0
                                    labelInFollowingLoop = true;
2762
0
                                    break;
2763
0
                                }
2764
0
                            }
2765
0
                        }
2766
0
                    }
2767
2768
                    // hide FP for statements that just hide compiler warnings about unused function arguments
2769
0
                    bool silencedCompilerWarningOnly = false;
2770
0
                    const Token *silencedWarning = secondBreak;
2771
0
                    for (;;) {
2772
0
                        if (match58(silencedWarning)) {
2773
0
                            silencedWarning = silencedWarning->tokAt(5);
2774
0
                            continue;
2775
0
                        }
2776
0
                        if (silencedWarning && silencedWarning == scope->bodyEnd)
2777
0
                            silencedCompilerWarningOnly = true;
2778
0
                        break;
2779
0
                    }
2780
0
                    if (silencedWarning)
2781
0
                        secondBreak = silencedWarning;
2782
2783
0
                    if (!labelInFollowingLoop && !silencedCompilerWarningOnly && !isVardeclInSwitch(secondBreak))
2784
0
                        unreachableCodeError(secondBreak, tok, inconclusive);
2785
0
                    tok = findmatch53(secondBreak) ;
2786
1.19k
                } else if (secondBreak->scope() && secondBreak->scope()->isLoopScope() && secondBreak->str() == MatchCompiler::makeConstString("}") && tok->str() == MatchCompiler::makeConstString("continue")) {
2787
0
                    redundantContinueError(tok);
2788
0
                    tok = secondBreak;
2789
0
                } else
2790
1.19k
                    tok = secondBreak;
2791
2792
1.19k
                if (!tok)
2793
0
                    break;
2794
1.19k
                tok = tok->previous(); // Will be advanced again by for loop
2795
1.19k
            }
2796
13.5k
        }
2797
1.10k
    }
2798
763
}
2799
2800
void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
2801
0
{
2802
0
    reportError(tok, Severity::style, "duplicateBreak",
2803
0
                "Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
2804
0
                "Consecutive return, break, continue, goto or throw statements are unnecessary. "
2805
0
                "The second statement can never be executed, and so should be removed.", CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
2806
0
}
2807
2808
void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive)
2809
0
{
2810
0
    std::string msg = "Statements following ";
2811
0
    if (noreturn && (noreturn->function() || mSettings->library.isnoreturn(noreturn)))
2812
0
        msg += "noreturn function '" + noreturn->str() + "()'";
2813
0
    else if (noreturn && noreturn->isKeyword())
2814
0
        msg += "'" + noreturn->str() + "'";
2815
0
    else
2816
0
        msg += "return, break, continue, goto or throw";
2817
0
    msg += " will never be executed.";
2818
0
    reportError(tok, Severity::style, "unreachableCode",
2819
0
                msg, CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
2820
0
}
2821
2822
void CheckOther::redundantContinueError(const Token *tok)
2823
0
{
2824
0
    reportError(tok, Severity::style, "redundantContinue",
2825
0
                "'continue' is redundant since it is the last statement in a loop.", CWE561, Certainty::normal);
2826
0
}
2827
2828
0
static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings& settings) {
2829
0
    if (!tok)
2830
0
        return false;
2831
0
    if (tok->isNumber() || tok->tokType() == Token::eString || tok->tokType() == Token::eChar || tok->isBoolean())
2832
0
        return true;
2833
0
    bool needsCheck = tok->varId() > 0;
2834
0
    if (!needsCheck) {
2835
0
        if (tok->isArithmeticalOp())
2836
0
            return isSimpleExpr(tok->astOperand1(), var, settings) && (!tok->astOperand2() || isSimpleExpr(tok->astOperand2(), var, settings));
2837
0
        const Token* ftok = tok->previous();
2838
0
        if (match32(ftok) &&
2839
0
            ((ftok->function() && ftok->function()->isConst()) || settings.library.isFunctionConst(ftok->str(), /*pure*/ true)))
2840
0
            needsCheck = true;
2841
0
        else if (tok->str() == MatchCompiler::makeConstString("[")) {
2842
0
            needsCheck = tok->astOperand1() && tok->astOperand1()->varId() > 0;
2843
0
            tok = tok->astOperand1();
2844
0
        }
2845
0
        else if (isLeafDot(tok->astOperand2())) {
2846
0
            needsCheck = tok->astOperand2()->varId() > 0;
2847
0
            tok = tok->astOperand2();
2848
0
        }
2849
0
    }
2850
0
    return (needsCheck && !findExpressionChanged(tok, tok->astParent(), var->scope()->bodyEnd, settings));
2851
0
}
2852
2853
//---------------------------------------------------------------------------
2854
// Check scope of variables..
2855
//---------------------------------------------------------------------------
2856
void CheckOther::checkVariableScope()
2857
763
{
2858
763
    if (mSettings->clang)
2859
0
        return;
2860
2861
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("variableScope"))
2862
0
        return;
2863
2864
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
2865
2866
    // In C it is common practice to declare local variables at the
2867
    // start of functions.
2868
763
    if (mSettings->daca && mTokenizer->isC())
2869
0
        return;
2870
2871
763
    logChecker("CheckOther::checkVariableScope"); // style,notclang
2872
2873
4.57k
    for (const Variable* var : symbolDatabase->variableList()) {
2874
4.57k
        if (!var || !var->isLocal() || var->isConst())
2875
4.57k
            continue;
2876
2877
0
        if (var->nameToken()->isExpandedMacro())
2878
0
            continue;
2879
2880
0
        const bool isPtrOrRef = var->isPointer() || var->isReference();
2881
0
        const bool isSimpleType = var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType() || (var->typeStartToken()->isC() && var->type() && var->type()->isStructType());
2882
0
        if (!isPtrOrRef && !isSimpleType && !astIsContainer(var->nameToken()))
2883
0
            continue;
2884
2885
0
        if (mTokenizer->hasIfdef(var->nameToken(), var->scope()->bodyEnd))
2886
0
            continue;
2887
2888
        // reference of range for loop variable..
2889
0
        if (match59(var->nameToken()->previous())) {
2890
0
            const Token *otherVarToken = var->nameToken()->tokAt(2);
2891
0
            const Variable *otherVar = otherVarToken->variable();
2892
0
            if (otherVar && match60(otherVar->nameToken()) &&
2893
0
                otherVar->nameToken()->next()->astParent() &&
2894
0
                match61(otherVar->nameToken()->next()->astParent()->previous()))
2895
0
                continue;
2896
0
        }
2897
2898
0
        bool forHead = false; // Don't check variables declared in header of a for loop
2899
0
        for (const Token* tok = var->typeStartToken(); tok; tok = tok->previous()) {
2900
0
            if (tok->str() == MatchCompiler::makeConstString("(")) {
2901
0
                forHead = true;
2902
0
                break;
2903
0
            }
2904
0
            if (match62(tok))
2905
0
                break;
2906
0
        }
2907
0
        if (forHead)
2908
0
            continue;
2909
2910
0
        const Token* tok = var->nameToken()->next();
2911
0
        bool isConstructor = false;
2912
0
        if (match63(tok, var->declarationId())) { // bailout for assignment
2913
0
            tok = tok->tokAt(2)->astOperand2();
2914
0
            if (!isSimpleExpr(tok, var, *mSettings))
2915
0
                continue;
2916
0
        }
2917
0
        else if (match64(tok)) { // bailout for constructor
2918
0
            isConstructor = true;
2919
0
            const Token* argTok = tok->astOperand2();
2920
0
            bool bail = false;
2921
0
            while (argTok) {
2922
0
                if (match65(argTok)) {
2923
0
                    if (!isSimpleExpr(argTok->astOperand2(), var, *mSettings)) {
2924
0
                        bail = true;
2925
0
                        break;
2926
0
                    }
2927
0
                } else if (argTok->str() != MatchCompiler::makeConstString(".") && !isSimpleExpr(argTok, var, *mSettings)) {
2928
0
                    bail = true;
2929
0
                    break;
2930
0
                }
2931
0
                argTok = argTok->astOperand1();
2932
0
            }
2933
0
            if (bail)
2934
0
                continue;
2935
0
        }
2936
        // bailout if initialized with function call that has possible side effects
2937
0
        if (!isConstructor && match66(tok) && match67(tok->astOperand2()))
2938
0
            continue;
2939
0
        bool reduce = true;
2940
0
        bool used = false; // Don't warn about unused variables
2941
0
        for (; tok && tok != var->scope()->bodyEnd; tok = tok->next()) {
2942
0
            if (tok->str() == MatchCompiler::makeConstString("{") && tok->scope() != tok->previous()->scope() && !tok->isExpandedMacro() && !isWithinScope(tok, var, Scope::ScopeType::eLambda)) {
2943
0
                if (used) {
2944
0
                    bool used2 = false;
2945
0
                    if (!checkInnerScope(tok, var, used2) || used2) {
2946
0
                        reduce = false;
2947
0
                        break;
2948
0
                    }
2949
0
                } else if (!checkInnerScope(tok, var, used)) {
2950
0
                    reduce = false;
2951
0
                    break;
2952
0
                }
2953
2954
0
                tok = tok->link();
2955
2956
                // parse else if blocks..
2957
0
            } else if (match68(tok) && match69(tok->linkAt(3))) {
2958
0
                tok = tok->next();
2959
0
            } else if (tok->varId() == var->declarationId() || tok->str() == MatchCompiler::makeConstString("goto")) {
2960
0
                reduce = false;
2961
0
                break;
2962
0
            }
2963
0
        }
2964
2965
0
        if (reduce && used)
2966
0
            variableScopeError(var->nameToken(), var->name());
2967
0
    }
2968
763
}
2969
2970
// used to check if an argument to a function might depend on another argument
2971
static bool mayDependOn(const ValueType *other, const ValueType *original)
2972
0
{
2973
0
    if (!other || !original)
2974
0
        return false;
2975
2976
    // other must be pointer
2977
0
    if (!other->pointer)
2978
0
        return false;
2979
2980
    // must be same underlying type
2981
0
    if (other->type != original->type)
2982
0
        return false;
2983
2984
0
    const int otherPtr = other->pointer + (other->reference == Reference::LValue ? 1 : 0);
2985
0
    const int originalPtr = original->pointer;
2986
2987
0
    if (otherPtr == originalPtr) {
2988
        // if other is not const than original may be copied to other
2989
0
        return !other->isConst(otherPtr);
2990
0
    }
2991
2992
    // other may be reassigned to original
2993
0
    return otherPtr > originalPtr;
2994
0
}
2995
2996
bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used) const
2997
0
{
2998
0
    const Scope* scope = tok->next()->scope();
2999
0
    bool loopVariable = scope->isLoopScope();
3000
0
    bool noContinue = true;
3001
0
    const Token* forHeadEnd = nullptr;
3002
0
    const Token* end = tok->link();
3003
0
    if (scope->type == Scope::eUnconditional && (tok->strAt(-1) == MatchCompiler::makeConstString(")") || tok->previous()->isName())) // Might be an unknown macro like BOOST_FOREACH
3004
0
        loopVariable = true;
3005
3006
0
    if (scope->type == Scope::eDo) {
3007
0
        end = end->linkAt(2);
3008
0
    } else if (loopVariable && tok->strAt(-1) == MatchCompiler::makeConstString(")")) {
3009
0
        tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
3010
0
    } else if (scope->type == Scope::eSwitch) {
3011
0
        for (const Scope* innerScope : scope->nestedList) {
3012
0
            if (used) {
3013
0
                bool used2 = false;
3014
0
                if (!checkInnerScope(innerScope->bodyStart, var, used2) || used2) {
3015
0
                    return false;
3016
0
                }
3017
0
            } else if (!checkInnerScope(innerScope->bodyStart, var, used)) {
3018
0
                return false;
3019
0
            }
3020
0
        }
3021
0
    }
3022
3023
0
    bool bFirstAssignment=false;
3024
0
    for (; tok && tok != end; tok = tok->next()) {
3025
0
        if (tok->str() == MatchCompiler::makeConstString("goto"))
3026
0
            return false;
3027
0
        if (tok->str() == MatchCompiler::makeConstString("continue"))
3028
0
            noContinue = false;
3029
3030
0
        if (match61(tok))
3031
0
            forHeadEnd = tok->linkAt(1);
3032
0
        if (tok == forHeadEnd)
3033
0
            forHeadEnd = nullptr;
3034
3035
0
        if (loopVariable && noContinue && tok->scope() == scope && !forHeadEnd && scope->type != Scope::eSwitch && match70(tok, var->declarationId())) { // Assigned in outer scope.
3036
0
            loopVariable = false;
3037
0
            std::pair<const Token*, const Token*> range = tok->next()->findExpressionStartEndTokens();
3038
0
            if (range.first)
3039
0
                range.first = range.first->next();
3040
0
            const Token* exprTok = findExpression(var->nameToken()->exprId(), range.first, range.second, [&](const Token* tok2) {
3041
0
                return tok2->varId() == var->declarationId();
3042
0
            });
3043
0
            if (exprTok) {
3044
0
                tok = exprTok;
3045
0
                loopVariable = true;
3046
0
            }
3047
0
        }
3048
3049
0
        if (loopVariable && match71(tok, var->declarationId())) // Variable used in loop
3050
0
            return false;
3051
3052
0
        if (match72(tok, var->declarationId())) // Taking address of variable
3053
0
            return false;
3054
3055
0
        if (match70(tok, var->declarationId())) {
3056
0
            if (!bFirstAssignment && var->isInit() && findmatch73(tok->tokAt(2), findmatch41(tok->tokAt(3)) , var->declarationId()) )
3057
0
                return false;
3058
0
            bFirstAssignment = true;
3059
0
        }
3060
3061
0
        if (!bFirstAssignment && match74(tok, var->declarationId())) // dereferencing means access to previous content
3062
0
            return false;
3063
3064
0
        if (match75(tok, var->declarationId()) && (var->isArray() || var->isPointer() || (var->valueType() && var->valueType()->container))) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
3065
0
            return false;
3066
3067
0
        if (tok->varId() == var->declarationId()) {
3068
0
            used = true;
3069
0
            if (scope == tok->scope()) {
3070
0
                if (scope->type == Scope::eSwitch)
3071
0
                    return false; // Used in outer switch scope - unsafe or impossible to reduce scope
3072
3073
0
                if (scope->bodyStart && scope->bodyStart->isSimplifiedScope())
3074
0
                    return false; // simplified if/for/switch init statement
3075
0
            }
3076
0
            if (var->isArrayOrPointer()) {
3077
0
                int argn{};
3078
0
                if (const Token* ftok = getTokenArgumentFunction(tok, argn)) { // var passed to function?
3079
0
                    if (ftok->next()->astParent()) { // return value used?
3080
0
                        if (ftok->function() && Function::returnsPointer(ftok->function()))
3081
0
                            return false;
3082
0
                        const std::string ret = mSettings->library.returnValueType(ftok); // assume that var is returned
3083
0
                        if (!ret.empty() && ret.back() == '*')
3084
0
                            return false;
3085
0
                    }
3086
0
                    if (ftok->function()) {
3087
0
                        const std::list<Variable> &argvars = ftok->function()->argumentList;
3088
0
                        if (const Variable* argvar = ftok->function()->getArgumentVar(argn)) {
3089
0
                            if (!std::all_of(argvars.cbegin(), argvars.cend(), [&](const Variable& other) {
3090
0
                                return &other == argvar || !mayDependOn(other.valueType(), argvar->valueType());
3091
0
                            }))
3092
0
                                return false;
3093
0
                        }
3094
0
                    }
3095
0
                }
3096
0
            }
3097
0
            const auto yield = astContainerYield(tok);
3098
0
            if (yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT)
3099
0
                return false;
3100
0
        }
3101
0
    }
3102
3103
0
    return true;
3104
0
}
3105
3106
void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
3107
0
{
3108
0
    reportError(tok,
3109
0
                Severity::style,
3110
0
                "variableScope",
3111
0
                "$symbol:" + varname + "\n"
3112
0
                "The scope of the variable '$symbol' can be reduced.\n"
3113
0
                "The scope of the variable '$symbol' can be reduced. Warning: Be careful "
3114
0
                "when fixing this message, especially when there are inner loops. Here is an "
3115
0
                "example where cppcheck will write that the scope for 'i' can be reduced:\n"
3116
0
                "void f(int x)\n"
3117
0
                "{\n"
3118
0
                "    int i = 0;\n"
3119
0
                "    if (x) {\n"
3120
0
                "        // it's safe to move 'int i = 0;' here\n"
3121
0
                "        for (int n = 0; n < 10; ++n) {\n"
3122
0
                "            // it is possible but not safe to move 'int i = 0;' here\n"
3123
0
                "            do_something(&i);\n"
3124
0
                "        }\n"
3125
0
                "    }\n"
3126
0
                "}\n"
3127
0
                "When you see this message it is always safe to reduce the variable scope 1 level.", CWE398, Certainty::normal);
3128
0
}
3129
3130
//---------------------------------------------------------------------------
3131
// Comma in return statement: return a+1, b++;. (experimental)
3132
//---------------------------------------------------------------------------
3133
void CheckOther::checkCommaSeparatedReturn()
3134
763
{
3135
    // This is experimental for now. See #5076
3136
763
    if ((true) || !mSettings->severity.isEnabled(Severity::style)) // NOLINT(readability-simplify-boolean-expr)
3137
763
        return;
3138
3139
    // logChecker
3140
3141
0
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
3142
0
        if (tok->str() == MatchCompiler::makeConstString("return")) {
3143
0
            tok = tok->next();
3144
0
            while (tok && tok->str() != MatchCompiler::makeConstString(";")) {
3145
0
                if (tok->link() && match76(tok))
3146
0
                    tok = tok->link();
3147
3148
0
                if (!tok->isExpandedMacro() && tok->str() == MatchCompiler::makeConstString(",") && tok->linenr() != tok->next()->linenr())
3149
0
                    commaSeparatedReturnError(tok);
3150
3151
0
                tok = tok->next();
3152
0
            }
3153
            // bailout: missing semicolon (invalid code / bad tokenizer)
3154
0
            if (!tok)
3155
0
                break;
3156
0
        }
3157
0
    }
3158
0
}
3159
3160
void CheckOther::commaSeparatedReturnError(const Token *tok)
3161
0
{
3162
0
    reportError(tok,
3163
0
                Severity::style,
3164
0
                "commaSeparatedReturn",
3165
0
                "Comma is used in return statement. The comma can easily be misread as a ';'.\n"
3166
0
                "Comma is used in return statement. When comma is used in a return statement it can "
3167
0
                "easily be misread as a semicolon. For example in the code below the value "
3168
0
                "of 'b' is returned if the condition is true, but it is easy to think that 'a+1' is "
3169
0
                "returned:\n"
3170
0
                "    if (x)\n"
3171
0
                "        return a + 1,\n"
3172
0
                "    b++;\n"
3173
0
                "However it can be useful to use comma in macros. Cppcheck does not warn when such a "
3174
0
                "macro is then used in a return statement, it is less likely such code is misunderstood.", CWE398, Certainty::normal);
3175
0
}
3176
3177
static bool isLargeContainer(const Variable* var, const Settings* settings)
3178
0
{
3179
0
    const ValueType* vt = var->valueType();
3180
0
    if (vt->container->size_templateArgNo < 0)
3181
0
        return true;
3182
0
    const std::size_t maxByValueSize = 2 * settings->platform.sizeof_pointer;
3183
0
    if (var->dimensions().empty()) {
3184
0
        if (vt->container->startPattern == MatchCompiler::makeConstString("std :: bitset <")) {
3185
0
            if (vt->containerTypeToken->hasKnownIntValue())
3186
0
                return vt->containerTypeToken->getKnownIntValue() / 8 > maxByValueSize;
3187
0
        }
3188
0
        return false;
3189
0
    }
3190
0
    const ValueType vtElem = ValueType::parseDecl(vt->containerTypeToken, *settings);
3191
0
    const auto elemSize = std::max<std::size_t>(ValueFlow::getSizeOf(vtElem, *settings), 1);
3192
0
    const auto arraySize = var->dimension(0) * elemSize;
3193
0
    return arraySize > maxByValueSize;
3194
0
}
3195
3196
void CheckOther::checkPassByReference()
3197
763
{
3198
763
    if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC())
3199
0
        return;
3200
3201
763
    logChecker("CheckOther::checkPassByReference"); // performance,c++
3202
3203
763
    const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
3204
3205
4.57k
    for (const Variable* var : symbolDatabase->variableList()) {
3206
4.57k
        if (!var || !var->isClass() || var->isPointer() || (var->isArray() && !var->isStlType()) || var->isReference() || var->isEnumType())
3207
4.57k
            continue;
3208
3209
0
        const bool isRangeBasedFor = astIsRangeBasedForDecl(var->nameToken());
3210
0
        if (!var->isArgument() && !isRangeBasedFor)
3211
0
            continue;
3212
3213
0
        if (!isRangeBasedFor && var->scope() && var->scope()->function->arg->link()->strAt(-1) == MatchCompiler::makeConstString("..."))
3214
0
            continue; // references could not be used as va_start parameters (#5824)
3215
3216
0
        const Token * const varDeclEndToken = var->declEndToken();
3217
0
        if ((varDeclEndToken && varDeclEndToken->isExternC()) ||
3218
0
            (var->scope() && var->scope()->function && var->scope()->function->tokenDef && var->scope()->function->tokenDef->isExternC()))
3219
0
            continue; // references cannot be used in functions in extern "C" blocks
3220
3221
0
        bool inconclusive = false;
3222
3223
0
        const bool isContainer = var->valueType() && var->valueType()->type == ValueType::Type::CONTAINER && var->valueType()->container && !var->valueType()->container->view;
3224
0
        if (isContainer && !isLargeContainer(var, mSettings))
3225
0
            continue;
3226
0
        if (!isContainer) {
3227
0
            if (var->type() && !var->type()->isEnumType()) { // Check if type is a struct or class.
3228
                // Ensure that it is a large object.
3229
0
                if (!var->type()->classScope)
3230
0
                    inconclusive = true;
3231
0
                else if (!var->valueType() || ValueFlow::getSizeOf(*var->valueType(), *mSettings) <= 2 * mSettings->platform.sizeof_pointer)
3232
0
                    continue;
3233
0
            }
3234
0
            else
3235
0
                continue;
3236
0
        }
3237
3238
0
        if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive))
3239
0
            continue;
3240
3241
0
        if (var->isArray() && (!var->isStlType() || match77(var->nameToken()->next())))
3242
0
            continue;
3243
3244
0
        const bool isConst = var->isConst();
3245
0
        if (isConst) {
3246
0
            passedByValueError(var, inconclusive, isRangeBasedFor);
3247
0
            continue;
3248
0
        }
3249
3250
        // Check if variable could be const
3251
0
        if (!isRangeBasedFor && (!var->scope() || var->scope()->function->isImplicitlyVirtual()))
3252
0
            continue;
3253
3254
0
        if (!isVariableChanged(var, *mSettings)) {
3255
0
            passedByValueError(var, inconclusive, isRangeBasedFor);
3256
0
        }
3257
0
    }
3258
763
}
3259
3260
void CheckOther::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor)
3261
0
{
3262
0
    std::string id = isRangeBasedFor ? "iterateByValue" : "passedByValue";
3263
0
    const std::string action = isRangeBasedFor ? "declared as": "passed by";
3264
0
    const std::string type = isRangeBasedFor ? "Range variable" : "Function parameter";
3265
0
    std::string msg = "$symbol:" + (var ? var->name() : "") + "\n" +
3266
0
                      type + " '$symbol' should be " + action + " const reference.";
3267
0
    ErrorPath errorPath;
3268
0
    if (var && var->scope() && var->scope()->function && var->scope()->function->functionPointerUsage) {
3269
0
        id += "Callback";
3270
0
        errorPath.emplace_front(var->scope()->function->functionPointerUsage, "Function pointer used here.");
3271
0
        msg += " However it seems that '" + var->scope()->function->name() + "' is a callback function.";
3272
0
    }
3273
0
    if (var)
3274
0
        errorPath.emplace_back(var->nameToken(), msg);
3275
0
    if (isRangeBasedFor)
3276
0
        msg += "\nVariable '$symbol' is used to iterate by value. It could be declared as a const reference which is usually faster and recommended in C++.";
3277
0
    else
3278
0
        msg += "\nParameter '$symbol' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.";
3279
0
    reportError(errorPath, Severity::performance, id.c_str(), msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
3280
0
}
3281
3282
static bool isVariableMutableInInitializer(const Token* start, const Token * end, nonneg int varid)
3283
0
{
3284
0
    if (!start)
3285
0
        return false;
3286
0
    if (!end)
3287
0
        return false;
3288
0
    for (const Token *tok = start; tok != end; tok = tok->next()) {
3289
0
        if (tok->varId() != varid)
3290
0
            continue;
3291
0
        if (tok->astParent()) {
3292
0
            const Token * memberTok = tok->astParent()->previous();
3293
0
            if (match78(memberTok) && memberTok->variable()) {
3294
0
                const Variable * memberVar = memberTok->variable();
3295
0
                if (memberVar->isClass())
3296
                    //TODO: check if the called constructor could live with a const variable
3297
                    // pending that, assume the worst (that it can't)
3298
0
                    return true;
3299
0
                if (!memberVar->isReference())
3300
0
                    continue;
3301
0
                if (memberVar->isConst())
3302
0
                    continue;
3303
0
            }
3304
0
        }
3305
0
        return true;
3306
0
    }
3307
0
    return false;
3308
0
}
3309
3310
void CheckOther::checkConstVariable()
3311
763
{
3312
763
    if ((!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings->isPremiumEnabled("constVariable"))
3313
0
        return;
3314
3315
763
    logChecker("CheckOther::checkConstVariable"); // style,c++
3316
3317
763
    const SymbolDatabase *const symbolDatabase = mTokenizer->getSymbolDatabase();
3318
3319
4.57k
    for (const Variable *var : symbolDatabase->variableList()) {
3320
4.57k
        if (!var)
3321
763
            continue;
3322
3.81k
        if (!var->isReference())
3323
3.81k
            continue;
3324
0
        if (var->isRValueReference())
3325
0
            continue;
3326
0
        if (var->isPointer())
3327
0
            continue;
3328
0
        if (var->isConst())
3329
0
            continue;
3330
0
        const Scope* scope = var->scope();
3331
0
        if (!scope)
3332
0
            continue;
3333
0
        const Function* function = scope->function;
3334
0
        if (!function && !scope->isLocal())
3335
0
            continue;
3336
0
        if (function && var->isArgument()) {
3337
0
            if (function->isImplicitlyVirtual() || function->templateDef)
3338
0
                continue;
3339
0
            if (function->isConstructor() && isVariableMutableInInitializer(function->constructorMemberInitialization(), scope->bodyStart, var->declarationId()))
3340
0
                continue;
3341
0
        }
3342
0
        if (var->isGlobal())
3343
0
            continue;
3344
0
        if (var->isStatic())
3345
0
            continue;
3346
0
        if (var->isArray() && !var->isStlType())
3347
0
            continue;
3348
0
        if (var->isEnumType())
3349
0
            continue;
3350
0
        if (var->isVolatile())
3351
0
            continue;
3352
0
        if (var->isMaybeUnused())
3353
0
            continue;
3354
0
        if (var->nameToken()->isExpandedMacro())
3355
0
            continue;
3356
0
        if (isStructuredBindingVariable(var)) // TODO: check all bound variables
3357
0
            continue;
3358
0
        if (isVariableChanged(var, *mSettings))
3359
0
            continue;
3360
0
        const bool hasFunction = function != nullptr;
3361
0
        if (!hasFunction) {
3362
0
            const Scope* functionScope = scope;
3363
0
            do {
3364
0
                functionScope = functionScope->nestedIn;
3365
0
            } while (functionScope && !(function = functionScope->function));
3366
0
        }
3367
0
        if (function && (Function::returnsReference(function) || Function::returnsPointer(function)) && !Function::returnsConst(function)) {
3368
0
            std::vector<const Token*> returns = Function::findReturns(function);
3369
0
            if (std::any_of(returns.cbegin(), returns.cend(), [&](const Token* retTok) {
3370
0
                if (retTok->varId() == var->declarationId())
3371
0
                    return true;
3372
0
                while (retTok && retTok->isCast())
3373
0
                    retTok = retTok->astOperand2();
3374
0
                while (match30(retTok))
3375
0
                    retTok = retTok->astOperand2();
3376
0
                if (match79(retTok))
3377
0
                    retTok = retTok->astOperand1();
3378
0
                return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken(), *mSettings);
3379
0
            }))
3380
0
                continue;
3381
0
        }
3382
        // Skip if another non-const variable is initialized with this variable
3383
0
        {
3384
            //Is it the right side of an initialization of a non-const reference
3385
0
            bool usedInAssignment = false;
3386
0
            for (const Token* tok = var->nameToken(); tok != scope->bodyEnd && tok != nullptr; tok = tok->next()) {
3387
0
                if (match80(tok, var->declarationId())) {
3388
0
                    const Variable* refvar = tok->next()->variable();
3389
0
                    if (refvar && !refvar->isConst() && refvar->nameToken() == tok->next()) {
3390
0
                        usedInAssignment = true;
3391
0
                        break;
3392
0
                    }
3393
0
                }
3394
0
                if (tok->isUnaryOp("&") && match72(tok, var->declarationId())) {
3395
0
                    const Token* opTok = tok->astParent();
3396
0
                    int argn = -1;
3397
0
                    if (opTok && (opTok->isUnaryOp("!") || opTok->isComparisonOp()))
3398
0
                        continue;
3399
0
                    if (opTok && (opTok->isAssignmentOp() || opTok->isCalculation())) {
3400
0
                        if (opTok->isCalculation()) {
3401
0
                            if (opTok->astOperand1() != tok)
3402
0
                                opTok = opTok->astOperand1();
3403
0
                            else
3404
0
                                opTok = opTok->astOperand2();
3405
0
                        }
3406
0
                        if (opTok && opTok->valueType() && var->valueType() && opTok->valueType()->isConst(var->valueType()->pointer))
3407
0
                            continue;
3408
0
                    } else if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
3409
0
                        bool inconclusive{};
3410
0
                        if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
3411
0
                            continue;
3412
0
                    }
3413
0
                    usedInAssignment = true;
3414
0
                    break;
3415
0
                }
3416
0
                if (astIsRangeBasedForDecl(tok) && match81(tok->astParent()->astOperand2(), var->declarationId())) {
3417
0
                    const Variable* refvar = tok->astParent()->astOperand1()->variable();
3418
0
                    if (refvar && refvar->isReference() && !refvar->isConst()) {
3419
0
                        usedInAssignment = true;
3420
0
                        break;
3421
0
                    }
3422
0
                }
3423
0
            }
3424
0
            if (usedInAssignment)
3425
0
                continue;
3426
0
        }
3427
3428
0
        constVariableError(var, hasFunction ? function : nullptr);
3429
0
    }
3430
763
}
3431
3432
static const Token* getVariableChangedStart(const Variable* p)
3433
0
{
3434
0
    if (p->isArgument())
3435
0
        return p->scope()->bodyStart;
3436
0
    const Token* start = p->nameToken()->next();
3437
0
    if (start->isSplittedVarDeclEq())
3438
0
        start = start->tokAt(3);
3439
0
    return start;
3440
0
}
3441
3442
static bool isConstPointerVariable(const Variable* p, const Settings& settings)
3443
0
{
3444
0
    const int indirect = p->isArray() ? p->dimensions().size() : 1;
3445
0
    const Token* start = getVariableChangedStart(p);
3446
0
    while (const Token* tok =
3447
0
               findVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, settings)) {
3448
0
        if (p->isReference())
3449
0
            return false;
3450
        // Assigning a pointer through another pointer may still be const
3451
0
        if (!match31(tok->astParent()))
3452
0
            return false;
3453
0
        if (!astIsLHS(tok))
3454
0
            return false;
3455
0
        start = tok->next();
3456
0
    }
3457
0
    return true;
3458
0
}
3459
3460
namespace {
3461
    struct CompareVariables {
3462
0
        bool operator()(const Variable* a, const Variable* b) const {
3463
0
            const int fileA = a->nameToken()->fileIndex();
3464
0
            const int fileB = b->nameToken()->fileIndex();
3465
0
            if (fileA != fileB)
3466
0
                return fileA < fileB;
3467
0
            const int lineA = a->nameToken()->linenr();
3468
0
            const int lineB = b->nameToken()->linenr();
3469
0
            if (lineA != lineB)
3470
0
                return lineA < lineB;
3471
0
            const int columnA = a->nameToken()->column();
3472
0
            const int columnB = b->nameToken()->column();
3473
0
            return columnA < columnB;
3474
0
        }
3475
    };
3476
}
3477
3478
void CheckOther::checkConstPointer()
3479
763
{
3480
763
    if (!mSettings->severity.isEnabled(Severity::style) &&
3481
763
        !mSettings->isPremiumEnabled("constParameter") &&
3482
763
        !mSettings->isPremiumEnabled("constParameterPointer") &&
3483
763
        !mSettings->isPremiumEnabled("constParameterReference") &&
3484
763
        !mSettings->isPremiumEnabled("constVariablePointer"))
3485
0
        return;
3486
3487
763
    logChecker("CheckOther::checkConstPointer"); // style
3488
3489
763
    std::set<const Variable*, CompareVariables> pointers, nonConstPointers;
3490
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
3491
54.8k
        const Variable* const var = tok->variable();
3492
54.8k
        if (!var)
3493
43.1k
            continue;
3494
11.6k
        if (!var->isLocal() && !var->isArgument())
3495
11.6k
            continue;
3496
0
        const Token* const nameTok = var->nameToken();
3497
0
        if (tok == nameTok) {
3498
            // declarations of (static) pointers are (not) split up, array declarations are never split up
3499
0
            if (var->isLocal() && (!var->isStatic() || match77(nameTok->next())) &&
3500
0
                !astIsRangeBasedForDecl(nameTok))
3501
0
                continue;
3502
0
        }
3503
        // Skip function pointers
3504
0
        if (match82(nameTok))
3505
0
            continue;
3506
0
        const ValueType* const vt = tok->valueType();
3507
0
        if (!vt)
3508
0
            continue;
3509
0
        if ((vt->pointer != 1 && !(vt->pointer == 2 && var->isArray())) || (vt->constness & 1))
3510
0
            continue;
3511
0
        if (var->typeStartToken()->isTemplateArg())
3512
0
            continue;
3513
0
        if (std::find(nonConstPointers.cbegin(), nonConstPointers.cend(), var) != nonConstPointers.cend())
3514
0
            continue;
3515
0
        pointers.emplace(var);
3516
0
        const Token* parent = tok->astParent();
3517
0
        enum Deref : std::uint8_t { NONE, DEREF, MEMBER } deref = NONE;
3518
0
        bool hasIncDecPlus = false;
3519
0
        if (parent && (parent->isUnaryOp("*") || (((hasIncDecPlus = parent->isIncDecOp()) || (hasIncDecPlus = (parent->str() == MatchCompiler::makeConstString("+")))) &&
3520
0
                                                  parent->astParent() && parent->astParent()->isUnaryOp("*"))))
3521
0
            deref = DEREF;
3522
0
        else if (match77(parent) && parent->astOperand1() == tok && tok != nameTok)
3523
0
            deref = DEREF;
3524
0
        else if (match83(parent) && match30(parent->astParent()))
3525
0
            deref = MEMBER;
3526
0
        else if (match30(parent))
3527
0
            deref = MEMBER;
3528
0
        else if (astIsRangeBasedForDecl(tok))
3529
0
            continue;
3530
0
        if (deref != NONE) {
3531
0
            const Token* gparent = parent->astParent();
3532
0
            while (match77(gparent) && parent != gparent->astOperand2() && parent->str() == gparent->str())
3533
0
                gparent = gparent->astParent();
3534
0
            if (deref == MEMBER) {
3535
0
                if (!gparent)
3536
0
                    continue;
3537
0
                if (parent->astOperand2()) {
3538
0
                    if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst())
3539
0
                        continue;
3540
0
                    if (mSettings->library.isFunctionConst(parent->astOperand2()))
3541
0
                        continue;
3542
0
                }
3543
0
            }
3544
0
            if (hasIncDecPlus) {
3545
0
                parent = gparent;
3546
0
                gparent = gparent ? gparent->astParent() : nullptr;
3547
0
            }
3548
0
            if (match84(gparent) && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*"))
3549
0
                continue;
3550
0
            int argn = -1;
3551
0
            if (match48(gparent)) {
3552
0
                const Function* function = gparent->scope()->function;
3553
0
                if (function && (!Function::returnsReference(function) || Function::returnsConst(function)))
3554
0
                    continue;
3555
0
            }
3556
0
            else if (match85(gparent) && parent == gparent->astOperand2()) {
3557
0
                bool takingRef = false, nonConstPtrAssignment = false;
3558
0
                const Token *lhs = gparent->astOperand1();
3559
0
                if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs && !lhs->variable()->isConst())
3560
0
                    takingRef = true;
3561
0
                if (lhs && lhs->valueType() && lhs->valueType()->pointer && (lhs->valueType()->constness & 1) == 0 &&
3562
0
                    parent->valueType() && parent->valueType()->pointer)
3563
0
                    nonConstPtrAssignment = true;
3564
0
                if (!takingRef && !nonConstPtrAssignment)
3565
0
                    continue;
3566
0
            } else if (match77(gparent) && gparent->astOperand2() == parent)
3567
0
                continue;
3568
0
            else if (gparent && gparent->isCast() && gparent->valueType() &&
3569
0
                     ((gparent->valueType()->pointer == 0 && gparent->valueType()->reference == Reference::None) ||
3570
0
                      (var->valueType() && gparent->valueType()->isConst(var->valueType()->pointer))))
3571
0
                continue;
3572
0
            else if (const Token* ftok = getTokenArgumentFunction(parent, argn)) {
3573
0
                bool inconclusive{};
3574
0
                if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
3575
0
                    continue;
3576
0
            }
3577
0
        } else {
3578
0
            int argn = -1;
3579
0
            if (match86(parent))
3580
0
                continue;
3581
0
            if (hasIncDecPlus && !parent->astParent())
3582
0
                continue;
3583
0
            if (match67(parent) && match87(parent->astOperand1()))
3584
0
                continue;
3585
0
            if (match31(parent) && parent->astOperand1() == tok)
3586
0
                continue;
3587
0
            if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
3588
0
                if (ftok->function()) {
3589
0
                    const bool isCastArg = parent->isCast() && !ftok->function()->getOverloadedFunctions().empty(); // assume that cast changes the called function
3590
0
                    if (!isCastArg) {
3591
0
                        const Variable* argVar = ftok->function()->getArgumentVar(argn);
3592
0
                        if (argVar && argVar->valueType() && argVar->valueType()->isConst(vt->pointer)) {
3593
0
                            bool inconclusive{};
3594
0
                            if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
3595
0
                                continue;
3596
0
                        }
3597
0
                    }
3598
0
                } else {
3599
0
                    const auto dir = mSettings->library.getArgDirection(ftok, argn + 1);
3600
0
                    if (dir == Library::ArgumentChecks::Direction::DIR_IN)
3601
0
                        continue;
3602
0
                }
3603
0
            }
3604
0
            else if (match67(parent)) {
3605
0
                if (parent->isCast() && parent->valueType() && var->valueType() && parent->valueType()->isConst(var->valueType()->pointer))
3606
0
                    continue;
3607
0
            }
3608
0
        }
3609
0
        if (tok != nameTok)
3610
0
            nonConstPointers.emplace(var);
3611
0
    }
3612
763
    for (const Variable *p: pointers) {
3613
0
        if (p->isArgument()) {
3614
0
            if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier())
3615
0
                continue;
3616
0
            if (p->isMaybeUnused())
3617
0
                continue;
3618
0
        }
3619
0
        if (const Function* func = Scope::nestedInFunction(p->scope()))
3620
0
            if (func->templateDef)
3621
0
                continue;
3622
0
        if (std::find(nonConstPointers.cbegin(), nonConstPointers.cend(), p) == nonConstPointers.cend()) {
3623
            // const Token *start = getVariableChangedStart(p);
3624
            // const int indirect = p->isArray() ? p->dimensions().size() : 1;
3625
            // if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, *mSettings))
3626
            //     continue;
3627
0
            if (!isConstPointerVariable(p, *mSettings))
3628
0
                continue;
3629
0
            if (p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(match88(p->typeEndToken()) && !p->typeEndToken()->isSimplifiedTypedef()))
3630
0
                continue;
3631
0
            constVariableError(p, p->isArgument() ? p->scope()->function : nullptr);
3632
0
        }
3633
0
    }
3634
763
}
3635
3636
void CheckOther::constVariableError(const Variable *var, const Function *function)
3637
0
{
3638
0
    if (!var) {
3639
0
        reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const");
3640
0
        reportError(nullptr, Severity::style, "constVariable",  "Variable 'x' can be declared with const");
3641
0
        reportError(nullptr, Severity::style, "constParameterReference", "Parameter 'x' can be declared with const");
3642
0
        reportError(nullptr, Severity::style, "constVariableReference", "Variable 'x' can be declared with const");
3643
0
        reportError(nullptr, Severity::style, "constParameterPointer", "Parameter 'x' can be declared with const");
3644
0
        reportError(nullptr, Severity::style, "constVariablePointer", "Variable 'x' can be declared with const");
3645
0
        reportError(nullptr, Severity::style, "constParameterCallback", "Parameter 'x' can be declared with const, however it seems that 'f' is a callback function.");
3646
0
        return;
3647
0
    }
3648
3649
0
    const std::string vartype(var->isArgument() ? "Parameter" : "Variable");
3650
0
    const std::string& varname(var->name());
3651
0
    const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const");
3652
3653
0
    ErrorPath errorPath;
3654
0
    std::string id = "const" + vartype;
3655
0
    std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray;
3656
0
    errorPath.emplace_back(var->nameToken(), message);
3657
0
    if (var->isArgument() && function && function->functionPointerUsage) {
3658
0
        errorPath.emplace_front(function->functionPointerUsage, "You might need to cast the function pointer here");
3659
0
        id += "Callback";
3660
0
        message += ". However it seems that '" + function->name() + "' is a callback function, if '$symbol' is declared with const you might also need to cast function pointer(s).";
3661
0
    } else if (var->isReference()) {
3662
0
        id += "Reference";
3663
0
    } else if (var->isPointer() && !var->isArray()) {
3664
0
        id += "Pointer";
3665
0
    }
3666
3667
0
    reportError(errorPath, Severity::style, id.c_str(), message, CWE398, Certainty::normal);
3668
0
}
3669
3670
//---------------------------------------------------------------------------
3671
// Check usage of char variables..
3672
//---------------------------------------------------------------------------
3673
3674
void CheckOther::checkCharVariable()
3675
763
{
3676
763
    const bool warning = mSettings->severity.isEnabled(Severity::warning);
3677
763
    const bool portability = mSettings->severity.isEnabled(Severity::portability);
3678
763
    if (!warning && !portability)
3679
0
        return;
3680
3681
763
    logChecker("CheckOther::checkCharVariable"); // warning,portability
3682
3683
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
3684
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
3685
23.7k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
3686
22.6k
            if (match89(tok)) {
3687
0
                if (!tok->variable())
3688
0
                    continue;
3689
0
                if (!tok->variable()->isArray() && !tok->variable()->isPointer())
3690
0
                    continue;
3691
0
                const Token *index = tok->next()->astOperand2();
3692
0
                if (warning && tok->variable()->isArray() && astIsSignedChar(index) && index->getValueGE(0x80, *mSettings))
3693
0
                    signedCharArrayIndexError(tok);
3694
0
                if (portability && astIsUnknownSignChar(index) && index->getValueGE(0x80, *mSettings))
3695
0
                    unknownSignCharArrayIndexError(tok);
3696
22.6k
            } else if (warning && match90(tok) && tok->isBinaryOp()) {
3697
251
                bool warn = false;
3698
251
                if (astIsSignedChar(tok->astOperand1())) {
3699
0
                    const ValueFlow::Value *v1 = tok->astOperand1()->getValueLE(-1, *mSettings);
3700
0
                    const ValueFlow::Value *v2 = tok->astOperand2()->getMaxValue(false);
3701
0
                    if (!v1)
3702
0
                        v1 = tok->astOperand1()->getValueGE(0x80, *mSettings);
3703
0
                    if (v1 && !(tok->str() == MatchCompiler::makeConstString("&") && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100))
3704
0
                        warn = true;
3705
251
                } else if (astIsSignedChar(tok->astOperand2())) {
3706
0
                    const ValueFlow::Value *v1 = tok->astOperand2()->getValueLE(-1, *mSettings);
3707
0
                    const ValueFlow::Value *v2 = tok->astOperand1()->getMaxValue(false);
3708
0
                    if (!v1)
3709
0
                        v1 = tok->astOperand2()->getValueGE(0x80, *mSettings);
3710
0
                    if (v1 && !(tok->str() == MatchCompiler::makeConstString("&") && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100))
3711
0
                        warn = true;
3712
0
                }
3713
3714
                // is the result stored in a short|int|long?
3715
251
                if (warn && match31(tok->astParent())) {
3716
0
                    const Token *lhs = tok->astParent()->astOperand1();
3717
0
                    if (lhs && lhs->valueType() && lhs->valueType()->type >= ValueType::Type::SHORT)
3718
0
                        charBitOpError(tok); // This is an error..
3719
0
                }
3720
251
            }
3721
22.6k
        }
3722
1.10k
    }
3723
763
}
3724
3725
void CheckOther::signedCharArrayIndexError(const Token *tok)
3726
0
{
3727
0
    reportError(tok,
3728
0
                Severity::warning,
3729
0
                "signedCharArrayIndex",
3730
0
                "Signed 'char' type used as array index.\n"
3731
0
                "Signed 'char' type used as array index. If the value "
3732
0
                "can be greater than 127 there will be a buffer underflow "
3733
0
                "because of sign extension.", CWE128, Certainty::normal);
3734
0
}
3735
3736
void CheckOther::unknownSignCharArrayIndexError(const Token *tok)
3737
0
{
3738
0
    reportError(tok,
3739
0
                Severity::portability,
3740
0
                "unknownSignCharArrayIndex",
3741
0
                "'char' type used as array index.\n"
3742
0
                "'char' type used as array index. Values greater than 127 will be "
3743
0
                "treated depending on whether 'char' is signed or unsigned on target platform.", CWE758, Certainty::normal);
3744
0
}
3745
3746
void CheckOther::charBitOpError(const Token *tok)
3747
0
{
3748
0
    reportError(tok,
3749
0
                Severity::warning,
3750
0
                "charBitOp",
3751
0
                "When using 'char' variables in bit operations, sign extension can generate unexpected results.\n"
3752
0
                "When using 'char' variables in bit operations, sign extension can generate unexpected results. For example:\n"
3753
0
                "    char c = 0x80;\n"
3754
0
                "    int i = 0 | c;\n"
3755
0
                "    if (i & 0x8000)\n"
3756
0
                "        printf(\"not expected\");\n"
3757
0
                "The \"not expected\" will be printed on the screen.", CWE398, Certainty::normal);
3758
0
}
3759
3760
//---------------------------------------------------------------------------
3761
// Incomplete statement..
3762
//---------------------------------------------------------------------------
3763
3764
static bool isType(const Token * tok, bool unknown)
3765
0
{
3766
0
    if (tok && (tok->isStandardType() || (!tok->isKeyword() && match20(tok)) || tok->str() == MatchCompiler::makeConstString("auto")))
3767
0
        return true;
3768
0
    if (tok && tok->varId())
3769
0
        return false;
3770
0
    if (match91(tok))
3771
0
        return isType(tok->astOperand2(), unknown);
3772
0
    if (match17(tok) && tok->link())
3773
0
        return true;
3774
0
    if (unknown && match92(tok))
3775
0
        return true;
3776
0
    return false;
3777
0
}
3778
3779
static bool isVarDeclOp(const Token* tok)
3780
0
{
3781
0
    if (!tok)
3782
0
        return false;
3783
0
    const Token * vartok = tok->astOperand2();
3784
0
    if (vartok && vartok->variable() && vartok->variable()->nameToken() == vartok)
3785
0
        return true;
3786
0
    const Token * typetok = tok->astOperand1();
3787
0
    return isType(typetok, vartok && vartok->varId() != 0);
3788
0
}
3789
3790
static bool isBracketAccess(const Token* tok)
3791
3.18k
{
3792
3.18k
    if (!match77(tok) || !tok->astOperand1())
3793
3.18k
        return false;
3794
0
    tok = tok->astOperand1();
3795
0
    if (tok->str() == MatchCompiler::makeConstString("."))
3796
0
        tok = tok->astOperand2();
3797
0
    while (match77(tok))
3798
0
        tok = tok->astOperand1();
3799
0
    if (!tok || !tok->variable())
3800
0
        return false;
3801
0
    return tok->variable()->nameToken() != tok;
3802
0
}
3803
3804
3.18k
static bool isConstant(const Token* tok) {
3805
3.18k
    return tok && (tok->isEnumerator() || match93(tok));
3806
3.18k
}
3807
3808
static bool isConstStatement(const Token *tok, bool isNestedBracket = false)
3809
3.18k
{
3810
3.18k
    if (!tok)
3811
0
        return false;
3812
3.18k
    if (tok->isExpandedMacro())
3813
0
        return false;
3814
3.18k
    if (tok->varId() != 0)
3815
0
        return true;
3816
3.18k
    if (isConstant(tok))
3817
0
        return true;
3818
3.18k
    if (match94(tok) &&
3819
3.18k
        (match95(tok->previous()) || isVarDeclOp(tok)))
3820
0
        return false;
3821
3.18k
    if (match96(tok) && !astIsIntegral(tok, false))
3822
0
        return false;
3823
3.18k
    const Token* tok2 = tok;
3824
6.37k
    while (tok2) {
3825
3.18k
        if (match97(tok2->astOperand1()))
3826
0
            return false;
3827
3.18k
        tok2 = tok2->astParent();
3828
3.18k
    }
3829
3.18k
    if (match40(tok))
3830
0
        return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
3831
3.18k
    if (match98(tok) && (tok->astOperand1() || tok->astOperand2()))
3832
0
        return true;
3833
3.18k
    if (match99(tok->previous()))
3834
0
        return true;
3835
3.18k
    if (isCPPCast(tok)) {
3836
0
        if (match100(tok->astOperand1()) && match101(tok->astOperand1()->linkAt(1)->previous()))
3837
0
            return false;
3838
0
        return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2());
3839
0
    }
3840
3.18k
    if (tok->isCast() && tok->next() && tok->next()->isStandardType())
3841
0
        return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1());
3842
3.18k
    if (match30(tok))
3843
0
        return isConstStatement(tok->astOperand2());
3844
3.18k
    if (match65(tok)) {
3845
0
        if (tok->astParent()) // warn about const statement on rhs at the top level
3846
0
            return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
3847
3848
0
        const Token* lml = previousBeforeAstLeftmostLeaf(tok); // don't warn about matrix/vector assignment (e.g. Eigen)
3849
0
        if (lml)
3850
0
            lml = lml->next();
3851
0
        const Token* stream = lml;
3852
0
        while (stream && match102(stream->astParent()))
3853
0
            stream = stream->astParent();
3854
0
        return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2());
3855
0
    }
3856
3.18k
    if (match45(tok) && match103(tok->astOperand2())) // ternary operator
3857
0
        return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand2());
3858
3.18k
    if (isBracketAccess(tok) && isWithoutSideEffects(tok->astOperand1(), /*checkArrayAccess*/ true, /*checkReference*/ false)) {
3859
0
        const bool isChained = succeeds(tok->astParent(), tok);
3860
0
        if (match77(tok->astParent())) {
3861
0
            if (isChained)
3862
0
                return isConstStatement(tok->astOperand2()) && isConstStatement(tok->astParent());
3863
0
            return isNestedBracket && isConstStatement(tok->astOperand2());
3864
0
        }
3865
0
        return isConstStatement(tok->astOperand2(), /*isNestedBracket*/ !isChained);
3866
0
    }
3867
3.18k
    if (!tok->astParent() && findLambdaEndToken(tok))
3868
0
        return true;
3869
3.18k
    return false;
3870
3.18k
}
3871
3872
static bool isVoidStmt(const Token *tok)
3873
0
{
3874
0
    if (match104(tok))
3875
0
        return true;
3876
0
    if (isCPPCast(tok) && tok->astOperand1() && match105(tok->astOperand1()->next()))
3877
0
        return true;
3878
0
    const Token *tok2 = tok;
3879
0
    while (tok2->astOperand1())
3880
0
        tok2 = tok2->astOperand1();
3881
0
    if (match106(tok2->previous()) && match104(tok2->linkAt(-1)))
3882
0
        return true;
3883
0
    if (match104(tok2))
3884
0
        return true;
3885
0
    return match107(tok2->previous());
3886
0
}
3887
3888
static bool isConstTop(const Token *tok)
3889
23.7k
{
3890
23.7k
    if (!tok)
3891
0
        return false;
3892
23.7k
    if (!tok->astParent())
3893
12.7k
        return true;
3894
11.0k
    if (match51(tok->astParent()) &&
3895
11.0k
        match108(tok->astTop()->previous()) && match51(tok->astTop()->astOperand2())) {
3896
0
        if (match51(tok->astParent()->astParent()))
3897
0
            return tok->astParent()->astOperand2() == tok;
3898
0
        return tok->astParent()->astOperand1() == tok;
3899
0
    }
3900
11.0k
    if (match77(tok)) {
3901
0
        const Token* bracTok = tok;
3902
0
        while (match77(bracTok->astParent()))
3903
0
            bracTok = bracTok->astParent();
3904
0
        if (!bracTok->astParent())
3905
0
            return true;
3906
0
    }
3907
11.0k
    if (tok->str() == MatchCompiler::makeConstString(",") && tok->astParent()->isAssignmentOp())
3908
0
        return true;
3909
11.0k
    return false;
3910
11.0k
}
3911
3912
void CheckOther::checkIncompleteStatement()
3913
763
{
3914
763
    if (!mSettings->severity.isEnabled(Severity::warning) &&
3915
763
        !mSettings->isPremiumEnabled("constStatement"))
3916
0
        return;
3917
3918
763
    logChecker("CheckOther::checkIncompleteStatement"); // warning
3919
3920
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
3921
54.8k
        const Scope *scope = tok->scope();
3922
54.8k
        if (scope && !scope->isExecutable())
3923
31.1k
            continue;
3924
23.7k
        if (!isConstTop(tok))
3925
11.0k
            continue;
3926
12.7k
        if (tok->str() == MatchCompiler::makeConstString(",") && match61(tok->astTop()->previous()))
3927
0
            continue;
3928
3929
        // Do not warn for statement when both lhs and rhs has side effects:
3930
        //   dostuff() || x=213;
3931
12.7k
        if (match109(tok)) {
3932
0
            bool warn = false;
3933
0
            visitAstNodes(tok, [&warn](const Token *child) {
3934
0
                if (match109(child))
3935
0
                    return ChildrenToVisit::op1_and_op2;
3936
0
                if (child->isAssignmentOp())
3937
0
                    return ChildrenToVisit::none;
3938
0
                if (child->tokType() == Token::Type::eIncDecOp)
3939
0
                    return ChildrenToVisit::none;
3940
0
                if (match32(child->previous()))
3941
0
                    return ChildrenToVisit::none;
3942
0
                warn = true;
3943
0
                return ChildrenToVisit::done;
3944
0
            });
3945
0
            if (!warn)
3946
0
                continue;
3947
0
        }
3948
3949
12.7k
        const Token *rtok = nextAfterAstRightmostLeaf(tok);
3950
12.7k
        if (!match51(tok->astParent()) && !match51(rtok) &&
3951
12.7k
            !match110(tok->previous()) &&
3952
12.7k
            !(tok->isCpp() && tok->isCast() && !tok->astParent()) &&
3953
12.7k
            !match61(tok->tokAt(-2)) &&
3954
12.7k
            !match89(tok->tokAt(-1)) &&
3955
12.7k
            !(tok->str() == MatchCompiler::makeConstString(",") && tok->astParent() && tok->astParent()->isAssignmentOp()))
3956
9.52k
            continue;
3957
        // Skip statement expressions
3958
3.18k
        if (match111(rtok))
3959
0
            continue;
3960
3.18k
        if (!isConstStatement(tok))
3961
3.18k
            continue;
3962
0
        if (isVoidStmt(tok))
3963
0
            continue;
3964
0
        if (tok->isCpp() && tok->str() == MatchCompiler::makeConstString("&") && !(tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral()))
3965
            // Possible archive
3966
0
            continue;
3967
0
        const bool inconclusive = tok->isConstOp() && !mSettings->isPremiumEnabled("constStatement");
3968
0
        if (mSettings->certainty.isEnabled(Certainty::inconclusive) || !inconclusive)
3969
0
            constStatementError(tok, tok->isNumber() ? "numeric" : "string", inconclusive);
3970
0
    }
3971
763
}
3972
3973
void CheckOther::constStatementError(const Token *tok, const std::string &type, bool inconclusive)
3974
0
{
3975
0
    const Token *valueTok = tok;
3976
0
    while (valueTok && valueTok->isCast())
3977
0
        valueTok = valueTok->astOperand2() ? valueTok->astOperand2() : valueTok->astOperand1();
3978
3979
0
    std::string msg;
3980
0
    if (match112(tok))
3981
0
        msg = "Found suspicious equality comparison. Did you intend to assign a value instead?";
3982
0
    else if (match113(tok))
3983
0
        msg = "Found suspicious operator '" + tok->str() + "', result is not used.";
3984
0
    else if (match114(tok))
3985
0
        msg = "Unused variable value '" + tok->str() + "'";
3986
0
    else if (isConstant(valueTok)) {
3987
0
        std::string typeStr("string");
3988
0
        if (valueTok->isNumber())
3989
0
            typeStr = "numeric";
3990
0
        else if (valueTok->isBoolean())
3991
0
            typeStr = "bool";
3992
0
        else if (valueTok->tokType() == Token::eChar)
3993
0
            typeStr = "character";
3994
0
        else if (isNullOperand(valueTok))
3995
0
            typeStr = "NULL";
3996
0
        else if (valueTok->isEnumerator())
3997
0
            typeStr = "enumerator";
3998
0
        msg = "Redundant code: Found a statement that begins with " + typeStr + " constant.";
3999
0
    }
4000
0
    else if (!tok)
4001
0
        msg = "Redundant code: Found a statement that begins with " + type + " constant.";
4002
0
    else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) {
4003
0
        msg = "Redundant code: Found unused cast ";
4004
0
        msg += valueTok ? "of expression '" + valueTok->expressionString() + "'." : "expression.";
4005
0
    }
4006
0
    else if (tok->str() == MatchCompiler::makeConstString("?") && tok->tokType() == Token::Type::eExtendedOp)
4007
0
        msg = "Redundant code: Found unused result of ternary operator.";
4008
0
    else if (tok->str() == MatchCompiler::makeConstString(".") && tok->tokType() == Token::Type::eOther)
4009
0
        msg = "Redundant code: Found unused member access.";
4010
0
    else if (tok->str() == MatchCompiler::makeConstString("[") && tok->tokType() == Token::Type::eExtendedOp)
4011
0
        msg = "Redundant code: Found unused array access.";
4012
0
    else if (tok->str() == MatchCompiler::makeConstString("[") && !tok->astParent())
4013
0
        msg = "Redundant code: Found unused lambda.";
4014
0
    else if (mSettings->debugwarnings) {
4015
0
        reportError(tok, Severity::debug, "debug", "constStatementError not handled.");
4016
0
        return;
4017
0
    }
4018
0
    reportError(tok, Severity::warning, "constStatement", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
4019
0
}
4020
4021
//---------------------------------------------------------------------------
4022
// Detect division by zero.
4023
//---------------------------------------------------------------------------
4024
void CheckOther::checkZeroDivision()
4025
763
{
4026
763
    logChecker("CheckOther::checkZeroDivision");
4027
4028
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
4029
54.8k
        if (!tok->astOperand2() || !tok->astOperand1())
4030
46.5k
            continue;
4031
8.33k
        if (tok->str() != MatchCompiler::makeConstString("%") && tok->str() != MatchCompiler::makeConstString("/") && tok->str() != MatchCompiler::makeConstString("%=") && tok->str() != MatchCompiler::makeConstString("/="))
4032
8.17k
            continue;
4033
160
        if (!tok->valueType() || !tok->valueType()->isIntegral())
4034
72
            continue;
4035
88
        if (tok->scope() && tok->scope()->type == Scope::eEnum) // don't warn for compile-time error
4036
0
            continue;
4037
4038
        // Value flow..
4039
88
        const ValueFlow::Value *value = tok->astOperand2()->getValue(0LL);
4040
88
        if (value && mSettings->isEnabled(value, false))
4041
0
            zerodivError(tok, value);
4042
88
    }
4043
763
}
4044
4045
void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value)
4046
0
{
4047
0
    if (!tok && !value) {
4048
0
        reportError(tok, Severity::error, "zerodiv", "Division by zero.", CWE369, Certainty::normal);
4049
0
        reportError(tok, Severity::warning, "zerodivcond", ValueFlow::eitherTheConditionIsRedundant(nullptr) + " or there is division by zero.", CWE369, Certainty::normal);
4050
0
        return;
4051
0
    }
4052
4053
0
    const ErrorPath errorPath = getErrorPath(tok, value, "Division by zero");
4054
4055
0
    std::ostringstream errmsg;
4056
0
    if (value->condition) {
4057
0
        const int line = tok ? tok->linenr() : 0;
4058
0
        errmsg << ValueFlow::eitherTheConditionIsRedundant(value->condition)
4059
0
               << " or there is division by zero at line " << line << ".";
4060
0
    } else
4061
0
        errmsg << "Division by zero.";
4062
4063
0
    reportError(errorPath,
4064
0
                value->errorSeverity() ? Severity::error : Severity::warning,
4065
0
                value->condition ? "zerodivcond" : "zerodiv",
4066
0
                errmsg.str(), CWE369, value->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
4067
0
}
4068
4069
//---------------------------------------------------------------------------
4070
// Check for NaN (not-a-number) in an arithmetic expression, e.g.
4071
// double d = 1.0 / 0.0 + 100.0;
4072
//---------------------------------------------------------------------------
4073
4074
void CheckOther::checkNanInArithmeticExpression()
4075
763
{
4076
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("nanInArithmeticExpression"))
4077
0
        return;
4078
763
    logChecker("CheckOther::checkNanInArithmeticExpression"); // style
4079
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
4080
54.8k
        if (tok->str() != MatchCompiler::makeConstString("/"))
4081
54.8k
            continue;
4082
69
        if (!match115(tok->astParent()))
4083
65
            continue;
4084
4
        if (match116(tok->astOperand2()))
4085
0
            nanInArithmeticExpressionError(tok);
4086
4
    }
4087
763
}
4088
4089
void CheckOther::nanInArithmeticExpressionError(const Token *tok)
4090
0
{
4091
0
    reportError(tok, Severity::style, "nanInArithmeticExpression",
4092
0
                "Using NaN/Inf in a computation.\n"
4093
0
                "Using NaN/Inf in a computation. "
4094
0
                "Although nothing bad really happens, it is suspicious.", CWE369, Certainty::normal);
4095
0
}
4096
4097
//---------------------------------------------------------------------------
4098
// Creating instance of classes which are destroyed immediately
4099
//---------------------------------------------------------------------------
4100
void CheckOther::checkMisusedScopedObject()
4101
763
{
4102
    // Skip this check for .c files
4103
763
    if (mTokenizer->isC())
4104
0
        return;
4105
4106
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedScopedObject"))
4107
0
        return;
4108
4109
763
    logChecker("CheckOther::checkMisusedScopedObject"); // style,c++
4110
4111
22.6k
    auto getConstructorTok = [](const Token* tok, std::string& typeStr) -> const Token* {
4112
22.6k
        if (!match117(tok) || tok->next()->isKeyword())
4113
20.6k
            return nullptr;
4114
2.00k
        tok = tok->next();
4115
2.00k
        typeStr.clear();
4116
2.00k
        while (match118(tok)) {
4117
0
            typeStr += tok->str();
4118
0
            typeStr += "::";
4119
0
            tok = tok->tokAt(2);
4120
0
        }
4121
2.00k
        typeStr += tok->str();
4122
2.00k
        const Token* endTok = tok;
4123
2.00k
        if (match119(endTok))
4124
0
            endTok = endTok->linkAt(1);
4125
2.00k
        if (match120(endTok) && match121(endTok->linkAt(1)) &&
4126
2.00k
            !match51(endTok->next()->astParent())) { // for loop condition
4127
0
            return tok;
4128
0
        }
4129
2.00k
        return nullptr;
4130
2.00k
    };
4131
4132
763
    auto isLibraryConstructor = [&](const Token* tok, const std::string& typeStr) -> bool {
4133
0
        const Library::TypeCheck typeCheck = mSettings->library.getTypeCheck("unusedvar", typeStr);
4134
0
        if (typeCheck == Library::TypeCheck::check || typeCheck == Library::TypeCheck::checkFiniteLifetime)
4135
0
            return true;
4136
0
        return mSettings->library.detectContainerOrIterator(tok);
4137
0
    };
4138
4139
763
    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
4140
763
    std::string typeStr;
4141
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
4142
23.7k
        for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
4143
22.6k
            const Token* ctorTok = getConstructorTok(tok, typeStr);
4144
22.6k
            if (ctorTok && (((ctorTok->type() || ctorTok->isStandardType() || (ctorTok->function() && ctorTok->function()->isConstructor())) // TODO: The rhs of || should be removed; It is a workaround for a symboldatabase bug
4145
0
                             && (!ctorTok->function() || ctorTok->function()->isConstructor()) // // is not a function on this scope or is function in this scope and it's a ctor
4146
0
                             && ctorTok->str() != MatchCompiler::makeConstString("void")) || isLibraryConstructor(tok->next(), typeStr))) {
4147
0
                const Token* parTok = ctorTok->next();
4148
0
                if (match17(parTok) && parTok->link())
4149
0
                    parTok = parTok->link()->next();
4150
0
                if (const Token* arg = parTok->astOperand2()) {
4151
0
                    if (!isConstStatement(arg))
4152
0
                        continue;
4153
0
                    if (parTok->str() == MatchCompiler::makeConstString("(")) {
4154
0
                        if (arg->varId() && !(arg->variable() && arg->variable()->nameToken() != arg))
4155
0
                            continue;
4156
0
                        const Token* rml = nextAfterAstRightmostLeaf(arg);
4157
0
                        if (rml && rml->previous() && rml->previous()->varId())
4158
0
                            continue;
4159
0
                    }
4160
0
                }
4161
0
                tok = tok->next();
4162
0
                misusedScopeObjectError(ctorTok, typeStr);
4163
0
                tok = tok->next();
4164
0
            }
4165
22.6k
            if (tok->isAssignmentOp() && match67(tok->astOperand1()) && tok->astOperand1()->astOperand1()) {
4166
0
                if (const Function* ftok = tok->astOperand1()->astOperand1()->function()) {
4167
0
                    if (ftok->retType && match122(ftok->retType->classDef) && !Function::returnsReference(ftok, /*unknown*/ false, /*includeRValueRef*/ true))
4168
0
                        misusedScopeObjectError(tok->next(), ftok->retType->name(), /*isAssignment*/ true);
4169
0
                }
4170
0
            }
4171
22.6k
        }
4172
1.10k
    }
4173
763
}
4174
4175
void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment)
4176
0
{
4177
0
    std::string msg = "Instance of '$symbol' object is destroyed immediately";
4178
0
    msg += isAssignment ? ", assignment has no effect." : ".";
4179
0
    reportError(tok, Severity::style,
4180
0
                "unusedScopedObject",
4181
0
                "$symbol:" + varname + "\n" +
4182
0
                msg, CWE563, Certainty::normal);
4183
0
}
4184
4185
static const Token * getSingleExpressionInBlock(const Token * tok)
4186
212
{
4187
212
    if (!tok)
4188
0
        return nullptr;
4189
212
    const Token * top = tok->astTop();
4190
212
    const Token * nextExpression = nextAfterAstRightmostLeaf(top);
4191
212
    if (!match123(nextExpression))
4192
157
        return nullptr;
4193
55
    return top;
4194
212
}
4195
4196
//-----------------------------------------------------------------------------
4197
// check for duplicate code in if and else branches
4198
// if (a) { b = true; } else { b = true; }
4199
//-----------------------------------------------------------------------------
4200
void CheckOther::checkDuplicateBranch()
4201
763
{
4202
    // This is inconclusive since in practice most warnings are noise:
4203
    // * There can be unfixed low-priority todos. The code is fine as it
4204
    //   is but it could be possible to enhance it. Writing a warning
4205
    //   here is noise since the code is fine (see cppcheck, abiword, ..)
4206
    // * There can be overspecified code so some conditions can't be true
4207
    //   and their conditional code is a duplicate of the condition that
4208
    //   is always true just in case it would be false. See for instance
4209
    //   abiword.
4210
763
    if (!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
4211
0
        return;
4212
4213
763
    logChecker("CheckOther::checkDuplicateBranch"); // style,inconclusive
4214
4215
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
4216
4217
2.79k
    for (const Scope & scope : symbolDatabase->scopeList) {
4218
2.79k
        if (scope.type != Scope::eIf)
4219
2.29k
            continue;
4220
4221
        // check all the code in the function for if (..) else
4222
501
        if (match124(scope.bodyEnd)) {
4223
            // Make sure there are no macros (different macros might be expanded
4224
            // to the same code)
4225
279
            bool macro = false;
4226
4.41k
            for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd->linkAt(2); tok = tok->next()) {
4227
4.13k
                if (tok->isExpandedMacro()) {
4228
0
                    macro = true;
4229
0
                    break;
4230
0
                }
4231
4.13k
            }
4232
279
            if (macro)
4233
0
                continue;
4234
4235
279
            const Token * const tokIf = scope.bodyStart->next();
4236
279
            const Token * const tokElse = scope.bodyEnd->tokAt(3);
4237
4238
            // compare first tok before stringifying the whole blocks
4239
279
            const std::string tokIfStr = tokIf->stringify(false, true, false);
4240
279
            if (tokIfStr.empty())
4241
0
                continue;
4242
4243
279
            const std::string tokElseStr = tokElse->stringify(false, true, false);
4244
4245
279
            if (tokIfStr == tokElseStr) {
4246
                // save if branch code
4247
134
                const std::string branch1 = tokIf->stringifyList(scope.bodyEnd);
4248
4249
134
                if (branch1.empty())
4250
119
                    continue;
4251
4252
                // save else branch code
4253
15
                const std::string branch2 = tokElse->stringifyList(scope.bodyEnd->linkAt(2));
4254
4255
                // check for duplicates
4256
15
                if (branch1 == branch2) {
4257
2
                    duplicateBranchError(scope.classDef, scope.bodyEnd->next(), ErrorPath{});
4258
2
                    continue;
4259
2
                }
4260
15
            }
4261
4262
            // check for duplicates using isSameExpression
4263
158
            const Token * branchTop1 = getSingleExpressionInBlock(tokIf);
4264
158
            if (!branchTop1)
4265
104
                continue;
4266
54
            const Token * branchTop2 = getSingleExpressionInBlock(tokElse);
4267
54
            if (!branchTop2)
4268
53
                continue;
4269
1
            if (branchTop1->str() != branchTop2->str())
4270
0
                continue;
4271
1
            ErrorPath errorPath;
4272
1
            if (isSameExpression(false, branchTop1->astOperand1(), branchTop2->astOperand1(), *mSettings, true, true, &errorPath) &&
4273
1
                isSameExpression(false, branchTop1->astOperand2(), branchTop2->astOperand2(), *mSettings, true, true, &errorPath))
4274
0
                duplicateBranchError(scope.classDef, scope.bodyEnd->next(), std::move(errorPath));
4275
1
        }
4276
501
    }
4277
763
}
4278
4279
void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors)
4280
2
{
4281
2
    errors.emplace_back(tok2, "");
4282
2
    errors.emplace_back(tok1, "");
4283
4284
2
    reportError(errors, Severity::style, "duplicateBranch", "Found duplicate branches for 'if' and 'else'.\n"
4285
2
                "Finding the same code in an 'if' and related 'else' branch is suspicious and "
4286
2
                "might indicate a cut and paste or logic error. Please examine this code "
4287
2
                "carefully to determine if it is correct.", CWE398, Certainty::inconclusive);
4288
2
}
4289
4290
4291
//-----------------------------------------------------------------------------
4292
// Check for a free() of an invalid address
4293
// char* p = malloc(100);
4294
// free(p + 10);
4295
//-----------------------------------------------------------------------------
4296
void CheckOther::checkInvalidFree()
4297
763
{
4298
763
    std::map<int, bool> inconclusive;
4299
763
    std::map<int, std::string> allocation;
4300
4301
763
    logChecker("CheckOther::checkInvalidFree");
4302
4303
763
    const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
4304
763
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
4305
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
4306
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
4307
4308
            // Keep track of which variables were assigned addresses to newly-allocated memory
4309
21.5k
            if ((tok->isCpp() && match125(tok)) ||
4310
21.5k
                (match126(tok) && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) {
4311
0
                allocation.emplace(tok->varId(), tok->strAt(2));
4312
0
                inconclusive.emplace(tok->varId(), false);
4313
0
            }
4314
4315
            // If a previously-allocated pointer is incremented or decremented, any subsequent
4316
            // free involving pointer arithmetic may or may not be invalid, so we should only
4317
            // report an inconclusive result.
4318
21.5k
            else if (match127(tok) &&
4319
21.5k
                     tok->varId() == tok->tokAt(2)->varId() &&
4320
21.5k
                     allocation.find(tok->varId()) != allocation.end()) {
4321
0
                if (printInconclusive)
4322
0
                    inconclusive[tok->varId()] = true;
4323
0
                else {
4324
0
                    allocation.erase(tok->varId());
4325
0
                    inconclusive.erase(tok->varId());
4326
0
                }
4327
0
            }
4328
4329
            // If a previously-allocated pointer is assigned a completely new value,
4330
            // we can't know if any subsequent free() on that pointer is valid or not.
4331
21.5k
            else if (match128(tok)) {
4332
260
                allocation.erase(tok->varId());
4333
260
                inconclusive.erase(tok->varId());
4334
260
            }
4335
4336
            // If a variable that was previously assigned a newly-allocated memory location is
4337
            // added or subtracted from when used to free the memory, report an error.
4338
21.3k
            else if ((match129(tok) && mSettings->library.getDeallocFuncInfo(tok)) ||
4339
21.3k
                     match130(tok) ||
4340
21.3k
                     match131(tok)) {
4341
4342
0
                const int varIndex = tok->strAt(1) == MatchCompiler::makeConstString("(") ? 2 :
4343
0
                                     tok->strAt(3) == MatchCompiler::makeConstString("(") ? 4 : 1;
4344
0
                const int var1 = tok->tokAt(varIndex)->varId();
4345
0
                const int var2 = tok->tokAt(varIndex + 2)->varId();
4346
0
                const auto alloc1 = utils::as_const(inconclusive).find(var1);
4347
0
                const auto alloc2 = utils::as_const(inconclusive).find(var2);
4348
0
                if (alloc1 != inconclusive.end()) {
4349
0
                    invalidFreeError(tok, allocation[var1], alloc1->second);
4350
0
                } else if (alloc2 != inconclusive.end()) {
4351
0
                    invalidFreeError(tok, allocation[var2], alloc2->second);
4352
0
                }
4353
0
            }
4354
4355
            // If the previously-allocated variable is passed in to another function
4356
            // as a parameter, it might be modified, so we shouldn't report an error
4357
            // if it is later used to free memory
4358
21.3k
            else if (match32(tok) && !mSettings->library.isFunctionConst(tok->str(), true)) {
4359
722
                const Token* tok2 = findmatch132(tok->next(), tok->linkAt(1)) ;
4360
2.24k
                while (tok2 != nullptr) {
4361
1.52k
                    allocation.erase(tok->varId());
4362
1.52k
                    inconclusive.erase(tok2->varId());
4363
1.52k
                    tok2 = findmatch132(tok2->next(), tok->linkAt(1)) ;
4364
1.52k
                }
4365
722
            }
4366
21.5k
        }
4367
1.10k
    }
4368
763
}
4369
4370
void CheckOther::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive)
4371
0
{
4372
0
    std::string alloc = allocation;
4373
0
    if (alloc != MatchCompiler::makeConstString("new"))
4374
0
        alloc += "()";
4375
0
    std::string deallocated = (alloc == MatchCompiler::makeConstString("new")) ? "deleted" : "freed";
4376
0
    reportError(tok, Severity::error, "invalidFree", "Mismatching address is " + deallocated + ". The address you get from " + alloc + " must be " + deallocated + " without offset.", CWE(0U), inconclusive ? Certainty::inconclusive : Certainty::normal);
4377
0
}
4378
4379
4380
//---------------------------------------------------------------------------
4381
// check for the same expression on both sides of an operator
4382
// (x == x), (x && x), (x || x)
4383
// (x.y == x.y), (x.y && x.y), (x.y || x.y)
4384
//---------------------------------------------------------------------------
4385
4386
namespace {
4387
    bool notconst(const Function* func)
4388
1.10k
    {
4389
1.10k
        return !func->isConst();
4390
1.10k
    }
4391
4392
    void getConstFunctions(const SymbolDatabase *symbolDatabase, std::list<const Function*> &constFunctions)
4393
763
    {
4394
2.79k
        for (const Scope &scope : symbolDatabase->scopeList) {
4395
            // only add const functions that do not have a non-const overloaded version
4396
            // since it is pretty much impossible to tell which is being called.
4397
2.79k
            using StringFunctionMap = std::map<std::string, std::list<const Function*>>;
4398
2.79k
            StringFunctionMap functionsByName;
4399
2.79k
            for (const Function &func : scope.functionList) {
4400
1.10k
                functionsByName[func.tokenDef->str()].push_back(&func);
4401
1.10k
            }
4402
2.79k
            for (std::pair<const std::string, std::list<const Function*>>& it : functionsByName) {
4403
1.10k
                const auto nc = std::find_if(it.second.cbegin(), it.second.cend(), notconst);
4404
1.10k
                if (nc == it.second.cend()) {
4405
                    // ok to add all of them
4406
0
                    constFunctions.splice(constFunctions.end(), it.second);
4407
0
                }
4408
1.10k
            }
4409
2.79k
        }
4410
763
    }
4411
}
4412
4413
static bool
4414
isStaticAssert(const Settings &settings, const Token *tok)
4415
82
{
4416
82
    if (tok->isCpp() && settings.standards.cpp >= Standards::CPP11 &&
4417
82
        match133(tok)) {
4418
0
        return true;
4419
0
    }
4420
4421
82
    if (tok->isC() && settings.standards.c >= Standards::C11 &&
4422
82
        match134(tok)) {
4423
0
        return true;
4424
0
    }
4425
4426
82
    return false;
4427
82
}
4428
4429
void CheckOther::checkDuplicateExpression()
4430
763
{
4431
763
    {
4432
763
        const bool styleEnabled = mSettings->severity.isEnabled(Severity::style);
4433
763
        const bool premiumEnabled = mSettings->isPremiumEnabled("oppositeExpression") ||
4434
763
                                    mSettings->isPremiumEnabled("duplicateExpression") ||
4435
763
                                    mSettings->isPremiumEnabled("duplicateAssignExpression") ||
4436
763
                                    mSettings->isPremiumEnabled("duplicateExpressionTernary") ||
4437
763
                                    mSettings->isPremiumEnabled("duplicateValueTernary") ||
4438
763
                                    mSettings->isPremiumEnabled("selfAssignment") ||
4439
763
                                    mSettings->isPremiumEnabled("knownConditionTrueFalse");
4440
4441
763
        if (!styleEnabled && !premiumEnabled)
4442
0
            return;
4443
763
    }
4444
4445
763
    logChecker("CheckOther::checkDuplicateExpression"); // style,warning
4446
4447
    // Parse all executing scopes..
4448
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
4449
4450
763
    std::list<const Function*> constFunctions;
4451
763
    getConstFunctions(symbolDatabase, constFunctions);
4452
4453
1.10k
    for (const Scope *scope : symbolDatabase->functionScopes) {
4454
23.7k
        for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
4455
22.6k
            if (tok->str() == MatchCompiler::makeConstString("=") && match114(tok->astOperand1())) {
4456
240
                const Token * endStatement = findmatch41(tok) ;
4457
240
                if (match135(endStatement)) {
4458
2
                    endStatement = endStatement->tokAt(4);
4459
2
                }
4460
240
                if (match136(endStatement)) {
4461
0
                    const Token * nextAssign = endStatement->tokAt(1);
4462
0
                    const Token * var1 = tok->astOperand1();
4463
0
                    const Token * var2 = nextAssign->astOperand1();
4464
0
                    if (var1 && var2 &&
4465
0
                        match137(var1->previous()) &&
4466
0
                        match137(var2->previous()) &&
4467
0
                        var2->valueType() && var1->valueType() &&
4468
0
                        var2->valueType()->originalTypeName == var1->valueType()->originalTypeName &&
4469
0
                        var2->valueType()->pointer == var1->valueType()->pointer &&
4470
0
                        var2->valueType()->constness == var1->valueType()->constness &&
4471
0
                        var2->varId() != var1->varId() && (
4472
0
                            tok->astOperand2()->isArithmeticalOp() ||
4473
0
                            tok->astOperand2()->str() == MatchCompiler::makeConstString(".") ||
4474
0
                            match32(tok->astOperand2()->previous())
4475
0
                            ) &&
4476
0
                        tok->next()->tokType() != Token::eType &&
4477
0
                        isSameExpression(true, tok->next(), nextAssign->next(), *mSettings, true, false) &&
4478
0
                        isSameExpression(true, tok->astOperand2(), nextAssign->astOperand2(), *mSettings, true, false) &&
4479
0
                        tok->astOperand2()->expressionString() == nextAssign->astOperand2()->expressionString()) {
4480
0
                        bool differentDomain = false;
4481
0
                        const Scope * varScope = var1->scope() ? var1->scope() : scope;
4482
0
                        const Token* assignTok = findmatch41(var2) ;
4483
0
                        for (; assignTok && assignTok != varScope->bodyEnd; assignTok = assignTok->next()) {
4484
0
                            if (!match138(assignTok))
4485
0
                                continue;
4486
0
                            if (!assignTok->astOperand1())
4487
0
                                continue;
4488
0
                            if (!assignTok->astOperand2())
4489
0
                                continue;
4490
4491
0
                            if (assignTok->astOperand1()->varId() != var1->varId() &&
4492
0
                                assignTok->astOperand1()->varId() != var2->varId() &&
4493
0
                                !isSameExpression(true,
4494
0
                                                  tok->astOperand2(),
4495
0
                                                  assignTok->astOperand1(),
4496
0
                                                  *mSettings,
4497
0
                                                  true,
4498
0
                                                  true))
4499
0
                                continue;
4500
0
                            if (assignTok->astOperand2()->varId() != var1->varId() &&
4501
0
                                assignTok->astOperand2()->varId() != var2->varId() &&
4502
0
                                !isSameExpression(true,
4503
0
                                                  tok->astOperand2(),
4504
0
                                                  assignTok->astOperand2(),
4505
0
                                                  *mSettings,
4506
0
                                                  true,
4507
0
                                                  true))
4508
0
                                continue;
4509
0
                            differentDomain = true;
4510
0
                            break;
4511
0
                        }
4512
0
                        if (!differentDomain && !isUniqueExpression(tok->astOperand2()))
4513
0
                            duplicateAssignExpressionError(var1, var2, false);
4514
0
                        else if (mSettings->certainty.isEnabled(Certainty::inconclusive)) {
4515
0
                            diag(assignTok);
4516
0
                            duplicateAssignExpressionError(var1, var2, true);
4517
0
                        }
4518
0
                    }
4519
0
                }
4520
240
            }
4521
22.6k
            auto isInsideLambdaCaptureList = [](const Token* tok) {
4522
4.48k
                const Token* parent = tok->astParent();
4523
4.49k
                while (match65(parent))
4524
2
                    parent = parent->astParent();
4525
4.48k
                return isLambdaCaptureList(parent);
4526
4.48k
            };
4527
22.6k
            ErrorPath errorPath;
4528
22.6k
            if (tok->isOp() && tok->astOperand1() && !match139(tok) && !isInsideLambdaCaptureList(tok)) {
4529
4.48k
                if (match140(tok) && astIsFloat(tok->astOperand1(), true))
4530
97
                    continue;
4531
4.39k
                const bool pointerDereference = (tok->astOperand1() && tok->astOperand1()->isUnaryOp("*")) ||
4532
4.39k
                                                (tok->astOperand2() && tok->astOperand2()->isUnaryOp("*"));
4533
4.39k
                const bool followVar = (!isConstVarExpression(tok) || match141(tok)) && !pointerDereference;
4534
4.39k
                if (isSameExpression(true,
4535
4.39k
                                     tok->astOperand1(),
4536
4.39k
                                     tok->astOperand2(),
4537
4.39k
                                     *mSettings,
4538
4.39k
                                     true,
4539
4.39k
                                     followVar,
4540
4.39k
                                     &errorPath)) {
4541
376
                    if (isWithoutSideEffects(tok->astOperand1())) {
4542
376
                        const Token* loopTok = isInLoopCondition(tok);
4543
376
                        if (!loopTok ||
4544
376
                            !findExpressionChanged(tok, tok, loopTok->link()->linkAt(1), *mSettings)) {
4545
374
                            const bool isEnum = tok->scope()->type == Scope::eEnum;
4546
374
                            const bool assignment = !isEnum && tok->str() == MatchCompiler::makeConstString("=");
4547
374
                            if (assignment)
4548
77
                                selfAssignmentError(tok, tok->astOperand1()->expressionString());
4549
297
                            else if (!isEnum) {
4550
297
                                if (tok->str() == MatchCompiler::makeConstString("==")) {
4551
82
                                    const Token* parent = tok->astParent();
4552
95
                                    while (parent && parent->astParent()) {
4553
13
                                        parent = parent->astParent();
4554
13
                                    }
4555
82
                                    if (parent && parent->previous() && isStaticAssert(*mSettings, parent->previous())) {
4556
0
                                        continue;
4557
0
                                    }
4558
82
                                }
4559
297
                                duplicateExpressionError(tok->astOperand1(), tok->astOperand2(), tok, std::move(errorPath));
4560
297
                            }
4561
374
                        }
4562
376
                    }
4563
4.01k
                } else if (tok->str() == MatchCompiler::makeConstString("=") && match31(tok->astOperand2()) &&
4564
4.01k
                           isSameExpression(false,
4565
53
                                            tok->astOperand1(),
4566
53
                                            tok->astOperand2()->astOperand1(),
4567
53
                                            *mSettings,
4568
53
                                            true,
4569
53
                                            false)) {
4570
6
                    if (isWithoutSideEffects(tok->astOperand1())) {
4571
6
                        selfAssignmentError(tok, tok->astOperand1()->expressionString());
4572
6
                    }
4573
4.01k
                } else if (isOppositeExpression(tok->astOperand1(),
4574
4.01k
                                                tok->astOperand2(),
4575
4.01k
                                                *mSettings,
4576
4.01k
                                                false,
4577
4.01k
                                                true,
4578
4.01k
                                                &errorPath) &&
4579
4.01k
                           !match142(tok) &&
4580
4.01k
                           isWithoutSideEffects(tok->astOperand1())) {
4581
1
                    oppositeExpressionError(tok, std::move(errorPath));
4582
4.00k
                } else if (!match143(tok)) { // These operators are not associative
4583
3.83k
                    if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() &&
4584
3.83k
                        isSameExpression(true,
4585
48
                                         tok->astOperand2(),
4586
48
                                         tok->astOperand1()->astOperand2(),
4587
48
                                         *mSettings,
4588
48
                                         true,
4589
48
                                         followVar,
4590
48
                                         &errorPath) &&
4591
3.83k
                        isWithoutSideEffects(tok->astOperand2()))
4592
17
                        duplicateExpressionError(tok->astOperand2(), tok->astOperand1()->astOperand2(), tok, std::move(errorPath));
4593
3.81k
                    else if (tok->astOperand2() && isConstExpression(tok->astOperand1(), mSettings->library)) {
4594
2.69k
                        auto checkDuplicate = [&](const Token* exp1, const Token* exp2, const Token* ast1) {
4595
39
                            if (isSameExpression(true, exp1, exp2, *mSettings, true, true, &errorPath) &&
4596
39
                                isWithoutSideEffects(exp1) &&
4597
39
                                isWithoutSideEffects(ast1->astOperand2()))
4598
3
                                duplicateExpressionError(exp1, exp2, tok, errorPath, /*hasMultipleExpr*/ true);
4599
39
                        };
4600
2.69k
                        const Token *ast1 = tok->astOperand1();
4601
2.71k
                        while (ast1 && tok->str() == ast1->str()) { // chain of identical operators
4602
20
                            checkDuplicate(ast1->astOperand2(), tok->astOperand2(), ast1);
4603
20
                            if (ast1->astOperand1() && ast1->astOperand1()->str() != tok->str()) // check first condition in the chain
4604
19
                                checkDuplicate(ast1->astOperand1(), tok->astOperand2(), ast1);
4605
20
                            ast1 = ast1->astOperand1();
4606
20
                        }
4607
2.69k
                    }
4608
3.83k
                }
4609
18.1k
            } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == MatchCompiler::makeConstString(":") && tok->astParent() && tok->astParent()->str() == MatchCompiler::makeConstString("?")) {
4610
0
                if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) &&
4611
0
                    !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) &&
4612
0
                    isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()))
4613
0
                    duplicateValueTernaryError(tok);
4614
0
                else if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath))
4615
0
                    duplicateExpressionTernaryError(tok, std::move(errorPath));
4616
0
            }
4617
22.6k
        }
4618
1.10k
    }
4619
763
}
4620
4621
void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors)
4622
1
{
4623
1
    errors.emplace_back(opTok, "");
4624
4625
1
    const std::string& op = opTok ? opTok->str() : "&&";
4626
4627
1
    reportError(errors, Severity::style, "oppositeExpression", "Opposite expression on both sides of \'" + op + "\'.\n"
4628
1
                "Finding the opposite expression on both sides of an operator is suspicious and might "
4629
1
                "indicate a cut and paste or logic error. Please examine this code carefully to "
4630
1
                "determine if it is correct.", CWE398, Certainty::normal);
4631
1
}
4632
4633
void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr)
4634
317
{
4635
317
    errors.emplace_back(opTok, "");
4636
4637
317
    const std::string& expr1 = tok1 ? tok1->expressionString() : "x";
4638
317
    const std::string& expr2 = tok2 ? tok2->expressionString() : "x";
4639
4640
317
    const std::string& op = opTok ? opTok->str() : "&&";
4641
317
    std::string msg = "Same expression " + (hasMultipleExpr ? "\'" + expr1 + "\'" + " found multiple times in chain of \'" + op + "\' operators" : "on both sides of \'" + op + "\'");
4642
317
    const char *id = "duplicateExpression";
4643
317
    if (expr1 != expr2 && (!opTok || match144(opTok))) {
4644
0
        id = "knownConditionTrueFalse";
4645
0
        std::string exprMsg = "The comparison \'" + expr1 + " " + op +  " " + expr2 + "\' is always ";
4646
0
        if (match145(opTok))
4647
0
            msg = exprMsg + "true";
4648
0
        else if (match146(opTok))
4649
0
            msg = exprMsg + "false";
4650
0
    }
4651
4652
317
    if (expr1 != expr2 && !match147(tok1) && !match147(tok2))
4653
0
        msg += " because '" + expr1 + "' and '" + expr2 + "' represent the same value";
4654
4655
317
    reportError(errors, Severity::style, id, msg +
4656
317
                (std::string(".\nFinding the same expression ") + (hasMultipleExpr ? "more than once in a condition" : "on both sides of an operator")) +
4657
317
                " is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to "
4658
317
                "determine if it is correct.", CWE398, Certainty::normal);
4659
317
}
4660
4661
void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive)
4662
0
{
4663
0
    const std::list<const Token *> toks = { tok2, tok1 };
4664
4665
0
    const std::string& var1 = tok1 ? tok1->str() : "x";
4666
0
    const std::string& var2 = tok2 ? tok2->str() : "x";
4667
4668
0
    reportError(toks, Severity::style, "duplicateAssignExpression",
4669
0
                "Same expression used in consecutive assignments of '" + var1 + "' and '" + var2 + "'.\n"
4670
0
                "Finding variables '" + var1 + "' and '" + var2 + "' that are assigned the same expression "
4671
0
                "is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to "
4672
0
                "determine if it is correct.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
4673
0
}
4674
4675
void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors)
4676
0
{
4677
0
    errors.emplace_back(tok, "");
4678
0
    reportError(errors, Severity::style, "duplicateExpressionTernary", "Same expression in both branches of ternary operator.\n"
4679
0
                "Finding the same expression in both branches of ternary operator is suspicious as "
4680
0
                "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
4681
0
}
4682
4683
void CheckOther::duplicateValueTernaryError(const Token *tok)
4684
0
{
4685
0
    reportError(tok, Severity::style, "duplicateValueTernary", "Same value in both branches of ternary operator.\n"
4686
0
                "Finding the same value in both branches of ternary operator is suspicious as "
4687
0
                "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
4688
0
}
4689
4690
void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
4691
83
{
4692
83
    reportError(tok, Severity::style,
4693
83
                "selfAssignment",
4694
83
                "$symbol:" + varname + "\n"
4695
83
                "Redundant assignment of '$symbol' to itself.", CWE398, Certainty::normal);
4696
83
}
4697
4698
//-----------------------------------------------------------------------------
4699
// Check is a comparison of two variables leads to condition, which is
4700
// always true or false.
4701
// For instance: int a = 1; if(isless(a,a)){...}
4702
// In this case isless(a,a) always evaluates to false.
4703
//
4704
// Reference:
4705
// - http://www.cplusplus.com/reference/cmath/
4706
//-----------------------------------------------------------------------------
4707
void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse()
4708
763
{
4709
763
    if (!mSettings->severity.isEnabled(Severity::warning))
4710
0
        return;
4711
4712
763
    logChecker("CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse"); // warning
4713
4714
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
4715
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
4716
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
4717
21.5k
            if (tok->isName() && match148(tok)) {
4718
0
                const int varidLeft = tok->tokAt(2)->varId();// get the left varid
4719
0
                const int varidRight = tok->tokAt(4)->varId();// get the right varid
4720
                // compare varids: if they are not zero but equal
4721
                // --> the comparison function is called with the same variables
4722
0
                if (varidLeft == varidRight) {
4723
0
                    const std::string& functionName = tok->str(); // store function name
4724
0
                    const std::string& varNameLeft = tok->strAt(2); // get the left variable name
4725
0
                    if (functionName == MatchCompiler::makeConstString("isgreater") || functionName == MatchCompiler::makeConstString("isless") || functionName == MatchCompiler::makeConstString("islessgreater")) {
4726
                        // e.g.: isgreater(x,x) --> (x)>(x) --> false
4727
0
                        checkComparisonFunctionIsAlwaysTrueOrFalseError(tok, functionName, varNameLeft, false);
4728
0
                    } else { // functionName == MatchCompiler::makeConstString("isgreaterequal") || functionName == MatchCompiler::makeConstString("islessequal")
4729
                        // e.g.: isgreaterequal(x,x) --> (x)>=(x) --> true
4730
0
                        checkComparisonFunctionIsAlwaysTrueOrFalseError(tok, functionName, varNameLeft, true);
4731
0
                    }
4732
0
                }
4733
0
            }
4734
21.5k
        }
4735
1.10k
    }
4736
763
}
4737
void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result)
4738
0
{
4739
0
    const std::string strResult = bool_to_string(result);
4740
0
    const CWE cweResult = result ? CWE571 : CWE570;
4741
4742
0
    reportError(tok, Severity::warning, "comparisonFunctionIsAlwaysTrueOrFalse",
4743
0
                "$symbol:" + functionName + "\n"
4744
0
                "Comparison of two identical variables with $symbol(" + varName + "," + varName + ") always evaluates to " + strResult + ".\n"
4745
0
                "The function $symbol is designed to compare two variables. Calling this function with one variable (" + varName + ") "
4746
0
                "for both parameters leads to a statement which is always " + strResult + ".", cweResult, Certainty::normal);
4747
0
}
4748
4749
//---------------------------------------------------------------------------
4750
// Check testing sign of unsigned variables and pointers.
4751
//---------------------------------------------------------------------------
4752
void CheckOther::checkSignOfUnsignedVariable()
4753
763
{
4754
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsignedLessThanZero"))
4755
0
        return;
4756
4757
763
    logChecker("CheckOther::checkSignOfUnsignedVariable"); // style
4758
4759
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
4760
4761
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
4762
        // check all the code in the function
4763
22.6k
        for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
4764
21.5k
            const ValueFlow::Value *zeroValue = nullptr;
4765
21.5k
            const Token *nonZeroExpr = nullptr;
4766
21.5k
            if (comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr)) {
4767
0
                const ValueType* vt = nonZeroExpr->valueType();
4768
0
                if (vt->pointer)
4769
0
                    pointerLessThanZeroError(tok, zeroValue);
4770
0
                else
4771
0
                    unsignedLessThanZeroError(tok, zeroValue, nonZeroExpr->expressionString());
4772
21.5k
            } else if (testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) {
4773
0
                const ValueType* vt = nonZeroExpr->valueType();
4774
0
                if (vt->pointer)
4775
0
                    pointerPositiveError(tok, zeroValue);
4776
0
                else
4777
0
                    unsignedPositiveError(tok, zeroValue, nonZeroExpr->expressionString());
4778
0
            }
4779
21.5k
        }
4780
1.10k
    }
4781
763
}
4782
4783
bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress)
4784
21.6k
{
4785
21.6k
    if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
4786
20.6k
        return false;
4787
4788
934
    const ValueFlow::Value *v1 = tok->astOperand1()->getValue(0);
4789
934
    const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0);
4790
4791
934
    if (match149(tok) && v2 && v2->isKnown()) {
4792
4
        zeroValue = v2;
4793
4
        nonZeroExpr = tok->astOperand1();
4794
930
    } else if (match150(tok) && v1 && v1->isKnown()) {
4795
11
        zeroValue = v1;
4796
11
        nonZeroExpr = tok->astOperand2();
4797
919
    } else {
4798
919
        return false;
4799
919
    }
4800
4801
15
    if (const Variable* var = nonZeroExpr->variable())
4802
9
        if (var->typeStartToken()->isTemplateArg())
4803
0
            return suppress;
4804
4805
15
    const ValueType* vt = nonZeroExpr->valueType();
4806
15
    return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED);
4807
15
}
4808
4809
bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr)
4810
21.6k
{
4811
21.6k
    if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
4812
20.6k
        return false;
4813
4814
934
    const ValueFlow::Value *v1 = tok->astOperand1()->getValue(0);
4815
934
    const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0);
4816
4817
934
    if (match151(tok) && v2 && v2->isKnown()) {
4818
1
        zeroValue = v2;
4819
1
        nonZeroExpr = tok->astOperand1();
4820
933
    } else if (match152(tok) && v1 && v1->isKnown()) {
4821
5
        zeroValue = v1;
4822
5
        nonZeroExpr = tok->astOperand2();
4823
928
    } else {
4824
928
        return false;
4825
928
    }
4826
4827
6
    const ValueType* vt = nonZeroExpr->valueType();
4828
6
    return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED);
4829
934
}
4830
4831
void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
4832
0
{
4833
0
    reportError(getErrorPath(tok, v, "Unsigned less than zero"), Severity::style, "unsignedLessThanZero",
4834
0
                "$symbol:" + varname + "\n"
4835
0
                "Checking if unsigned expression '$symbol' is less than zero.\n"
4836
0
                "The unsigned expression '$symbol' will never be negative so it "
4837
0
                "is either pointless or an error to check if it is.", CWE570, Certainty::normal);
4838
0
}
4839
4840
void CheckOther::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v)
4841
0
{
4842
0
    reportError(getErrorPath(tok, v, "Pointer less than zero"), Severity::style, "pointerLessThanZero",
4843
0
                "A pointer can not be negative so it is either pointless or an error to check if it is.", CWE570, Certainty::normal);
4844
0
}
4845
4846
void CheckOther::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
4847
0
{
4848
0
    reportError(getErrorPath(tok, v, "Unsigned positive"), Severity::style, "unsignedPositive",
4849
0
                "$symbol:" + varname + "\n"
4850
0
                "Unsigned expression '$symbol' can't be negative so it is unnecessary to test it.", CWE570, Certainty::normal);
4851
0
}
4852
4853
void CheckOther::pointerPositiveError(const Token *tok, const ValueFlow::Value * v)
4854
0
{
4855
0
    reportError(getErrorPath(tok, v, "Pointer positive"), Severity::style, "pointerPositive",
4856
0
                "A pointer can not be negative so it is either pointless or an error to check if it is not.", CWE570, Certainty::normal);
4857
0
}
4858
4859
/* check if a constructor in given class scope takes a reference */
4860
static bool constructorTakesReference(const Scope * const classScope)
4861
0
{
4862
0
    return std::any_of(classScope->functionList.begin(), classScope->functionList.end(), [&](const Function& constructor) {
4863
0
        if (constructor.isConstructor()) {
4864
0
            for (int argnr = 0U; argnr < constructor.argCount(); argnr++) {
4865
0
                const Variable * const argVar = constructor.getArgumentVar(argnr);
4866
0
                if (argVar && argVar->isReference()) {
4867
0
                    return true;
4868
0
                }
4869
0
            }
4870
0
        }
4871
0
        return false;
4872
0
    });
4873
0
}
4874
4875
//---------------------------------------------------------------------------
4876
// This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &".
4877
// In most scenarios, "const A & a = getA()" will be more efficient.
4878
//---------------------------------------------------------------------------
4879
void CheckOther::checkRedundantCopy()
4880
763
{
4881
763
    if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings->certainty.isEnabled(Certainty::inconclusive))
4882
0
        return;
4883
4884
763
    logChecker("CheckOther::checkRedundantCopy"); // c++,performance,inconclusive
4885
4886
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
4887
4888
4.57k
    for (const Variable* var : symbolDatabase->variableList()) {
4889
4.57k
        if (!var || var->isReference() || var->isPointer() ||
4890
4.57k
            (!var->type() && !var->isStlType() && !(var->valueType() && var->valueType()->container)) || // bailout if var is of standard type, if it is a pointer or non-const
4891
4.57k
            (!var->isConst() && isVariableChanged(var, *mSettings)))
4892
4.57k
            continue;
4893
4894
0
        const Token* startTok = var->nameToken();
4895
0
        if (startTok->strAt(1) == MatchCompiler::makeConstString("=")) // %type% %name% = ... ;
4896
0
            ;
4897
0
        else if (match153(startTok->next()) && var->isClass()) {
4898
0
            if (!var->typeScope() && !(var->valueType() && var->valueType()->container))
4899
0
                continue;
4900
            // Object is instantiated. Warn if constructor takes arguments by value.
4901
0
            if (var->typeScope() && constructorTakesReference(var->typeScope()))
4902
0
                continue;
4903
0
        } else if (match51(startTok->next()) && startTok->next()->isSplittedVarDeclEq()) {
4904
0
            startTok = startTok->tokAt(2);
4905
0
        } else
4906
0
            continue;
4907
4908
0
        const Token* tok = startTok->next()->astOperand2();
4909
0
        if (!tok)
4910
0
            continue;
4911
0
        if (!match32(tok->previous()))
4912
0
            continue;
4913
0
        if (!match154(tok->link())) // bailout for usage like "const A a = getA()+3"
4914
0
            continue;
4915
4916
0
        const Token* dot = tok->astOperand1();
4917
0
        if (match30(dot)) {
4918
0
            const Token* varTok = dot->astOperand1();
4919
0
            const int indirect = varTok->valueType() ? varTok->valueType()->pointer : 0;
4920
0
            if (isVariableChanged(tok, tok->scope()->bodyEnd, indirect, varTok->varId(), /*globalvar*/ true, *mSettings))
4921
0
                continue;
4922
0
            if (isTemporary(dot, &mSettings->library, /*unknown*/ true))
4923
0
                continue;
4924
0
        }
4925
0
        if (exprDependsOnThis(tok->previous()))
4926
0
            continue;
4927
4928
0
        const Function* func = tok->previous()->function();
4929
0
        if (func && func->tokenDef->strAt(-1) == MatchCompiler::makeConstString("&")) {
4930
0
            const Scope* fScope = func->functionScope;
4931
0
            if (fScope && fScope->bodyEnd && match155(fScope->bodyEnd->tokAt(-3))) {
4932
0
                const Token* varTok = fScope->bodyEnd->tokAt(-2);
4933
0
                if (varTok->variable() && !varTok->variable()->isGlobal() &&
4934
0
                    (!varTok->variable()->type() || !varTok->variable()->type()->classScope ||
4935
0
                     (varTok->variable()->valueType() && ValueFlow::getSizeOf(*varTok->variable()->valueType(), *mSettings) > 2 * mSettings->platform.sizeof_pointer)))
4936
0
                    redundantCopyError(startTok, startTok->str());
4937
0
            }
4938
0
        }
4939
0
    }
4940
763
}
4941
4942
void CheckOther::redundantCopyError(const Token *tok,const std::string& varname)
4943
0
{
4944
0
    reportError(tok, Severity::performance, "redundantCopyLocalConst",
4945
0
                "$symbol:" + varname + "\n"
4946
0
                "Use const reference for '$symbol' to avoid unnecessary data copying.\n"
4947
0
                "The const variable '$symbol' is assigned a copy of the data. You can avoid "
4948
0
                "the unnecessary data copying by converting '$symbol' to const reference.",
4949
0
                CWE398,
4950
0
                Certainty::inconclusive); // since #5618 that check became inconclusive
4951
0
}
4952
4953
//---------------------------------------------------------------------------
4954
// Checking for shift by negative values
4955
//---------------------------------------------------------------------------
4956
4957
static bool isNegative(const Token *tok, const Settings &settings)
4958
0
{
4959
0
    return tok->valueType() && tok->valueType()->sign == ValueType::SIGNED && tok->getValueLE(-1LL, settings);
4960
0
}
4961
4962
void CheckOther::checkNegativeBitwiseShift()
4963
763
{
4964
763
    const bool portability = mSettings->severity.isEnabled(Severity::portability);
4965
4966
763
    logChecker("CheckOther::checkNegativeBitwiseShift");
4967
4968
55.2k
    for (const Token* tok = mTokenizer->tokens(); tok; tok = tok->next()) {
4969
54.5k
        tok = skipUnreachableBranch(tok);
4970
4971
54.5k
        if (!tok->astOperand1() || !tok->astOperand2())
4972
46.2k
            continue;
4973
4974
8.26k
        if (!match156(tok))
4975
8.26k
            continue;
4976
4977
        // don't warn if lhs is a class. this is an overloaded operator then
4978
1
        if (tok->isCpp()) {
4979
1
            const ValueType * lhsType = tok->astOperand1()->valueType();
4980
1
            if (!lhsType || !lhsType->isIntegral() || lhsType->pointer)
4981
1
                continue;
4982
1
        }
4983
4984
        // bailout if operation is protected by ?:
4985
0
        bool ternary = false;
4986
0
        for (const Token *parent = tok; parent; parent = parent->astParent()) {
4987
0
            if (match47(parent)) {
4988
0
                ternary = true;
4989
0
                break;
4990
0
            }
4991
0
        }
4992
0
        if (ternary)
4993
0
            continue;
4994
4995
        // Get negative rhs value. preferably a value which doesn't have 'condition'.
4996
0
        if (portability && isNegative(tok->astOperand1(), *mSettings))
4997
0
            negativeBitwiseShiftError(tok, 1);
4998
0
        else if (isNegative(tok->astOperand2(), *mSettings))
4999
0
            negativeBitwiseShiftError(tok, 2);
5000
0
    }
5001
763
}
5002
5003
5004
void CheckOther::negativeBitwiseShiftError(const Token *tok, int op)
5005
0
{
5006
0
    if (op == 1)
5007
        // LHS - this is used by intention in various software, if it
5008
        // is used often in a project and works as expected then this is
5009
        // a portability issue
5010
0
        reportError(tok, Severity::portability, "shiftNegativeLHS", "Shifting a negative value is technically undefined behaviour", CWE758, Certainty::normal);
5011
0
    else // RHS
5012
0
        reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value is undefined behaviour", CWE758, Certainty::normal);
5013
0
}
5014
5015
//---------------------------------------------------------------------------
5016
// Check for incompletely filled buffers.
5017
//---------------------------------------------------------------------------
5018
void CheckOther::checkIncompleteArrayFill()
5019
763
{
5020
763
    if (!mSettings->certainty.isEnabled(Certainty::inconclusive))
5021
0
        return;
5022
763
    const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
5023
763
    const bool printPortability = mSettings->severity.isEnabled(Severity::portability);
5024
763
    if (!printPortability && !printWarning)
5025
0
        return;
5026
5027
763
    logChecker("CheckOther::checkIncompleteArrayFill"); // warning,portability,inconclusive
5028
5029
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5030
5031
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
5032
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
5033
21.5k
            if (match157(tok)) {
5034
0
                std::vector<const Token*> args = getArguments(tok);
5035
0
                if (args.size() != 3)
5036
0
                    continue;
5037
0
                const Token* tok2 = args[0];
5038
0
                if (tok2->str() == MatchCompiler::makeConstString("::"))
5039
0
                    tok2 = tok2->next();
5040
0
                while (match158(tok2))
5041
0
                    tok2 = tok2->tokAt(2);
5042
0
                if (!match159(tok2))
5043
0
                    continue;
5044
5045
0
                const Variable *var = tok2->variable();
5046
0
                if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0))
5047
0
                    continue;
5048
5049
0
                if (!args[2]->hasKnownIntValue() || args[2]->getKnownIntValue() != var->dimension(0))
5050
0
                    continue;
5051
0
                int size = mTokenizer->sizeOfType(var->typeStartToken());
5052
0
                if (size == 0 && var->valueType()->pointer)
5053
0
                    size = mSettings->platform.sizeof_pointer;
5054
0
                else if (size == 0 && var->valueType())
5055
0
                    size = ValueFlow::getSizeOf(*var->valueType(), *mSettings);
5056
0
                const Token* tok3 = tok->next()->astOperand2()->astOperand1()->astOperand1();
5057
0
                if ((size != 1 && size != 100 && size != 0) || var->isPointer()) {
5058
0
                    if (printWarning)
5059
0
                        incompleteArrayFillError(tok, tok3->expressionString(), tok->str(), false);
5060
0
                } else if (var->valueType()->type == ValueType::Type::BOOL && printPortability) // sizeof(bool) is not 1 on all platforms
5061
0
                    incompleteArrayFillError(tok, tok3->expressionString(), tok->str(), true);
5062
0
            }
5063
21.5k
        }
5064
1.10k
    }
5065
763
}
5066
5067
void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean)
5068
0
{
5069
0
    if (boolean)
5070
0
        reportError(tok, Severity::portability, "incompleteArrayFill",
5071
0
                    "$symbol:" + buffer + "\n"
5072
0
                    "$symbol:" + function + "\n"
5073
0
                    "Array '" + buffer + "' might be filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
5074
0
                    "The array '" + buffer + "' is filled incompletely. The function '" + function + "()' needs the size given in bytes, but the type 'bool' is larger than 1 on some platforms. Did you forget to multiply the size with 'sizeof(*" + buffer + ")'?", CWE131, Certainty::inconclusive);
5075
0
    else
5076
0
        reportError(tok, Severity::warning, "incompleteArrayFill",
5077
0
                    "$symbol:" + buffer + "\n"
5078
0
                    "$symbol:" + function + "\n"
5079
0
                    "Array '" + buffer + "' is filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
5080
0
                    "The array '" + buffer + "' is filled incompletely. The function '" + function + "()' needs the size given in bytes, but an element of the given array is larger than one byte. Did you forget to multiply the size with 'sizeof(*" + buffer + ")'?", CWE131, Certainty::inconclusive);
5081
0
}
5082
5083
//---------------------------------------------------------------------------
5084
// Detect NULL being passed to variadic function.
5085
//---------------------------------------------------------------------------
5086
5087
void CheckOther::checkVarFuncNullUB()
5088
763
{
5089
763
    if (!mSettings->severity.isEnabled(Severity::portability))
5090
0
        return;
5091
5092
763
    logChecker("CheckOther::checkVarFuncNullUB"); // portability
5093
5094
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5095
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
5096
23.7k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
5097
            // Is NULL passed to a function?
5098
22.6k
            if (match160(tok)) {
5099
                // Locate function name in this function call.
5100
0
                const Token *ftok = tok;
5101
0
                int argnr = 1;
5102
0
                while (ftok && ftok->str() != MatchCompiler::makeConstString("(")) {
5103
0
                    if (ftok->str() == MatchCompiler::makeConstString(")"))
5104
0
                        ftok = ftok->link();
5105
0
                    else if (ftok->str() == MatchCompiler::makeConstString(","))
5106
0
                        ++argnr;
5107
0
                    ftok = ftok->previous();
5108
0
                }
5109
0
                ftok = ftok ? ftok->previous() : nullptr;
5110
0
                if (ftok && ftok->isName()) {
5111
                    // If this is a variadic function then report error
5112
0
                    const Function *f = ftok->function();
5113
0
                    if (f && f->argCount() <= argnr) {
5114
0
                        const Token *tok2 = f->argDef;
5115
0
                        tok2 = tok2 ? tok2->link() : nullptr; // goto ')'
5116
0
                        if (tok2 && match161(tok2->tokAt(-1)))
5117
0
                            varFuncNullUBError(tok);
5118
0
                    }
5119
0
                }
5120
0
            }
5121
22.6k
        }
5122
1.10k
    }
5123
763
}
5124
5125
void CheckOther::varFuncNullUBError(const Token *tok)
5126
0
{
5127
0
    reportError(tok,
5128
0
                Severity::portability,
5129
0
                "varFuncNullUB",
5130
0
                "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
5131
0
                "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
5132
0
                "The C99 standard, in section 7.15.1.1, states that if the type used by va_arg() is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined.\n"
5133
0
                "The value of the NULL macro is an implementation-defined null pointer constant (7.17), which can be any integer constant expression with the value 0, or such an expression casted to (void*) (6.3.2.3). This includes values like 0, 0L, or even 0LL.\n"
5134
0
                "In practice on common architectures, this will cause real crashes if sizeof(int) != sizeof(void*), and NULL is defined to 0 or any other null pointer constant that promotes to int.\n"
5135
0
                "To reproduce you might be able to use this little code example on 64bit platforms. If the output includes \"ERROR\", the sentinel had only 4 out of 8 bytes initialized to zero and was not detected as the final argument to stop argument processing via va_arg(). Changing the 0 to (void*)0 or 0L will make the \"ERROR\" output go away.\n"
5136
0
                "#include <stdarg.h>\n"
5137
0
                "#include <stdio.h>\n"
5138
0
                "\n"
5139
0
                "void f(char *s, ...) {\n"
5140
0
                "    va_list ap;\n"
5141
0
                "    va_start(ap,s);\n"
5142
0
                "    for (;;) {\n"
5143
0
                "        char *p = va_arg(ap,char*);\n"
5144
0
                "        printf(\"%018p, %s\\n\", p, (long)p & 255 ? p : \"\");\n"
5145
0
                "        if(!p) break;\n"
5146
0
                "    }\n"
5147
0
                "    va_end(ap);\n"
5148
0
                "}\n"
5149
0
                "\n"
5150
0
                "void g() {\n"
5151
0
                "    char *s2 = \"x\";\n"
5152
0
                "    char *s3 = \"ERROR\";\n"
5153
0
                "\n"
5154
0
                "    // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64\n"
5155
0
                "    f(\"first\", s2, s2, s2, s2, s2, 0, s3, (char*)0);\n"
5156
0
                "}\n"
5157
0
                "\n"
5158
0
                "void h() {\n"
5159
0
                "    int i;\n"
5160
0
                "    volatile unsigned char a[1000];\n"
5161
0
                "    for (i = 0; i<sizeof(a); i++)\n"
5162
0
                "        a[i] = -1;\n"
5163
0
                "}\n"
5164
0
                "\n"
5165
0
                "int main() {\n"
5166
0
                "    h();\n"
5167
0
                "    g();\n"
5168
0
                "    return 0;\n"
5169
0
                "}", CWE475, Certainty::normal);
5170
0
}
5171
5172
void CheckOther::checkRedundantPointerOp()
5173
763
{
5174
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantPointerOp"))
5175
0
        return;
5176
5177
763
    logChecker("CheckOther::checkRedundantPointerOp"); // style
5178
5179
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
5180
54.8k
        if (tok->isExpandedMacro() && tok->str() == MatchCompiler::makeConstString("("))
5181
0
            tok = tok->link();
5182
5183
54.8k
        bool addressOfDeref{};
5184
54.8k
        if (tok->isUnaryOp("&") && tok->astOperand1()->isUnaryOp("*"))
5185
0
            addressOfDeref = true;
5186
54.8k
        else if (tok->isUnaryOp("*") && tok->astOperand1()->isUnaryOp("&"))
5187
0
            addressOfDeref = false;
5188
54.8k
        else
5189
54.8k
            continue;
5190
5191
        // variable
5192
0
        const Token *varTok = tok->astOperand1()->astOperand1();
5193
0
        if (!varTok || varTok->isExpandedMacro())
5194
0
            continue;
5195
5196
0
        if (!addressOfDeref) { // dereference of address
5197
0
            if (tok->isExpandedMacro())
5198
0
                continue;
5199
0
            if (varTok->valueType() && varTok->valueType()->pointer && varTok->valueType()->reference == Reference::LValue)
5200
0
                continue;
5201
0
        }
5202
5203
0
        const Variable *var = varTok->variable();
5204
0
        if (!var || (addressOfDeref && !var->isPointer()))
5205
0
            continue;
5206
5207
0
        redundantPointerOpError(tok, var->name(), false, addressOfDeref);
5208
0
    }
5209
763
}
5210
5211
void CheckOther::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref)
5212
0
{
5213
0
    std::string msg = "$symbol:" + varname + "\nRedundant pointer operation on '$symbol' - it's already a ";
5214
0
    msg += addressOfDeref ? "pointer." : "variable.";
5215
0
    reportError(tok, Severity::style, "redundantPointerOp", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
5216
0
}
5217
5218
void CheckOther::checkInterlockedDecrement()
5219
763
{
5220
763
    if (!mSettings->platform.isWindows()) {
5221
763
        return;
5222
763
    }
5223
5224
0
    logChecker("CheckOther::checkInterlockedDecrement"); // windows-platform
5225
5226
0
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
5227
0
        if (tok->isName() && match162(tok)) {
5228
0
            const Token* interlockedVarTok = tok->tokAt(3);
5229
0
            const Token* checkStartTok =  interlockedVarTok->tokAt(5);
5230
0
            if ((match163(checkStartTok) && checkStartTok->strAt(2) == interlockedVarTok->str()) ||
5231
0
                (match164(checkStartTok) && checkStartTok->strAt(1) == interlockedVarTok->str()) ||
5232
0
                (match165(checkStartTok) && checkStartTok->str() == interlockedVarTok->str()) ||
5233
0
                (match166(checkStartTok) && checkStartTok->str() == interlockedVarTok->str())) {
5234
0
                raceAfterInterlockedDecrementError(checkStartTok);
5235
0
            }
5236
0
        } else if (match167(tok)) {
5237
0
            const Token* condEnd = tok->linkAt(1);
5238
0
            const Token* funcTok = tok->tokAt(2);
5239
0
            const Token* firstAccessTok = funcTok->str() == MatchCompiler::makeConstString("::") ? funcTok->tokAt(4) : funcTok->tokAt(3);
5240
0
            if (condEnd && condEnd->next() && condEnd->linkAt(1)) {
5241
0
                const Token* ifEndTok = condEnd->linkAt(1);
5242
0
                if (match168(ifEndTok)) {
5243
0
                    const Token* secondAccessTok = ifEndTok->tokAt(2);
5244
0
                    if (secondAccessTok->str() == firstAccessTok->str()) {
5245
0
                        raceAfterInterlockedDecrementError(secondAccessTok);
5246
0
                    }
5247
0
                } else if (match169(ifEndTok)) {
5248
0
                    const Token* secondAccessTok = ifEndTok->tokAt(4);
5249
0
                    if (secondAccessTok->str() == firstAccessTok->str()) {
5250
0
                        raceAfterInterlockedDecrementError(secondAccessTok);
5251
0
                    }
5252
0
                }
5253
0
            }
5254
0
        }
5255
0
    }
5256
0
}
5257
5258
void CheckOther::raceAfterInterlockedDecrementError(const Token* tok)
5259
0
{
5260
0
    reportError(tok, Severity::error, "raceAfterInterlockedDecrement",
5261
0
                "Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.", CWE362, Certainty::normal);
5262
0
}
5263
5264
void CheckOther::checkUnusedLabel()
5265
763
{
5266
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("unusedLabel"))
5267
0
        return;
5268
5269
763
    logChecker("CheckOther::checkUnusedLabel"); // style,warning
5270
5271
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5272
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
5273
1.10k
        const bool hasIfdef = mTokenizer->hasIfdef(scope->bodyStart, scope->bodyEnd);
5274
23.7k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
5275
22.6k
            if (!tok->scope()->isExecutable())
5276
0
                tok = tok->scope()->bodyEnd;
5277
5278
22.6k
            if (match170(tok) && !tok->tokAt(1)->isKeyword()) {
5279
0
                const std::string tmp("goto " + tok->strAt(1));
5280
0
                if (!Token::findsimplematch(scope->bodyStart->next(), tmp.c_str(), tmp.size(), scope->bodyEnd->previous()) && !tok->next()->isExpandedMacro())
5281
0
                    unusedLabelError(tok->next(), tok->next()->scope()->type == Scope::eSwitch, hasIfdef);
5282
0
            }
5283
22.6k
        }
5284
1.10k
    }
5285
763
}
5286
5287
void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef)
5288
0
{
5289
0
    if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style))
5290
0
        return;
5291
5292
0
    std::string id = "unusedLabel";
5293
0
    if (inSwitch)
5294
0
        id += "Switch";
5295
0
    if (hasIfdef)
5296
0
        id += "Configuration";
5297
5298
0
    std::string msg = "$symbol:" + (tok ? tok->str() : "") + "\nLabel '$symbol' is not used.";
5299
0
    if (hasIfdef)
5300
0
        msg += " There is #if in function body so the label might be used in code that is removed by the preprocessor.";
5301
0
    if (inSwitch)
5302
0
        msg += " Should this be a 'case' of the enclosing switch()?";
5303
5304
0
    reportError(tok,
5305
0
                inSwitch ? Severity::warning : Severity::style,
5306
0
                id,
5307
0
                msg,
5308
0
                CWE398,
5309
0
                Certainty::normal);
5310
0
}
5311
5312
static bool checkEvaluationOrderC(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & selfAssignmentError)
5313
0
{
5314
    // self assignment..
5315
0
    if (tok2 == tok && tok->str() == MatchCompiler::makeConstString("=") && parent->str() == MatchCompiler::makeConstString("=") && isSameExpression(false, tok->astOperand1(), parent->astOperand1(), settings, true, false)) {
5316
0
        if (settings.severity.isEnabled(Severity::warning) && isSameExpression(true, tok->astOperand1(), parent->astOperand1(), settings, true, false))
5317
0
            selfAssignmentError = true;
5318
0
        return false;
5319
0
    }
5320
    // Is expression used?
5321
0
    bool foundError = false;
5322
0
    visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) {
5323
0
        if (tok3->str() == MatchCompiler::makeConstString("&") && !tok3->astOperand2())
5324
0
            return ChildrenToVisit::none; // don't handle address-of for now
5325
0
        if (tok3->str() == MatchCompiler::makeConstString("(") && match171(tok3->previous()))
5326
0
            return ChildrenToVisit::none; // don't care about sizeof usage
5327
0
        if (isSameExpression(false, tok->astOperand1(), tok3, settings, true, false))
5328
0
            foundError = true;
5329
0
        return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
5330
0
    });
5331
5332
0
    return foundError;
5333
0
}
5334
5335
static bool checkEvaluationOrderCpp11(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings)
5336
0
{
5337
0
    if (tok->isAssignmentOp()) // TODO check assignment
5338
0
        return false;
5339
0
    if (tok->previous() == tok->astOperand1() && parent->isArithmeticalOp() && parent->isBinaryOp()) {
5340
0
        if (parent->astParent() && parent->astParent()->isAssignmentOp() && isSameExpression(false, tok->astOperand1(), parent->astParent()->astOperand1(), settings, true, false))
5341
0
            return true;
5342
0
    }
5343
0
    bool foundUndefined{false};
5344
0
    visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) {
5345
0
        if (tok3->str() == MatchCompiler::makeConstString("&") && !tok3->astOperand2())
5346
0
            return ChildrenToVisit::none; // don't handle address-of for now
5347
0
        if (tok3->str() == MatchCompiler::makeConstString("(") && match171(tok3->previous()))
5348
0
            return ChildrenToVisit::none; // don't care about sizeof usage
5349
0
        if (isSameExpression(false, tok->astOperand1(), tok3, settings, true, false))
5350
0
            foundUndefined = true;
5351
0
        return foundUndefined ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
5352
0
    });
5353
5354
0
    return foundUndefined;
5355
0
}
5356
5357
static bool checkEvaluationOrderCpp17(const Token * tok, const Token * tok2, const Token * parent, const Settings & settings, bool & foundUnspecified)
5358
1.26k
{
5359
1.26k
    if (tok->isAssignmentOp())
5360
298
        return false;
5361
968
    bool foundUndefined{false};
5362
1.15k
    visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(), [&](const Token *tok3) {
5363
1.15k
        if (tok3->str() == MatchCompiler::makeConstString("&") && !tok3->astOperand2())
5364
1
            return ChildrenToVisit::none; // don't handle address-of for now
5365
1.15k
        if (tok3->str() == MatchCompiler::makeConstString("(") && match171(tok3->previous()))
5366
0
            return ChildrenToVisit::none; // don't care about sizeof usage
5367
1.15k
        if (isSameExpression(false, tok->astOperand1(), tok3, settings, true, false) && parent->isArithmeticalOp() && parent->isBinaryOp())
5368
19
            foundUndefined = true;
5369
1.15k
        if (tok3->tokType() == Token::eIncDecOp && isSameExpression(false, tok->astOperand1(), tok3->astOperand1(), settings, true, false)) {
5370
42
            if (parent->isArithmeticalOp() && parent->isBinaryOp())
5371
18
                foundUndefined = true;
5372
24
            else
5373
24
                foundUnspecified = true;
5374
42
        }
5375
1.15k
        return (foundUndefined || foundUnspecified) ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
5376
1.15k
    });
5377
5378
968
    return foundUndefined || foundUnspecified;
5379
1.26k
}
5380
5381
void CheckOther::checkEvaluationOrder()
5382
763
{
5383
763
    logChecker("CheckOther::checkEvaluationOrder");
5384
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5385
1.10k
    for (const Scope * functionScope : symbolDatabase->functionScopes) {
5386
23.7k
        for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
5387
22.6k
            if (!tok->isIncDecOp() && !tok->isAssignmentOp())
5388
19.7k
                continue;
5389
2.88k
            if (!tok->astOperand1())
5390
1
                continue;
5391
4.08k
            for (const Token *tok2 = tok;; tok2 = tok2->astParent()) {
5392
                // If ast parent is a sequence point then break
5393
4.08k
                const Token * const parent = tok2->astParent();
5394
4.08k
                if (!parent)
5395
2.44k
                    break;
5396
1.64k
                if (match172(parent))
5397
0
                    break;
5398
1.64k
                if (parent->str() == MatchCompiler::makeConstString(",")) {
5399
2
                    const Token *par = parent;
5400
4
                    while (match65(par))
5401
2
                        par = par->astParent();
5402
                    // not function or in a while clause => break
5403
2
                    if (!(par && par->str() == MatchCompiler::makeConstString("(") && par->astOperand2() && par->strAt(-1) != MatchCompiler::makeConstString("while")))
5404
2
                        break;
5405
                    // control flow (if|while|etc) => break
5406
0
                    if (match69(par->link()))
5407
0
                        break;
5408
                    // sequence point in function argument: dostuff((1,2),3) => break
5409
0
                    par = par->next();
5410
0
                    while (par && (par->previous() != parent))
5411
0
                        par = par->nextArgument();
5412
0
                    if (!par)
5413
0
                        break;
5414
0
                }
5415
1.64k
                if (parent->str() == MatchCompiler::makeConstString("(") && parent->astOperand2())
5416
376
                    break;
5417
5418
1.26k
                bool foundError{false}, foundUnspecified{false}, bSelfAssignmentError{false};
5419
1.26k
                if (mTokenizer->isCPP() && mSettings->standards.cpp >= Standards::CPP11) {
5420
1.26k
                    if (mSettings->standards.cpp >= Standards::CPP17)
5421
1.26k
                        foundError = checkEvaluationOrderCpp17(tok, tok2, parent, *mSettings, foundUnspecified);
5422
0
                    else
5423
0
                        foundError = checkEvaluationOrderCpp11(tok, tok2, parent, *mSettings);
5424
1.26k
                }
5425
0
                else
5426
0
                    foundError = checkEvaluationOrderC(tok, tok2, parent, *mSettings, bSelfAssignmentError);
5427
5428
1.26k
                if (foundError) {
5429
61
                    unknownEvaluationOrder(parent, foundUnspecified);
5430
61
                    break;
5431
61
                }
5432
1.20k
                if (bSelfAssignmentError) {
5433
0
                    selfAssignmentError(parent, tok->astOperand1()->expressionString());
5434
0
                    break;
5435
0
                }
5436
1.20k
            }
5437
2.87k
        }
5438
1.10k
    }
5439
763
}
5440
5441
void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior)
5442
61
{
5443
61
    isUnspecifiedBehavior ?
5444
24
    reportError(tok, Severity::portability, "unknownEvaluationOrder",
5445
24
                "Expression '" + (tok ? tok->expressionString() : std::string("x++, x++")) + "' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17", CWE768, Certainty::normal)
5446
61
    :   reportError(tok, Severity::error, "unknownEvaluationOrder",
5447
37
                    "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal);
5448
61
}
5449
5450
void CheckOther::checkAccessOfMovedVariable()
5451
763
{
5452
763
    if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11)
5453
0
        return;
5454
763
    if (!mSettings->isPremiumEnabled("accessMoved") && !mSettings->severity.isEnabled(Severity::warning))
5455
0
        return;
5456
763
    logChecker("CheckOther::checkAccessOfMovedVariable"); // c++11,warning
5457
763
    const bool reportInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
5458
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5459
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
5460
1.10k
        const Token * scopeStart = scope->bodyStart;
5461
1.10k
        if (scope->function) {
5462
1.10k
            const Token * memberInitializationStart = scope->function->constructorMemberInitialization();
5463
1.10k
            if (memberInitializationStart)
5464
0
                scopeStart = memberInitializationStart;
5465
1.10k
        }
5466
22.6k
        for (const Token* tok = scopeStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
5467
21.5k
            if (!tok->astParent())
5468
10.5k
                continue;
5469
11.0k
            const ValueFlow::Value * movedValue = tok->getMovedValue();
5470
11.0k
            if (!movedValue || movedValue->moveKind == ValueFlow::Value::MoveKind::NonMovedVariable)
5471
11.0k
                continue;
5472
0
            if (movedValue->isInconclusive() && !reportInconclusive)
5473
0
                continue;
5474
5475
0
            bool inconclusive = false;
5476
0
            bool accessOfMoved = false;
5477
0
            if (tok->strAt(1) == MatchCompiler::makeConstString(".")) {
5478
0
                if (tok->next()->originalName() == MatchCompiler::makeConstString("->"))
5479
0
                    accessOfMoved = true;
5480
0
                else
5481
0
                    inconclusive = true;
5482
0
            } else {
5483
0
                const ExprUsage usage = getExprUsage(tok, 0, *mSettings);
5484
0
                if (usage == ExprUsage::Used)
5485
0
                    accessOfMoved = true;
5486
0
                if (usage == ExprUsage::PassedByReference)
5487
0
                    accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, *mSettings, &inconclusive);
5488
0
                else if (usage == ExprUsage::Inconclusive)
5489
0
                    inconclusive = true;
5490
0
            }
5491
0
            if (accessOfMoved || (inconclusive && reportInconclusive))
5492
0
                accessMovedError(tok, tok->str(), movedValue, inconclusive || movedValue->isInconclusive());
5493
0
        }
5494
1.10k
    }
5495
763
}
5496
5497
void CheckOther::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
5498
0
{
5499
0
    if (!tok) {
5500
0
        reportError(tok, Severity::warning, "accessMoved", "Access of moved variable 'v'.", CWE672, Certainty::normal);
5501
0
        reportError(tok, Severity::warning, "accessForwarded", "Access of forwarded variable 'v'.", CWE672, Certainty::normal);
5502
0
        return;
5503
0
    }
5504
5505
0
    const char * errorId = nullptr;
5506
0
    std::string kindString;
5507
0
    switch (value->moveKind) {
5508
0
    case ValueFlow::Value::MoveKind::MovedVariable:
5509
0
        errorId = "accessMoved";
5510
0
        kindString = "moved";
5511
0
        break;
5512
0
    case ValueFlow::Value::MoveKind::ForwardedVariable:
5513
0
        errorId = "accessForwarded";
5514
0
        kindString = "forwarded";
5515
0
        break;
5516
0
    default:
5517
0
        return;
5518
0
    }
5519
0
    const std::string errmsg("$symbol:" + varname + "\nAccess of " + kindString + " variable '$symbol'.");
5520
0
    const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
5521
0
    reportError(errorPath, Severity::warning, errorId, errmsg, CWE672, inconclusive ? Certainty::inconclusive : Certainty::normal);
5522
0
}
5523
5524
5525
5526
void CheckOther::checkFuncArgNamesDifferent()
5527
763
{
5528
763
    const bool style = mSettings->severity.isEnabled(Severity::style);
5529
763
    const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
5530
763
    const bool warning = mSettings->severity.isEnabled(Severity::warning);
5531
5532
763
    if (!(warning || (style && inconclusive)) && !mSettings->isPremiumEnabled("funcArgNamesDifferent"))
5533
0
        return;
5534
5535
763
    logChecker("CheckOther::checkFuncArgNamesDifferent"); // style,warning,inconclusive
5536
5537
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5538
    // check every function
5539
1.10k
    for (const Scope *scope : symbolDatabase->functionScopes) {
5540
1.10k
        const Function * function = scope->function;
5541
        // only check functions with arguments
5542
1.10k
        if (!function || function->argCount() == 0)
5543
1.10k
            continue;
5544
5545
        // only check functions with separate declarations and definitions
5546
0
        if (function->argDef == function->arg)
5547
0
            continue;
5548
5549
        // get the function argument name tokens
5550
0
        std::vector<const Token *>  declarations(function->argCount());
5551
0
        std::vector<const Token *>  definitions(function->argCount());
5552
0
        const Token * decl = function->argDef->next();
5553
0
        for (int j = 0; j < function->argCount(); ++j) {
5554
0
            declarations[j] = nullptr;
5555
0
            definitions[j] = nullptr;
5556
            // get the definition
5557
0
            const Variable * variable = function->getArgumentVar(j);
5558
0
            if (variable) {
5559
0
                definitions[j] = variable->nameToken();
5560
0
            }
5561
            // get the declaration (search for first token with varId)
5562
0
            while (decl && !match173(decl)) {
5563
                // skip everything after the assignment because
5564
                // it could also have a varId or be the first
5565
                // token with a varId if there is no name token
5566
0
                if (decl->str() == MatchCompiler::makeConstString("=")) {
5567
0
                    decl = decl->nextArgument();
5568
0
                    break;
5569
0
                }
5570
                // skip over template
5571
0
                if (decl->link())
5572
0
                    decl = decl->link();
5573
0
                else if (decl->varId())
5574
0
                    declarations[j] = decl;
5575
0
                decl = decl->next();
5576
0
            }
5577
0
            if (match65(decl))
5578
0
                decl = decl->next();
5579
0
        }
5580
        // check for different argument order
5581
0
        if (warning) {
5582
0
            bool order_different = false;
5583
0
            for (int j = 0; j < function->argCount(); ++j) {
5584
0
                if (!declarations[j] || !definitions[j] || declarations[j]->str() == definitions[j]->str())
5585
0
                    continue;
5586
5587
0
                for (int k = 0; k < function->argCount(); ++k) {
5588
0
                    if (j != k && definitions[k] && declarations[j]->str() == definitions[k]->str()) {
5589
0
                        order_different = true;
5590
0
                        break;
5591
0
                    }
5592
0
                }
5593
0
            }
5594
0
            if (order_different) {
5595
0
                funcArgOrderDifferent(function->name(), function->argDef->next(), function->arg->next(), declarations, definitions);
5596
0
                continue;
5597
0
            }
5598
0
        }
5599
        // check for different argument names
5600
0
        if (style && inconclusive) {
5601
0
            for (int j = 0; j < function->argCount(); ++j) {
5602
0
                if (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str())
5603
0
                    funcArgNamesDifferent(function->name(), j, declarations[j], definitions[j]);
5604
0
            }
5605
0
        }
5606
0
    }
5607
763
}
5608
5609
void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg int index,
5610
                                       const Token* declaration, const Token* definition)
5611
0
{
5612
0
    std::list<const Token *> tokens = { declaration,definition };
5613
0
    reportError(tokens, Severity::style, "funcArgNamesDifferent",
5614
0
                "$symbol:" + functionName + "\n"
5615
0
                "Function '$symbol' argument " + std::to_string(index + 1) + " names different: declaration '" +
5616
0
                (declaration ? declaration->str() : std::string("A")) + "' definition '" +
5617
0
                (definition ? definition->str() : std::string("B")) + "'.", CWE628, Certainty::inconclusive);
5618
0
}
5619
5620
void CheckOther::funcArgOrderDifferent(const std::string & functionName,
5621
                                       const Token* declaration, const Token* definition,
5622
                                       const std::vector<const Token *> & declarations,
5623
                                       const std::vector<const Token *> & definitions)
5624
0
{
5625
0
    std::list<const Token *> tokens = {
5626
0
        !declarations.empty() ? declarations[0] ? declarations[0] : declaration : nullptr,
5627
0
        !definitions.empty() ? definitions[0] ? definitions[0] : definition : nullptr
5628
0
    };
5629
0
    std::string msg = "$symbol:" + functionName + "\nFunction '$symbol' argument order different: declaration '";
5630
0
    for (std::size_t i = 0; i < declarations.size(); ++i) {
5631
0
        if (i != 0)
5632
0
            msg += ", ";
5633
0
        if (declarations[i])
5634
0
            msg += declarations[i]->str();
5635
0
    }
5636
0
    msg += "' definition '";
5637
0
    for (std::size_t i = 0; i < definitions.size(); ++i) {
5638
0
        if (i != 0)
5639
0
            msg += ", ";
5640
0
        if (definitions[i])
5641
0
            msg += definitions[i]->str();
5642
0
    }
5643
0
    msg += "'";
5644
0
    reportError(tokens, Severity::warning, "funcArgOrderDifferent", msg, CWE683, Certainty::normal);
5645
0
}
5646
5647
static const Token *findShadowed(const Scope *scope, const Variable& var, int linenr)
5648
0
{
5649
0
    if (!scope)
5650
0
        return nullptr;
5651
0
    for (const Variable &v : scope->varlist) {
5652
0
        if (scope->isExecutable() && v.nameToken()->linenr() > linenr)
5653
0
            continue;
5654
0
        if (v.name() == var.name())
5655
0
            return v.nameToken();
5656
0
    }
5657
0
    auto it = std::find_if(scope->functionList.cbegin(), scope->functionList.cend(), [&](const Function& f) {
5658
0
        return f.type == Function::Type::eFunction && f.name() == var.name() && precedes(f.tokenDef, var.nameToken());
5659
0
    });
5660
0
    if (it != scope->functionList.end())
5661
0
        return it->tokenDef;
5662
5663
0
    if (scope->type == Scope::eLambda)
5664
0
        return nullptr;
5665
0
    const Token* shadowed = findShadowed(scope->nestedIn, var, linenr);
5666
0
    if (!shadowed)
5667
0
        shadowed = findShadowed(scope->functionOf, var, linenr);
5668
0
    return shadowed;
5669
0
}
5670
5671
void CheckOther::checkShadowVariables()
5672
763
{
5673
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("shadowVariable"))
5674
0
        return;
5675
763
    logChecker("CheckOther::checkShadowVariables"); // style
5676
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5677
2.79k
    for (const Scope & scope : symbolDatabase->scopeList) {
5678
2.79k
        if (!scope.isExecutable() || scope.type == Scope::eLambda)
5679
763
            continue;
5680
2.03k
        const Scope *functionScope = &scope;
5681
3.27k
        while (functionScope && functionScope->type != Scope::ScopeType::eFunction && functionScope->type != Scope::ScopeType::eLambda)
5682
1.23k
            functionScope = functionScope->nestedIn;
5683
2.03k
        for (const Variable &var : scope.varlist) {
5684
0
            if (var.nameToken() && var.nameToken()->isExpandedMacro()) // #8903
5685
0
                continue;
5686
5687
0
            if (functionScope && functionScope->type == Scope::ScopeType::eFunction && functionScope->function) {
5688
0
                const auto & argList = functionScope->function->argumentList;
5689
0
                auto it = std::find_if(argList.cbegin(), argList.cend(), [&](const Variable& arg) {
5690
0
                    return arg.nameToken() && var.name() == arg.name();
5691
0
                });
5692
0
                if (it != argList.end()) {
5693
0
                    shadowError(var.nameToken(), it->nameToken(), "argument");
5694
0
                    continue;
5695
0
                }
5696
0
            }
5697
5698
0
            const Token *shadowed = findShadowed(scope.nestedIn, var, var.nameToken()->linenr());
5699
0
            if (!shadowed)
5700
0
                shadowed = findShadowed(scope.functionOf, var, var.nameToken()->linenr());
5701
0
            if (!shadowed)
5702
0
                continue;
5703
0
            if (scope.type == Scope::eFunction && scope.className == var.name())
5704
0
                continue;
5705
0
            if (functionScope->functionOf && functionScope->functionOf->isClassOrStructOrUnion() && functionScope->function && functionScope->function->isStatic() &&
5706
0
                shadowed->variable() && !shadowed->variable()->isLocal())
5707
0
                continue;
5708
0
            shadowError(var.nameToken(), shadowed, (shadowed->varId() != 0) ? "variable" : "function");
5709
0
        }
5710
2.03k
    }
5711
763
}
5712
5713
void CheckOther::shadowError(const Token *var, const Token *shadowed, const std::string& type)
5714
0
{
5715
0
    ErrorPath errorPath;
5716
0
    errorPath.emplace_back(shadowed, "Shadowed declaration");
5717
0
    errorPath.emplace_back(var, "Shadow variable");
5718
0
    const std::string &varname = var ? var->str() : type;
5719
0
    const std::string Type = char(std::toupper(type[0])) + type.substr(1);
5720
0
    const std::string id = "shadow" + Type;
5721
0
    const std::string message = "$symbol:" + varname + "\nLocal variable \'$symbol\' shadows outer " + type;
5722
0
    reportError(errorPath, Severity::style, id.c_str(), message, CWE398, Certainty::normal);
5723
0
}
5724
5725
static bool isVariableExpression(const Token* tok)
5726
0
{
5727
0
    if (tok->varId() != 0)
5728
0
        return true;
5729
0
    if (match30(tok))
5730
0
        return isVariableExpression(tok->astOperand1()) &&
5731
0
               isVariableExpression(tok->astOperand2());
5732
0
    if (match77(tok))
5733
0
        return isVariableExpression(tok->astOperand1());
5734
0
    return false;
5735
0
}
5736
5737
static bool isVariableExprHidden(const Token* tok)
5738
0
{
5739
0
    if (!tok)
5740
0
        return false;
5741
0
    if (!tok->astParent())
5742
0
        return false;
5743
0
    if (match88(tok->astParent()) && match174(tok->astSibling()))
5744
0
        return true;
5745
0
    if (match175(tok->astParent()) && match176(tok->astSibling()))
5746
0
        return true;
5747
0
    if (match177(tok->astParent()) && match178(tok->astSibling()))
5748
0
        return true;
5749
0
    return false;
5750
0
}
5751
5752
void CheckOther::checkKnownArgument()
5753
763
{
5754
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownArgument"))
5755
0
        return;
5756
763
    logChecker("CheckOther::checkKnownArgument"); // style
5757
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5758
1.10k
    for (const Scope *functionScope : symbolDatabase->functionScopes) {
5759
23.7k
        for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
5760
22.6k
            if (!tok->hasKnownIntValue() || tok->isExpandedMacro())
5761
21.4k
                continue;
5762
1.22k
            if (match179(tok))
5763
100
                continue;
5764
1.12k
            if (!match180(tok->astParent()))
5765
1.02k
                continue;
5766
107
            if (tok->astParent()->isCast() || (tok->isCast() && match179(tok->astOperand2())))
5767
0
                continue;
5768
107
            int argn = -1;
5769
107
            const Token* ftok = getTokenArgumentFunction(tok, argn);
5770
107
            if (!ftok)
5771
0
                continue;
5772
107
            if (ftok->isCast())
5773
0
                continue;
5774
107
            if (match181(ftok))
5775
107
                continue;
5776
0
            if (tok == tok->astParent()->previous())
5777
0
                continue;
5778
0
            if (isConstVarExpression(tok))
5779
0
                continue;
5780
0
            if (match32(tok->astOperand1()))
5781
0
                continue;
5782
0
            const Token * tok2 = tok;
5783
0
            if (isCPPCast(tok2))
5784
0
                tok2 = tok2->astOperand2();
5785
0
            if (isVariableExpression(tok2))
5786
0
                continue;
5787
0
            if (tok->isComparisonOp() &&
5788
0
                isSameExpression(
5789
0
                    true, tok->astOperand1(), tok->astOperand2(), *mSettings, true, true))
5790
0
                continue;
5791
            // ensure that there is a integer variable in expression with unknown value
5792
0
            const Token* vartok = nullptr;
5793
0
            visitAstNodes(tok, [&](const Token* child) {
5794
0
                if (match182(child)) {
5795
0
                    if (child->hasKnownIntValue())
5796
0
                        return ChildrenToVisit::none;
5797
0
                    if (astIsIntegral(child, false) && !astIsPointer(child) && child->values().empty()) {
5798
0
                        vartok = child;
5799
0
                        return ChildrenToVisit::done;
5800
0
                    }
5801
0
                }
5802
0
                return ChildrenToVisit::op1_and_op2;
5803
0
            });
5804
0
            if (!vartok)
5805
0
                continue;
5806
0
            if (vartok->astSibling() &&
5807
0
                findAstNode(vartok->astSibling(), [](const Token* child) {
5808
0
                return match171(child);
5809
0
            }))
5810
0
                continue;
5811
            // ensure that function name does not contain "assert"
5812
0
            std::string funcname = ftok->str();
5813
0
            strTolower(funcname);
5814
0
            if (funcname.find("assert") != std::string::npos)
5815
0
                continue;
5816
0
            knownArgumentError(tok, ftok, &tok->values().front(), vartok->expressionString(), isVariableExprHidden(vartok));
5817
0
        }
5818
1.10k
    }
5819
763
}
5820
5821
void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden)
5822
0
{
5823
0
    if (!tok) {
5824
0
        reportError(tok, Severity::style, "knownArgument", "Argument 'x-x' to function 'func' is always 0. It does not matter what value 'x' has.");
5825
0
        reportError(tok, Severity::style, "knownArgumentHiddenVariableExpression", "Argument 'x*0' to function 'func' is always 0. Constant literal calculation disable/hide variable expression 'x'.");
5826
0
        return;
5827
0
    }
5828
5829
0
    const MathLib::bigint intvalue = value->intvalue;
5830
0
    const std::string &expr = tok->expressionString();
5831
0
    const std::string &fun = ftok->str();
5832
5833
0
    std::string ftype = "function ";
5834
0
    if (ftok->type())
5835
0
        ftype = "constructor ";
5836
0
    else if (fun == MatchCompiler::makeConstString("{"))
5837
0
        ftype = "init list ";
5838
5839
0
    const char *id;
5840
0
    std::string errmsg = "Argument '" + expr + "' to " + ftype + fun + " is always " + MathLib::toString(intvalue) + ". ";
5841
0
    if (!isVariableExpressionHidden) {
5842
0
        id = "knownArgument";
5843
0
        errmsg += "It does not matter what value '" + varexpr + "' has.";
5844
0
    } else {
5845
0
        id = "knownArgumentHiddenVariableExpression";
5846
0
        errmsg += "Constant literal calculation disable/hide variable expression '" + varexpr + "'.";
5847
0
    }
5848
5849
0
    const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
5850
0
    reportError(errorPath, Severity::style, id, errmsg, CWE570, Certainty::normal);
5851
0
}
5852
5853
void CheckOther::checkKnownPointerToBool()
5854
763
{
5855
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownPointerToBool"))
5856
0
        return;
5857
763
    logChecker("CheckOther::checkKnownPointerToBool"); // style
5858
763
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
5859
1.10k
    for (const Scope* functionScope : symbolDatabase->functionScopes) {
5860
23.7k
        for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
5861
22.6k
            if (!tok->hasKnownIntValue())
5862
21.4k
                continue;
5863
1.22k
            if (!astIsPointer(tok))
5864
1.22k
                continue;
5865
0
            if (match183(tok->astParent()))
5866
0
                continue;
5867
0
            if (tok->astParent() && match184(tok->astParent()->previous()))
5868
0
                continue;
5869
0
            if (tok->isExpandedMacro())
5870
0
                continue;
5871
0
            if (findParent(tok, [](const Token* parent) {
5872
0
                return parent->isExpandedMacro();
5873
0
            }))
5874
0
                continue;
5875
0
            if (!isUsedAsBool(tok, *mSettings))
5876
0
                continue;
5877
0
            const ValueFlow::Value& value = tok->values().front();
5878
0
            knownPointerToBoolError(tok, &value);
5879
0
        }
5880
1.10k
    }
5881
763
}
5882
5883
void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value)
5884
0
{
5885
0
    if (!tok) {
5886
0
        reportError(tok, Severity::style, "knownPointerToBool", "Pointer expression 'p' converted to bool is always true.");
5887
0
        return;
5888
0
    }
5889
0
    std::string cond = bool_to_string(!!value->intvalue);
5890
0
    const std::string& expr = tok->expressionString();
5891
0
    std::string errmsg = "Pointer expression '" + expr + "' converted to bool is always " + cond + ".";
5892
0
    const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
5893
0
    reportError(errorPath, Severity::style, "knownPointerToBool", errmsg, CWE570, Certainty::normal);
5894
0
}
5895
5896
void CheckOther::checkComparePointers()
5897
763
{
5898
763
    logChecker("CheckOther::checkComparePointers");
5899
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
5900
1.10k
    for (const Scope *functionScope : symbolDatabase->functionScopes) {
5901
23.7k
        for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
5902
22.6k
            if (!match185(tok))
5903
21.9k
                continue;
5904
720
            const Token *tok1 = tok->astOperand1();
5905
720
            if (!astIsPointer(tok1))
5906
719
                continue;
5907
1
            const Token *tok2 = tok->astOperand2();
5908
1
            if (!astIsPointer(tok2))
5909
1
                continue;
5910
0
            ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1);
5911
0
            if (!v1.isLocalLifetimeValue())
5912
0
                continue;
5913
0
            ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2);
5914
0
            if (!v2.isLocalLifetimeValue())
5915
0
                continue;
5916
0
            const Variable *var1 = v1.tokvalue->variable();
5917
0
            const Variable *var2 = v2.tokvalue->variable();
5918
0
            if (!var1 || !var2)
5919
0
                continue;
5920
0
            if (v1.tokvalue->varId() == v2.tokvalue->varId())
5921
0
                continue;
5922
0
            if (var1->isReference() || var2->isReference())
5923
0
                continue;
5924
0
            if (var1->isRValueReference() || var2->isRValueReference())
5925
0
                continue;
5926
0
            if (const Token* parent2 = getParentLifetime(v2.tokvalue, mSettings->library))
5927
0
                if (var1 == parent2->variable())
5928
0
                    continue;
5929
0
            if (const Token* parent1 = getParentLifetime(v1.tokvalue, mSettings->library))
5930
0
                if (var2 == parent1->variable())
5931
0
                    continue;
5932
0
            comparePointersError(tok, &v1, &v2);
5933
0
        }
5934
1.10k
    }
5935
763
}
5936
5937
void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2)
5938
0
{
5939
0
    ErrorPath errorPath;
5940
0
    std::string verb = "Comparing";
5941
0
    if (match186(tok))
5942
0
        verb = "Subtracting";
5943
0
    const char * const id = (verb[0] == 'C') ? "comparePointers" : "subtractPointers";
5944
0
    if (v1) {
5945
0
        errorPath.emplace_back(v1->tokvalue->variable()->nameToken(), "Variable declared here.");
5946
0
        errorPath.insert(errorPath.end(), v1->errorPath.cbegin(), v1->errorPath.cend());
5947
0
    }
5948
0
    if (v2) {
5949
0
        errorPath.emplace_back(v2->tokvalue->variable()->nameToken(), "Variable declared here.");
5950
0
        errorPath.insert(errorPath.end(), v2->errorPath.cbegin(), v2->errorPath.cend());
5951
0
    }
5952
0
    errorPath.emplace_back(tok, "");
5953
0
    reportError(
5954
0
        errorPath, Severity::error, id, verb + " pointers that point to different objects", CWE570, Certainty::normal);
5955
0
}
5956
5957
void CheckOther::checkModuloOfOne()
5958
763
{
5959
763
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("moduloofone"))
5960
0
        return;
5961
5962
763
    logChecker("CheckOther::checkModuloOfOne"); // style
5963
5964
55.6k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
5965
54.8k
        if (!tok->astOperand2() || !tok->astOperand1())
5966
46.5k
            continue;
5967
8.33k
        if (tok->str() != MatchCompiler::makeConstString("%"))
5968
8.24k
            continue;
5969
91
        if (!tok->valueType() || !tok->valueType()->isIntegral())
5970
44
            continue;
5971
5972
        // Value flow..
5973
47
        const ValueFlow::Value *value = tok->astOperand2()->getValue(1LL);
5974
47
        if (value && value->isKnown())
5975
0
            checkModuloOfOneError(tok);
5976
47
    }
5977
763
}
5978
5979
void CheckOther::checkModuloOfOneError(const Token *tok)
5980
0
{
5981
0
    reportError(tok, Severity::style, "moduloofone", "Modulo of one is always equal to zero");
5982
0
}
5983
5984
//-----------------------------------------------------------------------------
5985
// Overlapping write (undefined behavior)
5986
//-----------------------------------------------------------------------------
5987
static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigint *offset, const Settings& settings, MathLib::bigint* sizeValue = nullptr)
5988
0
{
5989
0
    if (!expr)
5990
0
        return false;
5991
0
    const Token *bufToken, *offsetToken;
5992
0
    MathLib::bigint elementSize = 0;
5993
0
    if (expr->isUnaryOp("&") && match77(expr->astOperand1())) {
5994
0
        bufToken = expr->astOperand1()->astOperand1();
5995
0
        offsetToken = expr->astOperand1()->astOperand2();
5996
0
        if (expr->astOperand1()->valueType())
5997
0
            elementSize =  ValueFlow::getSizeOf(*expr->astOperand1()->valueType(), settings);
5998
0
    } else if (match187(expr) && expr->isBinaryOp()) {
5999
0
        const bool pointer1 = (expr->astOperand1()->valueType() && expr->astOperand1()->valueType()->pointer > 0);
6000
0
        const bool pointer2 = (expr->astOperand2()->valueType() && expr->astOperand2()->valueType()->pointer > 0);
6001
0
        if (pointer1 && !pointer2) {
6002
0
            bufToken = expr->astOperand1();
6003
0
            offsetToken = expr->astOperand2();
6004
0
            auto vt = *expr->astOperand1()->valueType();
6005
0
            --vt.pointer;
6006
0
            elementSize = ValueFlow::getSizeOf(vt, settings);
6007
0
        } else if (!pointer1 && pointer2) {
6008
0
            bufToken = expr->astOperand2();
6009
0
            offsetToken = expr->astOperand1();
6010
0
            auto vt = *expr->astOperand2()->valueType();
6011
0
            --vt.pointer;
6012
0
            elementSize = ValueFlow::getSizeOf(vt, settings);
6013
0
        } else {
6014
0
            return false;
6015
0
        }
6016
0
    } else if (expr->valueType() && expr->valueType()->pointer > 0) {
6017
0
        buf = expr;
6018
0
        *offset = 0;
6019
0
        auto vt = *expr->valueType();
6020
0
        --vt.pointer;
6021
0
        elementSize = ValueFlow::getSizeOf(vt, settings);
6022
0
        if (elementSize > 0) {
6023
0
            *offset *= elementSize;
6024
0
            if (sizeValue)
6025
0
                *sizeValue *= elementSize;
6026
0
        }
6027
0
        return true;
6028
0
    } else {
6029
0
        return false;
6030
0
    }
6031
0
    if (!bufToken->valueType() || !bufToken->valueType()->pointer)
6032
0
        return false;
6033
0
    if (!offsetToken->hasKnownIntValue())
6034
0
        return false;
6035
0
    buf = bufToken;
6036
0
    *offset = offsetToken->getKnownIntValue();
6037
0
    if (elementSize > 0) {
6038
0
        *offset *= elementSize;
6039
0
        if (sizeValue)
6040
0
            *sizeValue *= elementSize;
6041
0
    }
6042
0
    return true;
6043
0
}
6044
6045
void CheckOther::checkOverlappingWrite()
6046
763
{
6047
763
    logChecker("CheckOther::checkOverlappingWrite");
6048
763
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
6049
1.10k
    for (const Scope *functionScope : symbolDatabase->functionScopes) {
6050
23.7k
        for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
6051
22.6k
            if (tok->isAssignmentOp()) {
6052
                // check if LHS is a union member..
6053
2.24k
                const Token * const lhs = tok->astOperand1();
6054
2.24k
                if (!match30(lhs) || !lhs->isBinaryOp())
6055
2.24k
                    continue;
6056
0
                const Variable * const lhsvar = lhs->astOperand1()->variable();
6057
0
                if (!lhsvar || !lhsvar->typeScope() || lhsvar->typeScope()->type != Scope::ScopeType::eUnion)
6058
0
                    continue;
6059
0
                const Token* const lhsmember = lhs->astOperand2();
6060
0
                if (!lhsmember)
6061
0
                    continue;
6062
6063
                // Is other union member used in RHS?
6064
0
                const Token *errorToken = nullptr;
6065
0
                visitAstNodes(tok->astOperand2(), [lhsvar, lhsmember, &errorToken](const Token *rhs) {
6066
0
                    if (!match30(rhs))
6067
0
                        return ChildrenToVisit::op1_and_op2;
6068
0
                    if (!rhs->isBinaryOp() || rhs->astOperand1()->variable() != lhsvar)
6069
0
                        return ChildrenToVisit::none;
6070
0
                    if (lhsmember->str() == rhs->astOperand2()->str())
6071
0
                        return ChildrenToVisit::none;
6072
0
                    const Variable* rhsmembervar = rhs->astOperand2()->variable();
6073
0
                    const Scope* varscope1 = lhsmember->variable() ? lhsmember->variable()->typeStartToken()->scope() : nullptr;
6074
0
                    const Scope* varscope2 = rhsmembervar ? rhsmembervar->typeStartToken()->scope() : nullptr;
6075
0
                    if (varscope1 && varscope1 == varscope2 && varscope1 != lhsvar->typeScope())
6076
                        // lhsmember and rhsmember are declared in same anonymous scope inside union
6077
0
                        return ChildrenToVisit::none;
6078
0
                    errorToken = rhs->astOperand2();
6079
0
                    return ChildrenToVisit::done;
6080
0
                });
6081
0
                if (errorToken)
6082
0
                    overlappingWriteUnion(tok);
6083
20.4k
            } else if (match32(tok)) {
6084
722
                const Library::NonOverlappingData *nonOverlappingData = mSettings->library.getNonOverlappingData(tok);
6085
722
                if (!nonOverlappingData)
6086
722
                    continue;
6087
0
                const std::vector<const Token *> args = getArguments(tok);
6088
0
                if (nonOverlappingData->ptr1Arg <= 0 || nonOverlappingData->ptr1Arg > args.size())
6089
0
                    continue;
6090
0
                if (nonOverlappingData->ptr2Arg <= 0 || nonOverlappingData->ptr2Arg > args.size())
6091
0
                    continue;
6092
6093
0
                const Token *ptr1 = args[nonOverlappingData->ptr1Arg - 1];
6094
0
                if (ptr1->hasKnownIntValue() && ptr1->getKnownIntValue() == 0)
6095
0
                    continue;
6096
6097
0
                const Token *ptr2 = args[nonOverlappingData->ptr2Arg - 1];
6098
0
                if (ptr2->hasKnownIntValue() && ptr2->getKnownIntValue() == 0)
6099
0
                    continue;
6100
6101
                // TODO: nonOverlappingData->strlenArg
6102
0
                const int sizeArg = std::max(nonOverlappingData->sizeArg, nonOverlappingData->countArg);
6103
0
                if (sizeArg <= 0 || sizeArg > args.size()) {
6104
0
                    if (nonOverlappingData->sizeArg == -1) {
6105
0
                        ErrorPath errorPath;
6106
0
                        constexpr bool macro = true;
6107
0
                        constexpr bool pure = true;
6108
0
                        constexpr bool follow = true;
6109
0
                        if (!isSameExpression(macro, ptr1, ptr2, *mSettings, pure, follow, &errorPath))
6110
0
                            continue;
6111
0
                        overlappingWriteFunction(tok, tok->str());
6112
0
                    }
6113
0
                    continue;
6114
0
                }
6115
0
                const bool isCountArg = nonOverlappingData->countArg > 0;
6116
0
                if (!args[sizeArg-1]->hasKnownIntValue())
6117
0
                    continue;
6118
0
                MathLib::bigint sizeValue = args[sizeArg-1]->getKnownIntValue();
6119
0
                const Token *buf1, *buf2;
6120
0
                MathLib::bigint offset1, offset2;
6121
0
                if (!getBufAndOffset(ptr1, buf1, &offset1, *mSettings, isCountArg ? &sizeValue : nullptr))
6122
0
                    continue;
6123
0
                if (!getBufAndOffset(ptr2, buf2, &offset2, *mSettings))
6124
0
                    continue;
6125
6126
0
                if (offset1 < offset2 && offset1 + sizeValue <= offset2)
6127
0
                    continue;
6128
0
                if (offset2 < offset1 && offset2 + sizeValue <= offset1)
6129
0
                    continue;
6130
6131
0
                ErrorPath errorPath;
6132
0
                constexpr bool macro = true;
6133
0
                constexpr bool pure = true;
6134
0
                constexpr bool follow = true;
6135
0
                if (!isSameExpression(macro, buf1, buf2, *mSettings, pure, follow, &errorPath))
6136
0
                    continue;
6137
0
                overlappingWriteFunction(tok, tok->str());
6138
0
            }
6139
22.6k
        }
6140
1.10k
    }
6141
763
}
6142
6143
void CheckOther::overlappingWriteUnion(const Token *tok)
6144
0
{
6145
0
    reportError(tok, Severity::error, "overlappingWriteUnion", "Overlapping read/write of union is undefined behavior");
6146
0
}
6147
6148
void CheckOther::overlappingWriteFunction(const Token *tok, const std::string& funcname)
6149
0
{
6150
0
    reportError(tok, Severity::error, "overlappingWriteFunction", "Overlapping read/write in " + funcname + "() is undefined behavior");
6151
0
}
6152
6153
void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
6154
763
{
6155
763
    CheckOther checkOther(&tokenizer, &tokenizer.getSettings(), errorLogger);
6156
6157
    // Checks
6158
763
    checkOther.warningOldStylePointerCast();
6159
763
    checkOther.suspiciousFloatingPointCast();
6160
763
    checkOther.invalidPointerCast();
6161
763
    checkOther.checkCharVariable();
6162
763
    checkOther.redundantBitwiseOperationInSwitchError();
6163
763
    checkOther.checkSuspiciousCaseInSwitch();
6164
763
    checkOther.checkDuplicateBranch();
6165
763
    checkOther.checkDuplicateExpression();
6166
763
    checkOther.checkRedundantAssignment();
6167
763
    checkOther.checkUnreachableCode();
6168
763
    checkOther.checkSuspiciousSemicolon();
6169
763
    checkOther.checkVariableScope();
6170
763
    checkOther.checkSignOfUnsignedVariable();  // don't ignore casts (#3574)
6171
763
    checkOther.checkIncompleteArrayFill();
6172
763
    checkOther.checkVarFuncNullUB();
6173
763
    checkOther.checkNanInArithmeticExpression();
6174
763
    checkOther.checkCommaSeparatedReturn();
6175
763
    checkOther.checkRedundantPointerOp();
6176
763
    checkOther.checkZeroDivision();
6177
763
    checkOther.checkNegativeBitwiseShift();
6178
763
    checkOther.checkInterlockedDecrement();
6179
763
    checkOther.checkUnusedLabel();
6180
763
    checkOther.checkEvaluationOrder();
6181
763
    checkOther.checkFuncArgNamesDifferent();
6182
763
    checkOther.checkShadowVariables();
6183
763
    checkOther.checkKnownArgument();
6184
763
    checkOther.checkKnownPointerToBool();
6185
763
    checkOther.checkComparePointers();
6186
763
    checkOther.checkIncompleteStatement();
6187
763
    checkOther.checkRedundantCopy();
6188
763
    checkOther.clarifyCalculation();
6189
763
    checkOther.checkPassByReference();
6190
763
    checkOther.checkConstVariable();
6191
763
    checkOther.checkConstPointer();
6192
763
    checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
6193
763
    checkOther.checkInvalidFree();
6194
763
    checkOther.clarifyStatement();
6195
763
    checkOther.checkCastIntToCharAndBack();
6196
763
    checkOther.checkMisusedScopedObject();
6197
763
    checkOther.checkAccessOfMovedVariable();
6198
763
    checkOther.checkModuloOfOne();
6199
763
    checkOther.checkOverlappingWrite();
6200
763
}
6201
6202
void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
6203
0
{
6204
0
    CheckOther c(nullptr, settings, errorLogger);
6205
6206
    // error
6207
0
    c.zerodivError(nullptr, nullptr);
6208
0
    c.misusedScopeObjectError(nullptr, "varname");
6209
0
    c.invalidPointerCastError(nullptr,  "float *", "double *", false, false);
6210
0
    c.negativeBitwiseShiftError(nullptr, 1);
6211
0
    c.negativeBitwiseShiftError(nullptr, 2);
6212
0
    c.raceAfterInterlockedDecrementError(nullptr);
6213
0
    c.invalidFreeError(nullptr, "malloc", false);
6214
0
    c.overlappingWriteUnion(nullptr);
6215
0
    c.overlappingWriteFunction(nullptr, "funcname");
6216
6217
    //performance
6218
0
    c.redundantCopyError(nullptr,  "varname");
6219
0
    c.redundantCopyError(nullptr, nullptr, "var");
6220
6221
    // style/warning
6222
0
    c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
6223
0
    c.checkCastIntToCharAndBackError(nullptr, "func_name");
6224
0
    c.cstyleCastError(nullptr);
6225
0
    c.suspiciousFloatingPointCastError(nullptr);
6226
0
    c.passedByValueError(nullptr, false);
6227
0
    c.constVariableError(nullptr, nullptr);
6228
0
    c.constStatementError(nullptr, "type", false);
6229
0
    c.signedCharArrayIndexError(nullptr);
6230
0
    c.unknownSignCharArrayIndexError(nullptr);
6231
0
    c.charBitOpError(nullptr);
6232
0
    c.variableScopeError(nullptr,  "varname");
6233
0
    c.redundantAssignmentInSwitchError(nullptr, nullptr, "var");
6234
0
    c.suspiciousCaseInSwitchError(nullptr,  "||");
6235
0
    c.selfAssignmentError(nullptr,  "varname");
6236
0
    c.clarifyCalculationError(nullptr,  "+");
6237
0
    c.clarifyStatementError(nullptr);
6238
0
    c.duplicateBranchError(nullptr, nullptr, ErrorPath{});
6239
0
    c.duplicateAssignExpressionError(nullptr, nullptr, true);
6240
0
    c.oppositeExpressionError(nullptr, ErrorPath{});
6241
0
    c.duplicateExpressionError(nullptr, nullptr, nullptr, ErrorPath{});
6242
0
    c.duplicateValueTernaryError(nullptr);
6243
0
    c.duplicateExpressionTernaryError(nullptr, ErrorPath{});
6244
0
    c.duplicateBreakError(nullptr,  false);
6245
0
    c.unreachableCodeError(nullptr, nullptr,  false);
6246
0
    c.unsignedLessThanZeroError(nullptr, nullptr, "varname");
6247
0
    c.unsignedPositiveError(nullptr, nullptr, "varname");
6248
0
    c.pointerLessThanZeroError(nullptr, nullptr);
6249
0
    c.pointerPositiveError(nullptr, nullptr);
6250
0
    c.suspiciousSemicolonError(nullptr);
6251
0
    c.incompleteArrayFillError(nullptr,  "buffer", "memset", false);
6252
0
    c.varFuncNullUBError(nullptr);
6253
0
    c.nanInArithmeticExpressionError(nullptr);
6254
0
    c.commaSeparatedReturnError(nullptr);
6255
0
    c.redundantPointerOpError(nullptr,  "varname", false, /*addressOfDeref*/ true);
6256
0
    c.unusedLabelError(nullptr, false, false);
6257
0
    c.unusedLabelError(nullptr, false, true);
6258
0
    c.unusedLabelError(nullptr, true, false);
6259
0
    c.unusedLabelError(nullptr, true, true);
6260
0
    c.unknownEvaluationOrder(nullptr);
6261
0
    c.accessMovedError(nullptr, "v", nullptr, false);
6262
0
    c.funcArgNamesDifferent("function", 1, nullptr, nullptr);
6263
0
    c.redundantBitwiseOperationInSwitchError(nullptr, "varname");
6264
0
    c.shadowError(nullptr, nullptr, "variable");
6265
0
    c.shadowError(nullptr, nullptr, "function");
6266
0
    c.shadowError(nullptr, nullptr, "argument");
6267
0
    c.knownArgumentError(nullptr, nullptr, nullptr, "x", false);
6268
0
    c.knownPointerToBoolError(nullptr, nullptr);
6269
0
    c.comparePointersError(nullptr, nullptr, nullptr);
6270
0
    c.redundantAssignmentError(nullptr, nullptr, "var", false);
6271
0
    c.redundantInitializationError(nullptr, nullptr, "var", false);
6272
6273
0
    const std::vector<const Token *> nullvec;
6274
0
    c.funcArgOrderDifferent("function", nullptr, nullptr, nullvec, nullvec);
6275
0
    c.checkModuloOfOneError(nullptr);
6276
0
}