Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/token.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: (|{|[|<
7
887
static inline bool match1(const Token* tok) {
8
887
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && 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("<"))))
9
721
        return false;
10
166
    return true;
11
887
}
12
// pattern: )|;
13
3.91k
static inline bool match2(const Token* tok) {
14
3.91k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString(";"))))
15
3.18k
        return false;
16
721
    return true;
17
3.91k
}
18
// pattern: (|{|[
19
0
static inline bool match3(const Token* tok) {
20
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))))
21
0
        return false;
22
0
    return true;
23
0
}
24
// pattern: >|;
25
0
static inline bool match4(const Token* tok) {
26
0
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || (tok->str() == MatchCompiler::makeConstString(";"))))
27
0
        return false;
28
0
    return true;
29
0
}
30
// pattern: ]
31
64
static inline bool match5(const Token* tok) {
32
64
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
33
64
        return false;
34
0
    return true;
35
64
}
36
// pattern: operator %op% <
37
64
static inline bool match6(const Token* tok) {
38
64
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("operator")))
39
64
        return false;
40
0
    tok = tok->next();
41
0
    if (!tok || !tok->isOp())
42
0
        return false;
43
0
    tok = tok->next();
44
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
45
0
        return false;
46
0
    return true;
47
0
}
48
// pattern: operator [([] [)]] <
49
64
static inline bool match7(const Token* tok) {
50
64
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("operator")))
51
64
        return false;
52
0
    tok = tok->next();
53
0
    if (!tok || tok->str().size() != 1U || !strchr("([", tok->str()[0]))
54
0
        return false;
55
0
    tok = tok->next();
56
0
    if (!tok || tok->str().size() != 1U || !strchr(")]", tok->str()[0]))
57
0
        return false;
58
0
    tok = tok->next();
59
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
60
0
        return false;
61
0
    return true;
62
0
}
63
// pattern: template <
64
2.94k
static inline bool match8(const Token* tok) {
65
2.94k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("template")))
66
2.94k
        return false;
67
0
    tok = tok->next();
68
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
69
0
        return false;
70
0
    return true;
71
0
}
72
// pattern: [;{}]
73
2.94k
static inline bool match9(const Token* tok) {
74
2.94k
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
75
2.44k
        return false;
76
508
    return true;
77
2.94k
}
78
// pattern: {|[|(
79
2.05k
static inline bool match10(const Token* tok) {
80
2.05k
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
81
1.99k
        return false;
82
59
    return true;
83
2.05k
}
84
// pattern: }|]|)|;
85
1.99k
static inline bool match11(const Token* tok) {
86
1.99k
    if (!tok || !(((tok->tokType() == Token::eBracket) && 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->str() == MatchCompiler::makeConstString(";"))))
87
1.52k
        return false;
88
475
    return true;
89
1.99k
}
90
// pattern: [,=]
91
0
static inline bool match12(const Token* tok) {
92
0
    if (!tok || tok->str().size() != 1U || !strchr(",=", tok->str()[0]))
93
0
        return false;
94
0
    return true;
95
0
}
96
// pattern: class|typename|.
97
0
static inline bool match13(const Token* tok) {
98
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("typename")) || (tok->str() == MatchCompiler::makeConstString("."))))
99
0
        return false;
100
0
    return true;
101
0
}
102
// pattern: =|::
103
0
static inline bool match14(const Token* tok) {
104
0
    if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString("::"))))
105
0
        return false;
106
0
    return true;
107
0
}
108
// pattern: }|]|)
109
0
static inline bool match15(const Token* tok) {
110
0
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))))
111
0
        return false;
112
0
    return true;
113
0
}
114
// pattern: {|{|(|;
115
0
static inline bool match16(const Token* tok) {
116
0
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString(";"))))
117
0
        return false;
118
0
    return true;
119
0
}
120
// pattern: const|volatile|final|override|&|&&|noexcept
121
0
static inline bool match17(const Token* tok) {
122
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("final")) || (tok->str() == MatchCompiler::makeConstString("override")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->str() == MatchCompiler::makeConstString("noexcept"))))
123
0
        return false;
124
0
    return true;
125
0
}
126
// pattern: throw|noexcept
127
0
static inline bool match18(const Token* tok) {
128
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("throw")) || (tok->str() == MatchCompiler::makeConstString("noexcept"))))
129
0
        return false;
130
0
    return true;
131
0
}
132
// pattern: :|, %name%
133
0
static inline bool match19(const Token* tok) {
134
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(","))))
135
0
        return false;
136
0
    tok = tok->next();
137
0
    if (!tok || !tok->isName())
138
0
        return false;
139
0
    return true;
140
0
}
141
// pattern: %name% :: %name%
142
0
static inline bool match20(const Token* tok) {
143
0
    if (!tok || !tok->isName())
144
0
        return false;
145
0
    tok = tok->next();
146
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
147
0
        return false;
148
0
    tok = tok->next();
149
0
    if (!tok || !tok->isName())
150
0
        return false;
151
0
    return true;
152
0
}
153
// pattern: :: %name%
154
0
static inline bool match21(const Token* tok) {
155
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
156
0
        return false;
157
0
    tok = tok->next();
158
0
    if (!tok || !tok->isName())
159
0
        return false;
160
0
    return true;
161
0
}
162
// pattern: %name%|>
163
0
static inline bool match22(const Token* tok) {
164
0
    if (!tok || !(tok->isName() || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">"))))
165
0
        return false;
166
0
    return true;
167
0
}
168
// pattern: namespace|class|struct|union %name% {|::|:|<
169
0
static inline bool match23(const Token* tok) {
170
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("namespace")) || (tok->str() == MatchCompiler::makeConstString("class")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("struct")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union"))))
171
0
        return false;
172
0
    tok = tok->next();
173
0
    if (!tok || !tok->isName())
174
0
        return false;
175
0
    tok = tok->next();
176
0
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))))
177
0
        return false;
178
0
    return true;
179
0
}
180
// pattern: {|:|<
181
0
static inline bool match24(const Token* tok) {
182
0
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))))
183
0
        return false;
184
0
    return true;
185
0
}
186
// pattern: {
187
19.7k
static inline bool match25(const Token* tok) {
188
19.7k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
189
19.7k
        return false;
190
0
    return true;
191
19.7k
}
192
// pattern: }
193
0
static inline bool match26(const Token* tok) {
194
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
195
0
        return false;
196
0
    return true;
197
0
}
198
// pattern: ;|{
199
0
static inline bool match27(const Token* tok) {
200
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
201
0
        return false;
202
0
    return true;
203
0
}
204
// pattern: using namespace %name% ::|;
205
0
static inline bool match28(const Token* tok) {
206
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("using")))
207
0
        return false;
208
0
    tok = tok->next();
209
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("namespace")))
210
0
        return false;
211
0
    tok = tok->next();
212
0
    if (!tok || !tok->isName())
213
0
        return false;
214
0
    tok = tok->next();
215
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString(";"))))
216
0
        return false;
217
0
    return true;
218
0
}
219
// pattern: (|[|{
220
12.8k
static inline bool match29(const Token* tok) {
221
12.8k
    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->str() == MatchCompiler::makeConstString("{"))))
222
12.8k
        return false;
223
0
    return true;
224
12.8k
}
225
// pattern: ( ::| %type%
226
0
static inline bool match30(const Token* tok) {
227
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
228
0
        return false;
229
0
    tok = tok->next();
230
0
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
231
0
        tok = tok->next();
232
0
    if (!tok || !(tok->isName() && tok->varId() == 0U))
233
0
        return false;
234
0
    return true;
235
0
}
236
// pattern: %cop%|++|--
237
0
static inline bool match31(const Token* tok) {
238
0
    if (!tok || !(tok->isConstOp() || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--"))))
239
0
        return false;
240
0
    return true;
241
0
}
242
// pattern: *|&
243
0
static inline bool match32(const Token* tok) {
244
0
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))))
245
0
        return false;
246
0
    return true;
247
0
}
248
// pattern: %name%|%num% %name%|%num%
249
42.3k
static inline bool match33(const Token* tok) {
250
42.3k
    if (!tok || !(tok->isName() || tok->isNumber()))
251
18.4k
        return false;
252
23.9k
    tok = tok->next();
253
23.9k
    if (!tok || !(tok->isName() || tok->isNumber()))
254
23.9k
        return false;
255
0
    return true;
256
23.9k
}
257
// pattern: ,|(
258
0
static inline bool match34(const Token* tok) {
259
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
260
0
        return false;
261
0
    return true;
262
0
}
263
// pattern: return
264
5.97k
static inline bool match35(const Token* tok) {
265
5.97k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
266
5.97k
        return false;
267
2
    return true;
268
5.97k
}
269
// pattern: %type%|= (|{
270
3.98k
static inline bool match36(const Token* tok) {
271
3.98k
    if (!tok || !((tok->isName() && tok->varId() == 0U) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))))
272
3.64k
        return false;
273
336
    tok = tok->next();
274
336
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
275
336
        return false;
276
0
    return true;
277
336
}
278
// pattern: =
279
5.97k
static inline bool match37(const Token* tok) {
280
5.97k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
281
5.97k
        return false;
282
0
    return true;
283
5.97k
}
284
// pattern: .
285
5.97k
static inline bool match38(const Token* tok) {
286
5.97k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
287
5.97k
        return false;
288
0
    return true;
289
5.97k
}
290
// pattern: [
291
3.98k
static inline bool match39(const Token* tok) {
292
3.98k
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
293
3.98k
        return false;
294
0
    return true;
295
3.98k
}
296
// pattern: auto
297
1.47k
static inline bool match40(const Token* tok) {
298
1.47k
    if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto")))
299
1.47k
        return false;
300
0
    return true;
301
1.47k
}
302
// pattern: ; %varid% =
303
0
static inline bool match41(const Token* tok, const int varid) {
304
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
305
0
        return false;
306
0
    tok = tok->next();
307
0
    if (varid==0U)
308
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
309
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
310
0
        return false;
311
0
    tok = tok->next();
312
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
313
0
        return false;
314
0
    return true;
315
0
}
316
// pattern: !!=
317
0
static inline bool match42(const Token* tok) {
318
0
    if (tok && tok->str() == MatchCompiler::makeConstString("="))
319
0
        return false;
320
0
    return true;
321
0
}
322
// pattern: %name% ::
323
0
static inline bool match43(const Token* tok) {
324
0
    if (!tok || !tok->isName())
325
0
        return false;
326
0
    tok = tok->next();
327
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
328
0
        return false;
329
0
    return true;
330
0
}
331
// pattern: new
332
0
static inline bool match44(const Token* tok) {
333
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("new")))
334
0
        return false;
335
0
    return true;
336
0
}
337
// pattern: (
338
0
static inline bool match45(const Token* tok) {
339
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
340
0
        return false;
341
0
    return true;
342
0
}
343
// pattern: <
344
0
static inline bool match46(const Token* tok) {
345
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
346
0
        return false;
347
0
    return true;
348
0
}
349
// pattern: %name%|.|::|*|&|&&|<|(|template|decltype|sizeof
350
0
static inline bool match47(const Token* tok) {
351
0
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("template")) || (tok->str() == MatchCompiler::makeConstString("decltype")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("sizeof"))))
352
0
        return false;
353
0
    return true;
354
0
}
355
// pattern: (|<
356
0
static inline bool match48(const Token* tok) {
357
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))))
358
0
        return false;
359
0
    return true;
360
0
}
361
// pattern: ] (|{
362
0
static inline bool match49(const Token* tok) {
363
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
364
0
        return false;
365
0
    tok = tok->next();
366
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
367
0
        return false;
368
0
    return true;
369
0
}
370
// pattern: ) {
371
0
static inline bool match50(const Token* tok) {
372
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
373
0
        return false;
374
0
    tok = tok->next();
375
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
376
0
        return false;
377
0
    return true;
378
0
}
379
// pattern: )
380
0
static inline bool match51(const Token* tok) {
381
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
382
0
        return false;
383
0
    return true;
384
0
}
385
// pattern: mutable|constexpr|consteval|noexcept|.
386
0
static inline bool match52(const Token* tok) {
387
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("mutable")) || (tok->str() == MatchCompiler::makeConstString("constexpr")) || (tok->str() == MatchCompiler::makeConstString("consteval")) || (tok->str() == MatchCompiler::makeConstString("noexcept")) || (tok->str() == MatchCompiler::makeConstString("."))))
388
0
        return false;
389
0
    return true;
390
0
}
391
// pattern: noexcept (
392
0
static inline bool match53(const Token* tok) {
393
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("noexcept")))
394
0
        return false;
395
0
    tok = tok->next();
396
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
397
0
        return false;
398
0
    return true;
399
0
}
400
/*
401
 * Cppcheck - A tool for static C/C++ code analysis
402
 * Copyright (C) 2007-2024 Cppcheck team.
403
 *
404
 * This program is free software: you can redistribute it and/or modify
405
 * it under the terms of the GNU General Public License as published by
406
 * the Free Software Foundation, either version 3 of the License, or
407
 * (at your option) any later version.
408
 *
409
 * This program is distributed in the hope that it will be useful,
410
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
411
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
412
 * GNU General Public License for more details.
413
 *
414
 * You should have received a copy of the GNU General Public License
415
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
416
 */
417
418
#include "token.h"
419
420
#include "astutils.h"
421
#include "errortypes.h"
422
#include "library.h"
423
#include "settings.h"
424
#include "simplecpp.h"
425
#include "symboldatabase.h"
426
#include "tokenlist.h"
427
#include "utils.h"
428
#include "tokenrange.h"
429
#include "valueflow.h"
430
431
#include <algorithm>
432
#include <cassert>
433
#include <cctype>
434
#include <climits>
435
#include <cstdio>
436
#include <cstring>
437
#include <functional>
438
#include <iostream>
439
#include <iterator>
440
#include <map>
441
#include <set>
442
#include <sstream>
443
#include <stack>
444
#include <type_traits>
445
#include <unordered_set>
446
#include <utility>
447
448
namespace {
449
    struct less {
450
        template<class T, class U>
451
126
        bool operator()(const T &x, const U &y) const {
452
126
            return x < y;
453
126
        }
token.cpp:bool (anonymous namespace)::less::operator()<long long, long long>(long long const&, long long const&) const
Line
Count
Source
451
126
        bool operator()(const T &x, const U &y) const {
452
126
            return x < y;
453
126
        }
Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<long long, double>(long long const&, double const&) const
Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<double, long long>(double const&, long long const&) const
Unexecuted instantiation: token.cpp:bool (anonymous namespace)::less::operator()<double, double>(double const&, double const&) const
454
    };
455
}
456
457
const std::list<ValueFlow::Value> TokenImpl::mEmptyValueList;
458
459
Token::Token(TokensFrontBack &tokensFrontBack)
460
64.1k
    : mTokensFrontBack(tokensFrontBack)
461
64.1k
    , mIsC(mTokensFrontBack.list.isC())
462
64.1k
    , mIsCpp(mTokensFrontBack.list.isCPP())
463
64.1k
{
464
64.1k
    mImpl = new TokenImpl();
465
64.1k
}
466
467
Token::Token(const Token* tok)
468
0
    : Token(const_cast<Token*>(tok)->mTokensFrontBack)
469
0
{
470
0
    fileIndex(tok->fileIndex());
471
0
    linenr(tok->linenr());
472
0
}
473
474
Token::~Token()
475
64.1k
{
476
64.1k
    delete mImpl;
477
64.1k
}
478
479
/*
480
 * Get a TokenRange which starts at this token and contains every token following it in order up to but not including 't'
481
 * e.g. for the sequence of tokens A B C D E, C.until(E) would yield the Range C D
482
 * note t can be nullptr to iterate all the way to the end.
483
 */
