Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/valueflow.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
5.03k
static inline bool match1(const Token* tok) {
8
5.03k
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<="))))
9
3.09k
        return false;
10
1.94k
    return true;
11
5.03k
}
12
// pattern: >|>=
13
3.09k
static inline bool match2(const Token* tok) {
14
3.09k
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">="))))
15
1.74k
        return false;
16
1.34k
    return true;
17
3.09k
}
18
// pattern: ==|!=|>=|<=
19
2.51k
static inline bool match3(const Token* tok) {
20
2.51k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<="))))
21
1.29k
        return false;
22
1.22k
    return true;
23
2.51k
}
24
// pattern: {
25
1.30k
static inline bool match4(const Token* tok) {
26
1.30k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
27
392
        return false;
28
910
    return true;
29
1.30k
}
30
// pattern: return|continue|break|throw|goto
31
30
template<class T> static inline T * findmatch5(T * start_tok, const Token * end) {
32
60
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
33
34
31
    T * tok = start_tok;
35
31
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || (tok->str() == MatchCompiler::makeConstString("throw")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto"))))
36
30
        continue;
37
1
    return start_tok;
38
31
    }
39
29
    return nullptr;
40
30
}
41
// pattern: false|true
42
10.9k
static inline bool match6(const Token* tok) {
43
10.9k
    if (!tok || !(((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false")) || ((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("true"))))
44
10.9k
        return false;
45
0
    return true;
46
10.9k
}
47
// pattern: [(,] NULL [,)]
48
54.9k
static inline bool match7(const Token* tok) {
49
54.9k
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
50
52.8k
        return false;
51
2.09k
    tok = tok->next();
52
2.09k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("NULL")))
53
2.09k
        return false;
54
0
    tok = tok->next();
55
0
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
56
0
        return false;
57
0
    return true;
58
0
}
59
// pattern: %var% [ %num%| ] = {
60
0
static inline bool match8(const Token* tok) {
61
0
    if (!tok || !(tok->varId() != 0))
62
0
        return false;
63
0
    tok = tok->next();
64
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
65
0
        return false;
66
0
    tok = tok->next();
67
0
    if (tok && (tok->isNumber()))
68
0
        tok = tok->next();
69
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
70
0
        return false;
71
0
    tok = tok->next();
72
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
73
0
        return false;
74
0
    tok = tok->next();
75
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
76
0
        return false;
77
0
    return true;
78
0
}
79
// pattern: =
80
24.9k
static inline bool match9(const Token* tok) {
81
24.9k
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
82
22.4k
        return false;
83
2.53k
    return true;
84
24.9k
}
85
// pattern: const %type% %var% [ %num%| ] = {
86
43.2k
static inline bool match10(const Token* tok) {
87
43.2k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")))
88
43.2k
        return false;
89
0
    tok = tok->next();
90
0
    if (!tok || !(tok->isName() && tok->varId() == 0U))
91
0
        return false;
92
0
    tok = tok->next();
93
0
    if (!tok || !(tok->varId() != 0))
94
0
        return false;
95
0
    tok = tok->next();
96
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
97
0
        return false;
98
0
    tok = tok->next();
99
0
    if (tok && (tok->isNumber()))
100
0
        tok = tok->next();
101
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
102
0
        return false;
103
0
    tok = tok->next();
104
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
105
0
        return false;
106
0
    tok = tok->next();
107
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
108
0
        return false;
109
0
    return true;
110
0
}
111
// pattern: const char %var% [ %num%| ] = %str% ;
112
43.2k
static inline bool match11(const Token* tok) {
113
43.2k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")))
114
43.2k
        return false;
115
0
    tok = tok->next();
116
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("char")))
117
0
        return false;
118
0
    tok = tok->next();
119
0
    if (!tok || !(tok->varId() != 0))
120
0
        return false;
121
0
    tok = tok->next();
122
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
123
0
        return false;
124
0
    tok = tok->next();
125
0
    if (tok && (tok->isNumber()))
126
0
        tok = tok->next();
127
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
128
0
        return false;
129
0
    tok = tok->next();
130
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
131
0
        return false;
132
0
    tok = tok->next();
133
0
    if (!tok || !(tok->tokType() == Token::eString))
134
0
        return false;
135
0
    tok = tok->next();
136
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
137
0
        return false;
138
0
    return true;
139
0
}
140
// pattern: %comp%
141
89.7k
static inline bool match12(const Token* tok) {
142
89.7k
    if (!tok || !tok->isComparisonOp())
143
86.7k
        return false;
144
3.00k
    return true;
145
89.7k
}
146
// pattern: (|%name%
147
0
static inline bool match13(const Token* tok) {
148
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || tok->isName()))
149
0
        return false;
150
0
    return true;
151
0
}
152
// pattern: if|while|for (
153
585k
static inline bool match14(const Token* tok) {
154
585k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for"))))
155
510k
        return false;
156
75.5k
    tok = tok->next();
157
75.5k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
158
0
        return false;
159
75.5k
    return true;
160
75.5k
}
161
// pattern: [
162
177k
static inline bool match15(const Token* tok) {
163
177k
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))
164
177k
        return false;
165
0
    return true;
166
177k
}
167
// pattern: . %name% (
168
115k
static inline bool match16(const Token* tok) {
169
115k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
170
115k
        return false;
171
0
    tok = tok->next();
172
0
    if (!tok || !tok->isName())
173
0
        return false;
174
0
    tok = tok->next();
175
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
176
0
        return false;
177
0
    return true;
178
0
}
179
// pattern: ==|>=|<=|/
180
4.11k
static inline bool match17(const Token* tok) {
181
4.11k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/"))))
182
3.76k
        return false;
183
350
    return true;
184
4.11k
}
185
// pattern: !=|>|<|%|-
186
3.76k
static inline bool match18(const Token* tok) {
187
3.76k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
188
3.04k
        return false;
189
717
    return true;
190
3.76k
}
191
// pattern: -|%|&|^
192
0
static inline bool match19(const Token* tok) {
193
0
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^"))))
194
0
        return false;
195
0
    return true;
196
0
}
197
// pattern: true|false
198
75.5k
static inline bool match20(const Token* tok) {
199
75.5k
    if (!tok || !(((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("true")) || ((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false"))))
200
75.5k
        return false;
201
0
    return true;
202
75.5k
}
203
// pattern: <|<=|>|>=
204
0
static inline bool match21(const Token* tok) {
205
0
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">="))))
206
0
        return false;
207
0
    return true;
208
0
}
209
// pattern: ?
210
77.9k
static inline bool match22(const Token* tok) {
211
77.9k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")))
212
77.9k
        return false;
213
0
    return true;
214
77.9k
}
215
// pattern: %
216
75.5k
static inline bool match23(const Token* tok) {
217
75.5k
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")))
218
75.4k
        return false;
219
134
    return true;
220
75.5k
}
221
// pattern: abs|labs|llabs|fabs|fabsf|fabsl (
222
113k
static inline bool match24(const Token* tok) {
223
113k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("abs")) || (tok->str() == MatchCompiler::makeConstString("labs")) || (tok->str() == MatchCompiler::makeConstString("llabs")) || (tok->str() == MatchCompiler::makeConstString("fabs")) || (tok->str() == MatchCompiler::makeConstString("fabsf")) || (tok->str() == MatchCompiler::makeConstString("fabsl"))))
224
113k
        return false;
225
0
    tok = tok->next();
226
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
227
0
        return false;
228
0
    return true;
229
0
}
230
// pattern: . data|c_str (
231
75.5k
static inline bool match25(const Token* tok) {
232
75.5k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
233
75.5k
        return false;
234
0
    tok = tok->next();
235
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("data")) || (tok->str() == MatchCompiler::makeConstString("c_str"))))
236
0
        return false;
237
0
    tok = tok->next();
238
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
239
0
        return false;
240
0
    return true;
241
0
}
242
// pattern: make_shared|make_unique <
243
75.5k
static inline bool match26(const Token* tok) {
244
75.5k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("make_shared")) || (tok->str() == MatchCompiler::makeConstString("make_unique"))))
245
75.5k
        return false;
246
0
    tok = tok->next();
247
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
248
0
        return false;
249
0
    return true;
250
0
}
251
// pattern: > (
252
0
static inline bool match27(const Token* tok) {
253
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))
254
0
        return false;
255
0
    tok = tok->next();
256
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
257
0
        return false;
258
0
    return true;
259
0
}
260
// pattern: this
261
75.5k
static inline bool match28(const Token* tok) {
262
75.5k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("this")))
263
75.5k
        return false;
264
0
    return true;
265
75.5k
}
266
// pattern: %name% =
267
0
static inline bool match29(const Token* tok) {
268
0
    if (!tok || !tok->isName())
269
0
        return false;
270
0
    tok = tok->next();
271
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
272
0
        return false;
273
0
    return true;
274
0
}
275
// pattern: ++|--|&
276
7.87k
static inline bool match30(const Token* tok) {
277
7.87k
    if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))))
278
7.18k
        return false;
279
692
    return true;
280
7.87k
}
281
// pattern: & %name% =
282
1.58k
static inline bool match31(const Token* tok) {
283
1.58k
    if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))
284
1.58k
        return false;
285
0
    tok = tok->next();
286
0
    if (!tok || !tok->isName())
287
0
        return false;
288
0
    tok = tok->next();
289
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
290
0
        return false;
291
0
    return true;
292
0
}
293
// pattern: [(,]
294
1.59k
static inline bool match32(const Token* tok) {
295
1.59k
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
296
1.59k
        return false;
297
0
    return true;
298
1.59k
}
299
// pattern: ;
300
686
static inline bool match33(const Token* tok) {
301
686
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
302
686
        return false;
303
0
    return true;
304
686
}
305
// pattern: ...
306
11.2k
static inline bool match34(const Token* tok) {
307
11.2k
    if (!tok || !((tok->tokType() == Token::eEllipsis) && tok->str() == MatchCompiler::makeConstString("...")))
308
11.2k
        return false;
309
0
    return true;
310
11.2k
}
311
// pattern: =|{
312
0
static inline bool match35(const Token* tok) {
313
0
    if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
314
0
        return false;
315
0
    return true;
316
0
}
317
// pattern: :
318
0
static inline bool match36(const Token* tok) {
319
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
320
0
        return false;
321
0
    return true;
322
0
}
323
// pattern: for (
324
156
static inline bool match37(const Token* tok) {
325
156
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")))
326
156
        return false;
327
0
    tok = tok->next();
328
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
329
0
        return false;
330
0
    return true;
331
0
}
332
// pattern: %name% (
333
102k
static inline bool match38(const Token* tok) {
334
102k
    if (!tok || !tok->isName())
335
64.2k
        return false;
336
38.4k
    tok = tok->next();
337
38.4k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
338
34.9k
        return false;
339
3.48k
    return true;
340
38.4k
}
341
// pattern: .|::|[
342
0
static inline bool match39(const Token* tok) {
343
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))))
344
0
        return false;
345
0
    return true;
346
0
}
347
// pattern: .
348
187
static inline bool match40(const Token* tok) {
349
187
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
350
187
        return false;
351
0
    return true;
352
187
}
353
// pattern: ,
354
0
static inline bool match41(const Token* tok) {
355
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))
356
0
        return false;
357
0
    return true;
358
0
}
359
// pattern: const|volatile|auto|&|&&
360
0
static inline bool match42(const Token* tok) {
361
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || ((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
362
0
        return false;
363
0
    return true;
364
0
}
365
// pattern: auto
366
0
static inline bool match43(const Token* tok) {
367
0
    if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto")))
368
0
        return false;
369
0
    return true;
370
0
}
371
// pattern: ) {
372
3.55k
static inline bool match44(const Token* tok) {
373
3.55k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
374
0
        return false;
375
3.55k
    tok = tok->next();
376
3.55k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
377
187
        return false;
378
3.37k
    return true;
379
3.55k
}
380
// pattern: if (
381
4.89k
static inline bool match45(const Token* tok) {
382
4.89k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")))
383
3.93k
        return false;
384
957
    tok = tok->next();
385
957
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
386
0
        return false;
387
957
    return true;
388
957
}
389
// pattern: } else {
390
1.25k
static inline bool match46(const Token* tok) {
391
1.25k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
392
0
        return false;
393
1.25k
    tok = tok->next();
394
1.25k
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else")))
395
705
        return false;
396
547
    tok = tok->next();
397
547
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
398
0
        return false;
399
547
    return true;
400
547
}
401
// pattern: %var% {|(
402
392
static inline bool match47(const Token* tok) {
403
392
    if (!tok || !(tok->varId() != 0))
404
386
        return false;
405
6
    tok = tok->next();
406
6
    if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
407
6
        return false;
408
0
    return true;
409
6
}
410
// pattern: (
411
0
static inline bool match48(const Token* tok) {
412
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
413
0
        return false;
414
0
    return true;
415
0
}
416
// pattern: std :: ref|cref|tie|front_inserter|back_inserter
417
187
static inline bool match49(const Token* tok) {
418
187
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
419
187
        return false;
420
0
    tok = tok->next();
421
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
422
0
        return false;
423
0
    tok = tok->next();
424
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("ref")) || (tok->str() == MatchCompiler::makeConstString("cref")) || (tok->str() == MatchCompiler::makeConstString("tie")) || (tok->str() == MatchCompiler::makeConstString("front_inserter")) || (tok->str() == MatchCompiler::makeConstString("back_inserter"))))
425
0
        return false;
426
0
    return true;
427
0
}
428
// pattern: std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind
429
187
static inline bool match50(const Token* tok) {
430
187
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
431
187
        return false;
432
0
    tok = tok->next();
433
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
434
0
        return false;
435
0
    tok = tok->next();
436
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("make_tuple")) || (tok->str() == MatchCompiler::makeConstString("tuple_cat")) || (tok->str() == MatchCompiler::makeConstString("make_pair")) || (tok->str() == MatchCompiler::makeConstString("make_reverse_iterator")) || (tok->str() == MatchCompiler::makeConstString("next")) || (tok->str() == MatchCompiler::makeConstString("prev")) || (tok->str() == MatchCompiler::makeConstString("move")) || (tok->str() == MatchCompiler::makeConstString("bind"))))
437
0
        return false;
438
0
    return true;
439
0
}
440
// pattern: . push_back|push_front|insert|push|assign
441
0
static inline bool match51(const Token* tok) {
442
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
443
0
        return false;
444
0
    tok = tok->next();
445
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("push_back")) || (tok->str() == MatchCompiler::makeConstString("push_front")) || (tok->str() == MatchCompiler::makeConstString("insert")) || (tok->str() == MatchCompiler::makeConstString("push")) || (tok->str() == MatchCompiler::makeConstString("assign"))))
446
0
        return false;
447
0
    return true;
448
0
}
449
// pattern: (|{
450
187
static inline bool match52(const Token* tok) {
451
187
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
452
0
        return false;
453
187
    return true;
454
187
}
455
// pattern: %var% (
456
0
static inline bool match53(const Token* tok) {
457
0
    if (!tok || !(tok->varId() != 0))
458
0
        return false;
459
0
    tok = tok->next();
460
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
461
0
        return false;
462
0
    return true;
463
0
}
464
// pattern: %name%
465
0
static inline bool match54(const Token* tok) {
466
0
    if (!tok || !tok->isName())
467
0
        return false;
468
0
    return true;
469
0
}
470
// pattern: ] (
471
0
static inline bool match55(const Token* tok) {
472
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]")))
473
0
        return false;
474
0
    tok = tok->next();
475
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
476
0
        return false;
477
0
    return true;
478
0
}
479
// pattern: {
480
0
template<class T> static inline T * findmatch56(T * start_tok) {
481
0
    for (; start_tok; start_tok = start_tok->next()) {
482
483
0
    T * tok = start_tok;
484
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
485
0
        continue;
486
0
    return start_tok;
487
0
    }
488
0
    return nullptr;
489
0
}
490
// pattern: this !!.
491
0
static inline bool match57(const Token* tok) {
492
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("this")))
493
0
        return false;
494
0
    tok = tok->next();
495
0
    if (tok && tok->str() == MatchCompiler::makeConstString("."))
496
0
        return false;
497
0
    return true;
498
0
}
499
// pattern: * this
500
0
static inline bool match58(const Token* tok) {
501
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
502
0
        return false;
503
0
    tok = tok->next();
504
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("this")))
505
0
        return false;
506
0
    return true;
507
0
}
508
// pattern: %var%
509
0
static inline bool match59(const Token* tok) {
510
0
    if (!tok || !(tok->varId() != 0))
511
0
        return false;
512
0
    return true;
513
0
}
514
// pattern: return
515
425
static inline bool match60(const Token* tok) {
516
425
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
517
425
        return false;
518
0
    return true;
519
425
}
520
// pattern: *
521
12
static inline bool match61(const Token* tok) {
522
12
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")))
523
12
        return false;
524
0
    return true;
525
12
}
526
// pattern: .|[
527
12
static inline bool match62(const Token* tok) {
528
12
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))))
529
12
        return false;
530
0
    return true;
531
12
}
532
// pattern: data|c_str
533
0
static inline bool match63(const Token* tok) {
534
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("data")) || (tok->str() == MatchCompiler::makeConstString("c_str"))))
535
0
        return false;
536
0
    return true;
537
0
}
538
// pattern: =|return|%name%|{|,|> {
539
65.1k
static inline bool match64(const Token* tok) {
540
65.1k
    if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || tok->isName() || ((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(">"))))
541
27.9k
        return false;
542
37.1k
    tok = tok->next();
543
37.1k
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
544
36.3k
        return false;
545
796
    return true;
546
37.1k
}
547
// pattern: . get ( )
548
0
static inline bool match65(const Token* tok) {
549
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
550
0
        return false;
551
0
    tok = tok->next();
552
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("get")))
553
0
        return false;
554
0
    tok = tok->next();
555
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
556
0
        return false;
557
0
    tok = tok->next();
558
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
559
0
        return false;
560
0
    return true;
561
0
}
562
// pattern: std :: move ( %var% )
563
0
static inline bool match66(const Token* tok) {
564
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
565
0
        return false;
566
0
    tok = tok->next();
567
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
568
0
        return false;
569
0
    tok = tok->next();
570
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("move")))
571
0
        return false;
572
0
    tok = tok->next();
573
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
574
0
        return false;
575
0
    tok = tok->next();
576
0
    if (!tok || !(tok->varId() != 0))
577
0
        return false;
578
0
    tok = tok->next();
579
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
580
0
        return false;
581
0
    return true;
582
0
}
583
// pattern: std :: forward <
584
0
static inline bool match67(const Token* tok) {
585
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
586
0
        return false;
587
0
    tok = tok->next();
588
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
589
0
        return false;
590
0
    tok = tok->next();
591
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("forward")))
592
0
        return false;
593
0
    tok = tok->next();
594
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")))
595
0
        return false;
596
0
    return true;
597
0
}
598
// pattern: > ( %var% )
599
0
static inline bool match68(const Token* tok) {
600
0
    if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))
601
0
        return false;
602
0
    tok = tok->next();
603
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
604
0
        return false;
605
0
    tok = tok->next();
606
0
    if (!tok || !(tok->varId() != 0))
607
0
        return false;
608
0
    tok = tok->next();
609
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
610
0
        return false;
611
0
    return true;
612
0
}
613
// pattern: %varid% . %name% (
614
0
static inline bool match69(const Token* tok, const int varid) {
615
0
    if (varid==0U)
616
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
617
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
618
0
        return false;
619
0
    tok = tok->next();
620
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
621
0
        return false;
622
0
    tok = tok->next();
623
0
    if (!tok || !tok->isName())
624
0
        return false;
625
0
    tok = tok->next();
626
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
627
0
        return false;
628
0
    return true;
629
0
}
630
// pattern: [({]
631
25
static inline bool match70(const Token* tok) {
632
25
    if (!tok || tok->str().size() != 1U || !strchr("({", tok->str()[0]))
633
25
        return false;
634
0
    return true;
635
25
}
636
// pattern: %var% . reset|clear (
637
39.6k
static inline bool match71(const Token* tok) {
638
39.6k
    if (!tok || !(tok->varId() != 0))
639
32.4k
        return false;
640
7.20k
    tok = tok->next();
641
7.20k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
642
7.20k
        return false;
643
0
    tok = tok->next();
644
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("reset")) || (tok->str() == MatchCompiler::makeConstString("clear"))))
645
0
        return false;
646
0
    tok = tok->next();
647
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
648
0
        return false;
649
0
    return true;
650
0
}
651
// pattern: %var%|.
652
0
static inline bool match72(const Token* tok) {
653
0
    if (!tok || !((tok->varId() != 0) || (tok->str() == MatchCompiler::makeConstString("."))))
654
0
        return false;
655
0
    return true;
656
0
}
657
// pattern: }
658
162
static inline bool match73(const Token* tok) {
659
162
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
660
0
        return false;
661
162
    return true;
662
162
}
663
// pattern: break|continue ;
664
78
static inline bool match74(const Token* tok) {
665
78
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue"))))
666
78
        return false;
667
0
    tok = tok->next();
668
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
669
0
        return false;
670
0
    return true;
671
0
}
672
// pattern: %comp%|%oror%|&&
673
0
static inline bool match75(const Token* tok) {
674
0
    if (!tok || !(tok->isComparisonOp() || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
675
0
        return false;
676
0
    return true;
677
0
}
678
// pattern: strlen (
679
0
static inline bool match76(const Token* tok) {
680
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("strlen")))
681
0
        return false;
682
0
    tok = tok->next();
683
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
684
0
        return false;
685
0
    return true;
686
0
}
687
// pattern: *|/|<<|>>|^|+|-|%or%
688
37.7k
static inline bool match77(const Token* tok) {
689
37.7k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") )))
690
36.9k
        return false;
691
826
    return true;
692
37.7k
}
693
// pattern: <<|>>|/
694
67
static inline bool match78(const Token* tok) {
695
67
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/"))))
696
61
        return false;
697
6
    return true;
698
67
}
699
// pattern: <<|>>|^|+|-|%or%
700
61
static inline bool match79(const Token* tok) {
701
61
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") )))
702
10
        return false;
703
51
    return true;
704
61
}
705
// pattern: *|/
706
40
static inline bool match80(const Token* tok) {
707
40
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/"))))
708
30
        return false;
709
10
    return true;
710
40
}
711
// pattern: -|%comp%
712
39.6k
static inline bool match81(const Token* tok) {
713
39.6k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || tok->isComparisonOp()))
714
37.7k
        return false;
715
1.94k
    return true;
716
39.6k
}
717
// pattern: ++
718
0
static inline bool match82(const Token* tok) {
719
0
    if (!tok || !((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")))
720
0
        return false;
721
0
    return true;
722
0
}
723
// pattern: --
724
0
static inline bool match83(const Token* tok) {
725
0
    if (!tok || !((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")))
726
0
        return false;
727
0
    return true;
728
0
}
729
// pattern: %var% ; %var%
730
10
static inline bool match84(const Token* tok) {
731
10
    if (!tok || !(tok->varId() != 0))
732
7
        return false;
733
3
    tok = tok->next();
734
3
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
735
1
        return false;
736
2
    tok = tok->next();
737
2
    if (!tok || !(tok->varId() != 0))
738
2
        return false;
739
0
    return true;
740
2
}
741
// pattern: bool|_Bool
742
10
static inline bool match85(const Token* tok) {
743
10
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("bool")) || (tok->str() == MatchCompiler::makeConstString("_Bool"))))
744
10
        return false;
745
0
    return true;
746
10
}
747
// pattern: %var% (|{
748
35.7k
static inline bool match86(const Token* tok) {
749
35.7k
    if (!tok || !(tok->varId() != 0))
750
29.0k
        return false;
751
6.73k
    tok = tok->next();
752
6.73k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
753
6.73k
        return false;
754
0
    return true;
755
6.73k
}
756
// pattern: swap (
757
39.6k
static inline bool match87(const Token* tok) {
758
39.6k
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("swap")))
759
39.6k
        return false;
760
0
    tok = tok->next();
761
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
762
0
        return false;
763
0
    return true;
764
0
}
765
// pattern: ==|!|(
766
1.00k
static inline bool match88(const Token* tok) {
767
1.00k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
768
801
        return false;
769
205
    return true;
770
1.00k
}
771
// pattern: !=|%var%|(
772
511
static inline bool match89(const Token* tok) {
773
511
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || (tok->varId() != 0) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))))
774
463
        return false;
775
48
    return true;
776
511
}
777
// pattern: break|goto
778
84
template<class T> static inline T * findmatch90(T * start_tok, const Token * end) {
779
888
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
780
781
804
    T * tok = start_tok;
782
804
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto"))))
783
804
        continue;
784
0
    return start_tok;
785
804
    }
786
84
    return nullptr;
787
84
}
788
// pattern: !=|=|(|.
789
1.26k
static inline bool match91(const Token* tok) {
790
1.26k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("."))))
791
1.00k
        return false;
792
262
    return true;
793
1.26k
}
794
// pattern: ==|!
795
1.26k
static inline bool match92(const Token* tok) {
796
1.26k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!"))))
797
1.04k
        return false;
798
226
    return true;
799
1.26k
}
800
// pattern: :|;|,
801
307k
static inline bool match93(const Token* tok) {
802
307k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(","))))
803
265k
        return false;
804
42.7k
    return true;
805
307k
}
806
// pattern: &&|%oror%|?|!
807
202k
static inline bool match94(const Token* tok) {
808
202k
    if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!"))))
809
202k
        return false;
810
0
    return true;
811
202k
}
812
// pattern: %assign%
813
1.24k
static inline bool match95(const Token* tok) {
814
1.24k
    if (!tok || !tok->isAssignmentOp())
815
1.24k
        return false;
816
0
    return true;
817
1.24k
}
818
// pattern: %assign%|++|--
819
1.24k
static inline bool match96(const Token* tok) {
820
1.24k
    if (!tok || !(tok->isAssignmentOp() || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--"))))
821
1.14k
        return false;
822
96
    return true;
823
1.24k
}
824
// pattern: <|>|<=|>=
825
1.12k
static inline bool match97(const Token* tok) {
826
1.12k
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">="))))
827
413
        return false;
828
715
    return true;
829
1.12k
}
830
// pattern: for|while (
831
653
static inline bool match98(const Token* tok) {
832
653
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
833
497
        return false;
834
156
    tok = tok->next();
835
156
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
836
0
        return false;
837
156
    return true;
838
156
}
839
// pattern: !
840
2.02k
static inline bool match99(const Token* tok) {
841
2.02k
    if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))
842
2.02k
        return false;
843
0
    return true;
844
2.02k
}
845
// pattern: ==|!=
846
31.0k
static inline bool match100(const Token* tok) {
847
31.0k
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!="))))
848
28.4k
        return false;
849
2.62k
    return true;
850
31.0k
}
851
// pattern: !=
852
0
static inline bool match101(const Token* tok) {
853
0
    if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")))
854
0
        return false;
855
0
    return true;
856
0
}
857
// pattern: %oror%|&&
858
4.29k
static inline bool match102(const Token* tok) {
859
4.29k
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&"))))
860
4.29k
        return false;
861
0
    return true;
862
4.29k
}
863
// pattern: ++|--
864
0
static inline bool match103(const Token* tok) {
865
0
    if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--"))))
866
0
        return false;
867
0
    return true;
868
0
}
869
// pattern: while (
870
50
static inline bool match104(const Token* tok) {
871
50
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))
872
36
        return false;
873
14
    tok = tok->next();
874
14
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
875
0
        return false;
876
14
    return true;
877
14
}
878
// pattern: while|for (
879
331
static inline bool match105(const Token* tok) {
880
331
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for"))))
881
247
        return false;
882
84
    tok = tok->next();
883
84
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
884
0
        return false;
885
84
    return true;
886
84
}
887
// pattern: &&|%oror%
888
115
static inline bool match106(const Token* tok) {
889
115
    if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||"))))
890
115
        return false;
891
0
    return true;
892
115
}
893
// pattern: == false
894
0
static inline bool match107(const Token* tok) {
895
0
    if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")))
896
0
        return false;
897
0
    tok = tok->next();
898
0
    if (!tok || !((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false")))
899
0
        return false;
900
0
    return true;
901
0
}
902
// pattern: } while (
903
0
static inline bool match108(const Token* tok) {
904
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
905
0
        return false;
906
0
    tok = tok->next();
907
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))
908
0
        return false;
909
0
    tok = tok->next();
910
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
911
0
        return false;
912
0
    return true;
913
0
}
914
// pattern: %oror%|&&|?
915
12.9k
static inline bool match109(const Token* tok) {
916
12.9k
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?"))))
917
12.9k
        return false;
918
0
    return true;
919
12.9k
}
920
// pattern: if|while (
921
35.0k
static inline bool match110(const Token* tok) {
922
35.0k
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
923
31.2k
        return false;
924
3.76k
    tok = tok->next();
925
3.76k
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
926
0
        return false;
927
3.76k
    return true;
928
3.76k
}
929
// pattern: %comp%|%assign%
930
2.01k
static inline bool match111(const Token* tok) {
931
2.01k
    if (!tok || !(tok->isComparisonOp() || tok->isAssignmentOp()))
932
272
        return false;
933
1.74k
    return true;
934
2.01k
}
935
// pattern: %|<<|>>|&|^|~|%or%
936
1.64k
static inline bool match112(const Token* tok) {
937
1.64k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("~")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") )))
938
1.55k
        return false;
939
91
    return true;
940
1.64k
}
941
// pattern: NULL|nullptr
942
868
static inline bool match113(const Token* tok) {
943
868
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("NULL")) || (tok->str() == MatchCompiler::makeConstString("nullptr"))))
944
868
        return false;
945
0
    return true;
946
868
}
947
// pattern: +|-|*|/
948
777
static inline bool match114(const Token* tok) {
949
777
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/"))))
950
636
        return false;
951
141
    return true;
952
777
}
953
// pattern: %comp%|-
954
23.6k
static inline bool match115(const Token* tok) {
955
23.6k
    if (!tok || !(tok->isComparisonOp() || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
956
22.1k
        return false;
957
1.56k
    return true;
958
23.6k
}
959
// pattern: ?|&&|!|%oror%
960
22.1k
static inline bool match116(const Token* tok) {
961
22.1k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||"))))
962
22.1k
        return false;
963
0
    return true;
964
22.1k
}
965
// pattern: ) (
966
0
static inline bool match117(const Token* tok) {
967
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
968
0
        return false;
969
0
    tok = tok->next();
970
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
971
0
        return false;
972
0
    return true;
973
0
}
974
// pattern: %varid%
975
0
template<class T> static inline T * findmatch118(T * start_tok, const Token * end, int varid) {
976
0
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
977
978
0
    T * tok = start_tok;
979
0
    if (varid==0U)
980
0
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
981
0
    if (!tok || !(tok->isName() && tok->varId() == varid))
982
0
        continue;
983
0
    return start_tok;
984
0
    }
985
0
    return nullptr;
986
0
}
987
// pattern: switch ( %var% ) {
988
0
static inline bool match119(const Token* tok) {
989
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("switch")))
990
0
        return false;
991
0
    tok = tok->next();
992
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
993
0
        return false;
994
0
    tok = tok->next();
995
0
    if (!tok || !(tok->varId() != 0))
996
0
        return false;
997
0
    tok = tok->next();
998
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
999
0
        return false;
1000
0
    tok = tok->next();
1001
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
1002
0
        return false;
1003
0
    return true;
1004
0
}
1005
// pattern: case %num% :
1006
0
static inline bool match120(const Token* tok) {
1007
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case")))
1008
0
        return false;
1009
0
    tok = tok->next();
1010
0
    if (!tok || !tok->isNumber())
1011
0
        return false;
1012
0
    tok = tok->next();
1013
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
1014
0
        return false;
1015
0
    return true;
1016
0
}
1017
// pattern: break ;
1018
0
static inline bool match121(const Token* tok) {
1019
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")))
1020
0
        return false;
1021
0
    tok = tok->next();
1022
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1023
0
        return false;
1024
0
    return true;
1025
0
}
1026
// pattern: ;| case
1027
0
static inline bool match122(const Token* tok) {
1028
0
    if (tok && ((tok->str() == MatchCompiler::makeConstString(";"))))
1029
0
        tok = tok->next();
1030
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case")))
1031
0
        return false;
1032
0
    return true;
1033
0
}
1034
// pattern: ;| case %num% :
1035
0
static inline bool match123(const Token* tok) {
1036
0
    if (tok && ((tok->str() == MatchCompiler::makeConstString(";"))))
1037
0
        tok = tok->next();
1038
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case")))
1039
0
        return false;
1040
0
    tok = tok->next();
1041
0
    if (!tok || !tok->isNumber())
1042
0
        return false;
1043
0
    tok = tok->next();
1044
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")))
1045
0
        return false;
1046
0
    return true;
1047
0
}
1048
// pattern: %comp%|%oror%|&&|!
1049
0
static inline bool match124(const Token* tok) {
1050
0
    if (!tok || !(tok->isComparisonOp() || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!"))))
1051
0
        return false;
1052
0
    return true;
1053
0
}
1054
// pattern: %var% = %num%|%str%|%char%|%name% [,)]
1055
0
static inline bool match125(const Token* tok) {
1056
0
    if (!tok || !(tok->varId() != 0))
1057
0
        return false;
1058
0
    tok = tok->next();
1059
0
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1060
0
        return false;
1061
0
    tok = tok->next();
1062
0
    if (!tok || !(tok->isNumber() || (tok->tokType() == Token::eString) || (tok->tokType() == Token::eChar) || tok->isName()))
1063
0
        return false;
1064
0
    tok = tok->next();
1065
0
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
1066
0
        return false;
1067
0
    return true;
1068
0
}
1069
// pattern: goto|asm|setjmp|longjmp
1070
0
template<class T> static inline T * findmatch126(T * start_tok, const Token * end) {
1071
0
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
1072
1073
0
    T * tok = start_tok;
1074
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("asm")) || (tok->str() == MatchCompiler::makeConstString("setjmp")) || (tok->str() == MatchCompiler::makeConstString("longjmp"))))
1075
0
        continue;
1076
0
    return start_tok;
1077
0
    }
1078
0
    return nullptr;
1079
0
}
1080
// pattern: [&*(]
1081
0
static inline bool match127(const Token* tok) {
1082
0
    if (!tok || tok->str().size() != 1U || !strchr("&*(", tok->str()[0]))
1083
0
        return false;
1084
0
    return true;
1085
0
}
1086
// pattern: %var% ;|[
1087
41.3k
static inline bool match128(const Token* tok) {
1088
41.3k
    if (!tok || !(tok->varId() != 0))
1089
34.1k
        return false;
1090
7.20k
    tok = tok->next();
1091
7.20k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))))
1092
3.68k
        return false;
1093
3.51k
    return true;
1094
7.20k
}
1095
// pattern: union
1096
0
template<class T> static inline T * findmatch129(T * start_tok, const Token * end) {
1097
0
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {
1098
1099
0
    T * tok = start_tok;
1100
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union")))
1101
0
        continue;
1102
0
    return start_tok;
1103
0
    }
1104
0
    return nullptr;
1105
0
}
1106
// pattern: %name% . %name% (
1107
0
static inline bool match130(const Token* tok) {
1108
0
    if (!tok || !tok->isName())
1109
0
        return false;
1110
0
    tok = tok->next();
1111
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
1112
0
        return false;
1113
0
    tok = tok->next();
1114
0
    if (!tok || !tok->isName())
1115
0
        return false;
1116
0
    tok = tok->next();
1117
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1118
0
        return false;
1119
0
    return true;
1120
0
}
1121
// pattern: +|-
1122
4.39k
static inline bool match131(const Token* tok) {
1123
4.39k
    if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))))
1124
4.34k
        return false;
1125
58
    return true;
1126
4.39k
}
1127
// pattern: -
1128
0
static inline bool match132(const Token* tok) {
1129
0
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))
1130
0
        return false;
1131
0
    return true;
1132
0
}
1133
// pattern: %assign%|<<
1134
0
static inline bool match133(const Token* tok) {
1135
0
    if (!tok || !(tok->isAssignmentOp() || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<"))))
1136
0
        return false;
1137
0
    return true;
1138
0
}
1139
// pattern: %var% (|{|;
1140
0
static inline bool match134(const Token* tok) {
1141
0
    if (!tok || !(tok->varId() != 0))
1142
0
        return false;
1143
0
    tok = tok->next();
1144
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";"))))
1145
0
        return false;
1146
0
    return true;
1147
0
}
1148
// pattern: %var% ;
1149
0
static inline bool match135(const Token* tok) {
1150
0
    if (!tok || !(tok->varId() != 0))
1151
0
        return false;
1152
0
    tok = tok->next();
1153
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1154
0
        return false;
1155
0
    return true;
1156
0
}
1157
// pattern: . reset (
1158
0
static inline bool match136(const Token* tok) {
1159
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
1160
0
        return false;
1161
0
    tok = tok->next();
1162
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("reset")))
1163
0
        return false;
1164
0
    tok = tok->next();
1165
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1166
0
        return false;
1167
0
    return true;
1168
0
}
1169
// pattern: ( )
1170
0
static inline bool match137(const Token* tok) {
1171
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1172
0
        return false;
1173
0
    tok = tok->next();
1174
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1175
0
        return false;
1176
0
    return true;
1177
0
}
1178
// pattern: . release ( )
1179
0
static inline bool match138(const Token* tok) {
1180
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
1181
0
        return false;
1182
0
    tok = tok->next();
1183
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("release")))
1184
0
        return false;
1185
0
    tok = tok->next();
1186
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1187
0
        return false;
1188
0
    tok = tok->next();
1189
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")))
1190
0
        return false;
1191
0
    return true;
1192
0
}
1193
// pattern: . release|reset (
1194
0
static inline bool match139(const Token* tok) {
1195
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
1196
0
        return false;
1197
0
    tok = tok->next();
1198
0
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("release")) || (tok->str() == MatchCompiler::makeConstString("reset"))))
1199
0
        return false;
1200
0
    tok = tok->next();
1201
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
1202
0
        return false;
1203
0
    return true;
1204
0
}
1205
// pattern: %name%|> (|{
1206
0
static inline bool match140(const Token* tok) {
1207
0
    if (!tok || !(tok->isName() || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">"))))
1208
0
        return false;
1209
0
    tok = tok->next();
1210
0
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
1211
0
        return false;
1212
0
    return true;
1213
0
}
1214
// pattern: +
1215
3.91k
static inline bool match141(const Token* tok) {
1216
3.91k
    if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")))
1217
3.87k
        return false;
1218
41
    return true;
1219
3.91k
}
1220
// pattern: %str%
1221
2.25k
static inline bool match142(const Token* tok) {
1222
2.25k
    if (!tok || !(tok->tokType() == Token::eString))
1223
2.25k
        return false;
1224
0
    return true;
1225
2.25k
}
1226
// pattern: %name% ;
1227
0
static inline bool match143(const Token* tok) {
1228
0
    if (!tok || !tok->isName())
1229
0
        return false;
1230
0
    tok = tok->next();
1231
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1232
0
        return false;
1233
0
    return true;
1234
0
}
1235
// pattern: %name% {
1236
0
static inline bool match144(const Token* tok) {
1237
0
    if (!tok || !tok->isName())
1238
0
        return false;
1239
0
    tok = tok->next();
1240
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))
1241
0
        return false;
1242
0
    return true;
1243
0
}
1244
// pattern: } ;
1245
0
static inline bool match145(const Token* tok) {
1246
0
    if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))
1247
0
        return false;
1248
0
    tok = tok->next();
1249
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1250
0
        return false;
1251
0
    return true;
1252
0
}
1253
// pattern: for|while
1254
0
static inline bool match146(const Token* tok) {
1255
0
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
1256
0
        return false;
1257
0
    return true;
1258
0
}
1259
// pattern: %name%|;|{|} %var% = %str% ;
1260
39.6k
static inline bool match147(const Token* tok) {
1261
39.6k
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
1262
13.4k
        return false;
1263
26.2k
    tok = tok->next();
1264
26.2k
    if (!tok || !(tok->varId() != 0))
1265
26.0k
        return false;
1266
198
    tok = tok->next();
1267
198
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1268
143
        return false;
1269
55
    tok = tok->next();
1270
55
    if (!tok || !(tok->tokType() == Token::eString))
1271
55
        return false;
1272
0
    tok = tok->next();
1273
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
1274
0
        return false;
1275
0
    return true;
1276
0
}
1277
// pattern: >|return (|{
1278
39.6k
static inline bool match148(const Token* tok) {
1279
39.6k
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return"))))
1280
37.3k
        return false;
1281
2.34k
    tok = tok->next();
1282
2.34k
    if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))))
1283
2.19k
        return false;
1284
147
    return true;
1285
2.34k
}
1286
// pattern: ;|{|} %var% =
1287
39.6k
static inline bool match149(const Token* tok) {
1288
39.6k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))))
1289
29.1k
        return false;
1290
10.5k
    tok = tok->next();
1291
10.5k
    if (!tok || !(tok->varId() != 0))
1292
10.4k
        return false;
1293
25
    tok = tok->next();
1294
25
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1295
0
        return false;
1296
25
    return true;
1297
25
}
1298
// pattern: %type%
1299
0
static inline bool match150(const Token* tok) {
1300
0
    if (!tok || !(tok->isName() && tok->varId() == 0U))
1301
0
        return false;
1302
0
    return true;
1303
0
}
1304
// pattern: [;{}] %var% =
1305
22.6k
static inline bool match151(const Token* tok) {
1306
22.6k
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
1307
16.5k
        return false;
1308
6.15k
    tok = tok->next();
1309
6.15k
    if (!tok || !(tok->varId() != 0))
1310
6.14k
        return false;
1311
14
    tok = tok->next();
1312
14
    if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")))
1313
0
        return false;
1314
14
    return true;
1315
14
}
1316
// pattern: [{[(<]
1317
0
static inline bool match152(const Token* tok) {
1318
0
    if (!tok || tok->str().size() != 1U || !strchr("{[(<", tok->str()[0]))
1319
0
        return false;
1320
0
    return true;
1321
0
}
1322
// pattern: %name%|%num% %name%|%num%
1323
0
static inline bool match153(const Token* tok) {
1324
0
    if (!tok || !(tok->isName() || tok->isNumber()))
1325
0
        return false;
1326
0
    tok = tok->next();
1327
0
    if (!tok || !(tok->isName() || tok->isNumber()))
1328
0
        return false;
1329
0
    return true;
1330
0
}
1331
/*
1332
 * Cppcheck - A tool for static C/C++ code analysis
1333
 * Copyright (C) 2007-2024 Cppcheck team.
1334
 *
1335
 * This program is free software: you can redistribute it and/or modify
1336
 * it under the terms of the GNU General Public License as published by
1337
 * the Free Software Foundation, either version 3 of the License, or
1338
 * (at your option) any later version.
1339
 *
1340
 * This program is distributed in the hope that it will be useful,
1341
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1342
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1343
 * GNU General Public License for more details.
1344
 *
1345
 * You should have received a copy of the GNU General Public License
1346
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1347
 */