484
// cppcheck-suppress unusedFunction // only used in testtokenrange.cpp
485
ConstTokenRange Token::until(const Token* t) const
486
0
{
487
0
    return ConstTokenRange(this, t);
488
0
}
489
490
static const std::unordered_set<std::string> controlFlowKeywords = {
491
    "goto",
492
    "do",
493
    "if",
494
    "else",
495
    "for",
496
    "while",
497
    "switch",
498
    "case",
499
    "break",
500
    "continue",
501
    "return"
502
};
503
504
void Token::update_property_info()
505
100k
{
506
100k
    setFlag(fIsControlFlowKeyword, controlFlowKeywords.find(mStr) != controlFlowKeywords.end());
507
100k
    isStandardType(false);
508
509
100k
    if (!mStr.empty()) {
510
100k
        if (mStr == MatchCompiler::makeConstString("true") || mStr == MatchCompiler::makeConstString("false"))
511
0
            tokType(eBoolean);
512
100k
        else if (isStringLiteral(mStr)) {
513
2
            tokType(eString);
514
2
            isLong(isPrefixStringCharLiteral(mStr, '"', "L"));
515
2
        }
516
100k
        else if (isCharLiteral(mStr)) {
517
0
            tokType(eChar);
518
0
            isLong(isPrefixStringCharLiteral(mStr, '\'', "L"));
519
0
        }
520
100k
        else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name
521
53.2k
            if (mImpl->mVarId)
522
0
                tokType(eVariable);
523
53.2k
            else if (mTokensFrontBack.list.isKeyword(mStr) || mStr == MatchCompiler::makeConstString("asm")) // TODO: not a keyword
524
15.4k
                tokType(eKeyword);
525
37.7k
            else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword)
526
37.7k
                tokType(eName);
527
53.2k
        } else if (simplecpp::Token::isNumberLike(mStr)) {
528
6.06k
            if ((MathLib::isInt(mStr) || MathLib::isFloat(mStr)) && mStr.find('_') == std::string::npos)
529
6.06k
                tokType(eNumber);
530
0
            else
531
0
                tokType(eName); // assume it is a user defined literal
532
40.9k
        } else if (mStr == MatchCompiler::makeConstString("=") || mStr == MatchCompiler::makeConstString("<<=") || mStr == MatchCompiler::makeConstString(">>=") ||
533
40.9k
                   (mStr.size() == 2U && mStr[1] == '=' && std::strchr("+-*/%&^|", mStr[0])))
534
14.8k
            tokType(eAssignmentOp);
535
26.1k
        else if (mStr.size() == 1 && mStr.find_first_of(",[]()?:") != std::string::npos)
536
5.29k
            tokType(eExtendedOp);
537
20.8k
        else if (mStr==MatchCompiler::makeConstString("<<") || mStr==MatchCompiler::makeConstString(">>") || (mStr.size()==1 && mStr.find_first_of("+-*/%") != std::string::npos))
538
1.47k
            tokType(eArithmeticalOp);
539
19.3k
        else if (mStr.size() == 1 && mStr.find_first_of("&|^~") != std::string::npos)
540
553
            tokType(eBitOp);
541
18.8k
        else if (mStr.size() <= 2 &&
542
18.8k
                 (mStr == MatchCompiler::makeConstString("&&") ||
543
18.8k
                  mStr == MatchCompiler::makeConstString("||") ||
544
18.8k
                  mStr == MatchCompiler::makeConstString("!")))
545
0
            tokType(eLogicalOp);
546
18.8k
        else if (mStr.size() <= 2 && !mLink &&
547
18.8k
                 (mStr == MatchCompiler::makeConstString("==") ||
548
18.8k
                  mStr == MatchCompiler::makeConstString("!=") ||
549
18.8k
                  mStr == MatchCompiler::makeConstString("<") ||
550
18.8k
                  mStr == MatchCompiler::makeConstString("<=") ||
551
18.8k
                  mStr == MatchCompiler::makeConstString(">") ||
552
18.8k
                  mStr == MatchCompiler::makeConstString(">=")))
553
1.17k
            tokType(eComparisonOp);
554
17.6k
        else if (mStr == MatchCompiler::makeConstString("<=>"))
555
0
            tokType(eComparisonOp);
556
17.6k
        else if (mStr.size() == 2 &&
557
17.6k
                 (mStr == MatchCompiler::makeConstString("++") ||
558
807
                  mStr == MatchCompiler::makeConstString("--")))
559
807
            tokType(eIncDecOp);
560
16.8k
        else if (mStr.size() == 1 && (mStr.find_first_of("{}") != std::string::npos || (mLink && mStr.find_first_of("<>") != std::string::npos)))
561
4.84k
            tokType(eBracket);
562
12.0k
        else if (mStr == MatchCompiler::makeConstString("..."))
563
0
            tokType(eEllipsis);
564
12.0k
        else
565
12.0k
            tokType(eOther);
566
567
100k
        update_property_isStandardType();
568
100k
    } else {
569
0
        tokType(eNone);
570
0
    }
571
100k
}
572
573
static const std::unordered_set<std::string> stdTypes = { "bool"
574
                                                          , "_Bool"
575
                                                          , "char"
576
                                                          , "double"
577
                                                          , "float"
578
                                                          , "int"
579
                                                          , "long"
580
                                                          , "short"
581
                                                          , "size_t"
582
                                                          , "void"
583
                                                          , "wchar_t"
584
                                                          , "signed"
585
                                                          , "unsigned"
586
};
587
588
bool Token::isStandardType(const std::string& str)
589
50.3k
{
590
50.3k
    return stdTypes.find(str) != stdTypes.end();
591
50.3k
}
592
593
void Token::update_property_isStandardType()
594
100k
{
595
100k
    if (mStr.size() < 3 || mStr.size() > 7)
596
50.1k
        return;
597
598
50.1k
    if (isStandardType(mStr)) {
599
10.7k
        isStandardType(true);
600
10.7k
        tokType(eType);
601
10.7k
    }
602
50.1k
}
603
604
bool Token::isUpperCaseName() const
605
14.4k
{
606
14.4k
    if (!isName())
607
0
        return false;
608
14.4k
    return std::none_of(mStr.begin(), mStr.end(), [](char c) {
609
14.4k
        return std::islower(c);
610
14.4k
    });
611
14.4k
}
612
613
void Token::concatStr(std::string const& b)
614
0
{
615
0
    mStr.pop_back();
616
0
    mStr.append(getStringLiteral(b) + "\"");
617
618
0
    if (isCChar() && isStringLiteral(b) && b[0] != '"') {
619
0
        mStr.insert(0, b.substr(0, b.find('"')));
620
0
    }
621
0
    update_property_info();
622
0
}
623
624
std::string Token::strValue() const
625
0
{
626
0
    assert(mTokType == eString);
627
0
    std::string ret(getStringLiteral(mStr));
628
0
    std::string::size_type pos = 0U;
629
0
    while ((pos = ret.find('\\', pos)) != std::string::npos) {
630
0
        ret.erase(pos,1U);
631
0
        if (ret[pos] >= 'a') {
632
0
            if (ret[pos] == 'n')
633
0
                ret[pos] = '\n';
634
0
            else if (ret[pos] == 'r')
635
0
                ret[pos] = '\r';
636
0
            else if (ret[pos] == 't')
637
0
                ret[pos] = '\t';
638
0
        }
639
0
        if (ret[pos] == '0')
640
0
            return ret.substr(0,pos);
641
0
        pos++;
642
0
    }
643
0
    return ret;
644
0
}
645
646
void Token::deleteNext(nonneg int count)
647
983
{
648
1.96k
    while (mNext && count > 0) {
649
983
        Token *n = mNext;
650
651
        // #8154 we are about to be unknown -> destroy the link to us
652
983
        if (n->mLink && n->mLink->mLink == n)
653
0
            n->mLink->link(nullptr);
654
655
983
        mNext = n->next();
656
983
        delete n;
657
983
        --count;
658
983
    }
659
660
983
    if (mNext)
661
983
        mNext->previous(this);
662
0
    else
663
0
        mTokensFrontBack.back = this;
664
983
}
665
666
void Token::deletePrevious(nonneg int count)
667
0
{
668
0
    while (mPrevious && count > 0) {
669
0
        Token *p = mPrevious;
670
671
        // #8154 we are about to be unknown -> destroy the link to us
672
0
        if (p->mLink && p->mLink->mLink == p)
673
0
            p->mLink->link(nullptr);
674
675
0
        mPrevious = p->previous();
676
0
        delete p;
677
0
        --count;
678
0
    }
679
680
0
    if (mPrevious)
681
0
        mPrevious->next(this);
682
0
    else
683
0
        mTokensFrontBack.front = this;
684
0
}
685
686
void Token::swapWithNext()
687
0
{
688
0
    if (mNext) {
689
0
        std::swap(mStr, mNext->mStr);
690
0
        std::swap(mTokType, mNext->mTokType);
691
0
        std::swap(mFlags, mNext->mFlags);
692
0
        std::swap(mImpl, mNext->mImpl);
693
0
        if (mImpl->mTemplateSimplifierPointers)
694
            // cppcheck-suppress shadowFunction - TODO: fix this
695
0
            for (auto *templateSimplifierPointer : *mImpl->mTemplateSimplifierPointers) {
696
0
                templateSimplifierPointer->token(this);
697
0
            }
698
699
0
        if (mNext->mImpl->mTemplateSimplifierPointers)
700
            // cppcheck-suppress shadowFunction - TODO: fix this
701
0
            for (auto *templateSimplifierPointer : *mNext->mImpl->mTemplateSimplifierPointers) {
702
0
                templateSimplifierPointer->token(mNext);
703
0
            }
704
0
        if (mNext->mLink)
705
0
            mNext->mLink->mLink = this;
706
0
        if (this->mLink)
707
0
            this->mLink->mLink = mNext;
708
0
        std::swap(mLink, mNext->mLink);
709
0
    }
710
0
}
711
712
void Token::takeData(Token *fromToken)
713
188
{
714
188
    mStr = fromToken->mStr;
715
188
    tokType(fromToken->mTokType);
716
188
    mFlags = fromToken->mFlags;
717
188
    delete mImpl;
718
188
    mImpl = fromToken->mImpl;
719
188
    fromToken->mImpl = nullptr;
720
188
    if (mImpl->mTemplateSimplifierPointers)
721
        // cppcheck-suppress shadowFunction - TODO: fix this
722
0
        for (auto *templateSimplifierPointer : *mImpl->mTemplateSimplifierPointers) {
723
0
            templateSimplifierPointer->token(this);
724
0
        }
725
188
    mLink = fromToken->mLink;
726
188
    if (mLink)
727
42
        mLink->link(this);
728
188
}
729
730
void Token::deleteThis()
731
188
{
732
188
    if (mNext) { // Copy next to this and delete next
733
188
        takeData(mNext);
734
188
        mNext->link(nullptr); // mark as unlinked
735
188
        deleteNext();
736
188
    } else if (mPrevious) { // Copy previous to this and delete previous
737
0
        takeData(mPrevious);
738
0
        mPrevious->link(nullptr);
739
0
        deletePrevious();
740
0
    } else {
741
        // We are the last token in the list, we can't delete
742
        // ourselves, so just make us empty
743
0
        str(";");
744
0
    }
745
188
}
746
747
void Token::replace(Token *replaceThis, Token *start, Token *end)
748
0
{
749
    // Fix the whole in the old location of start and end
750
0
    if (start->previous())
751
0
        start->previous()->next(end->next());
752
753
0
    if (end->next())
754
0
        end->next()->previous(start->previous());
755
756
    // Move start and end to their new location
757
0
    if (replaceThis->previous())
758
0
        replaceThis->previous()->next(start);
759
760
0
    if (replaceThis->next())
761
0
        replaceThis->next()->previous(end);
762
763
0
    start->previous(replaceThis->previous());
764
0
    end->next(replaceThis->next());
765
766
0
    if (end->mTokensFrontBack.back == end) {
767
0
        while (end->next())
768
0
            end = end->next();
769
0
        end->mTokensFrontBack.back = end;
770
0
    }
771
772
    // Update mProgressValue, fileIndex and linenr
773
0
    for (Token *tok = start; tok != end->next(); tok = tok->next())
774
0
        tok->mImpl->mProgressValue = replaceThis->mImpl->mProgressValue;
775
776
    // Delete old token, which is replaced
777
0
    delete replaceThis;
778
0
}
779
780
static
781
#if defined(__GNUC__)
782
// GCC does not inline this by itself
783
// need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
784
inline __attribute__((always_inline))
785
#endif
786
int multiComparePercent(const Token *tok, const char*& haystack, nonneg int varid)
787
0
{
788
0
    ++haystack;
789
    // Compare only the first character of the string for optimization reasons
790
0
    switch (haystack[0]) {
791
0
    case 'v':
792
0
        if (haystack[3] == '%') { // %var%
793
0
            haystack += 4;
794
0
            if (tok->varId() != 0)
795
0
                return 1;
796
0
        } else { // %varid%
797
0
            if (varid == 0) {
798
0
                throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
799
0
            }
800
801
0
            haystack += 6;
802
803
0
            if (tok->varId() == varid)
804
0
                return 1;
805
0
        }
806
0
        break;
807
0
    case 't':
808
        // Type (%type%)
809
0
    {
810
0
        haystack += 5;
811
0
        if (tok->isName() && tok->varId() == 0)
812
0
            return 1;
813
0
    }
814
0
    break;
815
0
    case 'a':
816
        // Accept any token (%any%) or assign (%assign%)
817
0
    {
818
0
        if (haystack[3] == '%') { // %any%
819
0
            haystack += 4;
820
0
            return 1;
821
0
        }
822
        // %assign%
823
0
        haystack += 7;
824
0
        if (tok->isAssignmentOp())
825
0
            return 1;
826
0
    }
827
0
    break;
828
0
    case 'n':
829
        // Number (%num%) or name (%name%)
830
0
    {
831
0
        if (haystack[4] == '%') { // %name%
832
0
            haystack += 5;
833
0
            if (tok->isName())
834
0
                return 1;
835
0
        } else {
836
0
            haystack += 4;
837
0
            if (tok->isNumber())
838
0
                return 1;
839
0
        }
840
0
    }
841
0
    break;
842
0
    case 'c': {
843
0
        haystack += 1;
844
        // Character (%char%)
845
0
        if (haystack[0] == 'h') {
846
0
            haystack += 4;
847
0
            if (tok->tokType() == Token::eChar)
848
0
                return 1;
849
0
        }
850
        // Const operator (%cop%)
851
0
        else if (haystack[1] == 'p') {
852
0
            haystack += 3;
853
0
            if (tok->isConstOp())
854
0
                return 1;
855
0
        }
856
        // Comparison operator (%comp%)
857
0
        else {
858
0
            haystack += 4;
859
0
            if (tok->isComparisonOp())
860
0
                return 1;
861
0
        }
862
0
    }
863
0
    break;
864
0
    case 's':
865
        // String (%str%)
866
0
    {
867
0
        haystack += 4;
868
0
        if (tok->tokType() == Token::eString)
869
0
            return 1;
870
0
    }
871
0
    break;
872
0
    case 'b':
873
        // Bool (%bool%)
874
0
    {
875
0
        haystack += 5;
876
0
        if (tok->isBoolean())
877
0
            return 1;
878
0
    }
879
0
    break;
880
0
    case 'o': {
881
0
        ++haystack;
882
0
        if (haystack[1] == '%') {
883
            // Op (%op%)
884
0
            if (haystack[0] == 'p') {
885
0
                haystack += 2;
886
0
                if (tok->isOp())
887
0
                    return 1;
888
0
            }
889
            // Or (%or%)
890
0
            else {
891
0
                haystack += 2;
892
0
                if (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|"))
893
0
                    return 1;
894
0
            }
895
0
        }
896
897
        // Oror (%oror%)
898
0
        else {
899
0
            haystack += 4;
900
0
            if (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||"))
901
0
                return 1;
902
0
        }
903
0
    }
904
0
    break;
905
0
    default:
906
        //unknown %cmd%, abort
907
0
        throw InternalError(tok, "Unexpected command");
908
0
    }
909
910
0
    if (*haystack == '|')
911
0
        haystack += 1;
912
0
    else
913
0
        return -1;
914
915
0
    return 0xFFFF;
916
0
}
917
918
static
919
#if defined(__GNUC__)
920
// need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
921
inline __attribute__((always_inline))
922
#endif
923
int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid)
924
0
{
925
0
    const char *needle = tok->str().c_str();
926
0
    const char *needlePointer = needle;
927
0
    for (;;) {
928
0
        if (needlePointer == needle && haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ') {
929
0
            const int ret = multiComparePercent(tok, haystack, varid);
930
0
            if (ret < 2)
931
0
                return ret;
932
0
        } else if (*haystack == '|') {
933
0
            if (*needlePointer == 0) {
934
                // If needle is at the end, we have a match.
935
0
                return 1;
936
0
            }
937
938
0
            needlePointer = needle;
939
0
            ++haystack;
940
0
        } else if (*needlePointer == *haystack) {
941
0
            if (*needlePointer == '\0')
942
0
                return 1;
943
0
            ++needlePointer;
944
0
            ++haystack;
945
0
        } else if (*haystack == ' ' || *haystack == '\0') {
946
0
            if (needlePointer == needle)
947
0
                return 0;
948
0
            break;
949
0
        }
950
        // If haystack and needle don't share the same character,
951
        // find next '|' character.
952
0
        else {
953
0
            needlePointer = needle;
954
955
0
            do {
956
0
                ++haystack;
957
958
0
                if (*haystack == ' ' || *haystack == '\0') {
959
0
                    return -1;
960
0
                }
961
0
                if (*haystack == '|') {
962
0
                    break;
963
0
                }
964
0
            } while (true);
965
966
0
            ++haystack;
967
0
        }
968
0
    }
969
970
0
    if (*needlePointer == '\0')
971
0
        return 1;
972
973
0
    return -1;
974
0
}
975
976
// cppcheck-suppress unusedFunction - used in tests only
977
int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid)
978
0
{
979
0
    return multiCompareImpl(tok, haystack, varid);
980
0
}
981
982
bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_len)
983
4.20k
{
984
4.20k
    if (!tok)
985
0
        return false; // shortcut
986
4.20k
    const char *current = pattern;
987
4.20k
    const char *end = pattern + pattern_len;
988
    // cppcheck-suppress shadowFunction - TODO: fix this
989
4.20k
    const char *next = static_cast<const char*>(std::memchr(pattern, ' ', pattern_len));
990
4.20k
    if (!next)
991
4.20k
        next = end;
992
993
5.85k
    while (*current) {
994
4.20k
        const std::size_t length = next - current;
995
996
4.20k
        if (!tok || length != tok->mStr.length() || std::strncmp(current, tok->mStr.c_str(), length) != 0)
997
2.56k
            return false;
998
999
1.64k
        current = next;
1000
1.64k
        if (*next) {
1001
0
            next = std::strchr(++current, ' ');
1002
0
            if (!next)
1003
0
                next = end;
1004
0
        }
1005
1.64k
        tok = tok->next();
1006
1.64k
    }
1007
1008
1.64k
    return true;
1009
4.20k
}
1010
1011
bool Token::firstWordEquals(const char *str, const char *word)
1012
0
{
1013
0
    for (;;) {
1014
0
        if (*str != *word)
1015
0
            return (*str == ' ' && *word == 0);
1016
0
        if (*str == 0)
1017
0
            break;
1018
1019
0
        ++str;
1020
0
        ++word;
1021
0
    }
1022
1023
0
    return true;
1024
0
}
1025
1026
const char *Token::chrInFirstWord(const char *str, char c)
1027
0
{
1028
0
    for (;;) {
1029
0
        if (*str == ' ' || *str == 0)
1030
0
            return nullptr;
1031
1032
0
        if (*str == c)
1033
0
            return str;
1034
1035
0
        ++str;
1036
0
    }
1037
0
}
1038
1039
bool Token::Match(const Token *tok, const char pattern[], nonneg int varid)
1040
0
{
1041
0
    if (!(*pattern))
1042
0
        return true;
1043
1044
0
    const char *p = pattern;
1045
0
    while (true) {
1046
        // Skip spaces in pattern..
1047
0
        while (*p == ' ')
1048
0
            ++p;
1049
1050
        // No token => Success!
1051
0
        if (*p == '\0')
1052
0
            break;
1053
1054
0
        if (!tok) {
1055
            // If we have no tokens, pattern "!!else" should return true
1056
0
            if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
1057
0
                while (*p && *p != ' ')
1058
0
                    ++p;
1059
0
                continue;
1060
0
            }
1061
1062
0
            return false;
1063
0
        }
1064
1065
        // [.. => search for a one-character token..
1066
0
        if (p[0] == '[' && chrInFirstWord(p, ']')) {
1067
0
            if (tok->str().length() != 1)
1068
0
                return false;
1069
1070
0
            const char *temp = p+1;
1071
0
            bool chrFound = false;
1072
0
            int count = 0;
1073
0
            while (*temp && *temp != ' ') {
1074
0
                if (*temp == ']') {
1075
0
                    ++count;
1076
0
                }
1077
1078
0
                else if (*temp == tok->str()[0]) {
1079
0
                    chrFound = true;
1080
0
                    break;
1081
0
                }
1082
1083
0
                ++temp;
1084
0
            }
1085
1086
0
            if (count > 1 && tok->str()[0] == ']')
1087
0
                chrFound = true;
1088
1089
0
            if (!chrFound)
1090
0
                return false;
1091
1092
0
            p = temp;
1093
0
        }
1094
1095
        // Parse "not" options. Token can be anything except the given one
1096
0
        else if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
1097
0
            p += 2;
1098
0
            if (firstWordEquals(p, tok->str().c_str()))
1099
0
                return false;
1100
0
        }