1348
1349
/**
1350
 * @brief This is the ValueFlow component in Cppcheck.
1351
 *
1352
 * Each @sa Token in the token list has a list of values. These are
1353
 * the "possible" values for the Token at runtime.
1354
 *
1355
 * In the --debug and --debug-normal output you can see the ValueFlow data. For example:
1356
 *
1357
 *     int f()
1358
 *     {
1359
 *         int x = 10;
1360
 *         return 4 * x + 2;
1361
 *     }
1362
 *
1363
 * The --debug-normal output says:
1364
 *
1365
 *     ##Value flow
1366
 *     Line 3
1367
 *       10 always 10
1368
 *     Line 4
1369
 *       4 always 4
1370
 *       * always 40
1371
 *       x always 10
1372
 *       + always 42
1373
 *       2 always 2
1374
 *
1375
 * All value flow analysis is executed in the ValueFlow::setValues() function. The ValueFlow analysis is executed after
1376
 * the tokenizer/ast/symboldatabase/etc.. The ValueFlow analysis is done in a series of valueFlow* function calls, where
1377
 * each such function call can only use results from previous function calls. The function calls should be arranged so
1378
 * that valueFlow* that do not require previous ValueFlow information should be first.
1379
 *
1380
 * Type of analysis
1381
 * ================
1382
 *
1383
 * This is "flow sensitive" value flow analysis. We _usually_ track the value for 1 variable at a time.
1384
 *
1385
 * How are calculations handled
1386
 * ============================
1387
 *
1388
 * Here is an example code:
1389
 *
1390
 *   x = 3 + 4;
1391
 *
1392
 * The valueFlowNumber set the values for the "3" and "4" tokens by calling setTokenValue().
1393
 * The setTokenValue() handle the calculations automatically. When both "3" and "4" have values, the "+" can be
1394
 * calculated. setTokenValue() recursively calls itself when parents in calculations can be calculated.
1395
 *
1396
 * Forward / Reverse flow analysis
1397
 * ===============================
1398
 *
1399
 * In forward value flow analysis we know a value and see what happens when we are stepping the program forward. Like
1400
 * normal execution. The valueFlowForward is used in this analysis.
1401
 *
1402
 * In reverse value flow analysis we know the value of a variable at line X. And try to "execute backwards" to determine
1403
 * possible values before line X. The valueFlowReverse is used in this analysis.
1404
 *
1405
 *
1406
 */
1407
1408
#include "valueflow.h"
1409
1410
#include "analyzer.h"
1411
#include "astutils.h"
1412
#include "calculate.h"
1413
#include "checkuninitvar.h"
1414
#include "config.h"
1415
#include "errorlogger.h"
1416
#include "errortypes.h"
1417
#include "findtoken.h"
1418
#include "forwardanalyzer.h"
1419
#include "infer.h"
1420
#include "library.h"
1421
#include "mathlib.h"
1422
#include "path.h"
1423
#include "platform.h"
1424
#include "programmemory.h"
1425
#include "reverseanalyzer.h"
1426
#include "settings.h"
1427
#include "smallvector.h"
1428
#include "sourcelocation.h"
1429
#include "standards.h"
1430
#include "symboldatabase.h"
1431
#include "timer.h"
1432
#include "token.h"
1433
#include "tokenlist.h"
1434
#include "utils.h"
1435
#include "valueptr.h"
1436
#include "vfvalue.h"
1437
1438
#include "vf_analyzers.h"
1439
#include "vf_common.h"
1440
#include "vf_settokenvalue.h"
1441
1442
#include <algorithm>
1443
#include <array>
1444
#include <cassert>
1445
#include <chrono>
1446
#include <cstdint>
1447
#include <cstdlib>
1448
#include <cstring>
1449
#include <functional>
1450
#include <initializer_list>
1451
#include <iterator>
1452
#include <limits>
1453
#include <map>
1454
#include <memory>
1455
#include <numeric>
1456
#include <set>
1457
#include <sstream>
1458
#include <string>
1459
#include <unordered_map>
1460
#include <unordered_set>
1461
#include <vector>
1462
1463
static void bailoutInternal(const std::string& type,
1464
                            const TokenList& tokenlist,
1465
                            ErrorLogger& errorLogger,
1466
                            const Token* tok,
1467
                            const std::string& what,
1468
                            const std::string& file,
1469
                            int line,
1470
                            std::string function)
1471
0
{
1472
0
    if (function.find("operator") != std::string::npos)
1473
0
        function = "(valueFlow)";
1474
0
    ErrorMessage::FileLocation loc(tok, &tokenlist);
1475
0
    const std::string location = Path::stripDirectoryPart(file) + ":" + std::to_string(line) + ":";
1476
0
    ErrorMessage errmsg({std::move(loc)},
1477
0
                        tokenlist.getSourceFilePath(),
1478
0
                        Severity::debug,
1479
0
                        (file.empty() ? "" : location) + function + " bailout: " + what,
1480
0
                        type,
1481
0
                        Certainty::normal);
1482
0
    errorLogger.reportErr(errmsg);
1483
0
}
1484
1485
#define bailout2(type, tokenlist, errorLogger, tok, what)                                                              \
1486
0
    bailoutInternal((type), (tokenlist), (errorLogger), (tok), (what), __FILE__, __LINE__, __func__)
1487
1488
#define bailout(tokenlist, errorLogger, tok, what)                                                                     \
1489
0
    bailout2("valueFlowBailout", (tokenlist), (errorLogger), (tok), (what))
1490
1491
#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what)                                                        \
1492
0
    bailoutInternal("valueFlowBailoutIncompleteVar", (tokenlist), (errorLogger), (tok), (what), "", 0, __func__)
1493
1494
static void changeKnownToPossible(std::list<ValueFlow::Value>& values, int indirect = -1)
1495
1.28k
{
1496
1.97k
    for (ValueFlow::Value& v : values) {
1497
1.97k
        if (indirect >= 0 && v.indirect != indirect)
1498
0
            continue;
1499
1.97k
        v.changeKnownToPossible();
1500
1.97k
    }
1501
1.28k
}
1502
1503
static void removeImpossible(std::list<ValueFlow::Value>& values, int indirect = -1)
1504
0
{
1505
0
    values.remove_if([&](const ValueFlow::Value& v) {
1506
0
        if (indirect >= 0 && v.indirect != indirect)
1507
0
            return false;
1508
0
        return v.isImpossible();
1509
0
    });
1510
0
}
1511
1512
static void lowerToPossible(std::list<ValueFlow::Value>& values, int indirect = -1)
1513
0
{
1514
0
    changeKnownToPossible(values, indirect);
1515
0
    removeImpossible(values, indirect);
1516
0
}
1517
1518
static void changePossibleToKnown(std::list<ValueFlow::Value>& values, int indirect = -1)
1519
253
{
1520
253
    for (ValueFlow::Value& v : values) {
1521
253
        if (indirect >= 0 && v.indirect != indirect)
1522
0
            continue;
1523
253
        if (!v.isPossible())
1524
23
            continue;
1525
230
        if (v.bound != ValueFlow::Value::Bound::Point)
1526
0
            continue;
1527
230
        v.setKnown();
1528
230
    }
1529
253
}
1530
1531
static bool isNonConditionalPossibleIntValue(const ValueFlow::Value& v)
1532
0
{
1533
0
    if (v.conditional)
1534
0
        return false;
1535
0
    if (v.condition)
1536
0
        return false;
1537
0
    if (!v.isPossible())
1538
0
        return false;
1539
0
    if (!v.isIntValue())
1540
0
        return false;
1541
0
    return true;
1542
0
}
1543
1544
static void setValueUpperBound(ValueFlow::Value& value, bool upper)
1545
3.28k
{
1546
3.28k
    if (upper)
1547
1.64k
        value.bound = ValueFlow::Value::Bound::Upper;
1548
1.64k
    else
1549
1.64k
        value.bound = ValueFlow::Value::Bound::Lower;
1550
3.28k
}
1551
1552
static void setValueBound(ValueFlow::Value& value, const Token* tok, bool invert)
1553
5.03k
{
1554
5.03k
    if (match1(tok)) {
1555
1.94k
        setValueUpperBound(value, !invert);
1556
3.09k
    } else if (match2(tok)) {
1557
1.34k
        setValueUpperBound(value, invert);
1558
1.34k
    }
1559
5.03k
}
1560
1561
static void setConditionalValue(ValueFlow::Value& value, const Token* tok, MathLib::bigint i)
1562
5.03k
{
1563
5.03k
    assert(value.isIntValue());
1564
5.03k
    value.intvalue = i;
1565
5.03k
    value.assumeCondition(tok);
1566
5.03k
    value.setPossible();
1567
5.03k
}
1568
1569
static void setConditionalValues(const Token* tok,
1570
                                 bool lhs,
1571
                                 MathLib::bigint value,
1572
                                 ValueFlow::Value& true_value,
1573
                                 ValueFlow::Value& false_value)
1574
2.51k
{
1575
2.51k
    if (match3(tok)) {
1576
1.22k
        setConditionalValue(true_value, tok, value);
1577
1.22k
        const char* greaterThan = ">=";
1578
1.22k
        const char* lessThan = "<=";
1579
1.22k
        if (lhs)
1580
658
            std::swap(greaterThan, lessThan);
1581
1.22k
        if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
1582
180
            setConditionalValue(false_value, tok, value - 1);
1583
1.04k
        } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
1584
170
            setConditionalValue(false_value, tok, value + 1);
1585
874
        } else {
1586
874
            setConditionalValue(false_value, tok, value);
1587
874
        }
1588
1.29k
    } else {
1589
1.29k
        const char* greaterThan = ">";
1590
1.29k
        const char* lessThan = "<";
1591
1.29k
        if (lhs)
1592
656
            std::swap(greaterThan, lessThan);
1593
1.29k
        if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) {
1594
650
            setConditionalValue(true_value, tok, value + 1);
1595
650
            setConditionalValue(false_value, tok, value);
1596
650
        } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) {
1597
644
            setConditionalValue(true_value, tok, value - 1);
1598
644
            setConditionalValue(false_value, tok, value);
1599
644
        }
1600
1.29k
    }
1601
2.51k
    setValueBound(true_value, tok, lhs);
1602
2.51k
    setValueBound(false_value, tok, !lhs);
1603
2.51k
}
1604
1605
static bool isSaturated(MathLib::bigint value)
1606
578
{
1607
578
    return value == std::numeric_limits<MathLib::bigint>::max() || value == std::numeric_limits<MathLib::bigint>::min();
1608
578
}
1609
1610
static void parseCompareEachInt(
1611
    const Token* tok,
1612
    const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each,
1613
    const std::function<std::vector<ValueFlow::Value>(const Token*)>& evaluate)
1614
32.5k
{
1615
32.5k
    if (!tok->astOperand1() || !tok->astOperand2())
1616
17.1k
        return;
1617
15.4k
    if (tok->isComparisonOp()) {
1618
7.23k
        std::vector<ValueFlow::Value> value1 = evaluate(tok->astOperand1());
1619
7.23k
        std::vector<ValueFlow::Value> value2 = evaluate(tok->astOperand2());
1620
7.23k
        if (!value1.empty() && !value2.empty()) {
1621
18
            if (tok->astOperand1()->hasKnownIntValue())
1622
0
                value2.clear();
1623
18
            if (tok->astOperand2()->hasKnownIntValue())
1624
4
                value1.clear();
1625
18
        }
1626
7.23k
        for (const ValueFlow::Value& v1 : value1) {
1627
344
            if (isSaturated(v1.intvalue) || astIsFloat(tok->astOperand2(), /*unknown*/ false))
1628
0
                continue;
1629
344
            ValueFlow::Value true_value = v1;
1630
344
            ValueFlow::Value false_value = v1;
1631
344
            setConditionalValues(tok, true, v1.intvalue, true_value, false_value);
1632
344
            each(tok->astOperand2(), std::move(true_value), std::move(false_value));
1633
344
        }
1634
7.23k
        for (const ValueFlow::Value& v2 : value2) {
1635
234
            if (isSaturated(v2.intvalue) || astIsFloat(tok->astOperand1(), /*unknown*/ false))
1636
0
                continue;
1637
234
            ValueFlow::Value true_value = v2;
1638
234
            ValueFlow::Value false_value = v2;
1639
234
            setConditionalValues(tok, false, v2.intvalue, true_value, false_value);
1640
234
            each(tok->astOperand1(), std::move(true_value), std::move(false_value));
1641
234
        }
1642
7.23k
    }
1643
15.4k
}
1644
1645
static void parseCompareEachInt(
1646
    const Token* tok,
1647
    const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each)
1648
31.2k
{
1649
31.2k
    parseCompareEachInt(tok, each, [](const Token* t) -> std::vector<ValueFlow::Value> {
1650
12.0k
        if (t->hasKnownIntValue())
1651
496
            return {t->values().front()};
1652
11.5k
        std::vector<ValueFlow::Value> result;
1653
11.5k
        std::copy_if(t->values().cbegin(), t->values().cend(), std::back_inserter(result), [&](const ValueFlow::Value& v) {
1654
2.01k
            if (v.path < 1)
1655
2.01k
                return false;
1656
0
            if (!isNonConditionalPossibleIntValue(v))
1657
0
                return false;
1658
0
            return true;
1659
0
        });
1660
11.5k
        return result;
1661
12.0k
    });
1662
31.2k
}
1663
1664
const Token* ValueFlow::parseCompareInt(const Token* tok,
1665
                                        ValueFlow::Value& true_value,
1666
                                        ValueFlow::Value& false_value,
1667
                                        const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate)
1668
1.23k
{
1669
1.23k
    const Token* result = nullptr;
1670
1.23k
    parseCompareEachInt(
1671
1.23k
        tok,
1672
1.23k
        [&](const Token* vartok, ValueFlow::Value true_value2, ValueFlow::Value false_value2) {
1673
82
        if (result)
1674
14
            return;
1675
68
        result = vartok;
1676
68
        true_value = std::move(true_value2);
1677
68
        false_value = std::move(false_value2);
1678
68
    },
1679
2.47k
        [&](const Token* t) -> std::vector<ValueFlow::Value> {
1680
2.47k
        std::vector<ValueFlow::Value> r;
1681
2.47k
        std::vector<MathLib::bigint> v = evaluate(t);
1682
1683
2.47k
        std::transform(v.cbegin(), v.cend(), std::back_inserter(r), [&](MathLib::bigint i) {
1684
86
            return ValueFlow::Value{i};
1685
86
        });
1686
2.47k
        return r;
1687
2.47k
    });
1688
1.23k
    return result;
1689
1.23k
}
1690
1691
const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
1692
0
{
1693
0
    return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> {
1694
0
        if (t->hasKnownIntValue())
1695
0
            return {t->values().front().intvalue};
1696
0
        return std::vector<MathLib::bigint>{};
1697
0
    });
1698
0
}
1699
1700
static bool isEscapeScope(const Token* tok, const Settings& settings, bool unknown = false)
1701
30
{
1702
30
    if (!match4(tok))
1703
0
        return false;
1704
    // TODO this search for termTok in all subscopes. It should check the end of the scope.
1705
30
    const Token* termTok = findmatch5(tok, tok->link()) ;
1706
30
    if (termTok && termTok->scope() == tok->scope())
1707
1
        return true;
1708
29
    std::string unknownFunction;
1709
29
    if (settings.library.isScopeNoReturn(tok->link(), &unknownFunction))
1710
0
        return unknownFunction.empty() || unknown;
1711
29
    return false;
1712
29
}
1713
1714
void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value &result)
1715
7
{
1716
7
    if (value1.isKnown() && value2.isKnown())
1717
1
        result.setKnown();
1718
6
    else if (value1.isImpossible() || value2.isImpossible())
1719
0
        result.setImpossible();
1720
6
    else if (value1.isInconclusive() || value2.isInconclusive())
1721
0
        result.setInconclusive();
1722
6
    else
1723
6
        result.setPossible();
1724
7
    if (value1.tokvalue)
1725
1
        result.tokvalue = value1.tokvalue;
1726
6
    else if (value2.tokvalue)
1727
1
        result.tokvalue = value2.tokvalue;
1728
7
    if (value1.isSymbolicValue()) {
1729
0
        result.valueType = value1.valueType;
1730
0
        result.tokvalue = value1.tokvalue;
1731
0
    }
1732
7
    if (value2.isSymbolicValue()) {
1733
0
        result.valueType = value2.valueType;
1734
0
        result.tokvalue = value2.tokvalue;
1735
0
    }
1736
7
    if (value1.isIteratorValue())
1737
0
        result.valueType = value1.valueType;
1738
7
    if (value2.isIteratorValue())
1739
0
        result.valueType = value2.valueType;
1740
7
    result.condition = value1.condition ? value1.condition : value2.condition;
1741
7
    result.varId = (value1.varId != 0) ? value1.varId : value2.varId;
1742
7
    result.varvalue = (result.varId == value1.varId) ? value1.varvalue : value2.varvalue;
1743
7
    result.errorPath = (value1.errorPath.empty() ? value2 : value1).errorPath;
1744
7
    result.safe = value1.safe || value2.safe;
1745
7
    if (value1.bound == ValueFlow::Value::Bound::Point || value2.bound == ValueFlow::Value::Bound::Point) {
1746
7
        if (value1.bound == ValueFlow::Value::Bound::Upper || value2.bound == ValueFlow::Value::Bound::Upper)
1747
0
            result.bound = ValueFlow::Value::Bound::Upper;
1748
7
        if (value1.bound == ValueFlow::Value::Bound::Lower || value2.bound == ValueFlow::Value::Bound::Lower)
1749
0
            result.bound = ValueFlow::Value::Bound::Lower;
1750
7
    }
1751
7
    if (value1.path != value2.path)
1752
0
        result.path = -1;
1753
7
    else
1754
7
        result.path = value1.path;
1755
7
}
1756
1757
1758
template<class F>
1759
static size_t accumulateStructMembers(const Scope* scope, F f)
1760
0
{
1761
0
    size_t total = 0;
1762
0
    std::set<const Scope*> anonScopes;
1763
0
    for (const Variable& var : scope->varlist) {
1764
0
        if (var.isStatic())
1765
0
            continue;
1766
0
        if (const ValueType* vt = var.valueType()) {
1767
0
            if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
1768
0
                return 0;
1769
0
            const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), 1LL, [](MathLib::bigint i1, const Dimension& dim) {
1770
0
                return i1 * dim.num;
1771
0
            });
Unexecuted instantiation: valueflow.cpp:accumulateStructMembers<getAlignOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, getAlignOf(ValueType const&, Settings const&, int)::$_0)::{lambda(long long, Dimension const&)#1}::operator()(long long, Dimension const&) const
Unexecuted instantiation: valueflow.cpp:accumulateStructMembers<ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0)::{lambda(long long, Dimension const&)#1}::operator()(long long, Dimension const&) const
1772
0
            if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union
1773
0
                const auto ret = anonScopes.insert(var.nameToken()->scope());
1774
0
                if (ret.second)
1775
0
                    total = f(total, *vt, dim);
1776
0
            }
1777
0
            else
1778
0
                total = f(total, *vt, dim);
1779
0
        }
1780
0
        if (total == 0)
1781
0
            return 0;
1782
0
    }
1783
0
    return total;
1784
0
}
Unexecuted instantiation: valueflow.cpp:unsigned long accumulateStructMembers<getAlignOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, getAlignOf(ValueType const&, Settings const&, int)::$_0)
Unexecuted instantiation: valueflow.cpp:unsigned long accumulateStructMembers<ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0)
1785
1786
static size_t bitCeil(size_t x)
1787
0
{
1788
0
    if (x <= 1)
1789
0
        return 1;
1790
0
    --x;
1791
0
    x |= x >> 1;
1792
0
    x |= x >> 2;
1793
0
    x |= x >> 4;
1794
0
    x |= x >> 8;
1795
0
    x |= x >> 16;
1796
0
    x |= x >> 32;
1797
0
    return x + 1;
1798
0
}
1799
1800
static size_t getAlignOf(const ValueType& vt, const Settings& settings, int maxRecursion = 0)
1801
0
{
1802
0
    if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) {
1803
        // TODO: add bailout message
1804
0
        return 0;
1805
0
    }
1806
0
    if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) {
1807
0
        auto align = ValueFlow::getSizeOf(vt, settings);
1808
0
        return align == 0 ? 0 : bitCeil(align);
1809
0
    }
1810
0
    if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
1811
0
        auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/) {
1812
0
            size_t a = getAlignOf(vt2, settings, ++maxRecursion);
1813
0
            return std::max(max, a);
1814
0
        };
1815
0
        size_t total = 0;
1816
0
        if (const Type* dt = vt.typeScope->definedType) {
1817
0
            total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
1818
0
                if (bi.type && bi.type->classScope)
1819
0
                    v += accumulateStructMembers(bi.type->classScope, accHelper);
1820
0
                return v;
1821
0
            });
1822
0
        }
1823
0
        return total + accumulateStructMembers(vt.typeScope, accHelper);
1824
0
    }
1825
0
    if (vt.type == ValueType::Type::CONTAINER)
1826
0
        return settings.platform.sizeof_pointer; // Just guess
1827
0
    return 0;
1828
0
}
1829
1830
size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion)
1831
280
{
1832
280
    if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) {
1833
        // TODO: add bailout message
1834
0
        return 0;
1835
0
    }
1836
280
    if (vt.pointer || vt.reference != Reference::None)
1837
0
        return settings.platform.sizeof_pointer;
1838
280
    if (vt.type == ValueType::Type::BOOL || vt.type == ValueType::Type::CHAR)
1839
59
        return 1;
1840
221
    if (vt.type == ValueType::Type::SHORT)
1841
0
        return settings.platform.sizeof_short;
1842
221
    if (vt.type == ValueType::Type::WCHAR_T)
1843
0
        return settings.platform.sizeof_wchar_t;
1844
221
    if (vt.type == ValueType::Type::INT)
1845
221
        return settings.platform.sizeof_int;
1846
0
    if (vt.type == ValueType::Type::LONG)
1847
0
        return settings.platform.sizeof_long;
1848
0
    if (vt.type == ValueType::Type::LONGLONG)
1849
0
        return settings.platform.sizeof_long_long;
1850
0
    if (vt.type == ValueType::Type::FLOAT)
1851
0
        return settings.platform.sizeof_float;
1852
0
    if (vt.type == ValueType::Type::DOUBLE)
1853
0
        return settings.platform.sizeof_double;
1854
0
    if (vt.type == ValueType::Type::LONGDOUBLE)
1855
0
        return settings.platform.sizeof_long_double;
1856
0
    if (vt.type == ValueType::Type::CONTAINER)
1857
0
        return 3 * settings.platform.sizeof_pointer; // Just guess
1858
0
    if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
1859
0
        auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim) -> size_t {
1860
0
            size_t n = ValueFlow::getSizeOf(vt2, settings, ++maxRecursion);
1861
0
            size_t a = getAlignOf(vt2, settings);
1862
0
            if (n == 0 || a == 0)
1863
0
                return 0;
1864
0
            n *= dim;
1865
0
            size_t padding = (a - (total % a)) % a;
1866
0
            return vt.typeScope->type == Scope::eUnion ? std::max(total, n) : total + padding + n;
1867
0
        };
1868
0
        size_t total = accumulateStructMembers(vt.typeScope, accHelper);
1869
0
        if (const Type* dt = vt.typeScope->definedType) {
1870
0
            total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
1871
0
                if (bi.type && bi.type->classScope)
1872
0
                    v += accumulateStructMembers(bi.type->classScope, accHelper);
1873
0
                return v;
1874
0
            });
1875
0
        }
1876
0
        if (total == 0)
1877
0
            return 0;
1878
0
        size_t align = getAlignOf(vt, settings);
1879
0
        if (align == 0)
1880
0
            return 0;
1881
0
        total += (align - (total % align)) % align;
1882
0
        return total;
1883
0
    }
1884
0
    return 0;
1885
0
}
1886
1887
static void valueFlowNumber(TokenList &tokenlist, const Settings& settings)
1888
764
{
1889
55.6k
    for (Token *tok = tokenlist.front(); tok;) {
1890
54.9k
        tok = ValueFlow::valueFlowSetConstantValue(tok, settings);
1891
54.9k
    }
1892
1893
764
    if (tokenlist.isCPP() || settings.standards.c >= Standards::C23) {
1894
55.6k
        for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
1895
54.9k
            if (tok->isName() && !tok->varId() && match6(tok)) {
1896
0
                ValueFlow::Value value(tok->str() == MatchCompiler::makeConstString("true"));
1897
0
                if (!tok->isTemplateArg())
1898
0
                    value.setKnown();
1899
0
                setTokenValue(tok, std::move(value), settings);
1900
54.9k
            } else if (match7(tok)) {
1901
                // NULL function parameters are not simplified in the
1902
                // normal tokenlist
1903
0
                ValueFlow::Value value(0);
1904
0
                if (!tok->isTemplateArg())
1905
0
                    value.setKnown();
1906
0
                setTokenValue(tok->next(), std::move(value), settings);
1907
0
            }
1908
54.9k
        }
1909
764
    }
1910
764
}
1911
1912
static void valueFlowString(TokenList& tokenlist, const Settings& settings)
1913
764
{
1914
55.6k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
1915
54.9k
        if (tok->tokType() == Token::eString) {
1916
0
            ValueFlow::Value strvalue;
1917
0
            strvalue.valueType = ValueFlow::Value::ValueType::TOK;
1918
0
            strvalue.tokvalue = tok;
1919
0
            strvalue.setKnown();
1920
0
            setTokenValue(tok, std::move(strvalue), settings);
1921
0
        }
1922
54.9k
    }
1923
764
}
1924
1925
static void valueFlowArray(TokenList& tokenlist, const Settings& settings)
1926
764
{
1927
764
    std::map<nonneg int, const Token*> constantArrays;
1928
1929
55.6k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
1930
54.9k
        if (tok->varId() > 0) {
1931
            // array
1932
11.6k
            const auto it = utils::as_const(constantArrays).find(tok->varId());
1933
11.6k
            if (it != constantArrays.end()) {
1934
0
                ValueFlow::Value value;
1935
0
                value.valueType = ValueFlow::Value::ValueType::TOK;
1936
0
                value.tokvalue = it->second;
1937
0
                value.setKnown();
1938
0
                setTokenValue(tok, std::move(value), settings);
1939
0
            }
1940
1941
            // const array decl
1942
11.6k
            else if (tok->variable() && tok->variable()->isArray() && tok->variable()->isConst() &&
1943
11.6k
                     tok->variable()->nameToken() == tok && match8(tok)) {
1944
0
                Token* rhstok = tok->linkAt(1)->tokAt(2);
1945
0
                constantArrays[tok->varId()] = rhstok;
1946
0
                tok = rhstok->link();
1947
0
            }
1948
1949
            // pointer = array
1950
11.6k
            else if (tok->variable() && tok->variable()->isArray() && match9(tok->astParent()) &&
1951
11.6k
                     astIsRHS(tok) && tok->astParent()->astOperand1() && tok->astParent()->astOperand1()->variable() &&
1952
11.6k
                     tok->astParent()->astOperand1()->variable()->isPointer()) {
1953
0
                ValueFlow::Value value;
1954
0
                value.valueType = ValueFlow::Value::ValueType::TOK;
1955
0
                value.tokvalue = tok;
1956
0
                value.setKnown();
1957
0
                setTokenValue(tok, std::move(value), settings);
1958
0
            }
1959
11.6k
            continue;
1960
11.6k
        }
1961
1962
43.2k
        if (match10(tok)) {
1963
0
            Token* vartok = tok->tokAt(2);
1964
0
            Token* rhstok = vartok->linkAt(1)->tokAt(2);
1965
0
            constantArrays[vartok->varId()] = rhstok;
1966
0
            tok = rhstok->link();
1967
0
            continue;
1968
0
        }
1969
1970
43.2k
        if (match11(tok)) {
1971
0
            Token* vartok = tok->tokAt(2);
1972
0
            Token* strtok = vartok->linkAt(1)->tokAt(2);
1973
0
            constantArrays[vartok->varId()] = strtok;
1974
0
            tok = strtok->next();
1975
0
            continue;
1976
0
        }
1977
43.2k
    }
1978
764
}
1979
1980
static bool isNonZero(const Token* tok)
1981
0
{
1982
0
    return tok && (!tok->hasKnownIntValue() || tok->values().front().intvalue != 0);
1983
0
}
1984
1985
static const Token* getOtherOperand(const Token* tok)
1986
0
{
1987
0
    if (!tok)
1988
0
        return nullptr;
1989
0
    if (!tok->astParent())
1990
0
        return nullptr;
1991
0
    if (tok->astParent()->astOperand1() != tok)
1992
0
        return tok->astParent()->astOperand1();
1993
0
    if (tok->astParent()->astOperand2() != tok)
1994
0
        return tok->astParent()->astOperand2();
1995
0
    return nullptr;
1996
0
}
1997
1998
static void valueFlowArrayBool(TokenList& tokenlist, const Settings& settings)
1999
1.17k
{
2000
90.3k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
2001
89.1k
        if (tok->hasKnownIntValue())
2002
13.6k
            continue;
2003
75.5k
        const Variable* var = nullptr;
2004
75.5k
        bool known = false;
2005
75.5k
        const auto val =
2006
75.5k
            std::find_if(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue));
2007
75.5k
        if (val == tok->values().end()) {
2008
75.5k
            var = tok->variable();
2009
75.5k
            known = true;
2010
75.5k
        } else {
2011
0
            var = val->tokvalue->variable();
2012
0
            known = val->isKnown();
2013
0
        }
2014
75.5k
        if (!var)
2015
56.6k
            continue;
2016
18.9k
        if (!var->isArray() || var->isArgument() || var->isStlType())
2017
18.9k
            continue;
2018
0
        if (isNonZero(getOtherOperand(tok)) && match12(tok->astParent()))
2019
0
            continue;
2020
        // TODO: Check for function argument
2021
0
        if ((astIsBool(tok->astParent()) && !match13(tok->astParent())) ||
2022
0
            (tok->astParent() && match14(tok->astParent()->previous()))) {
2023
0
            ValueFlow::Value value{1};
2024
0
            if (known)
2025
0
                value.setKnown();
2026
0
            setTokenValue(tok, std::move(value), settings);
2027
0
        }
2028
0
    }
2029
1.17k
}
2030
2031
static void valueFlowArrayElement(TokenList& tokenlist, const Settings& settings)
2032
1.17k
{
2033
90.3k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
2034
89.1k
        if (tok->hasKnownIntValue())
2035
13.6k
            continue;
2036
75.5k
        const Token* indexTok = nullptr;
2037
75.5k
        const Token* arrayTok = nullptr;
2038
75.5k
        if (match15(tok) && tok->isBinaryOp()) {
2039
0
            indexTok = tok->astOperand2();
2040
0
            arrayTok = tok->astOperand1();
2041
75.5k
        } else if (match16(tok->tokAt(-2)) && astIsContainer(tok->tokAt(-2)->astOperand1())) {
2042
0
            arrayTok = tok->tokAt(-2)->astOperand1();
2043
0
            const Library::Container* container = getLibraryContainer(arrayTok);
2044
0
            if (!container || container->stdAssociativeLike)
2045
0
                continue;
2046
0
            const Library::Container::Yield yield = container->getYield(tok->strAt(-1));
2047
0
            if (yield != Library::Container::Yield::AT_INDEX)
2048
0
                continue;
2049
0
            indexTok = tok->astOperand2();
2050
0
        }
2051
2052
75.5k
        if (!indexTok || !arrayTok)
2053
75.5k
            continue;
2054
2055
0
        for (const ValueFlow::Value& arrayValue : arrayTok->values()) {
2056
0
            if (!arrayValue.isTokValue())
2057
0
                continue;
2058
0
            if (arrayValue.isImpossible())
2059
0
                continue;
2060
0
            for (const ValueFlow::Value& indexValue : indexTok->values()) {
2061
0
                if (!indexValue.isIntValue())
2062
0
                    continue;
2063
0
                if (indexValue.isImpossible())
2064
0
                    continue;
2065
0
                if (!arrayValue.isKnown() && !indexValue.isKnown() && arrayValue.varId != 0 && indexValue.varId != 0 &&
2066
0
                    !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue))
2067
0
                    continue;
2068
2069
0
                ValueFlow::Value result(0);
2070
0
                result.condition = arrayValue.condition ? arrayValue.condition : indexValue.condition;
2071
0
                result.setInconclusive(arrayValue.isInconclusive() || indexValue.isInconclusive());
2072
0
                result.varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId;
2073
0
                result.varvalue = (result.varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue;
2074
0
                if (arrayValue.valueKind == indexValue.valueKind)
2075
0
                    result.valueKind = arrayValue.valueKind;
2076
2077
0
                result.errorPath.insert(result.errorPath.end(),
2078
0
                                        arrayValue.errorPath.cbegin(),
2079
0
                                        arrayValue.errorPath.cend());
2080
0
                result.errorPath.insert(result.errorPath.end(),
2081
0
                                        indexValue.errorPath.cbegin(),
2082
0
                                        indexValue.errorPath.cend());
2083
2084
0
                const MathLib::bigint index = indexValue.intvalue;
2085
2086
0
                if (arrayValue.tokvalue->tokType() == Token::eString) {
2087
0
                    const std::string s = arrayValue.tokvalue->strValue();
2088
0
                    if (index == s.size()) {
2089
0
                        result.intvalue = 0;
2090
0
                        setTokenValue(tok, std::move(result), settings);
2091
0
                    } else if (index >= 0 && index < s.size()) {
2092
0
                        result.intvalue = s[static_cast<std::size_t>(index)];
2093
0
                        setTokenValue(tok, std::move(result), settings);
2094
0
                    }
2095
0
                } else if (match4(arrayValue.tokvalue)) {
2096
0
                    std::vector<const Token*> args = getArguments(arrayValue.tokvalue);
2097
0
                    if (index < 0 || index >= args.size())
2098
0
                        continue;
2099
0
                    const Token* arg = args[static_cast<std::size_t>(index)];
2100
0
                    if (!arg->hasKnownIntValue())
2101
0
                        continue;
2102
0
                    const ValueFlow::Value& v = arg->values().front();
2103
0
                    result.intvalue = v.intvalue;
2104
0
                    result.errorPath.insert(result.errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
2105
0
                    setTokenValue(tok, std::move(result), settings);
2106
0
                }
2107
0
            }
2108
0
        }
2109
0
    }
2110
1.17k
}
2111
2112
static void valueFlowPointerAlias(TokenList& tokenlist, const Settings& settings)
2113
764
{
2114
55.6k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
2115
        // not address of
2116
54.9k
        if (!tok->isUnaryOp("&"))
2117
54.9k
            continue;
2118
2119
        // parent should be a '='
2120
4
        if (!match9(tok->astParent()))
2121
4
            continue;
2122
2123
        // child should be some buffer or variable
2124
0
        const Token* vartok = tok->astOperand1();
2125
0
        while (vartok) {
2126
0
            if (vartok->str() == MatchCompiler::makeConstString("["))
2127
0
                vartok = vartok->astOperand1();
2128
0
            else if (vartok->str() == MatchCompiler::makeConstString(".") || vartok->str() == MatchCompiler::makeConstString("::"))
2129
0
                vartok = vartok->astOperand2();
2130
0
            else
2131
0
                break;
2132
0
        }
2133
0
        if (!(vartok && vartok->variable() && !vartok->variable()->isPointer()))
2134
0
            continue;
2135
2136
0
        ValueFlow::Value value;
2137
0
        value.valueType = ValueFlow::Value::ValueType::TOK;
2138
0
        value.tokvalue = tok;
2139
0
        setTokenValue(tok, std::move(value), settings);
2140
0
    }
2141
764
}
2142
2143
static void valueFlowBitAnd(TokenList& tokenlist, const Settings& settings)
2144
764
{
2145
55.6k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
2146
54.9k
        if (tok->str() != MatchCompiler::makeConstString("&"))
2147
54.7k
            continue;
2148
2149
139
        if (tok->hasKnownValue())
2150
2
            continue;
2151
2152
137
        if (!tok->astOperand1() || !tok->astOperand2())
2153
10
            continue;
2154
2155
127
        MathLib::bigint number;
2156
127
        if (MathLib::isInt(tok->astOperand1()->str()))
2157
1
            number = MathLib::toBigNumber(tok->astOperand1());
2158
126
        else if (MathLib::isInt(tok->astOperand2()->str()))
2159
3
            number = MathLib::toBigNumber(tok->astOperand2());
2160
123
        else
2161
123
            continue;
2162
2163
4
        int bit = 0;
2164
8
        while (bit <= (MathLib::bigint_bits - 2) && ((((MathLib::bigint)1) << bit) < number))
2165
4
            ++bit;
2166
2167
4
        if ((((MathLib::bigint)1) << bit) == number) {
2168
3
            setTokenValue(tok, ValueFlow::Value(0), settings);
2169
3
            setTokenValue(tok, ValueFlow::Value(number), settings);
2170
3
        }
2171
4
    }
2172
764
}
2173
2174
static void valueFlowSameExpressions(TokenList& tokenlist, const Settings& settings)
2175
764
{
2176
55.6k
    for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
2177
54.9k
        if (tok->hasKnownIntValue())
2178
8.49k
            continue;
2179
2180
46.4k
        if (!tok->astOperand1() || !tok->astOperand2())
2181
41.9k
            continue;
2182
2183
4.49k
        if (tok->astOperand1()->isLiteral() || tok->astOperand2()->isLiteral())
2184
21
            continue;
2185
2186
4.47k
        if (!astIsIntegral(tok->astOperand1(), false) && !astIsIntegral(tok->astOperand2(), false))
2187
361
            continue;
2188
2189
4.11k
        long long val;
2190
2191
4.11k
        if (match17(tok)) {
2192
350
            val = 1;
2193
350
        }
2194
3.76k
        else if (match18(tok)) {
2195
717
            val = 0;
2196
717
        }
2197
3.04k
        else
2198
3.04k
            continue;
2199
2200
1.06k
        ValueFlow::Value value(val);
2201
1.06k
        value.setKnown();
2202
2203
1.06k
        if (isSameExpression(false, tok->astOperand1(), tok->astOperand2(), settings, true, true, &value.errorPath)) {
2204
265
            setTokenValue(tok, std::move(value), settings);
2205
265
        }
2206
1.06k
    }
2207
764
}
2208
2209
static bool getExpressionRange(const Token* expr, MathLib::bigint* minvalue, MathLib::bigint* maxvalue)
2210
0
{
2211
0
    if (expr->hasKnownIntValue()) {
2212
0
        if (minvalue)
2213
0
            *minvalue = expr->values().front().intvalue;
2214
0
        if (maxvalue)
2215
0
            *maxvalue = expr->values().front().intvalue;
2216
0
        return true;
2217
0
    }
2218
2219
0
    if (expr->str() == MatchCompiler::makeConstString("&") && expr->astOperand1() && expr->astOperand2()) {
2220
0
        MathLib::bigint vals[4];
2221
0
        const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
2222
0
        const bool rhsHasKnownRange = getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]);
2223
0
        if (!lhsHasKnownRange && !rhsHasKnownRange)
2224
0
            return false;
2225
0
        if (!lhsHasKnownRange || !rhsHasKnownRange) {
2226
0
            if (minvalue)
2227
0
                *minvalue = lhsHasKnownRange ? vals[0] : vals[2];
2228
0
            if (maxvalue)
2229
0
                *maxvalue = lhsHasKnownRange ? vals[1] : vals[3];
2230
0
        } else {
2231
0
            if (minvalue)
2232
0
                *minvalue = vals[0] & vals[2];
2233
0
            if (maxvalue)
2234
0
                *maxvalue = vals[1] & vals[3];
2235
0
        }
2236
0
        return true;
2237
0
    }
2238
2239
0
    if (expr->str() == MatchCompiler::makeConstString("%") && expr->astOperand1() && expr->astOperand2()) {
2240
0
        MathLib::bigint vals[4];
2241
0
        if (!getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]))
2242
0
            return false;
2243
0
        if (vals[2] <= 0)
2244
0
            return false;
2245
0
        const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]);
2246
0
        if (lhsHasKnownRange && vals[0] < 0)
2247
0
            return false;
2248
        // If lhs has unknown value, it must be unsigned
2249
0
        if (!lhsHasKnownRange &&
2250
0
            (!expr->astOperand1()->valueType() || expr->astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED))
2251
0
            return false;
2252
0
        if (minvalue)
2253
0
            *minvalue = 0;
2254
0
        if (maxvalue)
2255
0
            *maxvalue = vals[3] - 1;
2256
0
        return true;
2257
0
    }
2258
2259
0
    return false;
2260
0
}
2261
2262
static void valueFlowRightShift(TokenList& tokenList, const Settings& settings)
2263
1.17k
{
2264
90.3k
    for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
2265
89.1k
        if (tok->str() != MatchCompiler::makeConstString(">>"))
2266
89.1k
            continue;
2267
2268
0
        if (tok->hasKnownValue())
2269
0
            continue;
2270
2271
0
        if (!tok->astOperand1() || !tok->astOperand2())
2272
0
            continue;
2273
2274
0
        if (!tok->astOperand2()->hasKnownValue())
2275
0
            continue;
2276
2277
0
        const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue;
2278
0
        if (rhsvalue < 0)
2279
0
            continue;
2280
2281
0
        if (!tok->astOperand1()->valueType() || !tok->astOperand1()->valueType()->isIntegral())
2282
0
            continue;
2283
2284
0
        if (!tok->astOperand2()->valueType() || !tok->astOperand2()->valueType()->isIntegral())
2285
0
            continue;
2286
2287
0
        MathLib::bigint lhsmax = 0;
2288
0
        if (!getExpressionRange(tok->astOperand1(), nullptr, &lhsmax))
2289
0
            continue;
2290
0
        if (lhsmax < 0)
2291
0
            continue;
2292
0
        int lhsbits;
2293
0
        if ((tok->astOperand1()->valueType()->type == ValueType::Type::CHAR) ||
2294
0
            (tok->astOperand1()->valueType()->type == ValueType::Type::SHORT) ||
2295
0
            (tok->astOperand1()->valueType()->type == ValueType::Type::WCHAR_T) ||
2296
0
            (tok->astOperand1()->valueType()->type == ValueType::Type::BOOL) ||
2297
0
            (tok->astOperand1()->valueType()->type == ValueType::Type::INT))
2298
0
            lhsbits = settings.platform.int_bit;
2299
0
        else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONG)
2300
0
            lhsbits = settings.platform.long_bit;
2301
0
        else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONGLONG)
2302
0
            lhsbits = settings.platform.long_long_bit;
2303
0
        else
2304
0
            continue;
2305
0
        if (rhsvalue >= lhsbits || rhsvalue >= MathLib::bigint_bits || (1ULL << rhsvalue) <= lhsmax)
2306
0
            continue;
2307
2308
0
        ValueFlow::Value val(0);
2309
0
        val.setKnown();
2310
0
        setTokenValue(tok, std::move(val), settings);
2311
0
    }