1101
1102
        // Parse multi options, such as void|int|char (accept token which is one of these 3)
1103
0
        else {
1104
0
            const int res = multiCompareImpl(tok, p, varid);
1105
0
            if (res == 0) {
1106
                // Empty alternative matches, use the same token on next round
1107
0
                while (*p && *p != ' ')
1108
0
                    ++p;
1109
0
                continue;
1110
0
            }
1111
0
            if (res == -1) {
1112
                // No match
1113
0
                return false;
1114
0
            }
1115
0
        }
1116
1117
        // using strchr() for the other instances leads to a performance decrease
1118
0
        if (!(p = strchr(p, ' ')))
1119
0
            break;
1120
1121
0
        tok = tok->next();
1122
0
    }
1123
1124
    // The end of the pattern has been reached and nothing wrong has been found
1125
0
    return true;
1126
0
}
1127
1128
nonneg int Token::getStrLength(const Token *tok)
1129
0
{
1130
0
    assert(tok != nullptr);
1131
0
    assert(tok->mTokType == eString);
1132
1133
0
    const std::string s(replaceEscapeSequences(getStringLiteral(tok->str())));
1134
1135
0
    const auto pos = s.find('\0');
1136
0
    return pos < s.size() ? pos : s.size();
1137
0
}
1138
1139
nonneg int Token::getStrArraySize(const Token *tok)
1140
0
{
1141
0
    assert(tok != nullptr);
1142
0
    assert(tok->tokType() == eString);
1143
    // cppcheck-suppress shadowFunction - TODO: fix this
1144
0
    const std::string str(getStringLiteral(tok->str()));
1145
0
    int sizeofstring = 1;
1146
0
    for (int i = 0; i < (int)str.size(); i++) {
1147
0
        if (str[i] == '\\')
1148
0
            ++i;
1149
0
        ++sizeofstring;
1150
0
    }
1151
0
    return sizeofstring;
1152
0
}
1153
1154
nonneg int Token::getStrSize(const Token *tok, const Settings &settings)
1155
0
{
1156
0
    assert(tok != nullptr && tok->tokType() == eString);
1157
0
    nonneg int sizeofType = 1;
1158
0
    if (tok->valueType()) {
1159
0
        ValueType vt(*tok->valueType());
1160
0
        vt.pointer = 0;
1161
0
        sizeofType = ValueFlow::getSizeOf(vt, settings);
1162
0
    }
1163
0
    return getStrArraySize(tok) * sizeofType;
1164
0
}
1165
1166
void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation)
1167
0
{
1168
    /**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */
1169
1170
    // Fix the gap, which tokens to be moved will leave
1171
0
    srcStart->previous()->next(srcEnd->next());
1172
0
    srcEnd->next()->previous(srcStart->previous());
1173
1174
    // Fix the tokens to be moved
1175
0
    srcEnd->next(newLocation->next());
1176
0
    srcStart->previous(newLocation);
1177
1178
    // Fix the tokens at newLocation
1179
0
    newLocation->next()->previous(srcEnd);
1180
0
    newLocation->next(srcStart);
1181
1182
    // Update _progressValue
1183
0
    for (Token *tok = srcStart; tok != srcEnd->next(); tok = tok->next())
1184
0
        tok->mImpl->mProgressValue = newLocation->mImpl->mProgressValue;
1185
0
}
1186
1187
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1188
static T* nextArgumentImpl(T *thisTok)
1189
721
{
1190
4.07k
    for (T* tok = thisTok; tok; tok = tok->next()) {
1191
4.07k
        if (tok->str() == MatchCompiler::makeConstString(","))
1192
0
            return tok->next();
1193
4.07k
        if (tok->link() && match1(tok))
1194
166
            tok = tok->link();
1195
3.91k
        else if (match2(tok))
1196
721
            return nullptr;
1197
4.07k
    }
1198
0
    return nullptr;
1199
721
}
token.cpp:Token const* nextArgumentImpl<Token const, void>(Token const*)
Line
Count
Source
1189
721
{
1190
4.07k
    for (T* tok = thisTok; tok; tok = tok->next()) {
1191
4.07k
        if (tok->str() == MatchCompiler::makeConstString(","))
1192
0
            return tok->next();
1193
4.07k
        if (tok->link() && match1(tok))
1194
166
            tok = tok->link();
1195
3.91k
        else if (match2(tok))
1196
721
            return nullptr;
1197
4.07k
    }
1198
0
    return nullptr;
1199
721
}
Unexecuted instantiation: token.cpp:Token* nextArgumentImpl<Token, void>(Token*)
1200
1201
const Token* Token::nextArgument() const
1202
721
{
1203
721
    return nextArgumentImpl(this);
1204
721
}
1205
1206
Token *Token::nextArgument()
1207
0
{
1208
0
    return nextArgumentImpl(this);
1209
0
}
1210
1211
const Token* Token::nextArgumentBeforeCreateLinks2() const
1212
0
{
1213
0
    for (const Token* tok = this; tok; tok = tok->next()) {
1214
0
        if (tok->str() == MatchCompiler::makeConstString(","))
1215
0
            return tok->next();
1216
0
        if (tok->link() && match3(tok))
1217
0
            tok = tok->link();
1218
0
        else if (tok->str() == MatchCompiler::makeConstString("<")) {
1219
0
            const Token* temp = tok->findClosingBracket();
1220
0
            if (temp)
1221
0
                tok = temp;
1222
0
        } else if (match2(tok))
1223
0
            return nullptr;
1224
0
    }
1225
0
    return nullptr;
1226
0
}
1227
1228
const Token* Token::nextTemplateArgument() const
1229
0
{
1230
0
    for (const Token* tok = this; tok; tok = tok->next()) {
1231
0
        if (tok->str() == MatchCompiler::makeConstString(","))
1232
0
            return tok->next();
1233
0
        if (tok->link() && match1(tok))
1234
0
            tok = tok->link();
1235
0
        else if (match4(tok))
1236
0
            return nullptr;
1237
0
    }
1238
0
    return nullptr;
1239
0
}
1240
1241
static bool isOperator(const Token *tok)
1242
0
{
1243
0
    if (tok->link())
1244
0
        tok = tok->link();
1245
    // TODO handle multi token operators
1246
0
    return tok->strAt(-1) == MatchCompiler::makeConstString("operator");
1247
0
}
1248
1249
const Token * Token::findClosingBracket() const
1250
572
{
1251
572
    if (mStr != MatchCompiler::makeConstString("<"))
1252
0
        return nullptr;
1253
1254
572
    if (!mPrevious)
1255
0
        return nullptr;
1256
1257
572
    if (!(mPrevious->isName() || match5(mPrevious) ||
1258
572
          match6(mPrevious->previous()) ||
1259
572
          match7(mPrevious->tokAt(-2))))
1260
64
        return nullptr;
1261
1262
508
    const Token *closing = nullptr;
1263
508
    const bool templateParameter(strAt(-1) == MatchCompiler::makeConstString("template"));
1264
508
    std::set<std::string> templateParameters;
1265
1266
508
    bool isDecl = true;
1267
2.94k
    for (const Token *prev = previous(); prev; prev = prev->previous()) {
1268
2.94k
        if (prev->str() == MatchCompiler::makeConstString("="))
1269
152
            isDecl = false;
1270
2.94k
        if (match8(prev))
1271
0
            isDecl = true;
1272
2.94k
        if (match9(prev))
1273
508
            break;
1274
2.94k
    }
1275
1276
508
    unsigned int depth = 0;
1277
2.05k
    for (closing = this; closing != nullptr; closing = closing->next()) {
1278
2.05k
        if (match10(closing)) {
1279
59
            closing = closing->link();
1280
59
            if (!closing)
1281
0
                return nullptr; // #6803
1282
1.99k
        } else if (match11(closing))
1283
475
            return nullptr;
1284
        // we can make some guesses for template parameters
1285
1.52k
        else if (closing->str() == MatchCompiler::makeConstString("<") && closing->previous() &&
1286
1.52k
                 (closing->previous()->isName() || match5(closing->previous()) || isOperator(closing->previous())) &&
1287
1.52k
                 (templateParameter ? templateParameters.find(closing->strAt(-1)) == templateParameters.end() : true))
1288
543
            ++depth;
1289
977
        else if (closing->str() == MatchCompiler::makeConstString(">")) {
1290
35
            if (--depth == 0)
1291
33
                return closing;
1292
942
        } else if (closing->str() == MatchCompiler::makeConstString(">>") || closing->str() == MatchCompiler::makeConstString(">>=")) {
1293
0
            if (!isDecl && depth == 1)
1294
0
                continue;
1295
0
            if (depth <= 2)
1296
0
                return closing;
1297
0
            depth -= 2;
1298
0
        }
1299
        // save named template parameter
1300
942
        else if (templateParameter && depth == 1 && match12(closing) &&
1301
942
                 closing->previous()->isName() && !match13(closing->previous()) && !match14(closing->tokAt(-2)))
1302
0
            templateParameters.insert(closing->strAt(-1));
1303
2.05k
    }
1304
1305
0
    return closing;
1306
508
}
1307
1308
Token * Token::findClosingBracket()
1309
268
{
1310
    // return value of const function
1311
268
    return const_cast<Token*>(static_cast<const Token*>(this)->findClosingBracket());
1312
268
}
1313
1314
const Token * Token::findOpeningBracket() const
1315
0
{
1316
0
    if (mStr != MatchCompiler::makeConstString(">"))
1317
0
        return nullptr;
1318
1319
0
    const Token *opening = nullptr;
1320
1321
0
    unsigned int depth = 0;
1322
0
    for (opening = this; opening != nullptr; opening = opening->previous()) {
1323
0
        if (match15(opening)) {
1324
0
            opening = opening->link();
1325
0
            if (!opening)
1326
0
                return nullptr;
1327
0
        } else if (match16(opening))
1328
0
            return nullptr;
1329
0
        else if (opening->str() == MatchCompiler::makeConstString(">"))
1330
0
            ++depth;
1331
0
        else if (opening->str() == MatchCompiler::makeConstString("<")) {
1332
0
            if (--depth == 0)
1333
0
                return opening;
1334
0
        }
1335
0
    }
1336
1337
0
    return opening;
1338
0
}
1339
1340
Token * Token::findOpeningBracket()
1341
0
{
1342
    // return value of const function
1343
0
    return const_cast<Token*>(static_cast<const Token*>(this)->findOpeningBracket());
1344
0
}
1345
1346
//---------------------------------------------------------------------------
1347
1348
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1349
static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len)
1350
0
{
1351
0
    for (T* tok = startTok; tok; tok = tok->next()) {
1352
0
        if (Token::simpleMatch(tok, pattern, pattern_len))
1353
0
            return tok;
1354
0
    }
1355
0
    return nullptr;
1356
0
}
Unexecuted instantiation: token.cpp:Token const* findsimplematchImpl<Token const, void>(Token const*, char const*, unsigned long)
Unexecuted instantiation: token.cpp:Token* findsimplematchImpl<Token, void>(Token*, char const*, unsigned long)
1357
1358
const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len)
1359
0
{
1360
0
    return findsimplematchImpl(startTok, pattern, pattern_len);
1361
0
}
1362
1363
Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len)
1364
0
{
1365
0
    return findsimplematchImpl(startTok, pattern, pattern_len);
1366
0
}
1367
1368
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1369
static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len, const Token * const end)
1370
0
{
1371
0
    for (T* tok = startTok; tok && tok != end; tok = tok->next()) {
1372
0
        if (Token::simpleMatch(tok, pattern, pattern_len))
1373
0
            return tok;
1374
0
    }
1375
0
    return nullptr;
1376
0
}
Unexecuted instantiation: token.cpp:Token const* findsimplematchImpl<Token const, void>(Token const*, char const*, unsigned long, Token const*)
Unexecuted instantiation: token.cpp:Token* findsimplematchImpl<Token, void>(Token*, char const*, unsigned long, Token const*)
1377
1378
const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end)
1379
0
{
1380
0
    return findsimplematchImpl(startTok, pattern, pattern_len, end);
1381
0
}
1382
1383
0
Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end) {
1384
0
    return findsimplematchImpl(startTok, pattern, pattern_len, end);
1385
0
}
1386
1387
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1388
static T *findmatchImpl(T * const startTok, const char pattern[], const nonneg int varId)
1389
0
{
1390
0
    for (T* tok = startTok; tok; tok = tok->next()) {
1391
0
        if (Token::Match(tok, pattern, varId))
1392
0
            return tok;
1393
0
    }
1394
0
    return nullptr;
1395
0
}
Unexecuted instantiation: token.cpp:Token const* findmatchImpl<Token const, void>(Token const*, char const*, int)
Unexecuted instantiation: token.cpp:Token* findmatchImpl<Token, void>(Token*, char const*, int)
1396
1397
const Token *Token::findmatch(const Token * const startTok, const char pattern[], const nonneg int varId)
1398
0
{
1399
0
    return findmatchImpl(startTok, pattern, varId);
1400
0
}
1401
1402
0
Token *Token::findmatch(Token * const startTok, const char pattern[], const nonneg int varId) {
1403
0
    return findmatchImpl(startTok, pattern, varId);
1404
0
}
1405
1406
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1407
static T *findmatchImpl(T * const startTok, const char pattern[], const Token * const end, const nonneg int varId)
1408
0
{
1409
0
    for (T* tok = startTok; tok && tok != end; tok = tok->next()) {
1410
0
        if (Token::Match(tok, pattern, varId))
1411
0
            return tok;
1412
0
    }
1413
0
    return nullptr;
1414
0
}
Unexecuted instantiation: token.cpp:Token const* findmatchImpl<Token const, void>(Token const*, char const*, Token const*, int)
Unexecuted instantiation: token.cpp:Token* findmatchImpl<Token, void>(Token*, char const*, Token const*, int)
1415
1416
const Token *Token::findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId)
1417
0
{
1418
0
    return findmatchImpl(startTok, pattern, end, varId);
1419
0
}
1420
1421
0
Token *Token::findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) {
1422
0
    return findmatchImpl(startTok, pattern, end, varId);
1423
0
}
1424
1425
void Token::function(const Function *f)
1426
58.2k
{
1427
58.2k
    mImpl->mFunction = f;
1428
58.2k
    if (f) {
1429
3.30k
        if (f->isLambda())
1430
0
            tokType(eLambda);
1431
3.30k
        else
1432
3.30k
            tokType(eFunction);
1433
54.9k
    } else if (mTokType == eFunction)
1434
1.10k
        tokType(eName);
1435
58.2k
}
1436
1437
Token* Token::insertToken(const std::string& tokenStr, const std::string& originalNameStr, const std::string& macroNameStr, bool prepend)
1438
63.3k
{
1439
63.3k
    Token *newToken;
1440
63.3k
    if (mStr.empty())
1441
0
        newToken = this;
1442
63.3k
    else
1443
63.3k
        newToken = new Token(mTokensFrontBack);
1444
63.3k
    newToken->str(tokenStr);
1445
63.3k
    newToken->originalName(originalNameStr);
1446
63.3k
    newToken->setMacroName(macroNameStr);
1447
1448
63.3k
    if (newToken != this) {
1449
63.3k
        newToken->mImpl->mLineNumber = mImpl->mLineNumber;
1450
63.3k
        newToken->mImpl->mFileIndex = mImpl->mFileIndex;
1451
63.3k
        newToken->mImpl->mProgressValue = mImpl->mProgressValue;
1452
1453
63.3k
        if (prepend) {
1454
0
            if (this->previous()) {
1455
0
                newToken->previous(this->previous());
1456
0
                newToken->previous()->next(newToken);
1457
0
            } else {
1458
0
                mTokensFrontBack.front = newToken;
1459
0
            }
1460
0
            this->previous(newToken);
1461
0
            newToken->next(this);
1462
63.3k
        } else {
1463
63.3k
            if (this->next()) {
1464
7.92k
                newToken->next(this->next());
1465
7.92k
                newToken->next()->previous(newToken);
1466
55.3k
            } else {
1467
55.3k
                mTokensFrontBack.back = newToken;
1468
55.3k
            }
1469
63.3k
            this->next(newToken);
1470
63.3k
            newToken->previous(this);
1471
63.3k
        }
1472
1473
63.3k
        if (mImpl->mScopeInfo) {
1474
            // If the brace is immediately closed there is no point opening a new scope for it
1475
0
            if (newToken->str() == MatchCompiler::makeConstString("{")) {
1476
0
                std::string nextScopeNameAddition;
1477
                // This might be the opening of a member function
1478
0
                Token *tok1 = newToken;
1479
0
                while (match17(tok1->previous()))
1480
0
                    tok1 = tok1->previous();
1481
0
                if (tok1->previous() && tok1->strAt(-1) == MatchCompiler::makeConstString(")")) {
1482
0
                    tok1 = tok1->linkAt(-1);
1483
0
                    if (match18(tok1->previous())) {
1484
0
                        tok1 = tok1->previous();
1485
0
                        while (match17(tok1->previous()))
1486
0
                            tok1 = tok1->previous();
1487
0
                        if (tok1->strAt(-1) != MatchCompiler::makeConstString(")"))
1488
0
                            return newToken;
1489
0
                    } else if (match19(newToken->tokAt(-2))) {
1490
0
                        tok1 = tok1->tokAt(-2);
1491
0
                        if (tok1->strAt(-1) != MatchCompiler::makeConstString(")"))
1492
0
                            return newToken;
1493
0
                    }
1494
0
                    if (tok1->strAt(-1) == MatchCompiler::makeConstString(">"))
1495
0
                        tok1 = tok1->previous()->findOpeningBracket();
1496
0
                    if (tok1 && match20(tok1->tokAt(-3))) {
1497
0
                        tok1 = tok1->tokAt(-2);
1498
                        // cppcheck-suppress shadowFunction - TODO: fix this
1499
0
                        std::string scope = tok1->strAt(-1);
1500
0
                        while (match21(tok1->tokAt(-2))) {
1501
0
                            scope = tok1->strAt(-3) + " :: " + scope;
1502
0
                            tok1 = tok1->tokAt(-2);
1503
0
                        }
1504
0
                        nextScopeNameAddition += scope;
1505
0
                    }
1506
0
                }
1507
1508
                // Or it might be a namespace/class/struct
1509
0
                if (match22(newToken->previous())) {
1510
0
                    Token* nameTok = newToken->previous();
1511
0
                    while (nameTok && !match23(nameTok)) {
1512
0
                        nameTok = nameTok->previous();
1513
0
                    }
1514
0
                    if (nameTok) {
1515
0
                        for (nameTok = nameTok->next(); nameTok && !match24(nameTok); nameTok = nameTok->next()) {
1516
0
                            nextScopeNameAddition.append(nameTok->str());
1517
0
                            nextScopeNameAddition.append(" ");
1518
0
                        }
1519
0
                        if (!nextScopeNameAddition.empty())
1520
0
                            nextScopeNameAddition.pop_back();
1521
0
                    }
1522
0
                }
1523
1524
                // New scope is opening, record it here
1525
0
                std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(mImpl->mScopeInfo->name, nullptr, mImpl->mScopeInfo->usingNamespaces);
1526
1527
0
                if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty()) newScopeInfo->name.append(" :: ");
1528
0
                newScopeInfo->name.append(nextScopeNameAddition);
1529
0
                nextScopeNameAddition = "";
1530
1531
0
                newToken->scopeInfo(std::move(newScopeInfo));
1532
0
            } else if (newToken->str() == MatchCompiler::makeConstString("}")) {
1533
0
                Token* matchingTok = newToken->previous();
1534
0
                int depth = 0;
1535
0
                while (matchingTok && (depth != 0 || !match25(matchingTok))) {
1536
0
                    if (match26(matchingTok)) depth++;
1537
0
                    if (match25(matchingTok)) depth--;
1538
0
                    matchingTok = matchingTok->previous();
1539
0
                }
1540
0
                if (matchingTok && matchingTok->previous()) {
1541
0
                    newToken->mImpl->mScopeInfo = matchingTok->previous()->scopeInfo();
1542
0
                }
1543
0
            } else {
1544
0
                if (prepend && newToken->previous()) {
1545
0
                    newToken->mImpl->mScopeInfo = newToken->previous()->scopeInfo();
1546
0
                } else {
1547
0
                    newToken->mImpl->mScopeInfo = mImpl->mScopeInfo;
1548
0
                }
1549
0
                if (newToken->str() == MatchCompiler::makeConstString(";")) {
1550
0
                    const Token* statementStart = newToken;
1551
0
                    while (statementStart->previous() && !match27(statementStart->previous())) {
1552
0
                        statementStart = statementStart->previous();
1553
0
                    }
1554
0
                    if (match28(statementStart)) {
1555
0
                        const Token * tok1 = statementStart->tokAt(2);
1556
0
                        std::string nameSpace;
1557
0
                        while (tok1 && tok1->str() != MatchCompiler::makeConstString(";")) {
1558
0
                            if (!nameSpace.empty())
1559
0
                                nameSpace += " ";
1560
0
                            nameSpace += tok1->str();
1561
0
                            tok1 = tok1->next();
1562
0
                        }
1563
0
                        mImpl->mScopeInfo->usingNamespaces.insert(nameSpace);
1564
0
                    }
1565
0
                }
1566
0
            }
1567
0
        }
1568
63.3k
    }