2312
1.17k
}
2313
2314
static std::vector<MathLib::bigint> minUnsignedValue(const Token* tok, int depth = 8)
2315
0
{
2316
0
    std::vector<MathLib::bigint> result;
2317
0
    if (!tok)
2318
0
        return result;
2319
0
    if (depth < 0)
2320
0
        return result;
2321
0
    if (tok->hasKnownIntValue()) {
2322
0
        result = {tok->values().front().intvalue};
2323
0
    } else if (!match19(tok) && tok->isConstOp() && tok->astOperand1() && tok->astOperand2()) {
2324
0
        std::vector<MathLib::bigint> op1 = minUnsignedValue(tok->astOperand1(), depth - 1);
2325
0
        if (!op1.empty()) {
2326
0
            std::vector<MathLib::bigint> op2 = minUnsignedValue(tok->astOperand2(), depth - 1);
2327
0
            if (!op2.empty()) {
2328
0
                result = calculate<std::vector<MathLib::bigint>>(tok->str(), op1.front(), op2.front());
2329
0
            }
2330
0
        }
2331
0
    }
2332
0
    if (result.empty() && astIsUnsigned(tok))
2333
0
        result = {0};
2334
0
    return result;
2335
0
}
2336
2337
static bool isConvertedToIntegral(const Token* tok, const Settings& settings)
2338
2
{
2339
2
    if (!tok)
2340
0
        return false;
2341
2
    std::vector<ValueType> parentTypes = getParentValueTypes(tok, settings);
2342
2
    if (parentTypes.empty())
2343
2
        return false;
2344
0
    const ValueType& vt = parentTypes.front();
2345
0
    return vt.type != ValueType::UNKNOWN_INT && vt.isIntegral();
2346
2
}
2347
2348
static bool isSameToken(const Token* tok1, const Token* tok2)
2349
0
{
2350
0
    if (!tok1 || !tok2)
2351
0
        return false;
2352
0
    if (tok1->exprId() != 0 && tok1->exprId() == tok2->exprId())
2353
0
        return true;
2354
0
    if (tok1->hasKnownIntValue() && tok2->hasKnownIntValue())
2355
0
        return tok1->values().front().intvalue == tok2->values().front().intvalue;
2356
0
    return false;
2357
0
}
2358
2359
static void valueFlowImpossibleValues(TokenList& tokenList, const Settings& settings)
2360
1.17k
{
2361
90.3k
    for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
2362
89.1k
        if (tok->hasKnownIntValue())
2363
13.6k
            continue;
2364
75.5k
        if (match20(tok))
2365
0
            continue;
2366
75.5k
        if (astIsBool(tok) || match12(tok)) {
2367
1.45k
            ValueFlow::Value lower{-1};
2368
1.45k
            lower.bound = ValueFlow::Value::Bound::Upper;
2369
1.45k
            lower.setImpossible();
2370
1.45k
            setTokenValue(tok, std::move(lower), settings);
2371
2372
1.45k
            ValueFlow::Value upper{2};
2373
1.45k
            upper.bound = ValueFlow::Value::Bound::Lower;
2374
1.45k
            upper.setImpossible();
2375
1.45k
            setTokenValue(tok, std::move(upper), settings);
2376
74.0k
        } else if (astIsUnsigned(tok) && !astIsPointer(tok)) {
2377
0
            std::vector<MathLib::bigint> minvalue = minUnsignedValue(tok);
2378
0
            if (minvalue.empty())
2379
0
                continue;
2380
0
            ValueFlow::Value value{std::max<MathLib::bigint>(0, minvalue.front()) - 1};
2381
0
            value.bound = ValueFlow::Value::Bound::Upper;
2382
0
            value.setImpossible();
2383
0
            setTokenValue(tok, std::move(value), settings);
2384
0
        }
2385
75.5k
        if (match22(tok) && match21(tok->astOperand1())) {
2386
0
            const Token* condTok = tok->astOperand1();
2387
0
            const Token* branchesTok = tok->astOperand2();
2388
2389
0
            auto tokens = makeArray(condTok->astOperand1(), condTok->astOperand2());
2390
0
            auto branches = makeArray(branchesTok->astOperand1(), branchesTok->astOperand2());
2391
0
            bool flipped = false;
2392
0
            if (std::equal(tokens.cbegin(), tokens.cend(), branches.crbegin(), &isSameToken))
2393
0
                flipped = true;
2394
0
            else if (!std::equal(tokens.cbegin(), tokens.cend(), branches.cbegin(), &isSameToken))
2395
0
                continue;
2396
0
            std::vector<ValueFlow::Value> values;
2397
0
            for (const Token* tok2 : tokens) {
2398
0
                if (tok2->hasKnownIntValue()) {
2399
0
                    values.emplace_back(tok2->values().front());
2400
0
                } else {
2401
0
                    ValueFlow::Value symValue{};
2402
0
                    symValue.valueType = ValueFlow::Value::ValueType::SYMBOLIC;
2403
0
                    symValue.tokvalue = tok2;
2404
0
                    values.push_back(symValue);
2405
0
                    std::copy_if(tok2->values().cbegin(),
2406
0
                                 tok2->values().cend(),
2407
0
                                 std::back_inserter(values),
2408
0
                                 [](const ValueFlow::Value& v) {
2409
0
                        if (!v.isKnown())
2410
0
                            return false;
2411
0
                        return v.isSymbolicValue();
2412
0
                    });
2413
0
                }
2414
0
            }
2415
0
            const bool isMin = match1(condTok) ^ flipped;
2416
0
            for (ValueFlow::Value& value : values) {
2417
0
                value.setImpossible();
2418
0
                if (isMin) {
2419
0
                    value.intvalue++;
2420
0
                    value.bound = ValueFlow::Value::Bound::Lower;
2421
0
                } else {
2422
0
                    value.intvalue--;
2423
0
                    value.bound = ValueFlow::Value::Bound::Upper;
2424
0
                }
2425
0
                setTokenValue(tok, std::move(value), settings);
2426
0
            }
2427
2428
75.5k
        } else if (match23(tok) && tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) {
2429
0
            ValueFlow::Value value{tok->astOperand2()->values().front()};
2430
0
            value.bound = ValueFlow::Value::Bound::Lower;
2431
0
            value.setImpossible();
2432
0
            setTokenValue(tok, std::move(value), settings);
2433
75.5k
        } else if (match24(tok)) {
2434
0
            ValueFlow::Value value{-1};
2435
0
            value.bound = ValueFlow::Value::Bound::Upper;
2436
0
            value.setImpossible();
2437
0
            setTokenValue(tok->next(), std::move(value), settings);
2438
75.5k
        } else if (match25(tok) && astIsContainerOwned(tok->astOperand1())) {
2439
0
            const Library::Container* container = getLibraryContainer(tok->astOperand1());
2440
0
            if (!container)
2441
0
                continue;
2442
0
            if (!container->stdStringLike)
2443
0
                continue;
2444
0
            if (container->view)
2445
0
                continue;
2446
0
            ValueFlow::Value value{0};
2447
0
            value.setImpossible();
2448
0
            setTokenValue(tok->tokAt(2), std::move(value), settings);
2449
75.5k
        } else if (match26(tok) && match27(tok->linkAt(1))) {
2450
0
            ValueFlow::Value value{0};
2451
0
            value.setImpossible();
2452
0
            setTokenValue(tok->linkAt(1)->next(), std::move(value), settings);
2453
75.5k
        } else if ((tokenList.isCPP() && match28(tok)) || tok->isUnaryOp("&")) {
2454
8
            ValueFlow::Value value{0};
2455
8
            value.setImpossible();
2456
8
            setTokenValue(tok, std::move(value), settings);
2457
75.5k
        } else if (tok->variable() && tok->variable()->isArray() && !tok->variable()->isArgument() &&
2458
75.5k
                   !tok->variable()->isStlType()) {
2459
0
            ValueFlow::Value value{0};
2460
0
            value.setImpossible();
2461
0
            setTokenValue(tok, std::move(value), settings);
2462
75.5k
        } else if (tok->isIncompleteVar() && tok->astParent() && tok->astParent()->isUnaryOp("-") &&
2463
75.5k
                   isConvertedToIntegral(tok->astParent(), settings)) {
2464
0
            ValueFlow::Value value{0};
2465
0
            value.setImpossible();
2466
0
            setTokenValue(tok, std::move(value), settings);
2467
0
        }
2468
75.5k
    }
2469
1.17k
}
2470
2471
static void valueFlowEnumValue(SymbolDatabase & symboldatabase, const Settings & settings)
2472
1.52k
{
2473
5.59k
    for (Scope & scope : symboldatabase.scopeList) {
2474
5.59k
        if (scope.type != Scope::eEnum)
2475
5.59k
            continue;
2476
0
        MathLib::bigint value = 0;
2477
0
        bool prev_enum_is_known = true;
2478
2479
0
        for (Enumerator & enumerator : scope.enumeratorList) {
2480
0
            if (enumerator.start) {
2481
0
                auto* rhs = const_cast<Token*>(enumerator.start->previous()->astOperand2());
2482
0
                ValueFlow::valueFlowConstantFoldAST(rhs, settings);
2483
0
                if (rhs && rhs->hasKnownIntValue()) {
2484
0
                    enumerator.value = rhs->values().front().intvalue;
2485
0
                    enumerator.value_known = true;
2486
0
                    value = enumerator.value + 1;
2487
0
                    prev_enum_is_known = true;
2488
0
                } else
2489
0
                    prev_enum_is_known = false;
2490
0
            } else if (prev_enum_is_known) {
2491
0
                enumerator.value = value++;
2492
0
                enumerator.value_known = true;
2493
0
            }
2494
0
        }
2495
0
    }
2496
1.52k
}
2497
2498
static void valueFlowGlobalConstVar(TokenList& tokenList, const Settings& settings)
2499
764
{
2500
    // Get variable values...
2501
764
    std::map<const Variable*, ValueFlow::Value> vars;
2502
55.6k
    for (const Token* tok = tokenList.front(); tok; tok = tok->next()) {
2503
54.9k
        if (!tok->variable())
2504
43.2k
            continue;
2505
        // Initialization...
2506
11.6k
        if (tok == tok->variable()->nameToken() && !tok->variable()->isVolatile() && !tok->variable()->isArgument() &&
2507
11.6k
            tok->variable()->isConst() && tok->valueType() && tok->valueType()->isIntegral() &&
2508
11.6k
            tok->valueType()->pointer == 0 && tok->valueType()->constness == 1 && match29(tok) &&
2509
11.6k
            tok->next()->astOperand2() && tok->next()->astOperand2()->hasKnownIntValue()) {
2510
0
            vars[tok->variable()] = tok->next()->astOperand2()->values().front();
2511
0
        }
2512
11.6k
    }
2513
2514
    // Set values..
2515
55.6k
    for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
2516
54.9k
        if (!tok->variable())
2517
43.2k
            continue;
2518
11.6k
        const auto var = utils::as_const(vars).find(tok->variable());
2519
11.6k
        if (var == vars.end())
2520
11.6k
            continue;
2521
0
        setTokenValue(tok, var->second, settings);
2522
0
    }
2523
764
}
2524
2525
static void valueFlowGlobalStaticVar(TokenList& tokenList, const Settings& settings)
2526
764
{
2527
    // Get variable values...
2528
764
    std::map<const Variable*, ValueFlow::Value> vars;
2529
55.6k
    for (const Token* tok = tokenList.front(); tok; tok = tok->next()) {
2530
54.9k
        if (!tok->variable())
2531
43.2k
            continue;
2532
        // Initialization...
2533
11.6k
        if (tok == tok->variable()->nameToken() && tok->variable()->isStatic() && !tok->variable()->isConst() &&
2534
11.6k
            tok->valueType() && tok->valueType()->isIntegral() && tok->valueType()->pointer == 0 &&
2535
11.6k
            tok->valueType()->constness == 0 && match29(tok) && tok->next()->astOperand2() &&
2536
11.6k
            tok->next()->astOperand2()->hasKnownIntValue()) {
2537
0
            vars[tok->variable()] = tok->next()->astOperand2()->values().front();
2538
11.6k
        } else {
2539
            // If variable is written anywhere in TU then remove it from vars
2540
11.6k
            if (!tok->astParent())
2541
3.82k
                continue;
2542
7.87k
            if (match30(tok->astParent()) && !tok->astParent()->astOperand2())
2543
633
                vars.erase(tok->variable());
2544
7.24k
            else if (tok->astParent()->isAssignmentOp()) {
2545
5.64k
                if (tok == tok->astParent()->astOperand1())
2546
4.06k
                    vars.erase(tok->variable());
2547
1.58k
                else if (tok->isCpp() && match31(tok->astParent()->tokAt(-2)))
2548
0
                    vars.erase(tok->variable());
2549
5.64k
            } else if (isLikelyStreamRead(tok->astParent())) {
2550
0
                vars.erase(tok->variable());
2551
1.59k
            } else if (match32(tok->astParent()))
2552
0
                vars.erase(tok->variable());
2553
7.87k
        }
2554
11.6k
    }
2555
2556
    // Set values..
2557
55.6k
    for (Token* tok = tokenList.front(); tok; tok = tok->next()) {
2558
54.9k
        if (!tok->variable())
2559
43.2k
            continue;
2560
11.6k
        const auto var = utils::as_const(vars).find(tok->variable());
2561
11.6k
        if (var == vars.end())
2562
11.6k
            continue;
2563
0
        setTokenValue(tok, var->second, settings);
2564
0
    }
2565
764
}
2566
2567
static Analyzer::Result valueFlowForward(Token* startToken,
2568
                                         const Token* endToken,
2569
                                         const Token* exprTok,
2570
                                         ValueFlow::Value value,
2571
                                         const TokenList& tokenlist,
2572
                                         ErrorLogger& errorLogger,
2573
                                         const Settings& settings,
2574
                                         SourceLocation loc = SourceLocation::current())
2575
3.03k
{
2576
3.03k
    if (settings.debugnormal)
2577
0
        setSourceLocation(value, loc, startToken);
2578
3.03k
    return valueFlowGenericForward(startToken,
2579
3.03k
                                   endToken,
2580
3.03k
                                   makeAnalyzer(exprTok, std::move(value), settings),
2581
3.03k
                                   tokenlist,
2582
3.03k
                                   errorLogger,
2583
3.03k
                                   settings);
2584
3.03k
}
2585
2586
static Analyzer::Result valueFlowForward(Token* startToken,
2587
                                         const Token* endToken,
2588
                                         const Token* exprTok,
2589
                                         std::list<ValueFlow::Value> values,
2590
                                         const TokenList& tokenlist,
2591
                                         ErrorLogger& errorLogger,
2592
                                         const Settings& settings,
2593
                                         SourceLocation loc = SourceLocation::current())
2594
2.03k
{
2595
2.03k
    Analyzer::Result result{};
2596
2.96k
    for (ValueFlow::Value& v : values) {
2597
2.96k
        result.update(valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc));
2598
2.96k
    }
2599
2.03k
    return result;
2600
2.03k
}
2601
2602
template<class ValueOrValues>
2603
static Analyzer::Result valueFlowForward(Token* startToken,
2604
                                         const Token* exprTok,
2605
                                         ValueOrValues v,
2606
                                         const TokenList& tokenlist,
2607
                                         ErrorLogger& errorLogger,
2608
                                         const Settings& settings,
2609
                                         SourceLocation loc = SourceLocation::current())
2610
0
{
2611
0
    const Token* endToken = nullptr;
2612
0
    const Function* f = Scope::nestedInFunction(startToken->scope());
2613
0
    if (f && f->functionScope)
2614
0
        endToken = f->functionScope->bodyEnd;
2615
0
    if (!endToken && exprTok && exprTok->variable() && !exprTok->variable()->isLocal())
2616
0
        endToken = startToken->scope()->bodyEnd;
2617
0
    return valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc);
2618
0
}
2619
2620
static Analyzer::Result valueFlowForwardRecursive(Token* top,
2621
                                                  const Token* exprTok,
2622
                                                  std::list<ValueFlow::Value> values,
2623
                                                  const TokenList& tokenlist,
2624
                                                  ErrorLogger& errorLogger,
2625
                                                  const Settings& settings,
2626
                                                  SourceLocation loc = SourceLocation::current())
2627
0
{
2628
0
    Analyzer::Result result{};
2629
0
    for (ValueFlow::Value& v : values) {
2630
0
        if (settings.debugnormal)
2631
0
            setSourceLocation(v, loc, top);
2632
0
        result.update(
2633
0
            valueFlowGenericForward(top, makeAnalyzer(exprTok, std::move(v), settings), tokenlist, errorLogger, settings));
2634
0
    }
2635
0
    return result;
2636
0
}
2637
2638
static void valueFlowReverse(Token* tok,
2639
                             const Token* const endToken,
2640
                             const Token* const varToken,
2641
                             std::list<ValueFlow::Value> values,
2642
                             const TokenList& tokenlist,
2643
                             ErrorLogger& errorLogger,
2644
                             const Settings& settings,
2645
                             SourceLocation loc = SourceLocation::current())
2646
633
{
2647
865
    for (ValueFlow::Value& v : values) {
2648
865
        if (settings.debugnormal)
2649
0
            setSourceLocation(v, loc, tok);
2650
865
        valueFlowGenericReverse(tok,
2651
865
                                endToken,
2652
865
                                makeReverseAnalyzer(varToken, std::move(v), settings),
2653
865
                                tokenlist,
2654
865
                                errorLogger,
2655
865
                                settings);
2656
865
    }
2657
633
}
2658
2659
// Deprecated
2660
static void valueFlowReverse(const TokenList& tokenlist,
2661
                             Token* tok,
2662
                             const Token* const varToken,
2663
                             ValueFlow::Value val,
2664
                             ErrorLogger& errorLogger,
2665
                             const Settings& settings,
2666
                             SourceLocation loc = SourceLocation::current())
2667
0
{
2668
0
    valueFlowReverse(tok, nullptr, varToken, {std::move(val)}, tokenlist, errorLogger, settings, loc);
2669
0
}
2670
2671
static bool isConditionKnown(const Token* tok, bool then)
2672
2.24k
{
2673
2.24k
    const char* op = "||";
2674
2.24k
    if (then)
2675
1.24k
        op = "&&";
2676
2.24k
    const Token* parent = tok->astParent();
2677
2.24k
    while (parent && (parent->str() == op || parent->str() == MatchCompiler::makeConstString("!") || parent->isCast()))
2678
0
        parent = parent->astParent();
2679
2.24k
    const Token* top = tok->astTop();
2680
2.24k
    if (match14(top->previous()))
2681
2.24k
        return parent == top || match33(parent);
2682
0
    return parent && parent->str() != op;
2683
2.24k
}
2684
2685
enum class LifetimeCapture : std::uint8_t { Undefined, ByValue, ByReference };
2686
2687
static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
2688
0
{
2689
0
    std::string result;
2690
0
    if (!val)
2691
0
        return "object";
2692
0
    switch (val->lifetimeKind) {
2693
0
    case ValueFlow::Value::LifetimeKind::Lambda:
2694
0
        result = "lambda";
2695
0
        break;
2696
0
    case ValueFlow::Value::LifetimeKind::Iterator:
2697
0
        result = "iterator";
2698
0
        break;
2699
0
    case ValueFlow::Value::LifetimeKind::Object:
2700
0
    case ValueFlow::Value::LifetimeKind::SubObject:
2701
0
    case ValueFlow::Value::LifetimeKind::Address:
2702
0
        if (astIsPointer(tok))
2703
0
            result = "pointer";
2704
0
        else if (match9(tok) && astIsPointer(tok->astOperand2()))
2705
0
            result = "pointer";
2706
0
        else
2707
0
            result = "object";
2708
0
        break;
2709
0
    }
2710
0
    return result;
2711
0
}
2712
2713
std::string ValueFlow::lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath)
2714
0
{
2715
0
    const Token *tokvalue = val ? val->tokvalue : nullptr;
2716
0
    const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr;
2717
0
    const Token *vartok = tokvar ? tokvar->nameToken() : nullptr;
2718
0
    const bool classVar = tokvar ? (!tokvar->isLocal() && !tokvar->isArgument() && !tokvar->isGlobal()) : false;
2719
0
    std::string type = lifetimeType(tok, val);
2720
0
    std::string msg = type;
2721
0
    if (vartok) {
2722
0
        if (!classVar)
2723
0
            errorPath.emplace_back(vartok, "Variable created here.");
2724
0
        const Variable * var = vartok->variable();
2725
0
        if (var) {
2726
0
            std::string submessage;
2727
0
            switch (val->lifetimeKind) {
2728
0
            case ValueFlow::Value::LifetimeKind::SubObject:
2729
0
            case ValueFlow::Value::LifetimeKind::Object:
2730
0
            case ValueFlow::Value::LifetimeKind::Address:
2731
0
                if (type == MatchCompiler::makeConstString("pointer"))
2732
0
                    submessage = " to local variable";
2733
0
                else
2734
0
                    submessage = " that points to local variable";
2735
0
                break;
2736
0
            case ValueFlow::Value::LifetimeKind::Lambda:
2737
0
                submessage = " that captures local variable";
2738
0
                break;
2739
0
            case ValueFlow::Value::LifetimeKind::Iterator:
2740
0
                submessage = " to local container";
2741
0
                break;
2742
0
            }
2743
0
            if (classVar)
2744
0
                submessage.replace(submessage.find("local"), 5, "member");
2745
0
            msg += submessage + " '" + var->name() + "'";
2746
0
        }
2747
0
    }
2748
0
    return msg;
2749
0
}
2750
2751
std::vector<ValueFlow::Value> ValueFlow::getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path)
2752
2.04k
{
2753
2.04k
    std::vector<ValueFlow::Value> result;
2754
2.04k
    auto pred = [&](const ValueFlow::Value& v) {
2755
386
        if (!v.isLocalLifetimeValue() && !(path != 0 && v.isSubFunctionLifetimeValue()))
2756
383
            return false;
2757
3
        if (!inconclusive && v.isInconclusive())
2758
0
            return false;
2759
3
        if (!v.tokvalue)
2760
0
            return false;
2761
3
        if (path >= 0 && v.path != 0 && v.path != path)
2762
0
            return false;
2763
3
        return true;
2764
3
    };
2765
2.04k
    std::copy_if(tok->values().cbegin(), tok->values().cend(), std::back_inserter(result), pred);
2766
2.04k
    return result;
2767
2.04k
}
2768
2769
static bool hasUniqueOwnership(const Token* tok)
2770
0
{
2771
0
    if (!tok)
2772
0
        return false;
2773
0
    const Variable* var = tok->variable();
2774
0
    if (var && var->isArray() && !var->isArgument())
2775
0
        return true;
2776
0
    if (astIsPointer(tok))
2777
0
        return false;
2778
0
    if (astIsUniqueSmartPointer(tok))
2779
0
        return true;
2780
0
    if (astIsContainerOwned(tok))
2781
0
        return true;
2782
0
    return false;
2783
0
}
2784
2785
// Check if dereferencing an object that doesn't have unique ownership
2786
static bool derefShared(const Token* tok)
2787
0
{
2788
0
    if (!tok)
2789
0
        return false;
2790
0
    if (!tok->isUnaryOp("*") && tok->str() != MatchCompiler::makeConstString("[") && tok->str() != MatchCompiler::makeConstString("."))
2791
0
        return false;
2792
0
    if (tok->str() == MatchCompiler::makeConstString(".") && tok->originalName() != MatchCompiler::makeConstString("->"))
2793
0
        return false;
2794
0
    const Token* ptrTok = tok->astOperand1();
2795
0
    return !hasUniqueOwnership(ptrTok);
2796
0
}
2797
2798
ValueFlow::Value ValueFlow::getLifetimeObjValue(const Token *tok, bool inconclusive)
2799
2
{
2800
2
    std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(tok, inconclusive);
2801
    // There should only be one lifetime
2802
2
    if (values.size() != 1)
2803
2
        return ValueFlow::Value{};
2804
0
    return values.front();
2805
2
}
2806
2807
template<class Predicate>
2808
static std::vector<ValueFlow::LifetimeToken> getLifetimeTokens(const Token* tok,
2809
                                                               bool escape,
2810
                                                               ErrorPath errorPath,
2811
                                                               Predicate pred,
2812
                                                               const Settings& settings,
2813
                                                               int depth = 20)