1569
63.3k
    return newToken;
1570
63.3k
}
1571
1572
void Token::eraseTokens(Token *begin, const Token *end)
1573
0
{
1574
0
    if (!begin || begin == end)
1575
0
        return;
1576
1577
0
    while (begin->next() && begin->next() != end) {
1578
0
        begin->deleteNext();
1579
0
    }
1580
0
}
1581
1582
void Token::createMutualLinks(Token *begin, Token *end)
1583
5.04k
{
1584
5.04k
    assert(begin != nullptr);
1585
5.04k
    assert(end != nullptr);
1586
5.04k
    assert(begin != end);
1587
5.04k
    begin->link(end);
1588
5.04k
    end->link(begin);
1589
5.04k
}
1590
1591
void Token::printOut() const
1592
0
{
1593
0
    printOut(std::cout, "");
1594
0
}
1595
1596
void Token::printOut(std::ostream& out, const char *title) const
1597
0
{
1598
0
    if (title && title[0])
1599
0
        out << "\n### " << title << " ###\n";
1600
0
    out << stringifyList(stringifyOptions::forPrintOut(), nullptr, nullptr) << std::endl;
1601
0
}
1602
1603
void Token::printOut(std::ostream& out, const char *title, const std::vector<std::string> &fileNames) const
1604
0
{
1605
0
    if (title && title[0])
1606
0
        out << "\n### " << title << " ###\n";
1607
0
    out << stringifyList(stringifyOptions::forPrintOut(), &fileNames, nullptr) << std::endl;
1608
0
}
1609
1610
// cppcheck-suppress unusedFunction - used for debugging
1611
void Token::printLines(std::ostream& out, int lines) const
1612
0
{
1613
0
    const Token *end = this;
1614
0
    while (end && end->linenr() < lines + linenr())
1615
0
        end = end->next();
1616
0
    out << stringifyList(stringifyOptions::forDebugExprId(), nullptr, end) << std::endl;
1617
0
}
1618
1619
std::string Token::stringify(const stringifyOptions& options) const
1620
1.10k
{
1621
1.10k
    std::string ret;
1622
1.10k
    if (options.attributes) {
1623
1.10k
        if (isUnsigned())
1624
0
            ret += "unsigned ";
1625
1.10k
        else if (isSigned())
1626
0
            ret += "signed ";
1627
1.10k
        if (isComplex())
1628
0
            ret += "_Complex ";
1629
1.10k
        if (isLong()) {
1630
0
            if (!(mTokType == eString || mTokType == eChar))
1631
0
                ret += "long ";
1632
0
        }
1633
1.10k
    }
1634
1.10k
    if (options.macro && isExpandedMacro())
1635
0
        ret += '$';
1636
1.10k
    if (isName() && mStr.find(' ') != std::string::npos) {
1637
0
        for (const char i : mStr) {
1638
0
            if (i != ' ')
1639
0
                ret += i;
1640
0
        }
1641
1.10k
    } else if (mStr[0] != '\"' || mStr.find('\0') == std::string::npos)
1642
1.10k
        ret += mStr;
1643
0
    else {
1644
0
        for (const char i : mStr) {
1645
0
            if (i == '\0')
1646
0
                ret += "\\0";
1647
0
            else
1648
0
                ret += i;
1649
0
        }
1650
0
    }
1651
1.10k
    if (options.varid && mImpl->mVarId != 0) {
1652
0
        ret += '@';
1653
0
        ret += (options.idtype ? "var" : "");
1654
0
        ret += std::to_string(mImpl->mVarId);
1655
1.10k
    } else if (options.exprid && mImpl->mExprId != 0) {
1656
0
        ret += '@';
1657
0
        ret += (options.idtype ? "expr" : "");
1658
0
        if ((mImpl->mExprId & (1U << efIsUnique)) != 0)
1659
0
            ret += "UNIQUE";
1660
0
        else
1661
0
            ret += std::to_string(mImpl->mExprId);
1662
0
    }
1663
1664
1.10k
    return ret;
1665
1.10k
}
1666
1667
std::string Token::stringify(bool varid, bool attributes, bool macro) const
1668
558
{
1669
558
    stringifyOptions options;
1670
558
    options.varid = varid;
1671
558
    options.attributes = attributes;
1672
558
    options.macro = macro;
1673
558
    return stringify(options);
1674
558
}
1675
1676
std::string Token::stringifyList(const stringifyOptions& options, const std::vector<std::string>* fileNames, const Token* end) const
1677
149
{
1678
149
    if (this == end)
1679
119
        return "";
1680
1681
30
    std::string ret;
1682
1683
30
    unsigned int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1U : 0U);