2814
11.2k
{
2815
11.2k
    if (!tok)
2816
0
        return std::vector<ValueFlow::LifetimeToken> {};
2817
11.2k
    if (match34(tok))
2818
0
        return std::vector<ValueFlow::LifetimeToken>{};
2819
11.2k
    const Variable *var = tok->variable();
2820
11.2k
    if (pred(tok))
2821
0
        return {{tok, std::move(errorPath)}};
2822
11.2k
    if (depth < 0)
2823
0
        return {{tok, std::move(errorPath)}};
2824
11.2k
    if (var && var->declarationId() == tok->varId()) {
2825
11.2k
        if (var->isReference() || var->isRValueReference()) {
2826
0
            const Token * const varDeclEndToken = var->declEndToken();
2827
0
            if (!varDeclEndToken)
2828
0
                return {{tok, true, std::move(errorPath)}};
2829
0
            if (var->isArgument()) {
2830
0
                errorPath.emplace_back(varDeclEndToken, "Passed to reference.");
2831
0
                return {{tok, true, std::move(errorPath)}};
2832
0
            }
2833
0
            if (match35(varDeclEndToken)) {
2834
0
                errorPath.emplace_back(varDeclEndToken, "Assigned to reference.");
2835
0
                const Token *vartok = varDeclEndToken->astOperand2();
2836
0
                const bool temporary = isTemporary(vartok, nullptr, true);
2837
0
                const bool nonlocal = var->isStatic() || var->isGlobal();
2838
0
                if (vartok == tok || (nonlocal && temporary) ||
2839
0
                    (!escape && (var->isConst() || var->isRValueReference()) && temporary))
2840
0
                    return {{tok, true, std::move(errorPath)}};
2841
0
                if (vartok)
2842
0
                    return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
2843
0
            } else if (match36(var->nameToken()->astParent()) &&
2844
0
                       var->nameToken()->astParent()->astParent() &&
2845
0
                       match37(var->nameToken()->astParent()->astParent()->previous())) {
2846
0
                errorPath.emplace_back(var->nameToken(), "Assigned to reference.");
2847
0
                const Token* vartok = var->nameToken();
2848
0
                if (vartok == tok)
2849
0
                    return {{tok, true, std::move(errorPath)}};
2850
0
                const Token* contok = var->nameToken()->astParent()->astOperand2();
2851
0
                if (astIsContainer(contok))
2852
0
                    return ValueFlow::LifetimeToken::setAddressOf(
2853
0
                        getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1),
2854
0
                        false);
2855
0
                return std::vector<ValueFlow::LifetimeToken>{};
2856
0
            } else {
2857
0
                return std::vector<ValueFlow::LifetimeToken> {};
2858
0
            }
2859
0
        }
2860
11.2k
    } else if (match38(tok->previous())) {
2861
0
        const Function *f = tok->previous()->function();
2862
0
        if (f) {
2863
0
            if (!Function::returnsReference(f))
2864
0
                return {{tok, std::move(errorPath)}};
2865
0
            std::vector<ValueFlow::LifetimeToken> result;
2866
0
            std::vector<const Token*> returns = Function::findReturns(f);
2867
0
            for (const Token* returnTok : returns) {
2868
0
                if (returnTok == tok)
2869
0
                    continue;
2870
0
                for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, settings, depth - returns.size())) {
2871
0
                    const Token* argvarTok = lt.token;
2872
0
                    const Variable* argvar = argvarTok->variable();
2873
0
                    if (!argvar)
2874
0
                        continue;
2875
0
                    const Token* argTok = nullptr;
2876
0
                    if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
2877
0
                        const int n = getArgumentPos(argvar, f);
2878
0
                        if (n < 0)
2879
0
                            return std::vector<ValueFlow::LifetimeToken> {};
2880
0
                        std::vector<const Token*> args = getArguments(tok->previous());
2881
                        // TODO: Track lifetimes of default parameters
2882
0
                        if (n >= args.size())
2883
0
                            return std::vector<ValueFlow::LifetimeToken> {};
2884
0
                        argTok = args[n];
2885
0
                        lt.errorPath.emplace_back(returnTok, "Return reference.");
2886
0
                        lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
2887
0
                    } else if (match16(tok->tokAt(-2)) && !derefShared(tok->tokAt(-2)) &&
2888
0
                               exprDependsOnThis(argvarTok)) {
2889
0
                        argTok = tok->tokAt(-2)->astOperand1();
2890
0
                        lt.errorPath.emplace_back(returnTok, "Return reference that depends on 'this'.");
2891
0
                        lt.errorPath.emplace_back(tok->previous(),
2892
0
                                                  "Calling member function on '" + argTok->expressionString() + "'.");
2893
0
                    }
2894
0
                    if (argTok) {
2895
0
                        std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive(
2896
0
                            getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()),
2897
0
                            returns.size() > 1);
2898
0
                        result.insert(result.end(), arglts.cbegin(), arglts.cend());
2899
0
                    }
2900
0
                }
2901
0
            }
2902
0
            return result;
2903
0
        }
2904
0
        if (match16(tok->tokAt(-2)) && tok->tokAt(-2)->originalName() != MatchCompiler::makeConstString("->") && astIsContainer(tok->tokAt(-2)->astOperand1())) {
2905
0
            const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1());
2906
0
            const Library::Container::Yield y = library->getYield(tok->strAt(-1));
2907
0
            if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) {
2908
0
                errorPath.emplace_back(tok->previous(), "Accessing container.");
2909
0
                return ValueFlow::LifetimeToken::setAddressOf(
2910
0
                    getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, settings, depth - 1),
2911
0
                    false);
2912
0
            }
2913
0
        }
2914
0
    } else if (match39(tok) || tok->isUnaryOp("*")) {
2915
2916
0
        const Token *vartok = tok;
2917
0
        while (vartok) {
2918
0
            if (vartok->str() == MatchCompiler::makeConstString("[") || vartok->isUnaryOp("*"))
2919
0
                vartok = vartok->astOperand1();
2920
0
            else if (vartok->str() == MatchCompiler::makeConstString(".")) {
2921
0
                if (!match40(vartok->astOperand1()) &&
2922
0
                    !(vartok->astOperand2() && vartok->astOperand2()->valueType() && vartok->astOperand2()->valueType()->reference != Reference::None))
2923
0
                    vartok = vartok->astOperand1();
2924
0
                else
2925
0
                    break;
2926
0
            }
2927
0
            else if (vartok->str() == MatchCompiler::makeConstString("::"))
2928
0
                vartok = vartok->astOperand2();
2929
0
            else
2930
0
                break;
2931
0
        }
2932
2933
0
        if (!vartok)
2934
0
            return {{tok, std::move(errorPath)}};
2935
0
        if (derefShared(vartok->astParent())) {
2936
0
            for (const ValueFlow::Value &v : vartok->values()) {
2937
0
                if (!v.isLocalLifetimeValue())
2938
0
                    continue;
2939
0
                if (v.tokvalue == tok)
2940
0
                    continue;
2941
0
                errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
2942
0
                return ValueFlow::LifetimeToken::setAddressOf(
2943
0
                    getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1),
2944
0
                    false);
2945
0
            }
2946
0
        } else {
2947
0
            return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1),
2948
0
                                                          !(astIsContainer(vartok) && match15(vartok->astParent())));
2949
0
        }
2950
0
    } else if (match4(tok) && getArgumentStart(tok) &&
2951
0
               !match41(getArgumentStart(tok)) && getArgumentStart(tok)->valueType()) {
2952
0
        const Token* vartok = getArgumentStart(tok);
2953
0
        auto vts = getParentValueTypes(tok, settings);
2954
0
        auto it = std::find_if(vts.cbegin(), vts.cend(), [&](const ValueType& vt) {
2955
0
            return vt.isTypeEqual(vartok->valueType());
2956
0
        });
Unexecuted instantiation: valueflow.cpp:getLifetimeTokens<ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0, Settings const&, int)::{lambda(ValueType const&)#1}::operator()(ValueType const&) const
Unexecuted instantiation: valueflow.cpp:getLifetimeTokens<ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0, Settings const&, int)::{lambda(ValueType const&)#1}::operator()(ValueType const&) const
2957
0
        if (it != vts.end())
2958
0
            return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
2959
0
    }
2960
11.2k
    return {{tok, std::move(errorPath)}};
2961
11.2k
}
valueflow.cpp:std::__1::vector<ValueFlow::LifetimeToken, std::__1::allocator<ValueFlow::LifetimeToken> > getLifetimeTokens<ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0, Settings const&, int)
Line
Count
Source
2814
11.2k
{
2815
11.2k
    if (!tok)
2816
0
        return std::vector<ValueFlow::LifetimeToken> {};
2817
11.2k
    if (match34(tok))
2818
0
        return std::vector<ValueFlow::LifetimeToken>{};
2819
11.2k
    const Variable *var = tok->variable();
2820
11.2k
    if (pred(tok))
2821
0
        return {{tok, std::move(errorPath)}};
2822
11.2k
    if (depth < 0)
2823
0
        return {{tok, std::move(errorPath)}};
2824
11.2k
    if (var && var->declarationId() == tok->varId()) {
2825
11.2k
        if (var->isReference() || var->isRValueReference()) {
2826
0
            const Token * const varDeclEndToken = var->declEndToken();
2827
0
            if (!varDeclEndToken)
2828
0
                return {{tok, true, std::move(errorPath)}};
2829
0
            if (var->isArgument()) {
2830
0
                errorPath.emplace_back(varDeclEndToken, "Passed to reference.");
2831
0
                return {{tok, true, std::move(errorPath)}};
2832
0
            }
2833
0
            if (match35(varDeclEndToken)) {
2834
0
                errorPath.emplace_back(varDeclEndToken, "Assigned to reference.");
2835
0
                const Token *vartok = varDeclEndToken->astOperand2();
2836
0
                const bool temporary = isTemporary(vartok, nullptr, true);
2837
0
                const bool nonlocal = var->isStatic() || var->isGlobal();
2838
0
                if (vartok == tok || (nonlocal && temporary) ||
2839
0
                    (!escape && (var->isConst() || var->isRValueReference()) && temporary))
2840
0
                    return {{tok, true, std::move(errorPath)}};
2841
0
                if (vartok)
2842
0
                    return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
2843
0
            } else if (match36(var->nameToken()->astParent()) &&
2844
0
                       var->nameToken()->astParent()->astParent() &&
2845
0
                       match37(var->nameToken()->astParent()->astParent()->previous())) {
2846
0
                errorPath.emplace_back(var->nameToken(), "Assigned to reference.");
2847
0
                const Token* vartok = var->nameToken();
2848
0
                if (vartok == tok)
2849
0
                    return {{tok, true, std::move(errorPath)}};
2850
0
                const Token* contok = var->nameToken()->astParent()->astOperand2();
2851
0
                if (astIsContainer(contok))
2852
0
                    return ValueFlow::LifetimeToken::setAddressOf(
2853
0
                        getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1),
2854
0
                        false);
2855
0
                return std::vector<ValueFlow::LifetimeToken>{};
2856
0
            } else {
2857
0
                return std::vector<ValueFlow::LifetimeToken> {};
2858
0
            }
2859
0
        }
2860
11.2k
    } else if (match38(tok->previous())) {
2861
0
        const Function *f = tok->previous()->function();
2862
0
        if (f) {
2863
0
            if (!Function::returnsReference(f))
2864
0
                return {{tok, std::move(errorPath)}};
2865
0
            std::vector<ValueFlow::LifetimeToken> result;
2866
0
            std::vector<const Token*> returns = Function::findReturns(f);
2867
0
            for (const Token* returnTok : returns) {
2868
0
                if (returnTok == tok)
2869
0
                    continue;
2870
0
                for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, settings, depth - returns.size())) {
2871
0
                    const Token* argvarTok = lt.token;
2872
0
                    const Variable* argvar = argvarTok->variable();
2873
0
                    if (!argvar)
2874
0
                        continue;
2875
0
                    const Token* argTok = nullptr;
2876
0
                    if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
2877
0
                        const int n = getArgumentPos(argvar, f);
2878
0
                        if (n < 0)
2879
0
                            return std::vector<ValueFlow::LifetimeToken> {};
2880
0
                        std::vector<const Token*> args = getArguments(tok->previous());
2881
                        // TODO: Track lifetimes of default parameters
2882
0
                        if (n >= args.size())
2883
0
                            return std::vector<ValueFlow::LifetimeToken> {};
2884
0
                        argTok = args[n];
2885
0
                        lt.errorPath.emplace_back(returnTok, "Return reference.");
2886
0
                        lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
2887
0
                    } else if (match16(tok->tokAt(-2)) && !derefShared(tok->tokAt(-2)) &&
2888
0
                               exprDependsOnThis(argvarTok)) {
2889
0
                        argTok = tok->tokAt(-2)->astOperand1();
2890
0
                        lt.errorPath.emplace_back(returnTok, "Return reference that depends on 'this'.");
2891
0
                        lt.errorPath.emplace_back(tok->previous(),
2892
0
                                                  "Calling member function on '" + argTok->expressionString() + "'.");
2893
0
                    }
2894
0
                    if (argTok) {
2895
0
                        std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive(
2896
0
                            getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()),
2897
0
                            returns.size() > 1);
2898
0
                        result.insert(result.end(), arglts.cbegin(), arglts.cend());
2899
0
                    }
2900
0
                }
2901
0
            }
2902
0
            return result;
2903
0
        }
2904
0
        if (match16(tok->tokAt(-2)) && tok->tokAt(-2)->originalName() != MatchCompiler::makeConstString("->") && astIsContainer(tok->tokAt(-2)->astOperand1())) {
2905
0
            const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1());
2906
0
            const Library::Container::Yield y = library->getYield(tok->strAt(-1));
2907
0
            if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) {
2908
0
                errorPath.emplace_back(tok->previous(), "Accessing container.");
2909
0
                return ValueFlow::LifetimeToken::setAddressOf(
2910
0
                    getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, settings, depth - 1),
2911
0
                    false);
2912
0
            }
2913
0
        }
2914
0
    } else if (match39(tok) || tok->isUnaryOp("*")) {
2915
2916
0
        const Token *vartok = tok;
2917
0
        while (vartok) {
2918
0
            if (vartok->str() == MatchCompiler::makeConstString("[") || vartok->isUnaryOp("*"))
2919
0
                vartok = vartok->astOperand1();
2920
0
            else if (vartok->str() == MatchCompiler::makeConstString(".")) {
2921
0
                if (!match40(vartok->astOperand1()) &&
2922
0
                    !(vartok->astOperand2() && vartok->astOperand2()->valueType() && vartok->astOperand2()->valueType()->reference != Reference::None))
2923
0
                    vartok = vartok->astOperand1();
2924
0
                else
2925
0
                    break;
2926
0
            }
2927
0
            else if (vartok->str() == MatchCompiler::makeConstString("::"))
2928
0
                vartok = vartok->astOperand2();
2929
0
            else
2930
0
                break;
2931
0
        }
2932
2933
0
        if (!vartok)
2934
0
            return {{tok, std::move(errorPath)}};
2935
0
        if (derefShared(vartok->astParent())) {
2936
0
            for (const ValueFlow::Value &v : vartok->values()) {
2937
0
                if (!v.isLocalLifetimeValue())
2938
0
                    continue;
2939
0
                if (v.tokvalue == tok)
2940
0
                    continue;
2941
0
                errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
2942
0
                return ValueFlow::LifetimeToken::setAddressOf(
2943
0
                    getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1),
2944
0
                    false);
2945
0
            }
2946
0
        } else {
2947
0
            return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1),
2948
0
                                                          !(astIsContainer(vartok) && match15(vartok->astParent())));
2949
0
        }
2950
0
    } else if (match4(tok) && getArgumentStart(tok) &&
2951
0
               !match41(getArgumentStart(tok)) && getArgumentStart(tok)->valueType()) {
2952
0
        const Token* vartok = getArgumentStart(tok);
2953
0
        auto vts = getParentValueTypes(tok, settings);
2954
0
        auto it = std::find_if(vts.cbegin(), vts.cend(), [&](const ValueType& vt) {
2955
0
            return vt.isTypeEqual(vartok->valueType());
2956
0
        });
2957
0
        if (it != vts.end())
2958
0
            return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
2959
0
    }
2960
11.2k
    return {{tok, std::move(errorPath)}};
2961
11.2k
}
Unexecuted instantiation: valueflow.cpp:std::__1::vector<ValueFlow::LifetimeToken, std::__1::allocator<ValueFlow::LifetimeToken> > getLifetimeTokens<ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0, Settings const&, int)
2962
2963
std::vector<ValueFlow::LifetimeToken> ValueFlow::getLifetimeTokens(const Token* tok, const Settings& settings, bool escape, ErrorPath errorPath)
2964
11.2k
{
2965
11.2k
    return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) {
2966
11.2k
        return false;
2967
11.2k
    }, settings);
2968
11.2k
}
2969
2970
bool ValueFlow::hasLifetimeToken(const Token* tok, const Token* lifetime, const Settings& settings)
2971
0
{
2972
0
    bool result = false;
2973
0
    getLifetimeTokens(tok, false, ErrorPath{}, [&](const Token* tok2) {
2974
0
        result = tok2->exprId() == lifetime->exprId();
2975
0
        return result;
2976
0
    }, settings);
2977
0
    return result;
2978
0
}
2979
2980
static const Token* getLifetimeToken(const Token* tok, ErrorPath& errorPath, const Settings& settings, bool* addressOf = nullptr)
2981
11.2k
{
2982
11.2k
    std::vector<ValueFlow::LifetimeToken> lts = ValueFlow::getLifetimeTokens(tok, settings);
2983
11.2k
    if (lts.size() != 1)
2984
0
        return nullptr;
2985
11.2k
    if (lts.front().inconclusive)
2986
0
        return nullptr;
2987
11.2k
    if (addressOf)
2988
0
        *addressOf = lts.front().addressOf;
2989
11.2k
    errorPath.insert(errorPath.end(), lts.front().errorPath.cbegin(), lts.front().errorPath.cend());
2990
11.2k
    return lts.front().token;
2991
11.2k
}
2992
2993
const Variable* ValueFlow::getLifetimeVariable(const Token* tok, ErrorPath& errorPath, const Settings& settings, bool* addressOf)
2994
11.2k
{
2995
11.2k
    const Token* tok2 = getLifetimeToken(tok, errorPath, settings, addressOf);
2996
11.2k
    if (tok2 && tok2->variable())
2997
11.2k
        return tok2->variable();
2998
0
    return nullptr;
2999
11.2k
}
3000
3001
const Variable* ValueFlow::getLifetimeVariable(const Token* tok, const Settings& settings)
3002
0
{
3003
0
    ErrorPath errorPath;
3004
0
    return getLifetimeVariable(tok, errorPath, settings, nullptr);
3005
0
}
3006
3007
static bool isNotLifetimeValue(const ValueFlow::Value& val)
3008
0
{
3009
0
    return !val.isLifetimeValue();
3010
0
}
3011
3012
static bool isLifetimeOwned(const ValueType* vtParent)
3013
2
{
3014
2
    if (vtParent->container)
3015
0
        return !vtParent->container->view;
3016
2
    return vtParent->type == ValueType::CONTAINER;
3017
2
}
3018
3019
static bool isLifetimeOwned(const ValueType *vt, const ValueType *vtParent)
3020
1
{
3021
1
    if (!vtParent)
3022
0
        return false;
3023
1
    if (isLifetimeOwned(vtParent))
3024
0
        return true;
3025
1
    if (!vt)
3026
0
        return false;
3027
    // If converted from iterator to pointer then the iterator is most likely a pointer
3028
1
    if (vtParent->pointer == 1 && vt->pointer == 0 && vt->type == ValueType::ITERATOR)
3029
0
        return false;
3030
1
    if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE) {
3031
1
        if (vt->pointer != vtParent->pointer)
3032
0
            return true;
3033
1
        if (vt->type != vtParent->type) {
3034
1
            if (vtParent->type == ValueType::RECORD)
3035
0
                return true;
3036
1
            if (isLifetimeOwned(vtParent))
3037
0
                return true;
3038
1
        }
3039
1
    }
3040
3041
1
    return false;