1684
    // cppcheck-suppress shadowFunction - TODO: fix this
1685
30
    unsigned int fileIndex = options.files ? ~0U : mImpl->mFileIndex;
1686
30
    std::map<int, unsigned int> lineNumbers;
1687
574
    for (const Token *tok = this; tok != end; tok = tok->next()) {
1688
544
        assert(tok && "end precedes token");
1689
544
        if (!tok)
1690
0
            return ret;
1691
544
        bool fileChange = false;
1692
544
        if (tok->mImpl->mFileIndex != fileIndex) {
1693
0
            if (fileIndex != ~0U) {
1694
0
                lineNumbers[fileIndex] = tok->mImpl->mFileIndex;
1695
0
            }
1696
1697
0
            fileIndex = tok->mImpl->mFileIndex;
1698
0
            if (options.files) {
1699
0
                ret += "\n\n##file ";
1700
0
                if (fileNames && fileNames->size() > tok->mImpl->mFileIndex)
1701
0
                    ret += fileNames->at(tok->mImpl->mFileIndex);
1702
0
                else
1703
0
                    ret += std::to_string(fileIndex);
1704
0
                ret += '\n';
1705
0
            }
1706
1707
0
            lineNumber = lineNumbers[fileIndex];
1708
0
            fileChange = true;
1709
0
        }
1710
1711
544
        if (options.linebreaks && (lineNumber != tok->linenr() || fileChange)) {
1712
0
            if (lineNumber+4 < tok->linenr() && fileIndex == tok->mImpl->mFileIndex) {
1713
0
                ret += '\n';
1714
0
                ret += std::to_string(lineNumber+1);
1715
0
                ret += ":\n|\n";
1716
0
                ret += std::to_string(tok->linenr()-1);
1717
0
                ret += ":\n";
1718
0
                ret += std::to_string(tok->linenr());
1719
0
                ret += ": ";
1720
0
            } else if (this == tok && options.linenumbers) {
1721
0
                ret += std::to_string(tok->linenr());
1722
0
                ret += ": ";
1723
0
            } else if (lineNumber > tok->linenr()) {
1724
0
                lineNumber = tok->linenr();
1725
0
                ret += '\n';
1726
0
                if (options.linenumbers) {
1727
0
                    ret += std::to_string(lineNumber);
1728
0
                    ret += ':';
1729
0
                    ret += ' ';
1730
0
                }
1731
0
            } else {
1732
0
                while (lineNumber < tok->linenr()) {
1733
0
                    ++lineNumber;
1734
0
                    ret += '\n';
1735
0
                    if (options.linenumbers) {
1736
0
                        ret += std::to_string(lineNumber);
1737
0
                        ret += ':';
1738
0
                        if (lineNumber == tok->linenr())
1739
0
                            ret += ' ';
1740
0
                    }
1741
0
                }
1742
0
            }
1743
0
            lineNumber = tok->linenr();
1744
0
        }
1745
1746
544
        ret += tok->stringify(options); // print token
1747
544
        if (tok->next() != end && (!options.linebreaks || (tok->next()->linenr() == tok->linenr() && tok->next()->fileIndex() == tok->fileIndex())))
1748
514
            ret += ' ';
1749
544
    }
1750
30
    if (options.linebreaks && (options.files || options.linenumbers))
1751
0
        ret += '\n';
1752
30
    return ret;
1753
30
}
1754
std::string Token::stringifyList(bool varid, bool attributes, bool linenumbers, bool linebreaks, bool files, const std::vector<std::string>* fileNames, const Token* end) const
1755
149
{
1756
149
    stringifyOptions options;
1757
149
    options.varid = varid;
1758
149
    options.attributes = attributes;
1759
149
    options.macro = attributes;
1760
149
    options.linenumbers = linenumbers;
1761
149
    options.linebreaks = linebreaks;
1762
149
    options.files = files;
1763
149
    return stringifyList(options, fileNames, end);
1764
149
}
1765
1766
std::string Token::stringifyList(const Token* end, bool attributes) const
1767
149
{
1768
149
    return stringifyList(false, attributes, false, false, false, nullptr, end);
1769
149
}
1770
1771
std::string Token::stringifyList(bool varid) const
1772
0
{
1773
0
    return stringifyList(varid, false, true, true, true, nullptr, nullptr);
1774
0
}
1775
1776
void Token::astParent(Token* tok)
1777
19.3k
{
1778
19.3k
    const Token* tok2 = tok;
1779
38.6k
    while (tok2) {
1780
19.3k
        if (this == tok2)
1781
0
            throw InternalError(this, "Internal error. AST cyclic dependency.");
1782
19.3k
        tok2 = tok2->astParent();
1783
19.3k
    }
1784
    // Clear children to avoid nodes referenced twice
1785
19.3k
    if (this->astParent()) {
1786
0
        Token* parent = this->astParent();
1787
0
        if (parent->astOperand1() == this)
1788
0
            parent->mImpl->mAstOperand1 = nullptr;
1789
0
        if (parent->astOperand2() == this)
1790
0
            parent->mImpl->mAstOperand2 = nullptr;
1791
0
    }
1792
19.3k
    mImpl->mAstParent = tok;
1793
19.3k
}
1794
1795
void Token::astOperand1(Token *tok)
1796
10.7k
{
1797
10.7k
    if (mImpl->mAstOperand1)
1798
0
        mImpl->mAstOperand1->astParent(nullptr);
1799
    // goto parent operator
1800
10.7k
    if (tok) {
1801
10.7k
        tok = tok->astTop();
1802
10.7k
        tok->astParent(this);
1803
10.7k
    }
1804
10.7k
    mImpl->mAstOperand1 = tok;
1805
10.7k
}
1806
1807
void Token::astOperand2(Token *tok)
1808
8.63k
{
1809
8.63k
    if (mImpl->mAstOperand2)
1810
0
        mImpl->mAstOperand2->astParent(nullptr);
1811
    // goto parent operator
1812
8.63k
    if (tok) {
1813
8.63k
        tok = tok->astTop();
1814
8.63k
        tok->astParent(this);
1815
8.63k
    }
1816
8.63k
    mImpl->mAstOperand2 = tok;
1817
8.63k
}
1818
1819
static const Token* goToLeftParenthesis(const Token* start, const Token* end)
1820
15.7k
{
1821
    // move start to lpar in such expression: '(*it).x'
1822
15.7k
    int par = 0;
1823
52.0k
    for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
1824
36.2k
        if (tok->str() == MatchCompiler::makeConstString("("))
1825
913
            ++par;
1826
35.3k
        else if (tok->str() == MatchCompiler::makeConstString(")")) {
1827
1.28k
            if (par == 0)
1828
852
                start = tok->link();
1829
428
            else
1830
428
                --par;
1831
1.28k
        }
1832
36.2k
    }
1833
15.7k
    return start;
1834
15.7k
}
1835
1836
static const Token* goToRightParenthesis(const Token* start, const Token* end)
1837
15.7k
{
1838
    // move end to rpar in such expression: '2>(x+1)'
1839
15.7k
    int par = 0;
1840
52.8k
    for (const Token *tok = end; tok && tok != start; tok = tok->previous()) {
1841
37.1k
        if (tok->str() == MatchCompiler::makeConstString(")"))
1842
1.28k
            ++par;
1843
35.8k
        else if (tok->str() == MatchCompiler::makeConstString("(")) {
1844
945
            if (par == 0)
1845
485
                end = tok->link();
1846
460
            else
1847
460
                --par;
1848
945
        }
1849
37.1k
    }
1850
15.7k
    return end;
1851
15.7k
}
1852
1853
std::pair<const Token *, const Token *> Token::findExpressionStartEndTokens() const
1854
15.7k
{
1855
15.7k
    const Token * const top = this;
1856
1857
    // find start node in AST tree
1858
15.7k
    const Token *start = top;
1859
28.0k
    while (start->astOperand1() && precedes(start->astOperand1(), start))
1860
12.2k
        start = start->astOperand1();
1861
1862
    // find end node in AST tree
1863
15.7k
    const Token *end = top;
1864
28.6k
    while (end->astOperand1() && (end->astOperand2() || end->isUnaryPreOp())) {
1865
        // lambda..
1866
12.8k
        if (end->str() == MatchCompiler::makeConstString("[")) {
1867
0
            const Token *lambdaEnd = findLambdaEndToken(end);
1868
0
            if (lambdaEnd) {
1869
0
                end = lambdaEnd;
1870
0
                break;
1871
0
            }
1872
0
        }
1873
12.8k
        if (match29(end) &&
1874
12.8k
            !(match30(end) && !end->astOperand2())) {
1875
0
            end = end->link();
1876
0
            break;
1877
0
        }
1878
12.8k
        end = end->astOperand2() ? end->astOperand2() : end->astOperand1();
1879
12.8k
    }
1880
1881
    // skip parentheses
1882
15.7k
    start = goToLeftParenthesis(start, end);
1883
15.7k
    end = goToRightParenthesis(start, end);
1884
15.7k
    if (match25(end))
1885
0
        end = end->link();
1886
1887
15.7k
    if (precedes(top, start))
1888
0
        throw InternalError(start, "Cannot find start of expression");
1889
15.7k
    if (succeeds(top, end))
1890
1
        throw InternalError(end, "Cannot find end of expression");
1891
1892
15.7k
    return std::pair<const Token *, const Token *>(start,end);
1893
15.7k
}
1894
1895
bool Token::isCalculation() const
1896
0
{
1897
0
    if (!match31(this))
1898
0
        return false;
1899
1900
0
    if (match32(this)) {
1901
        // dereference or address-of?
1902
0
        if (!this->astOperand2())
1903
0
            return false;
1904
1905
0
        if (this->astOperand2()->str() == MatchCompiler::makeConstString("["))
1906
0
            return false;
1907
1908
        // type specification?
1909
0
        std::stack<const Token *> operands;
1910
0
        operands.push(this);
1911
0
        while (!operands.empty()) {
1912
0
            const Token *op = operands.top();
1913
0
            operands.pop();
1914
0
            if (op->isNumber() || op->varId() > 0)
1915
0
                return true;
1916
0
            if (op->astOperand1())
1917
0
                operands.push(op->astOperand1());
1918
0
            if (op->astOperand2())
1919
0
                operands.push(op->astOperand2());
1920
0
            else if (match32(op))
1921
0
                return false;
1922
0
        }
1923
1924
        // type specification => return false
1925
0
        return false;
1926
0
    }
1927
1928
0
    return true;
1929
0
}
1930
1931
bool Token::isUnaryPreOp() const
1932
773
{
1933
773
    if (!astOperand1() || astOperand2())
1934
0
        return false;
1935
773
    if (this->tokType() != Token::eIncDecOp)
1936
270
        return true;
1937
503
    const Token *tokbefore = mPrevious;
1938
503
    const Token *tokafter = mNext;
1939
527
    for (int distance = 1; distance < 10 && tokbefore; distance++) {
1940
527
        if (tokbefore == mImpl->mAstOperand1)
1941
4
            return false;
1942
523
        if (tokafter == mImpl->mAstOperand1)
1943
499
            return true;
1944
24
        tokbefore = tokbefore->mPrevious;
1945
24
        tokafter  = tokafter->mPrevious;
1946
24
    }
1947
0
    return false; // <- guess
1948
503
}
1949
1950
static std::string stringFromTokenRange(const Token* start, const Token* end)
1951
10.9k
{
1952
10.9k
    std::string ret;
1953
10.9k
    if (end)
1954
10.9k
        end = end->next();
1955
53.2k
    for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
1956
42.3k
        if (tok->isUnsigned())
1957
0
            ret += "unsigned ";
1958
42.3k
        if (tok->isLong() && !tok->isLiteral())
1959
0
            ret += "long ";
1960
42.3k
        if (tok->tokType() == Token::eString) {
1961
0
            for (const unsigned char c: tok->str()) {
1962
0
                if (c == '\n')
1963
0
                    ret += "\\n";
1964
0
                else if (c == '\r')
1965
0
                    ret += "\\r";
1966
0
                else if (c == '\t')
1967
0
                    ret += "\\t";
1968
0
                else if (c >= ' ' && c <= 126)
1969
0
                    ret += c;
1970
0
                else {
1971
0
                    char str[10];
1972
0
                    sprintf(str, "\\x%02x", c);
1973
0
                    ret += str;
1974
0
                }
1975
0
            }
1976
42.3k
        } else if (tok->originalName().empty() || tok->isUnsigned() || tok->isLong()) {
1977
42.3k
            ret += tok->str();
1978
42.3k
        } else
1979
0
            ret += tok->originalName();
1980
42.3k
        if (match33(tok))
1981
0
            ret += ' ';
1982
42.3k
    }
1983
10.9k
    return ret;
1984
10.9k
}
1985
1986
std::string Token::expressionString() const
1987
10.9k
{
1988
10.9k
    const auto tokens = findExpressionStartEndTokens();
1989
10.9k
    return stringFromTokenRange(tokens.first, tokens.second);
1990
10.9k
}
1991
1992
static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out)
1993
0
{
1994
0
    const std::string strindent(indent, ' ');
1995
1996
0
    out << strindent << "<token str=\"" << tok->str() << '\"';
1997
0
    if (tok->varId())
1998
0
        out << " varId=\"" << tok->varId() << '\"';
1999
0
    if (tok->variable())
2000
0
        out << " variable=\"" << tok->variable() << '\"';
2001
0
    if (tok->function())
2002
0
        out << " function=\"" << tok->function() << '\"';
2003
0
    if (!tok->values().empty())
2004
0
        out << " values=\"" << &tok->values() << '\"';
2005
2006
0
    if (!tok->astOperand1() && !tok->astOperand2()) {
2007
0
        out << "/>" << std::endl;
2008
0
    }
2009
2010
0
    else {
2011
0
        out << '>' << std::endl;
2012
0
        if (tok->astOperand1())
2013
0
            astStringXml(tok->astOperand1(), indent+2U, out);
2014
0
        if (tok->astOperand2())
2015
0
            astStringXml(tok->astOperand2(), indent+2U, out);
2016
0
        out << strindent << "</token>" << std::endl;
2017
0
    }
2018
0
}
2019
2020
void Token::printAst(bool verbose, bool xml, const std::vector<std::string> &fileNames, std::ostream &out) const
2021
0
{
2022
0
    if (!xml)
2023
0
        out << "\n\n##AST" << std::endl;
2024
2025
0
    std::set<const Token *> printed;
2026
0
    for (const Token *tok = this; tok; tok = tok->next()) {
2027
0
        if (!tok->mImpl->mAstParent && tok->mImpl->mAstOperand1) {
2028
0
            if (printed.find(tok) != printed.end())
2029
0
                continue;
2030
0
            printed.insert(tok);
2031
2032
0
            if (xml) {
2033
0
                out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr()
2034
0
                    << "\" column=\"" << tok->column() << "\">" << std::endl;
2035
0
                astStringXml(tok, 2U, out);
2036
0
                out << "</ast>" << std::endl;
2037
0
            } else if (verbose)
2038
0
                out << "[" << fileNames[tok->fileIndex()] << ":" << tok->linenr() << "]" << std::endl << tok->astStringVerbose() << std::endl;
2039
0
            else
2040
0
                out << tok->astString(" ") << std::endl;
2041
0
            if (tok->str() == MatchCompiler::makeConstString("("))
2042
0
                tok = tok->link();
2043
0
        }
2044
0
    }
2045
0
}
2046
2047
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
2048
0
{
2049
0
    for (int i = 0; i < indent1; ++i)
2050
0
        str += ' ';
2051
0
    for (int i = indent1; i < indent2; i += 2)
2052
0
        str += "| ";
2053
0
}
2054
2055
void Token::astStringVerboseRecursive(std::string& ret, const nonneg int indent1, const nonneg int indent2) const
2056
0
{
2057
0
    if (isExpandedMacro())
2058
0
        ret += '$';
2059
0
    ret += mStr;
2060
0
    if (mImpl->mValueType)
2061
0
        ret += " \'" + mImpl->mValueType->str() + '\'';
2062
0
    if (function()) {
2063
0
        std::ostringstream ostr;
2064
0
        ostr << std::hex << function();
2065
0
        ret += " f:" + ostr.str();
2066
0
    }
2067
0
    ret += '\n';
2068
2069
0
    if (mImpl->mAstOperand1) {
2070
0
        int i1 = indent1, i2 = indent2 + 2;
2071
0
        if (indent1 == indent2 && !mImpl->mAstOperand2)
2072
0
            i1 += 2;
2073
0
        indent(ret, indent1, indent2);
2074
0
        ret += mImpl->mAstOperand2 ? "|-" : "`-";
2075
0
        mImpl->mAstOperand1->astStringVerboseRecursive(ret, i1, i2);
2076
0
    }
2077
0
    if (mImpl->mAstOperand2) {
2078
0
        int i1 = indent1, i2 = indent2 + 2;
2079
0
        if (indent1 == indent2)
2080
0
            i1 += 2;
2081
0
        indent(ret, indent1, indent2);
2082
0
        ret += "`-";
2083
0
        mImpl->mAstOperand2->astStringVerboseRecursive(ret, i1, i2);
2084
0
    }
2085
0
}
2086
2087
std::string Token::astStringVerbose() const
2088
0
{
2089
0
    std::string ret;
2090
0
    astStringVerboseRecursive(ret);
2091
0
    return ret;
2092
0
}
2093
2094
// cppcheck-suppress unusedFunction // used in test
2095
std::string Token::astStringZ3() const
2096
0
{
2097
0
    if (!astOperand1())
2098
0
        return str();
2099
0
    if (!astOperand2())
2100
0
        return "(" + str() + " " + astOperand1()->astStringZ3() + ")";
2101
0
    return "(" + str() + " " + astOperand1()->astStringZ3() + " " + astOperand2()->astStringZ3() + ")";
2102
0
}
2103
2104
void Token::printValueFlow(bool xml, std::ostream &out) const
2105
0
{
2106
0
    std::string outs;
2107
2108
    // cppcheck-suppress shadowFunction
2109
0
    int fileIndex = -1;
2110
0
    int line = 0;
2111
0
    if (xml)
2112
0
        outs += "  <valueflow>\n";
2113
0
    else
2114
0
        outs += "\n\n##Value flow\n";
2115
0
    for (const Token *tok = this; tok; tok = tok->next()) {
2116
        // cppcheck-suppress shadowFunction - TODO: fix this
2117
0
        const auto* const values = tok->mImpl->mValues;
2118
0
        if (!values)
2119
0
            continue;
2120
0
        if (values->empty()) // Values might be removed by removeContradictions
2121
0
            continue;
2122
0
        if (xml) {
2123
0
            outs += "    <values id=\"";
2124
0
            outs += id_string(values);
2125
0
            outs +=  "\">";
2126
0
            outs += '\n';
2127
0
        }
2128
0
        else {
2129
0
            if (fileIndex != tok->fileIndex()) {
2130
0
                outs += "File ";
2131
0
                outs += tok->mTokensFrontBack.list.getFiles()[tok->fileIndex()];
2132
0
                outs += '\n';
2133
0
                line = 0;
2134
0
            }
2135
0
            if (line != tok->linenr()) {
2136
0
                outs += "Line ";
2137
0
                outs += std::to_string(tok->linenr());
2138
0
                outs += '\n';
2139
0
            }
2140
0
        }
2141
0
        fileIndex = tok->fileIndex();
2142
0
        line = tok->linenr();
2143
0
        if (!xml) {
2144
0
            ValueFlow::Value::ValueKind valueKind = values->front().valueKind;
2145
0
            const bool same = std::all_of(values->begin(), values->end(), [&](const ValueFlow::Value& value) {
2146
0
                return value.valueKind == valueKind;
2147
0
            });
2148
0
            outs += "  ";
2149
0
            outs += tok->str();
2150
0
            outs += " ";
2151
0
            if (same) {
2152
0
                switch (valueKind) {
2153
0
                case ValueFlow::Value::ValueKind::Impossible:
2154
0
                case ValueFlow::Value::ValueKind::Known:
2155
0
                    outs += "always ";
2156
0
                    break;
2157
0
                case ValueFlow::Value::ValueKind::Inconclusive:
2158
0
                    outs += "inconclusive ";
2159
0
                    break;
2160
0
                case ValueFlow::Value::ValueKind::Possible:
2161
0
                    outs += "possible ";
2162
0
                    break;
2163
0
                }
2164
0
            }
2165
0
            if (values->size() > 1U)
2166
0
                outs += '{';
2167
0
        }
2168
0
        for (const ValueFlow::Value& value : *values) {
2169
0
            if (xml) {
2170
0
                outs += "      <value ";
2171
0
                switch (value.valueType) {
2172
0
                case ValueFlow::Value::ValueType::INT:
2173
0
                    if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED) {
2174
0
                        outs += "intvalue=\"";
2175
0
                        outs += MathLib::toString(static_cast<MathLib::biguint>(value.intvalue));
2176
0
                        outs += '\"';
2177
0
                    }
2178
0
                    else {
2179
0
                        outs += "intvalue=\"";
2180
0
                        outs += MathLib::toString(value.intvalue);
2181
0
                        outs += '\"';
2182
0
                    }
2183
0
                    break;
2184
0
                case ValueFlow::Value::ValueType::TOK:
2185
0
                    outs +=  "tokvalue=\"";
2186
0
                    outs += id_string(value.tokvalue);
2187
0
                    outs += '\"';
2188
0
                    break;
2189
0
                case ValueFlow::Value::ValueType::FLOAT:
2190
0
                    outs += "floatvalue=\"";
2191
0
                    outs += std::to_string(value.floatValue); // TODO: should this be MathLib::toString()?
2192
0
                    outs += '\"';
2193
0
                    break;
2194
0
                case ValueFlow::Value::ValueType::MOVED:
2195
0
                    outs += "movedvalue=\"";
2196
0
                    outs += ValueFlow::Value::toString(value.moveKind);
2197
0
                    outs += '\"';
2198
0
                    break;
2199
0
                case ValueFlow::Value::ValueType::UNINIT:
2200
0
                    outs +=  "uninit=\"1\"";
2201
0
                    break;
2202
0
                case ValueFlow::Value::ValueType::BUFFER_SIZE:
2203
0
                    outs += "buffer-size=\"";
2204
0
                    outs += MathLib::toString(value.intvalue);
2205
0
                    outs += "\"";
2206
0
                    break;
2207
0
                case ValueFlow::Value::ValueType::CONTAINER_SIZE:
2208
0
                    outs += "container-size=\"";
2209
0
                    outs += MathLib::toString(value.intvalue);
2210
0
                    outs += '\"';
2211
0
                    break;
2212
0
                case ValueFlow::Value::ValueType::ITERATOR_START:
2213
0
                    outs +=  "iterator-start=\"";
2214
0
                    outs += MathLib::toString(value.intvalue);
2215
0
                    outs += '\"';
2216
0
                    break;
2217
0
                case ValueFlow::Value::ValueType::ITERATOR_END:
2218
0
                    outs +=  "iterator-end=\"";
2219
0
                    outs += MathLib::toString(value.intvalue);
2220
0
                    outs += '\"';
2221
0
                    break;
2222
0
                case ValueFlow::Value::ValueType::LIFETIME:
2223
0
                    outs += "lifetime=\"";
2224
0
                    outs += id_string(value.tokvalue);
2225
0
                    outs += '\"';
2226
0
                    outs += " lifetime-scope=\"";
2227
0
                    outs += ValueFlow::Value::toString(value.lifetimeScope);
2228
0
                    outs += "\"";
2229
0
                    outs += " lifetime-kind=\"";
2230
0
                    outs += ValueFlow::Value::toString(value.lifetimeKind);
2231
0
                    outs += "\"";
2232
0
                    break;
2233
0
                case ValueFlow::Value::ValueType::SYMBOLIC:
2234
0
                    outs += "symbolic=\"";
2235
0
                    outs += id_string(value.tokvalue);
2236
0
                    outs += '\"';
2237
0
                    outs += " symbolic-delta=\"";
2238
0
                    outs += MathLib::toString(value.intvalue);
2239
0
                    outs += '\"';
2240
0
                    break;
2241
0
                }
2242
0
                outs += " bound=\"";
2243
0
                outs += ValueFlow::Value::toString(value.bound);
2244
0
                outs += "\"";
2245
0
                if (value.condition) {
2246
0
                    outs += " condition-line=\"";
2247
0
                    outs += std::to_string(value.condition->linenr());
2248
0
                    outs += '\"';
2249
0
                }
2250
0
                if (value.isKnown())
2251
0
                    outs += " known=\"true\"";
2252
0
                else if (value.isPossible())
2253
0
                    outs += " possible=\"true\"";
2254
0
                else if (value.isImpossible())
2255
0
                    outs += " impossible=\"true\"";
2256
0
                else if (value.isInconclusive())
2257
0
                    outs += " inconclusive=\"true\"";
2258
2259
0
                outs += " path=\"";
2260
0
                outs += MathLib::toString(value.path);
2261
0
                outs += "\"";
2262
2263
0
                outs += "/>\n";
2264
0
            }
2265
2266
0
            else {
2267
0
                if (&value != &values->front())
2268
0
                    outs += ",";
2269
0
                outs += value.toString();
2270
0
            }
2271
0
        }
2272
0
        if (xml)
2273
0
            outs += "    </values>\n";
2274
0
        else if (values->size() > 1U)
2275
0
            outs += "}\n";
2276
0
        else
2277
0
            outs += '\n';
2278
0
    }
2279
0
    if (xml)
2280
0
        outs += "  </valueflow>\n";
2281
2282
0
    out << outs;
2283
0
}
2284
2285
const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings &settings) const
2286
353
{
2287
353
    if (!mImpl->mValues)
2288
292
        return nullptr;
2289
63
    return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) {
2290
63
        return !v.isImpossible() && v.isIntValue() && v.intvalue <= val;
2291
63
    });
2292
353
}
2293
2294
const ValueFlow::Value * Token::getValueGE(const MathLib::bigint val, const Settings &settings) const
2295
353
{
2296
353
    if (!mImpl->mValues)
2297
292
        return nullptr;
2298
63
    return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) {
2299
63
        return !v.isImpossible() && v.isIntValue() && v.intvalue >= val;
2300
63
    });
2301
353
}
2302
2303
const ValueFlow::Value * Token::getValueNE(MathLib::bigint val) const
2304
0
{
2305
0
    if (!mImpl->mValues)
2306
0
        return nullptr;
2307
0
    const auto it = std::find_if(mImpl->mValues->cbegin(), mImpl->mValues->cend(), [=](const ValueFlow::Value& value) {
2308
0
        return value.isIntValue() && !value.isImpossible() && value.intvalue != val;
2309
0
    });
2310
0
    return it == mImpl->mValues->end() ? nullptr : &*it;
2311
0
}
2312
2313
const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, nonneg int argnr, const Settings &settings) const
2314
647
{
2315
647
    if (!mImpl->mValues)
2316
62
        return nullptr;
2317
585
    const ValueFlow::Value *ret = nullptr;
2318
1.61k
    for (auto it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2319
1.03k
        if (it->isImpossible())
2320
885
            continue;
2321
146
        if ((it->isIntValue() && !settings.library.isIntArgValid(ftok, argnr, it->intvalue)) ||
2322
146
            (it->isFloatValue() && !settings.library.isFloatArgValid(ftok, argnr, it->floatValue))) {
2323
0
            if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive()))
2324
0
                ret = &(*it);
2325
0
            if (!ret->isInconclusive() && !ret->condition)
2326
0
                break;
2327
0
        }
2328
146
    }
2329
585
    if (ret) {
2330
0
        if (ret->isInconclusive() && !settings.certainty.isEnabled(Certainty::inconclusive))
2331
0
            return nullptr;
2332
0
        if (ret->condition && !settings.severity.isEnabled(Severity::warning))
2333
0
            return nullptr;
2334
0
    }
2335
585
    return ret;
2336
585
}
2337
2338
const Token *Token::getValueTokenMinStrSize(const Settings &settings, MathLib::bigint* path) const
2339
0
{
2340
0
    if (!mImpl->mValues)
2341
0
        return nullptr;
2342
0
    const Token *ret = nullptr;
2343
0
    int minsize = INT_MAX;
2344
0
    for (auto it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2345
0
        if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) {
2346
0
            const int size = getStrSize(it->tokvalue, settings);
2347
0
            if (!ret || size < minsize) {
2348
0
                minsize = size;
2349
0
                ret = it->tokvalue;
2350
0
                if (path)
2351
0
                    *path = it->path;
2352
0
            }
2353
0
        }
2354
0
    }
2355
0
    return ret;
2356
0
}
2357
2358
const Token *Token::getValueTokenMaxStrLength() const
2359
0
{
2360
0
    if (!mImpl->mValues)
2361
0
        return nullptr;
2362
0
    const Token *ret = nullptr;
2363
0
    int maxlength = 0;
2364
0
    for (auto it = mImpl->mValues->cbegin(); it != mImpl->mValues->end(); ++it) {
2365
0
        if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) {
2366
0
            const int length = getStrLength(it->tokvalue);
2367
0
            if (!ret || length > maxlength) {
2368
0
                maxlength = length;
2369
0
                ret = it->tokvalue;
2370
0
            }
2371
0
        }
2372
0
    }
2373
0
    return ret;