3042
1
}
3043
3044
static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
3045
4
{
3046
4
    if (!vtParent)
3047
0
        return false;
3048
4
    if (!vt)
3049
0
        return false;
3050
4
    if (vt->pointer > 0 && vt->pointer == vtParent->pointer)
3051
0
        return true;
3052
4
    if (vtParent->container && vtParent->container->view)
3053
0
        return true;
3054
4
    if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE && vtParent->container == vt->container) {
3055
4
        if (vtParent->pointer > vt->pointer)
3056
0
            return true;
3057
4
        if (vtParent->pointer < vt->pointer && vtParent->isIntegral())
3058
2
            return true;
3059
2
        if (vtParent->str() == vt->str())
3060
1
            return true;
3061
2
    }
3062
3063
1
    return false;
3064
4
}
3065
3066
static const Token* skipCVRefs(const Token* tok, const Token* endTok)
3067
0
{
3068
0
    while (tok != endTok && match42(tok))
3069
0
        tok = tok->next();
3070
0
    return tok;
3071
0
}
3072
3073
static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const Token*, const Token*> y)
3074
1.73k
{
3075
1.73k
    const Token* start1 = x.first;
3076
1.73k
    const Token* start2 = y.first;
3077
1.73k
    if (start1 == nullptr || start2 == nullptr)
3078
1.73k
        return false;
3079
0
    while (start1 != x.second && start2 != y.second) {
3080
0
        const Token* tok1 = skipCVRefs(start1, x.second);
3081
0
        if (tok1 != start1) {
3082
0
            start1 = tok1;
3083
0
            continue;
3084
0
        }
3085
0
        const Token* tok2 = skipCVRefs(start2, y.second);
3086
0
        if (tok2 != start2) {
3087
0
            start2 = tok2;
3088
0
            continue;
3089
0
        }
3090
0
        if (start1->str() != start2->str())
3091
0
            return true;
3092
0
        start1 = start1->next();
3093
0
        start2 = start2->next();
3094
0
    }
3095
0
    start1 = skipCVRefs(start1, x.second);
3096
0
    start2 = skipCVRefs(start2, y.second);
3097
0
    return !(start1 == x.second && start2 == y.second);
3098
0
}
3099
static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y, bool cpp)
3100
0
{
3101
0
    TokenList tokenList(nullptr);
3102
0
    std::istringstream istr(y);
3103
0
    tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C); // TODO: check result?
3104
0
    return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back()));
3105
0
}
3106
static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y, bool cpp)
3107
3.46k
{
3108
3.46k
    if (y == nullptr)
3109
1.89k
        return false;
3110
1.57k
    if (y->originalTypeName.empty())
3111
1.57k
        return false;
3112
0
    return isNotEqual(x, y->originalTypeName, cpp);
3113
1.57k
}
3114
3115
static bool isDifferentType(const Token* src, const Token* dst)
3116
1.73k
{
3117
1.73k
    const Type* t = Token::typeOf(src);
3118
1.73k
    const Type* parentT = Token::typeOf(dst);
3119
1.73k
    if (t && parentT) {
3120
0
        if (t->classDef && parentT->classDef && t->classDef != parentT->classDef)
3121
0
            return true;
3122
1.73k
    } else {
3123
1.73k
        std::pair<const Token*, const Token*> decl = Token::typeDecl(src);
3124
1.73k
        std::pair<const Token*, const Token*> parentdecl = Token::typeDecl(dst);
3125
1.73k
        const bool isCpp = (src && src->isCpp()) || (dst && dst->isCpp());
3126
1.73k
        if (isNotEqual(decl, parentdecl) && !(isCpp && (match43(decl.first) || match43(parentdecl.first))))
3127
0
            return true;
3128
1.73k
        if (isNotEqual(decl, dst->valueType(), isCpp))
3129
0
            return true;
3130
1.73k
        if (isNotEqual(parentdecl, src->valueType(), isCpp))
3131
0
            return true;
3132
1.73k
    }
3133
1.73k
    return false;
3134
1.73k
}
3135
3136
bool ValueFlow::isLifetimeBorrowed(const Token *tok, const Settings &settings)
3137
6
{
3138
6
    if (!tok)
3139
0
        return true;
3140
6
    if (tok->str() == MatchCompiler::makeConstString(","))
3141
0
        return true;
3142
6
    if (!tok->astParent())
3143
0
        return true;
3144
6
    const Token* parent = nullptr;
3145
6
    const ValueType* vt = tok->valueType();
3146
6
    std::vector<ValueType> vtParents = getParentValueTypes(tok, settings, &parent);
3147
6
    for (const ValueType& vtParent : vtParents) {
3148
4
        if (isLifetimeBorrowed(vt, &vtParent))
3149
3
            return true;
3150
1
        if (isLifetimeOwned(vt, &vtParent))
3151
0
            return false;
3152
1
    }
3153
3
    if (parent) {
3154
1
        if (isDifferentType(tok, parent))
3155
0
            return false;
3156
1
    }
3157
3
    return true;
3158
3
}
3159
3160
static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings);
3161
3162
static void valueFlowLifetimeConstructor(Token *tok,
3163
                                         const TokenList &tokenlist,
3164
                                         ErrorLogger &errorLogger,
3165
                                         const Settings &settings);
3166
3167
static bool isRangeForScope(const Scope* scope)
3168
0
{
3169
0
    if (!scope)
3170
0
        return false;
3171
0
    if (scope->type != Scope::eFor)
3172
0
        return false;
3173
0
    if (!scope->bodyStart)
3174
0
        return false;
3175
0
    if (!match44(scope->bodyStart->previous()))
3176
0
        return false;
3177
0
    return match36(scope->bodyStart->linkAt(-1)->astOperand2());
3178
0
}
3179
3180
static const Token* getEndOfVarScope(const Variable* var)
3181
0
{
3182
0
    if (!var)
3183
0
        return nullptr;
3184
0
    const Scope* innerScope = var->scope();
3185
0
    const Scope* outerScope = innerScope;
3186
0
    if (var->typeStartToken() && var->typeStartToken()->scope())
3187
0
        outerScope = var->typeStartToken()->scope();
3188
0
    if (!innerScope && outerScope)
3189
0
        innerScope = outerScope;
3190
0
    if (!innerScope || !outerScope)
3191
0
        return nullptr;
3192
0
    if (!innerScope->isExecutable())
3193
0
        return nullptr;
3194
    // If the variable is defined in a for/while initializer then we want to
3195
    // pick one token after the end so forward analysis can analyze the exit
3196
    // conditions
3197
0
    if (innerScope != outerScope && outerScope->isExecutable() && innerScope->isLoopScope() &&
3198
0
        !isRangeForScope(innerScope))
3199
0
        return innerScope->bodyEnd->next();
3200
0
    return innerScope->bodyEnd;
3201
0
}
3202
3203
const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* defaultScope, bool smallest)
3204
2.86k
{
3205
2.86k
    const Token* end = nullptr;
3206
2.86k
    bool local = false;
3207
2.93k
    visitAstNodes(tok, [&](const Token* child) {
3208
2.93k
        if (const Variable* var = child->variable()) {
3209
483
            local |= var->isLocal();
3210
483
            if (var->isLocal() || var->isArgument()) {
3211
0
                const Token* varEnd = getEndOfVarScope(var);
3212
0
                if (!end || (smallest ? precedes(varEnd, end) : succeeds(varEnd, end)))
3213
0
                    end = varEnd;
3214
3215
0
                const Token* top = var->nameToken()->astTop();
3216
0
                if (match45(top->tokAt(-1))) { // variable declared in if (...)
3217
0
                    const Token* elseTok = top->link()->linkAt(1);
3218
0
                    if (match46(elseTok) && tok->scope()->isNestedIn(elseTok->tokAt(2)->scope()))
3219
0
                        end = tok->scope()->bodyEnd;
3220
0
                }
3221
0
            }
3222
483
        }
3223
2.93k
        return ChildrenToVisit::op1_and_op2;
3224
2.93k
    });
3225
2.86k
    if (!end && defaultScope)
3226
2.43k
        end = defaultScope->bodyEnd;
3227
2.86k
    if (!end) {
3228
425
        const Scope* scope = tok->scope();
3229
425
        if (scope)
3230
425
            end = scope->bodyEnd;
3231
        // If there is no local variables then pick the function scope
3232
425
        if (!local) {
3233
654
            while (scope && scope->isLocal())
3234
229
                scope = scope->nestedIn;
3235
425
            if (scope && scope->isExecutable())
3236
425
                end = scope->bodyEnd;
3237
425
        }
3238
425
    }
3239
2.86k
    return end;
3240
2.86k
}
3241
3242
static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
3243
205
{
3244
    // Forward lifetimes to constructed variable
3245
205
    if (match47(tok->previous()) && isVariableDecl(tok->previous())) {
3246
0
        std::list<ValueFlow::Value> values = tok->values();
3247
0
        values.remove_if(&isNotLifetimeValue);
3248
0
        valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), std::move(values), tokenlist, errorLogger, settings);
3249
0
        return;
3250
0
    }
3251
205
    Token *parent = tok->astParent();
3252
205
    while (parent && parent->str() == MatchCompiler::makeConstString(","))
3253
0
        parent = parent->astParent();
3254
205
    if (!parent)
3255
187
        return;
3256
    // Assignment
3257
18
    if (parent->str() == MatchCompiler::makeConstString("=") && (!parent->astParent() || match33(parent->astParent()))) {
3258
        // Rhs values..
3259
0
        if (!parent->astOperand2() || parent->astOperand2()->values().empty())
3260
0
            return;
3261
3262
0
        if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings))
3263
0
            return;
3264
3265
0
        const Token* expr = getLHSVariableToken(parent);
3266
0
        if (!expr)
3267
0
            return;
3268
3269
0
        if (expr->exprId() == 0)
3270
0
            return;
3271
3272
0
        const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr);
3273
3274
        // Only forward lifetime values
3275
0
        std::list<ValueFlow::Value> values = parent->astOperand2()->values();
3276
0
        values.remove_if(&isNotLifetimeValue);
3277
        // Dont forward lifetimes that overlap
3278
0
        values.remove_if([&](const ValueFlow::Value& value) {
3279
0
            return findAstNode(value.tokvalue, [&](const Token* child) {
3280
0
                return child->exprId() == expr->exprId();
3281
0
            });
3282
0
        });
3283
3284
        // Skip RHS
3285
0
        Token* nextExpression = nextAfterAstRightmostLeaf(parent);
3286
3287
0
        if (expr->exprId() > 0) {
3288
0
            valueFlowForward(nextExpression, endOfVarScope->next(), expr, values, tokenlist, errorLogger, settings);
3289
3290
0
            for (ValueFlow::Value& val : values) {
3291
0
                if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
3292
0
                    val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject;
3293
0
            }
3294
            // TODO: handle `[`
3295
0
            if (match40(parent->astOperand1())) {
3296
0
                const Token* parentLifetime =
3297
0
                    getParentLifetime(parent->astOperand1()->astOperand2(), settings.library);
3298
0
                if (parentLifetime && parentLifetime->exprId() > 0) {
3299
0
                    valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings);
3300
0
                }
3301
0
            }
3302
0
        }
3303
        // Constructor
3304
18
    } else if (match4(parent) && !isScopeBracket(parent)) {
3305
0
        valueFlowLifetimeConstructor(parent, tokenlist, errorLogger, settings);
3306
0
        valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3307
        // Function call
3308
18
    } else if (match38(parent->previous())) {
3309
0
        valueFlowLifetimeFunction(parent->previous(), tokenlist, errorLogger, settings);
3310
0
        valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3311
        // Variable
3312
18
    } else if (tok->variable() && tok->variable()->scope()) {
3313
0
        const Variable *var = tok->variable();
3314
0
        const Token *endOfVarScope = var->scope()->bodyEnd;
3315
3316
0
        std::list<ValueFlow::Value> values = tok->values();
3317
0
        Token *nextExpression = nextAfterAstRightmostLeaf(parent);
3318
        // Only forward lifetime values
3319
0
        values.remove_if(&isNotLifetimeValue);
3320
0
        valueFlowForward(nextExpression, endOfVarScope, tok, std::move(values), tokenlist, errorLogger, settings);
3321
        // Cast
3322
18
    } else if (parent->isCast()) {
3323
0
        std::list<ValueFlow::Value> values = tok->values();
3324
        // Only forward lifetime values
3325
0
        values.remove_if(&isNotLifetimeValue);
3326
0
        for (ValueFlow::Value& value:values)
3327
0
            setTokenValue(parent, std::move(value), settings);
3328
0
        valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings);
3329
0
    }
3330
18
}
3331
3332
struct LifetimeStore {
3333
    const Token* argtok{};
3334
    std::string message;
3335
    ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object;
3336
    ErrorPath errorPath;
3337
    bool inconclusive{};
3338
    bool forward = true;
3339
3340
0
    LifetimeStore() = default;
3341
3342
    LifetimeStore(const Token* argtok,
3343
                  std::string message,
3344
                  ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object,
3345
                  bool inconclusive = false)
3346
0
        : argtok(argtok),
3347
0
        message(std::move(message)),
3348
0
        type(type),
3349
0
        inconclusive(inconclusive)
3350
0
    {}
3351
3352
    template<class F>
3353
    static void forEach(const TokenList& tokenlist,
3354
                        ErrorLogger& errorLogger,
3355
                        const Settings& settings,
3356
                        const std::vector<const Token*>& argtoks,
3357
                        const std::string& message,
3358
                        ValueFlow::Value::LifetimeKind type,
3359
0
                        F f) {
3360
0
        std::set<Token*> forwardToks;
3361
0
        for (const Token* arg : argtoks) {
3362
0
            LifetimeStore ls{arg, message, type};
3363
0
            ls.forward = false;
3364
0
            f(ls);
3365
0
            if (ls.forwardTok)
3366
0
                forwardToks.emplace(ls.forwardTok);
3367
0
        }
3368
0
        for (auto* tok : forwardToks) {
3369
0
            valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3370
0
        }
3371
0
    }
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_0)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_1)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_2>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_2)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_0)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_1)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_0)
Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_1)
3372
3373
0
    static LifetimeStore fromFunctionArg(const Function * f, const Token *tok, const Variable *var, const TokenList &tokenlist, const Settings& settings, ErrorLogger &errorLogger) {
3374
0
        if (!var)
3375
0
            return LifetimeStore{};
3376
0
        if (!var->isArgument())
3377
0
            return LifetimeStore{};
3378
0
        const int n = getArgumentPos(var, f);
3379
0
        if (n < 0)
3380
0
            return LifetimeStore{};
3381
0
        std::vector<const Token *> args = getArguments(tok);
3382
0
        if (n >= args.size()) {
3383
0
            if (settings.debugwarnings)
3384
0
                bailout(tokenlist,
3385
0
                        errorLogger,
3386
0
                        tok,
3387
0
                        "Argument mismatch: Function '" + tok->str() + "' returning lifetime from argument index " +
3388
0
                        std::to_string(n) + " but only " + std::to_string(args.size()) +
3389
0
                        " arguments are available.");
3390
0
            return LifetimeStore{};
3391
0
        }
3392
0
        const Token *argtok2 = args[n];
3393
0
        return LifetimeStore{argtok2, "Passed to '" + tok->expressionString() + "'.", ValueFlow::Value::LifetimeKind::Object};
3394
0
    }
3395
3396
    template<class Predicate>
3397
    bool byRef(Token* tok,
3398
               const TokenList& tokenlist,
3399
               ErrorLogger& errorLogger,
3400
               const Settings& settings,
3401
               const Predicate& pred,
3402
               SourceLocation loc = SourceLocation::current())
3403
0
    {
3404
0
        if (!argtok)
3405
0
            return false;
3406
0
        bool update = false;
3407
0
        for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) {
3408
0
            if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3409
0
                continue;
3410
0
            if (!lt.token)
3411
0
                return false;
3412
0
            if (!pred(lt.token))
3413
0
                return false;
3414
0
            ErrorPath er = errorPath;
3415
0
            er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
3416
0
            er.emplace_back(argtok, message);
3417
3418
0
            ValueFlow::Value value;
3419
0
            value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3420
0
            value.lifetimeScope = ValueFlow::Value::LifetimeScope::Local;
3421
0
            value.tokvalue = lt.token;
3422
0
            value.errorPath = std::move(er);
3423
0
            value.lifetimeKind = type;
3424
0
            value.setInconclusive(lt.inconclusive || inconclusive);
3425
            // Don't add the value a second time
3426
0
            if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
3427
0
                return false;
3428
0
            if (settings.debugnormal)
3429
0
                setSourceLocation(value, loc, tok);
3430
0
            setTokenValue(tok, std::move(value), settings);
3431
0
            update = true;
3432
0
        }
3433
0
        if (update && forward)
3434
0
            forwardLifetime(tok, tokenlist, errorLogger, settings);
3435
0
        return update;
3436
0
    }
Unexecuted instantiation: bool LifetimeStore::byRef<std::__1::function<bool (Token const*)> >(Token*, TokenList const&, ErrorLogger&, Settings const&, std::__1::function<bool (Token const*)> const&, SourceLocation)
Unexecuted instantiation: bool LifetimeStore::byRef<LifetimeStore::byRef(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byRef(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1} const&, SourceLocation)
3437
3438
    bool byRef(Token* tok,
3439
               const TokenList& tokenlist,
3440
               ErrorLogger& errorLogger,
3441
               const Settings& settings,
3442
               SourceLocation loc = SourceLocation::current())
3443
0
    {
3444
0
        return byRef(
3445
0
            tok,
3446
0
            tokenlist,
3447
0
            errorLogger,
3448
0
            settings,
3449
0
            [](const Token*) {
3450
0
            return true;
3451
0
        },
3452
0
            loc);
3453
0
    }
3454
3455
    template<class Predicate>
3456
    bool byVal(Token* tok,
3457
               const TokenList& tokenlist,
3458
               ErrorLogger& errorLogger,
3459
               const Settings& settings,
3460
               const Predicate& pred,
3461
               SourceLocation loc = SourceLocation::current())
3462
0
    {
3463
0
        if (!argtok)
3464
0
            return false;
3465
0
        bool update = false;
3466
0
        if (argtok->values().empty()) {
3467
0
            ErrorPath er;
3468
0
            er.emplace_back(argtok, message);
3469
0
            for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) {
3470
0
                if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3471
0
                    continue;
3472
0
                ValueFlow::Value value;
3473
0
                value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3474
0
                value.tokvalue = lt.token;
3475
0
                value.capturetok = argtok;
3476
0
                value.errorPath = er;
3477
0
                value.lifetimeKind = type;
3478
0
                value.setInconclusive(inconclusive || lt.inconclusive);
3479
0
                const Variable* var = lt.token->variable();
3480
0
                if (var && var->isArgument()) {
3481
0
                    value.lifetimeScope = ValueFlow::Value::LifetimeScope::Argument;
3482
0
                } else {
3483
0
                    continue;
3484
0
                }
3485
                // Don't add the value a second time
3486
0
                if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
3487
0
                    continue;
3488
0
                if (settings.debugnormal)
3489
0
                    setSourceLocation(value, loc, tok);
3490
0
                setTokenValue(tok, std::move(value), settings);
3491
0
                update = true;
3492
0
            }
3493
0
        }
3494
0
        for (const ValueFlow::Value &v : argtok->values()) {
3495
0
            if (!v.isLifetimeValue())
3496
0
                continue;
3497
0
            const Token *tok3 = v.tokvalue;
3498
0
            for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok3, settings)) {
3499
0
                if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
3500
0
                    continue;
3501
0
                ErrorPath er = v.errorPath;
3502
0
                er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
3503
0
                if (!lt.token)
3504
0
                    return false;
3505
0
                if (!pred(lt.token))
3506
0
                    return false;
3507
0
                er.emplace_back(argtok, message);
3508
0
                er.insert(er.end(), errorPath.cbegin(), errorPath.cend());
3509
3510
0
                ValueFlow::Value value;
3511
0
                value.valueType = ValueFlow::Value::ValueType::LIFETIME;
3512
0
                value.lifetimeScope = v.lifetimeScope;
3513
0
                value.path = v.path;
3514
0
                value.tokvalue = lt.token;
3515
0
                value.capturetok = argtok;
3516
0
                value.errorPath = std::move(er);
3517
0
                value.lifetimeKind = type;
3518
0
                value.setInconclusive(lt.inconclusive || v.isInconclusive() || inconclusive);
3519
                // Don't add the value a second time
3520
0
                if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend())
3521
0
                    continue;
3522
0
                if (settings.debugnormal)
3523
0
                    setSourceLocation(value, loc, tok);
3524
0
                setTokenValue(tok, std::move(value), settings);
3525
0
                update = true;
3526
0
            }
3527
0
        }
3528
0
        if (update && forward)
3529
0
            forwardLifetime(tok, tokenlist, errorLogger, settings);
3530
0
        return update;
3531
0
    }