2374
0
}
2375
2376
static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y)
2377
1.62k
{
2378
1.62k
    if (x.bound != ValueFlow::Value::Bound::Point && x.bound == y.bound)
2379
0
        return true;
2380
1.62k
    if (x.valueType == ValueFlow::Value::ValueType::FLOAT)
2381
0
        return false;
2382
1.62k
    return std::abs(x.intvalue - y.intvalue) == 1;
2383
1.62k
}
2384
2385
static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x)
2386
0
{
2387
0
    const bool isPoint = x->bound == ValueFlow::Value::Bound::Point;
2388
0
    if (!isPoint)
2389
0
        x->decreaseRange();
2390
0
    else
2391
0
        x = values.erase(x);
2392
0
    return isPoint;
2393
0
}
2394
2395
static bool removeContradiction(std::list<ValueFlow::Value>& values)
2396
11.1k
{
2397
11.1k
    bool result = false;
2398
23.2k
    for (auto itx = values.begin(); itx != values.end(); ++itx) {
2399
12.0k
        if (itx->isNonValue())
2400
10
            continue;
2401
2402
12.0k
        auto ity = itx;
2403
12.0k
        ++ity;
2404
12.9k
        for (; ity != values.end(); ++ity) {
2405
918
            if (ity->isNonValue())
2406
0
                continue;
2407
918
            if (*itx == *ity)
2408
0
                continue;
2409
918
            if (itx->valueType != ity->valueType)
2410
10
                continue;
2411
908
            if (itx->isImpossible() == ity->isImpossible())
2412
845
                continue;
2413
63
            if (itx->isSymbolicValue() && !ValueFlow::Value::sameToken(itx->tokvalue, ity->tokvalue))
2414
0
                continue;
2415
63
            if (!itx->equalValue(*ity)) {
2416
126
                auto compare = [](const std::list<ValueFlow::Value>::const_iterator& x, const std::list<ValueFlow::Value>::const_iterator& y) {
2417
126
                    return x->compareValue(*y, less{});
2418
126
                };
2419
63
                auto itMax = std::max(itx, ity, compare);
2420
63
                auto itMin = std::min(itx, ity, compare);
2421
                // TODO: Adjust non-points instead of removing them
2422
63
                if (itMax->isImpossible() && itMax->bound == ValueFlow::Value::Bound::Upper) {
2423
0
                    values.erase(itMin);
2424
0
                    return true;
2425
0
                }
2426
63
                if (itMin->isImpossible() && itMin->bound == ValueFlow::Value::Bound::Lower) {
2427
0
                    values.erase(itMax);
2428
0
                    return true;
2429
0
                }
2430
63
                continue;
2431
63
            }
2432
0
            const bool removex = !itx->isImpossible() || ity->isKnown();
2433
0
            const bool removey = !ity->isImpossible() || itx->isKnown();
2434
0
            if (itx->bound == ity->bound) {
2435
0
                if (removex)
2436
0
                    values.erase(itx);
2437
0
                if (removey)
2438
0
                    values.erase(ity);
2439
                // itx and ity are invalidated
2440
0
                return true;
2441
0
            }
2442
0
            result = removex || removey;
2443
0
            bool bail = false;
2444
0
            if (removex && removePointValue(values, itx))
2445
0
                bail = true;
2446
0
            if (removey && removePointValue(values, ity))
2447
0
                bail = true;
2448
0
            if (bail)
2449
0
                return true;
2450
0
        }
2451
12.0k
    }
2452
11.1k
    return result;
2453
11.1k
}
2454
2455
using ValueIterator = std::list<ValueFlow::Value>::iterator;
2456
2457
template<class Iterator>
2458
// NOLINTNEXTLINE(performance-unnecessary-value-param) - false positive
2459
static ValueIterator removeAdjacentValues(std::list<ValueFlow::Value>& values, ValueIterator x, Iterator start, Iterator last)
2460
0
{
2461
0
    if (!isAdjacent(*x, **start))
2462
0
        return std::next(x);
2463
0
    auto it = std::adjacent_find(start, last, [](ValueIterator x, ValueIterator y) {
2464
0
        return !isAdjacent(*x, *y);
2465
0
    });
Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>) const
Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__list_iterator<ValueFlow::Value, void*>) const
2466
0
    if (it == last)
2467
0
        it--;
2468
0
    (*it)->bound = x->bound;
2469
0
    std::for_each(std::move(start), std::move(it), [&](ValueIterator y) {
2470
0
        values.erase(y);
2471
0
    });
Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>) const
Unexecuted instantiation: token.cpp:removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>)::{lambda(std::__1::__list_iterator<ValueFlow::Value, void*>)#1}::operator()(std::__1::__list_iterator<ValueFlow::Value, void*>) const
2472
0
    return values.erase(x);
2473
0
}
Unexecuted instantiation: token.cpp:std::__1::__list_iterator<ValueFlow::Value, void*> removeAdjacentValues<std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> > >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >, std::__1::reverse_iterator<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >)
Unexecuted instantiation: token.cpp:std::__1::__list_iterator<ValueFlow::Value, void*> removeAdjacentValues<std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> >&, std::__1::__list_iterator<ValueFlow::Value, void*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>, std::__1::__wrap_iter<std::__1::__list_iterator<ValueFlow::Value, void*>*>)
2474
2475
static void mergeAdjacent(std::list<ValueFlow::Value>& values)
2476
11.1k
{
2477
23.2k
    for (auto x = values.begin(); x != values.end();) {
2478
12.0k
        if (x->isNonValue()) {
2479
10
            x++;
2480
10
            continue;
2481
10
        }
2482
12.0k
        if (x->bound == ValueFlow::Value::Bound::Point) {
2483
9.44k
            x++;
2484
9.44k
            continue;
2485
9.44k
        }
2486
2.60k
        std::vector<ValueIterator> adjValues;
2487
6.96k
        for (auto y = values.begin(); y != values.end(); y++) {
2488
4.35k
            if (x == y)
2489
2.60k
                continue;
2490
1.75k
            if (y->isNonValue())
2491
0
                continue;
2492
1.75k
            if (x->valueType != y->valueType)
2493
16
                continue;
2494
1.73k
            if (x->valueKind != y->valueKind)
2495
115
                continue;
2496
1.62k
            if (x->isSymbolicValue() && !ValueFlow::Value::sameToken(x->tokvalue, y->tokvalue))
2497
0
                continue;
2498
1.62k
            if (x->bound != y->bound) {
2499
1.62k
                if (y->bound != ValueFlow::Value::Bound::Point && isAdjacent(*x, *y)) {
2500
0
                    adjValues.clear();
2501
0
                    break;
2502
0
                }
2503
                // No adjacent points for floating points
2504
1.62k
                if (x->valueType == ValueFlow::Value::ValueType::FLOAT)
2505
0
                    continue;
2506
1.62k
                if (y->bound != ValueFlow::Value::Bound::Point)
2507
1.62k
                    continue;
2508
1.62k
            }
2509
0
            if (x->bound == ValueFlow::Value::Bound::Lower && !y->compareValue(*x, less{}))
2510
0
                continue;
2511
0
            if (x->bound == ValueFlow::Value::Bound::Upper && !x->compareValue(*y, less{}))
2512
0
                continue;
2513
0
            adjValues.push_back(y);
2514
0
        }
2515
2.60k
        if (adjValues.empty()) {
2516
2.60k
            x++;
2517
2.60k
            continue;
2518
2.60k
        }
2519
0
        std::sort(adjValues.begin(), adjValues.end(), [&values](ValueIterator xx, ValueIterator yy) {
2520
0
            (void)values;
2521
0
            assert(xx != values.end() && yy != values.end());
2522
0
            return xx->compareValue(*yy, less{});
2523
0
        });
2524
0
        if (x->bound == ValueFlow::Value::Bound::Lower)
2525
0
            x = removeAdjacentValues(values, x, adjValues.rbegin(), adjValues.rend());
2526
0
        else if (x->bound == ValueFlow::Value::Bound::Upper)
2527
0
            x = removeAdjacentValues(values, x, adjValues.begin(), adjValues.end());
2528
0
    }
2529
11.1k
}
2530
2531
static void removeOverlaps(std::list<ValueFlow::Value>& values)
2532
11.1k
{
2533
12.0k
    for (const ValueFlow::Value& x : values) {
2534
12.0k
        if (x.isNonValue())
2535
10
            continue;
2536
13.8k
        values.remove_if([&](const ValueFlow::Value& y) {
2537
13.8k
            if (y.isNonValue())
2538
4
                return false;
2539
13.8k
            if (&x == &y)
2540
12.0k
                return false;
2541
1.83k
            if (x.valueType != y.valueType)
2542
20
                return false;
2543
1.81k
            if (x.valueKind != y.valueKind)
2544
126
                return false;
2545
            // TODO: Remove points covered in a lower or upper bound
2546
            // TODO: Remove lower or upper bound already covered by a lower and upper bound
2547
1.69k
            if (!x.equalValue(y))
2548
1.69k
                return false;
2549
0
            if (x.bound != y.bound)
2550
0
                return false;
2551
0
            return true;
2552
0
        });
2553
12.0k
    }
2554
11.1k
    mergeAdjacent(values);
2555
11.1k
}
2556
2557
// Removing contradictions is an NP-hard problem. Instead we run multiple
2558
// passes to try to catch most contradictions
2559
static void removeContradictions(std::list<ValueFlow::Value>& values)
2560
11.1k
{
2561
11.1k
    removeOverlaps(values);
2562
11.1k
    for (int i = 0; i < 4; i++) {
2563
11.1k
        if (!removeContradiction(values))
2564
11.1k
            return;
2565
0
        removeOverlaps(values);
2566
0
    }
2567
11.1k
}
2568
2569
static bool sameValueType(const ValueFlow::Value& x, const ValueFlow::Value& y)
2570
164
{
2571
164
    if (x.valueType != y.valueType)
2572
0
        return false;
2573
    // Symbolic are the same type if they share the same tokvalue
2574
164
    if (x.isSymbolicValue())
2575
106
        return x.tokvalue->exprId() == 0 || x.tokvalue->exprId() == y.tokvalue->exprId();
2576
58
    return true;
2577
164
}
2578
2579
bool Token::addValue(const ValueFlow::Value &value)
2580
12.9k
{
2581
12.9k
    if (value.isKnown() && mImpl->mValues) {
2582
        // Clear all other values of the same type since value is known
2583
156
        mImpl->mValues->remove_if([&](const ValueFlow::Value& x) {
2584
156
            return sameValueType(x, value);
2585
156
        });
2586
136
    }
2587
2588
    // Don't add a value if its already known
2589
12.9k
    if (!value.isKnown() && mImpl->mValues &&
2590
12.9k
        std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& x) {
2591
4.25k
        return x.isKnown() && sameValueType(x, value) && !x.equalValue(value);
2592
4.25k
    }))
2593
0
        return false;
2594
2595
    // assert(value.isKnown() || !mImpl->mValues || std::none_of(mImpl->mValues->begin(), mImpl->mValues->end(),
2596
    // [&](const ValueFlow::Value& x) {
2597
    //     return x.isKnown() && sameValueType(x, value);
2598
    // }));
2599
2600
12.9k
    if (mImpl->mValues) {
2601
        // Don't handle more than 10 values for performance reasons
2602
        // TODO: add setting?
2603
2.81k
        if (mImpl->mValues->size() >= 10U)
2604
0
            return false;
2605
2606
        // if value already exists, don't add it again
2607
2.81k
        auto it = mImpl->mValues->begin();
2608
4.50k
        for (; it != mImpl->mValues->end(); ++it) {
2609
            // different types => continue
2610
3.49k
            if (it->valueType != value.valueType)
2611
18
                continue;
2612
2613
3.47k
            if (it->isImpossible() != value.isImpossible())
2614
108
                continue;
2615
2616
            // different value => continue
2617
3.36k
            if (!it->equalValue(value))
2618
1.57k
                continue;
2619
2620
1.79k
            if ((value.isTokValue() || value.isLifetimeValue()) && (it->tokvalue != value.tokvalue) && (it->tokvalue->str() != value.tokvalue->str()))
2621
0
                continue;
2622
2623
            // same value, but old value is inconclusive so replace it
2624
1.79k
            if (it->isInconclusive() && !value.isInconclusive() && !value.isImpossible()) {
2625
0
                *it = value;
2626
0
                if (it->varId == 0)
2627
0
                    it->varId = mImpl->mVarId;
2628
0
                break;
2629
0
            }
2630
2631
            // Same value already exists, don't  add new value
2632
1.79k
            return false;
2633
1.79k
        }
2634
2635
        // Add value
2636
1.01k
        if (it == mImpl->mValues->end()) {
2637
1.01k
            ValueFlow::Value v(value);
2638
1.01k
            if (v.varId == 0)
2639
1.00k
                v.varId = mImpl->mVarId;
2640
1.01k
            if (v.isKnown() && v.isIntValue())
2641
48
                mImpl->mValues->push_front(std::move(v));
2642
968
            else
2643
968
                mImpl->mValues->push_back(std::move(v));
2644
1.01k
        }
2645
10.1k
    } else {
2646
10.1k
        ValueFlow::Value v(value);
2647
10.1k
        if (v.varId == 0)
2648
10.1k
            v.varId = mImpl->mVarId;
2649
10.1k
        mImpl->mValues = new std::list<ValueFlow::Value>;
2650
10.1k
        mImpl->mValues->push_back(std::move(v));
2651
10.1k
    }
2652
2653
11.1k
    removeContradictions(*mImpl->mValues);
2654
2655
11.1k
    return true;
2656
12.9k
}
2657
2658
void Token::assignProgressValues(Token *tok)
2659
1.65k
{
2660
1.65k
    int total_count = 0;
2661
114k
    for (Token *tok2 = tok; tok2; tok2 = tok2->next())
2662
113k
        ++total_count;
2663
1.65k
    int count = 0;
2664
114k
    for (Token *tok2 = tok; tok2; tok2 = tok2->next())
2665
113k
        tok2->mImpl->mProgressValue = count++ *100 / total_count;
2666
1.65k
}
2667
2668
void Token::assignIndexes()
2669
790
{
2670
    // cppcheck-suppress shadowFunction - TODO: fix this
2671
790
    int index = (mPrevious ? mPrevious->mImpl->mIndex : 0) + 1;
2672
57.6k
    for (Token *tok = this; tok; tok = tok->next())
2673
56.8k
        tok->mImpl->mIndex = index++;
2674
790
}
2675
2676
void Token::setValueType(ValueType *vt)
2677
372k
{
2678
372k
    if (vt != mImpl->mValueType) {
2679
196k
        delete mImpl->mValueType;
2680
196k
        mImpl->mValueType = vt;
2681
196k
    }
2682
372k
}
2683
2684
0
const ValueType *Token::argumentType() const {
2685
0
    const Token *top = this;
2686
0
    while (top && !match34(top->astParent()))
2687
0
        top = top->astParent();
2688
0
    return top ? top->mImpl->mValueType : nullptr;
2689
0
}
2690
2691
void Token::type(const ::Type *t)
2692
58.7k
{
2693
58.7k
    mImpl->mType = t;
2694
58.7k
    if (t) {
2695
0
        tokType(eType);
2696
0
        isEnumType(mImpl->mType->isEnumType());
2697
58.7k
    } else if (mTokType == eType)
2698
4.92k
        tokType(eName);
2699
58.7k
}
2700
2701
const ::Type* Token::typeOf(const Token* tok, const Token** typeTok)
2702
5.45k
{
2703
5.45k
    if (!tok)
2704
0
        return nullptr;
2705
5.45k
    if (typeTok != nullptr)
2706
2
        *typeTok = tok;
2707
5.45k
    const Token* lhsVarTok{};
2708
5.45k
    if (tok->type())
2709
0
        return tok->type();
2710
5.45k
    if (tok->variable())
2711
1.47k
        return tok->variable()->type();
2712
3.98k
    if (tok->function())
2713
0
        return tok->function()->retType;
2714
3.98k
    if (match35(tok)) {
2715
        // cppcheck-suppress shadowFunction - TODO: fix this
2716
1
        const Scope *scope = tok->scope();
2717
1
        if (!scope)
2718
0
            return nullptr;
2719
        // cppcheck-suppress shadowFunction - TODO: fix this
2720
1
        const Function *function = scope->function;
2721
1
        if (!function)
2722
0
            return nullptr;
2723
1
        return function->retType;
2724
1
    }
2725
3.98k
    if (match36(tok->previous()))
2726
0
        return typeOf(tok->previous(), typeTok);
2727
3.98k
    if (match37(tok) && (lhsVarTok = getLHSVariableToken(tok)) != tok->next())
2728
0
        return Token::typeOf(lhsVarTok, typeTok);
2729
3.98k
    if (match38(tok))
2730
0
        return Token::typeOf(tok->astOperand2(), typeTok);
2731
3.98k
    if (match39(tok))
2732
0
        return Token::typeOf(tok->astOperand1(), typeTok);
2733
3.98k
    if (match25(tok)) {
2734
0
        int argnr;
2735
0
        const Token* ftok = getTokenArgumentFunction(tok, argnr);
2736
0
        if (argnr < 0)
2737
0
            return nullptr;
2738
0
        if (!ftok)
2739
0
            return nullptr;
2740
0
        if (ftok == tok)
2741
0
            return nullptr;
2742
0
        std::vector<const Variable*> vars = getArgumentVars(ftok, argnr);
2743
0
        if (vars.empty())
2744
0
            return nullptr;
2745
0
        if (std::all_of(
2746
0
                vars.cbegin(), vars.cend(), [&](const Variable* var) {
2747
0
            return var->type() == vars.front()->type();
2748
0
        }))
2749
0
            return vars.front()->type();
2750
0
    }
2751
2752
3.98k
    return nullptr;
2753
3.98k
}
2754
2755
std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool pointedToType)
2756
3.46k
{
2757
3.46k
    if (!tok)
2758
0
        return {};
2759
3.46k
    if (tok->type())
2760
0
        return {tok, tok->next()};
2761
3.46k
    if (tok->variable()) {
2762
1.47k
        const Variable *var = tok->variable();
2763
1.47k
        if (!var->typeStartToken() || !var->typeEndToken())
2764
0
            return {};
2765
1.47k
        if (pointedToType && astIsSmartPointer(var->nameToken())) {
2766
0
            const ValueType* vt = var->valueType();
2767
0
            if (vt && vt->smartPointerTypeToken)
2768
0
                return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
2769
0
        }
2770
1.47k
        if (pointedToType && astIsIterator(var->nameToken())) {
2771
0
            const ValueType* vt = var->valueType();
2772
0
            if (vt && vt->containerTypeToken)
2773
0
                return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2774
0
        }
2775
1.47k
        std::pair<const Token*, const Token*> result;
2776
1.47k
        if (match40(var->typeStartToken())) {
2777
0
            const Token * tok2 = var->declEndToken();
2778
0
            if (match41(tok2, var->declarationId()))
2779
0
                tok2 = tok2->tokAt(2);
2780
0
            if (match37(tok2) && match42(tok2->astOperand2()) && tok != tok2->astOperand2()) {
2781
0
                tok2 = tok2->astOperand2();
2782
2783
0
                if (match39(tok2) && tok2->astOperand1()) {
2784
0
                    const ValueType* vt = tok2->astOperand1()->valueType();
2785
0
                    if (vt && vt->containerTypeToken)
2786
0
                        return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2787
0
                }
2788
2789
0
                const Token* varTok = tok2; // try to find a variable
2790
0
                if (match21(varTok))
2791
0
                    varTok = varTok->next();
2792
0
                while (match43(varTok))
2793
0
                    varTok = varTok->tokAt(2);
2794
0
                std::pair<const Token*, const Token*> r = typeDecl(varTok);
2795
0
                if (r.first)
2796
0
                    return r;
2797
2798
0
                if (pointedToType && tok2->astOperand1() && match44(tok2)) {
2799
0
                    if (match45(tok2->astOperand1()))
2800
0
                        return { tok2->next(), tok2->astOperand1() };
2801
0
                    const Token* declEnd = nextAfterAstRightmostLeaf(tok2->astOperand1());
2802
0
                    if (match46(declEnd) && declEnd->link())
2803
0
                        declEnd = declEnd->link()->next();
2804
0
                    return { tok2->next(), declEnd };
2805
0
                }
2806
0
                const Token *typeBeg{}, *typeEnd{};
2807
0
                if (tok2->str() == MatchCompiler::makeConstString("::") && match25(tok2->astOperand2())) { // empty initlist
2808
0
                    typeBeg = previousBeforeAstLeftmostLeaf(tok2);
2809
0
                    typeEnd = tok2->astOperand2();
2810
0
                }
2811
0
                else if (tok2->str() == MatchCompiler::makeConstString("{")) {
2812
0
                    typeBeg = previousBeforeAstLeftmostLeaf(tok2);
2813
0
                    typeEnd = tok2;
2814
0
                }
2815
0
                if (typeBeg)
2816
0
                    result = { typeBeg->next(), typeEnd }; // handle smart pointers/iterators first
2817
0
            }
2818
0
            if (astIsRangeBasedForDecl(var->nameToken()) && astIsContainer(var->nameToken()->astParent()->astOperand2())) { // range-based for
2819
0
                const ValueType* vt = var->nameToken()->astParent()->astOperand2()->valueType();
2820
0
                if (vt && vt->containerTypeToken)
2821
0
                    return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2822
0
            }
2823
0
        }
2824
1.47k
        if (result.first)
2825
0
            return result;
2826
1.47k
        return {var->typeStartToken(), var->typeEndToken()->next()};
2827
1.47k
    }
2828
1.99k
    if (match35(tok)) {
2829
        // cppcheck-suppress shadowFunction - TODO: fix this
2830
1
        const Scope* scope = tok->scope();
2831
1
        if (!scope)
2832
0
            return {};
2833
        // cppcheck-suppress shadowFunction - TODO: fix this
2834
1
        const Function* function = scope->function;
2835
1
        if (!function)
2836
0
            return {};
2837
1
        return { function->retDef, function->returnDefEnd() };
2838
1
    }
2839
1.99k
    if (tok->previous() && tok->previous()->function()) {
2840
        // cppcheck-suppress shadowFunction - TODO: fix this
2841
0
        const Function *function = tok->previous()->function();
2842
0
        return {function->retDef, function->returnDefEnd()};
2843
0
    }
2844
1.99k
    if (match37(tok))
2845
0
        return Token::typeDecl(tok->astOperand1());
2846
1.99k
    if (match38(tok))
2847
0
        return Token::typeDecl(tok->astOperand2());
2848
2849
1.99k
    const ::Type * t = typeOf(tok);
2850
1.99k
    if (!t || !t->classDef)
2851
1.99k
        return {};
2852
0
    return {t->classDef->next(), t->classDef->tokAt(2)};
2853
1.99k
}
2854
std::string Token::typeStr(const Token* tok)
2855
0
{
2856
0
    if (tok->valueType()) {
2857
0
        const ValueType * vt = tok->valueType();
2858
0
        std::string ret = vt->str();
2859
0
        if (!ret.empty())
2860
0
            return ret;
2861
0
    }
2862
0
    std::pair<const Token*, const Token*> r = Token::typeDecl(tok);
2863
0
    if (!r.first || !r.second)
2864
0
        return "";
2865
0
    return r.first->stringifyList(r.second, false);
2866
0
}
2867
2868
void Token::scopeInfo(std::shared_ptr<ScopeInfo2> newScopeInfo)
2869
115k
{
2870
115k
    mImpl->mScopeInfo = std::move(newScopeInfo);
2871
115k
}
2872
std::shared_ptr<ScopeInfo2> Token::scopeInfo() const
2873
116k
{
2874
116k
    return mImpl->mScopeInfo;
2875
116k
}
2876
2877
bool Token::hasKnownIntValue() const
2878
533k
{
2879
533k
    if (!mImpl->mValues)
2880
432k
        return false;
2881
129k
    return std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) {
2882
129k
        return value.isKnown() && value.isIntValue();
2883
129k
    });
2884
533k
}
2885
2886
bool Token::hasKnownValue() const
2887
564
{
2888
564
    return mImpl->mValues && std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown));
2889
564
}
2890
2891
bool Token::hasKnownValue(ValueFlow::Value::ValueType t) const
2892
0
{
2893
0
    return mImpl->mValues &&
2894
0
           std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2895
0
        return value.isKnown() && value.valueType == t;
2896
0
    });
2897
0
}
2898
2899
bool Token::hasKnownSymbolicValue(const Token* tok) const
2900
5.87k
{
2901
5.87k
    if (tok->exprId() == 0)
2902
0
        return false;
2903
5.87k
    return mImpl->mValues &&
2904
5.87k
           std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2905
935
        return value.isKnown() && value.isSymbolicValue() && value.tokvalue &&
2906
935
        value.tokvalue->exprId() == tok->exprId();
2907
935
    });
2908
5.87k
}
2909
2910
const ValueFlow::Value* Token::getKnownValue(ValueFlow::Value::ValueType t) const
2911
109k
{
2912
109k
    if (!mImpl->mValues)
2913
69.6k
        return nullptr;
2914
72.1k
    auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2915
72.1k
        return value.isKnown() && value.valueType == t;
2916
72.1k
    });
2917
40.3k
    return it == mImpl->mValues->end() ? nullptr : &*it;
2918
109k
}
2919
2920
const ValueFlow::Value* Token::getValue(const MathLib::bigint val) const
2921
3.87k
{
2922
3.87k
    if (!mImpl->mValues)
2923
3.35k
        return nullptr;
2924
770
    const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) {
2925
770
        return value.isIntValue() && !value.isImpossible() && value.intvalue == val;
2926
770
    });
2927
526
    return it == mImpl->mValues->end() ? nullptr : &*it;
2928
3.87k
}
2929
2930
template<class Compare>
2931
static const ValueFlow::Value* getCompareValue(const std::list<ValueFlow::Value>& values,
2932
                                               bool condition,
2933
                                               MathLib::bigint path,
2934
                                               Compare compare)
2935
0
{
2936
0
    const ValueFlow::Value* ret = nullptr;
2937
0
    for (const ValueFlow::Value& value : values) {
2938
0
        if (!value.isIntValue())
2939
0
            continue;
2940
0
        if (value.isImpossible())
2941
0
            continue;
2942
0
        if (path > -0 && value.path != 0 && value.path != path)
2943
0
            continue;
2944
0
        if ((!ret || compare(value.intvalue, ret->intvalue)) && ((value.condition != nullptr) == condition))
2945
0
            ret = &value;
2946
0
    }
2947
0
    return ret;
2948
0
}
Unexecuted instantiation: token.cpp:ValueFlow::Value const* getCompareValue<std::__1::greater<long long> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> > const&, bool, long long, std::__1::greater<long long>)
Unexecuted instantiation: token.cpp:ValueFlow::Value const* getCompareValue<std::__1::less<long long> >(std::__1::list<ValueFlow::Value, std::__1::allocator<ValueFlow::Value> > const&, bool, long long, std::__1::less<long long>)
2949
2950
const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const
2951
0
{
2952
0
    if (!mImpl->mValues)
2953
0
        return nullptr;
2954
0
    return getCompareValue(*mImpl->mValues, condition, path, std::greater<MathLib::bigint>{});
2955
0
}
2956
2957
const ValueFlow::Value* Token::getMinValue(bool condition, MathLib::bigint path) const
2958
0
{
2959
0
    if (!mImpl->mValues)
2960
0
        return nullptr;
2961
0
    return getCompareValue(*mImpl->mValues, condition, path, std::less<MathLib::bigint>{});
2962
0
}
2963
2964
const ValueFlow::Value* Token::getMovedValue() const
2965
11.0k
{
2966
11.0k
    if (!mImpl->mValues)
2967
8.82k
        return nullptr;
2968
3.05k
    const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) {
2969
3.05k
        return value.isMovedValue() && !value.isImpossible() &&
2970
3.05k
        value.moveKind != ValueFlow::Value::MoveKind::NonMovedVariable;
2971
3.05k
    });
2972
2.23k
    return it == mImpl->mValues->end() ? nullptr : &*it;
2973
11.0k
}
2974
2975
// cppcheck-suppress unusedFunction
2976
const ValueFlow::Value* Token::getContainerSizeValue(const MathLib::bigint val) const
2977
0
{
2978
0
    if (!mImpl->mValues)
2979
0
        return nullptr;
2980
0
    const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) {
2981
0
        return value.isContainerSizeValue() && !value.isImpossible() && value.intvalue == val;
2982
0
    });
2983
0
    return it == mImpl->mValues->end() ? nullptr : &*it;
2984
0
}
2985
2986
TokenImpl::~TokenImpl()
2987
64.1k
{
2988
64.1k
    delete mOriginalName;
2989
64.1k
    delete mValueType;
2990
64.1k
    delete mValues;
2991
2992
64.1k
    if (mTemplateSimplifierPointers) {
2993
0
        for (auto *templateSimplifierPointer : *mTemplateSimplifierPointers) {
2994
0
            templateSimplifierPointer->token(nullptr);
2995
0
        }
2996
0
    }
2997
64.1k
    delete mTemplateSimplifierPointers;
2998
2999
64.1k
    while (mCppcheckAttributes) {
3000
0
        CppcheckAttributes *c = mCppcheckAttributes;
3001
0
        mCppcheckAttributes = mCppcheckAttributes->next;
3002
0
        delete c;
3003
0
    }
3004
64.1k
}
3005
3006
void TokenImpl::setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value)
3007
0
{
3008
0
    CppcheckAttributes *attr = mCppcheckAttributes;
3009
0
    while (attr && attr->type != type)
3010
0
        attr = attr->next;
3011
0
    if (attr)
3012
0
        attr->value = value;
3013
0
    else {
3014
0
        attr = new CppcheckAttributes;
3015
0
        attr->type = type;
3016
0
        attr->value = value;
3017
0
        attr->next = mCppcheckAttributes;
3018
0
        mCppcheckAttributes = attr;
3019
0
    }
3020
0
}
3021
3022
bool TokenImpl::getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint &value) const
3023
0
{
3024
0
    CppcheckAttributes *attr = mCppcheckAttributes;
3025
0
    while (attr && attr->type != type)
3026
0
        attr = attr->next;
3027
0
    if (attr)
3028
0
        value = attr->value;
3029
0
    return attr != nullptr;
3030
0
}
3031
3032
Token* findTypeEnd(Token* tok)
3033
0
{
3034
0
    while (match47(tok)) {
3035
0
        if (match48(tok))
3036
0
            tok = tok->link();
3037
0
        if (!tok)
3038
0
            return nullptr;
3039
0
        tok = tok->next();
3040
0
    }
3041
0
    return tok;
3042
0
}
3043
3044
Token* findLambdaEndScope(Token* tok)
3045
0
{
3046
0
    if (!match39(tok))
3047
0
        return nullptr;
3048
0
    tok = tok->link();
3049
0
    if (!match49(tok))
3050
0
        return nullptr;
3051
0
    tok = tok->linkAt(1);
3052
0
    if (match26(tok))
3053
0
        return tok;
3054
0
    if (match50(tok))
3055
0
        return tok->linkAt(1);
3056
0
    if (!match51(tok))
3057
0
        return nullptr;
3058
0
    tok = tok->next();
3059
0
    while (match52(tok)) {
3060
0
        if (match53(tok))
3061
0
            tok = tok->linkAt(1);
3062
0
        if (match38(tok)) {
3063
0
            tok = findTypeEnd(tok);
3064
0
            break;
3065
0
        }
3066
0
        tok = tok->next();
3067
0
    }
3068
0
    if (match25(tok))
3069
0
        return tok->link();
3070
0
    return nullptr;
3071
0
}
3072
0
const Token* findLambdaEndScope(const Token* tok) {
3073
0
    return findLambdaEndScope(const_cast<Token*>(tok));
3074
0
}
3075
3076
1.10k
const std::string& Token::fileName() const {
3077
1.10k
    return mTokensFrontBack.list.getFiles()[mImpl->mFileIndex];
3078
1.10k
}