Unexecuted instantiation: bool LifetimeStore::byVal<std::__1::function<bool (Token const*)> >(Token*, TokenList const&, ErrorLogger&, Settings const&, std::__1::function<bool (Token const*)> const&, SourceLocation)
Unexecuted instantiation: bool LifetimeStore::byVal<LifetimeStore::byVal(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byVal(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1} const&, SourceLocation)
Unexecuted instantiation: bool LifetimeStore::byVal<LifetimeStore::byDerefCopy(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation) const::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byDerefCopy(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation) const::{lambda(Token const*)#1} const&, SourceLocation)
3532
3533
    bool byVal(Token* tok,
3534
               const TokenList& tokenlist,
3535
               ErrorLogger& errorLogger,
3536
               const Settings& settings,
3537
               SourceLocation loc = SourceLocation::current())
3538
0
    {
3539
0
        return byVal(
3540
0
            tok,
3541
0
            tokenlist,
3542
0
            errorLogger,
3543
0
            settings,
3544
0
            [](const Token*) {
3545
0
            return true;
3546
0
        },
3547
0
            loc);
3548
0
    }
3549
3550
    template<class Predicate>
3551
    bool byDerefCopy(Token* tok,
3552
                     const TokenList& tokenlist,
3553
                     ErrorLogger& errorLogger,
3554
                     const Settings& settings,
3555
                     Predicate pred,
3556
                     SourceLocation loc = SourceLocation::current()) const
3557
0
    {
3558
0
        bool update = false;
3559
0
        if (!settings.certainty.isEnabled(Certainty::inconclusive) && inconclusive)
3560
0
            return update;
3561
0
        if (!argtok)
3562
0
            return update;
3563
0
        if (!tok)
3564
0
            return update;
3565
0
        for (const ValueFlow::Value &v : argtok->values()) {
3566
0
            if (!v.isLifetimeValue())
3567
0
                continue;
3568
0
            const Token *tok2 = v.tokvalue;
3569
0
            ErrorPath er = v.errorPath;
3570
0
            const Variable *var = ValueFlow::getLifetimeVariable(tok2, er, settings);
3571
            // TODO: the inserted data is never used
3572
0
            er.insert(er.end(), errorPath.cbegin(), errorPath.cend());
3573
0
            if (!var)
3574
0
                continue;
3575
0
            const Token * const varDeclEndToken = var->declEndToken();
3576
0
            for (const Token *tok3 = tok; tok3 && tok3 != varDeclEndToken; tok3 = tok3->previous()) {
3577
0
                if (tok3->varId() == var->declarationId()) {
3578
0
                    update |= LifetimeStore{tok3, message, type, inconclusive}
3579
0
                    .byVal(tok, tokenlist, errorLogger, settings, pred, loc);
3580
0
                    break;
3581
0
                }
3582
0
            }
3583
0
        }
3584
0
        return update;
3585
0
    }
3586
3587
    bool byDerefCopy(Token* tok,
3588
                     const TokenList& tokenlist,
3589
                     ErrorLogger& errorLogger,
3590
                     const Settings& settings,
3591
                     SourceLocation loc = SourceLocation::current()) const
3592
0
    {
3593
0
        return byDerefCopy(
3594
0
            tok,
3595
0
            tokenlist,
3596
0
            errorLogger,
3597
0
            settings,
3598
0
            [](const Token*) {
3599
0
            return true;
3600
0
        },
3601
0
            loc);
3602
0
    }
3603
3604
private:
3605
    // cppcheck-suppress naming-privateMemberVariable
3606
    Token* forwardTok{};
3607
0
    void forwardLifetime(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) {
3608
0
        forwardTok = tok;
3609
0
        valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3610
0
    }
3611
};
3612
3613
static bool hasBorrowingVariables(const std::list<Variable>& vars, const std::vector<const Token*>& args, int depth = 10)
3614
0
{
3615
0
    if (depth < 0)
3616
0
        return true;
3617
0
    return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) {
3618
0
        if (const ValueType* vt = var.valueType()) {
3619
0
            if (vt->pointer > 0 &&
3620
0
                std::none_of(args.begin(), args.end(), [vt](const Token* arg) {
3621
0
                return arg->valueType() && arg->valueType()->type == vt->type;
3622
0
            }))
3623
0
                return false;
3624
0
            if (vt->pointer > 0)
3625
0
                return true;
3626
0
            if (vt->reference != Reference::None)
3627
0
                return true;
3628
0
            if (vt->isPrimitive())
3629
0
                return false;
3630
0
            if (vt->isEnum())
3631
0
                return false;
3632
            // TODO: Check container inner type
3633
0
            if (vt->type == ValueType::CONTAINER && vt->container)
3634
0
                return vt->container->view;
3635
0
            if (vt->typeScope)
3636
0
                return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1);
3637
0
        }
3638
0
        return true;
3639
0
    });
3640
0
}
3641
3642
static void valueFlowLifetimeUserConstructor(Token* tok,
3643
                                             const Function* constructor,
3644
                                             const std::string& name,
3645
                                             const std::vector<const Token*>& args,
3646
                                             const TokenList& tokenlist,
3647
                                             ErrorLogger& errorLogger,
3648
                                             const Settings& settings)
3649
0
{
3650
0
    if (!constructor)
3651
0
        return;
3652
0
    std::unordered_map<const Token*, const Variable*> argToParam;
3653
0
    for (std::size_t i = 0; i < args.size(); i++)
3654
0
        argToParam[args[i]] = constructor->getArgumentVar(i);
3655
0
    if (const Token* initList = constructor->constructorMemberInitialization()) {
3656
0
        std::unordered_map<const Variable*, LifetimeCapture> paramCapture;
3657
0
        for (const Token* tok2 : astFlatten(initList->astOperand2(), ",")) {
3658
0
            if (!match48(tok2))
3659
0
                continue;
3660
0
            if (!tok2->astOperand1())
3661
0
                continue;
3662
0
            if (!tok2->astOperand2())
3663
0
                continue;
3664
0
            const Variable* var = tok2->astOperand1()->variable();
3665
0
            const Token* expr = tok2->astOperand2();
3666
0
            if (!var)
3667
0
                continue;
3668
0
            if (!ValueFlow::isLifetimeBorrowed(expr, settings))
3669
0
                continue;
3670
0
            const Variable* argvar = ValueFlow::getLifetimeVariable(expr, settings);
3671
0
            if (var->isReference() || var->isRValueReference()) {
3672
0
                if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
3673
0
                    paramCapture[argvar] = LifetimeCapture::ByReference;
3674
0
                }
3675
0
            } else {
3676
0
                bool found = false;
3677
0
                for (const ValueFlow::Value& v : expr->values()) {
3678
0
                    if (!v.isLifetimeValue())
3679
0
                        continue;
3680
0
                    if (v.path > 0)
3681
0
                        continue;
3682
0
                    if (!v.tokvalue)
3683
0
                        continue;
3684
0
                    const Variable* lifeVar = v.tokvalue->variable();
3685
0
                    if (!lifeVar)
3686
0
                        continue;
3687
0
                    LifetimeCapture c = LifetimeCapture::Undefined;
3688
0
                    if (!v.isArgumentLifetimeValue() && (lifeVar->isReference() || lifeVar->isRValueReference()))
3689
0
                        c = LifetimeCapture::ByReference;
3690
0
                    else if (v.isArgumentLifetimeValue())
3691
0
                        c = LifetimeCapture::ByValue;
3692
0
                    if (c != LifetimeCapture::Undefined) {
3693
0
                        paramCapture[lifeVar] = c;
3694
0
                        found = true;
3695
0
                    }
3696
0
                }
3697
0
                if (!found && argvar && argvar->isArgument())
3698
0
                    paramCapture[argvar] = LifetimeCapture::ByValue;
3699
0
            }
3700
0
        }
3701
        // TODO: Use SubExpressionAnalyzer for members
3702
0
        LifetimeStore::forEach(tokenlist,
3703
0
                               errorLogger,
3704
0
                               settings,
3705
0
                               args,
3706
0
                               "Passed to constructor of '" + name + "'.",
3707
0
                               ValueFlow::Value::LifetimeKind::SubObject,
3708
0
                               [&](LifetimeStore& ls) {
3709
0
            const Variable* paramVar = argToParam.at(ls.argtok);
3710
0
            if (paramCapture.count(paramVar) == 0)
3711
0
                return;
3712
0
            const LifetimeCapture c = paramCapture.at(paramVar);
3713
0
            if (c == LifetimeCapture::ByReference)
3714
0
                ls.byRef(tok, tokenlist, errorLogger, settings);
3715
0
            else
3716
0
                ls.byVal(tok, tokenlist, errorLogger, settings);
3717
0
        });
3718
0
    } else if (hasBorrowingVariables(constructor->nestedIn->varlist, args)) {
3719
0
        LifetimeStore::forEach(tokenlist,
3720
0
                               errorLogger,
3721
0
                               settings,
3722
0
                               args,
3723
0
                               "Passed to constructor of '" + name + "'.",
3724
0
                               ValueFlow::Value::LifetimeKind::SubObject,
3725
0
                               [&](LifetimeStore& ls) {
3726
0
            ls.inconclusive = true;
3727
0
            const Variable* var = argToParam.at(ls.argtok);
3728
0
            if (var && !var->isConst() && var->isReference())
3729
0
                ls.byRef(tok, tokenlist, errorLogger, settings);
3730
0
            else
3731
0
                ls.byVal(tok, tokenlist, errorLogger, settings);
3732
0
        });
3733
0
    }
3734
0
}
3735
3736
static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
3737
187
{
3738
187
    if (!match38(tok))
3739
0
        return;
3740
187
    Token* memtok = nullptr;
3741
187
    if (match16(tok->astParent()) && astIsRHS(tok))
3742
0
        memtok = tok->astParent()->astOperand1();
3743
187
    const int returnContainer = settings.library.returnValueContainer(tok);
3744
187
    if (returnContainer >= 0) {
3745
0
        std::vector<const Token *> args = getArguments(tok);
3746
0
        for (int argnr = 1; argnr <= args.size(); ++argnr) {
3747
0
            const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr);
3748
0
            if (!i)
3749
0
                continue;
3750
0
            if (i->container != returnContainer)
3751
0
                continue;
3752
0
            const Token * const argTok = args[argnr - 1];
3753
0
            bool forward = false;
3754
0
            for (ValueFlow::Value val : argTok->values()) {
3755
0
                if (!val.isLifetimeValue())
3756
0
                    continue;
3757
0
                val.errorPath.emplace_back(argTok, "Passed to '" + tok->str() + "'.");
3758
0
                setTokenValue(tok->next(), std::move(val), settings);
3759
0
                forward = true;
3760
0
            }
3761
            // Check if lifetime is available to avoid adding the lifetime twice
3762
0
            if (forward) {
3763
0
                valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
3764
0
                break;
3765
0
            }
3766
0
        }
3767
187
    } else if (match49(tok->tokAt(-2))) {
3768
0
        for (const Token *argtok : getArguments(tok)) {
3769
0
            LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byRef(
3770
0
                tok->next(), tokenlist, errorLogger, settings);
3771
0
        }
3772
187
    } else if (match50(tok->tokAt(-2))) {
3773
0
        for (const Token *argtok : getArguments(tok)) {
3774
0
            LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal(
3775
0
                tok->next(), tokenlist, errorLogger, settings);
3776
0
        }
3777
187
    } else if (memtok && match51(tok->astParent()) &&
3778
187
               astIsNonStringContainer(memtok)) {
3779
0
        std::vector<const Token *> args = getArguments(tok);
3780
0
        const std::size_t n = args.size();
3781
0
        if (n > 1 && Token::typeStr(args[n - 2]) == Token::typeStr(args[n - 1]) &&
3782
0
            (((astIsIterator(args[n - 2]) && astIsIterator(args[n - 1])) ||
3783
0
              (astIsPointer(args[n - 2]) && astIsPointer(args[n - 1]))))) {
3784
0
            LifetimeStore{
3785
0
                args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
3786
0
            .byDerefCopy(memtok, tokenlist, errorLogger, settings);
3787
0
        } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) {
3788
0
            LifetimeStore{
3789
0
                args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
3790
0
            .byVal(memtok, tokenlist, errorLogger, settings);
3791
0
        }
3792
187
    } else if (tok->function()) {
3793
0
        const Function *f = tok->function();
3794
0
        if (f->isConstructor()) {
3795
0
            valueFlowLifetimeUserConstructor(tok->next(), f, tok->str(), getArguments(tok), tokenlist, errorLogger, settings);
3796
0
            return;
3797
0
        }
3798
0
        if (Function::returnsReference(f))
3799
0
            return;
3800
0
        std::vector<const Token*> returns = Function::findReturns(f);
3801
0
        const bool inconclusive = returns.size() > 1;
3802
0
        bool update = false;
3803
0
        for (const Token* returnTok : returns) {
3804
0
            if (returnTok == tok)
3805
0
                continue;
3806
0
            const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok, settings);
3807
0
            if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings))) {
3808
0
                LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, settings, errorLogger);
3809
0
                ls.inconclusive = inconclusive;
3810
0
                ls.forward = false;
3811
0
                update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
3812
0
            }
3813
0
            for (const ValueFlow::Value &v : returnTok->values()) {
3814
0
                if (!v.isLifetimeValue())
3815
0
                    continue;
3816
0
                if (!v.tokvalue)
3817
0
                    continue;
3818
0
                if (memtok &&
3819
0
                    (contains({ValueFlow::Value::LifetimeScope::ThisPointer, ValueFlow::Value::LifetimeScope::ThisValue},
3820
0
                              v.lifetimeScope) ||
3821
0
                     exprDependsOnThis(v.tokvalue))) {
3822
0
                    LifetimeStore ls = LifetimeStore{memtok,
3823
0
                                                     "Passed to member function '" + tok->expressionString() + "'.",
3824
0
                                                     ValueFlow::Value::LifetimeKind::Object};
3825
0
                    ls.inconclusive = inconclusive;
3826
0
                    ls.forward = false;
3827
0
                    ls.errorPath = v.errorPath;
3828
0
                    ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
3829
0
                    int thisIndirect = v.lifetimeScope == ValueFlow::Value::LifetimeScope::ThisValue ? 0 : 1;
3830
0
                    if (derefShared(memtok->astParent()))
3831
0
                        thisIndirect--;
3832
0
                    if (thisIndirect == -1)
3833
0
                        update |= ls.byDerefCopy(tok->next(), tokenlist, errorLogger, settings);
3834
0
                    else if (thisIndirect == 0)
3835
0
                        update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
3836
0
                    else if (thisIndirect == 1)
3837
0
                        update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
3838
0
                    continue;
3839
0
                }
3840
0
                const Variable *var = v.tokvalue->variable();
3841
0
                LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, settings, errorLogger);
3842
0
                if (!ls.argtok)
3843
0
                    continue;
3844
0
                ls.forward = false;
3845
0
                ls.inconclusive = inconclusive;
3846
0
                ls.errorPath = v.errorPath;
3847
0
                ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + ".");
3848
0
                if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) {
3849
0
                    update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings);
3850
0
                } else if (v.isArgumentLifetimeValue()) {
3851
0
                    update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings);
3852
0
                }
3853
0
            }
3854
0
        }
3855
0
        if (update)
3856
0
            valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
3857
187
    } else if (tok->valueType()) {
3858
        // TODO: Propagate lifetimes with library functions
3859
187
        if (settings.library.getFunction(tok->previous()))
3860
0
            return;
3861
187
        if (match40(tok->astParent()))
3862
0
            return;
3863
        // Assume constructing the valueType
3864
187
        valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings);
3865
187
        valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings);
3866
187
    } else {
3867
0
        const std::string& retVal = settings.library.returnValue(tok);
3868
0
        if (startsWith(retVal, "arg")) {
3869
0
            std::size_t iArg{};
3870
0
            try {
3871
0
                iArg = strToInt<std::size_t>(retVal.substr(3));
3872
0
            } catch (...) {
3873
0
                return;
3874
0
            }
3875
0
            std::vector<const Token*> args = getArguments(tok);
3876
0
            if (iArg > 0 && iArg <= args.size()) {
3877
0
                const Token* varTok = args[iArg - 1];
3878
0
                if (varTok->variable() && varTok->variable()->isLocal())
3879
0
                    LifetimeStore{ varTok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Address }.byRef(
3880
0
                    tok->next(), tokenlist, errorLogger, settings);
3881
0
            }
3882
0
        }
3883
0
    }
3884
187
}
3885
3886
static bool isScope(const Token* tok)
3887
983
{
3888
983
    if (!tok)
3889
0
        return false;
3890
983
    if (!match4(tok))
3891
187
        return false;
3892
796
    const Scope* scope = tok->scope();
3893
796
    if (!scope)
3894
0
        return false;
3895
796
    if (!scope->bodyStart)
3896
0
        return false;
3897
796
    return scope->bodyStart == tok;
3898
796
}
3899
3900
static const Function* findConstructor(const Scope* scope, const Token* tok, const std::vector<const Token*>& args)
3901
0
{
3902
0
    if (!tok)
3903
0
        return nullptr;
3904
0
    const Function* f = tok->function();
3905
0
    if (!f && tok->astOperand1())
3906
0
        f = tok->astOperand1()->function();
3907
    // Search for a constructor
3908
0
    if (!f || !f->isConstructor()) {
3909
0
        f = nullptr;
3910
0
        std::vector<const Function*> candidates;
3911
0
        for (const Function& function : scope->functionList) {
3912
0
            if (function.minArgCount() > args.size())
3913
0
                continue;
3914
0
            if (!function.isConstructor())
3915
0
                continue;
3916
0
            candidates.push_back(&function);
3917
0
        }
3918
        // TODO: Narrow the candidates
3919
0
        if (candidates.size() == 1)
3920
0
            f = candidates.front();
3921
0
    }
3922
0
    if (!f)
3923
0
        return nullptr;
3924
0
    return f;
3925
0
}
3926
3927
static void valueFlowLifetimeClassConstructor(Token* tok,
3928
                                              const Type* t,
3929
                                              const TokenList& tokenlist,
3930
                                              ErrorLogger& errorLogger,
3931
                                              const Settings& settings)
3932
0
{
3933
0
    if (!match52(tok))
3934
0
        return;
3935
0
    if (isScope(tok))
3936
0
        return;
3937
0
    if (!t) {
3938
0
        if (tok->valueType() && tok->valueType()->type != ValueType::RECORD)
3939
0
            return;
3940
0
        if (tok->str() != MatchCompiler::makeConstString("{") && !match53(tok->previous()) && !isVariableDecl(tok->previous()))
3941
0
            return;
3942
        // If the type is unknown then assume it captures by value in the
3943
        // constructor, but make each lifetime inconclusive
3944
0
        std::vector<const Token*> args = getArguments(tok);
3945
0
        LifetimeStore::forEach(tokenlist,
3946
0
                               errorLogger,
3947
0
                               settings,
3948
0
                               args,
3949
0
                               "Passed to initializer list.",
3950
0
                               ValueFlow::Value::LifetimeKind::SubObject,
3951
0
                               [&](LifetimeStore& ls) {
3952
0
            ls.inconclusive = true;
3953
0
            ls.byVal(tok, tokenlist, errorLogger, settings);
3954
0
        });
3955
0
        return;
3956
0
    }
3957
0
    const Scope* scope = t->classScope;
3958
0
    if (!scope)
3959
0
        return;
3960
    // Aggregate constructor
3961
0
    if (t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) {
3962
0
        std::vector<const Token*> args = getArguments(tok);
3963
0
        if (scope->numConstructors == 0) {
3964
0
            auto it = scope->varlist.cbegin();
3965
0
            LifetimeStore::forEach(
3966
0
                tokenlist,
3967
0
                errorLogger,
3968
0
                settings,
3969
0
                args,
3970
0
                "Passed to constructor of '" + t->name() + "'.",
3971
0
                ValueFlow::Value::LifetimeKind::SubObject,
3972
0
                [&](LifetimeStore& ls) {
3973
                // Skip static variable
3974
0
                it = std::find_if(it, scope->varlist.cend(), [](const Variable& var) {
3975
0
                    return !var.isStatic();
3976
0
                });
3977
0
                if (it == scope->varlist.cend())
3978
0
                    return;
3979
0
                const Variable& var = *it;
3980
0
                if (var.valueType() && var.valueType()->container && var.valueType()->container->stdStringLike && !var.valueType()->container->view)
3981
0
                    return; // TODO: check in isLifetimeBorrowed()?
3982
0
                if (var.isReference() || var.isRValueReference()) {
3983
0
                    ls.byRef(tok, tokenlist, errorLogger, settings);
3984
0
                } else if (ValueFlow::isLifetimeBorrowed(ls.argtok, settings)) {
3985
0
                    ls.byVal(tok, tokenlist, errorLogger, settings);
3986
0
                }
3987
0
                it++;
3988
0
            });
3989
0
        } else {
3990
0
            const Function* constructor = findConstructor(scope, tok, args);
3991
0
            valueFlowLifetimeUserConstructor(tok, constructor, t->name(), args, tokenlist, errorLogger, settings);
3992
0
        }
3993
0
    }
3994
0
}
3995
3996
static void valueFlowLifetimeConstructor(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings)
3997
187
{
3998
187
    if (!match52(tok))
3999
0
        return;
4000
187
    if (isScope(tok))
4001
0
        return;
4002
187
    std::vector<ValueType> vts;
4003
187
    if (tok->valueType()) {
4004
0
        vts = {*tok->valueType()};
4005
187
    } else if (match47(tok->previous()) && isVariableDecl(tok->previous()) &&
4006
187
               tok->previous()->valueType()) {
4007
0
        vts = {*tok->previous()->valueType()};
4008
187
    } else if (match4(tok) && !match54(tok->previous())) {
4009
0
        vts = getParentValueTypes(tok, settings);
4010
0
    }
4011
4012
187
    for (const ValueType& vt : vts) {
4013
0
        if (vt.pointer > 0) {
4014
0
            std::vector<const Token*> args = getArguments(tok);
4015
0
            LifetimeStore::forEach(tokenlist,
4016
0
                                   errorLogger,
4017
0
                                   settings,
4018
0
                                   args,
4019
0
                                   "Passed to initializer list.",
4020
0
                                   ValueFlow::Value::LifetimeKind::SubObject,
4021
0
                                   [&](LifetimeStore& ls) {
4022
0
                ls.byVal(tok, tokenlist, errorLogger, settings);
4023
0
            });
4024
0
        } else if (vt.container && vt.type == ValueType::CONTAINER) {
4025
0
            std::vector<const Token*> args = getArguments(tok);
4026
0
            if (args.size() == 1 && vt.container->view && astIsContainerOwned(args.front())) {
4027
0
                LifetimeStore{args.front(), "Passed to container view.", ValueFlow::Value::LifetimeKind::SubObject}
4028
0
                .byRef(tok, tokenlist, errorLogger, settings);
4029
0
            } else if (args.size() == 2 && (astIsIterator(args[0]) || astIsIterator(args[1]))) {
4030
0
                LifetimeStore::forEach(
4031
0
                    tokenlist,
4032
0
                    errorLogger,
4033
0
                    settings,
4034
0
                    args,
4035
0