Coverage Report

Created: 2023-09-25 06:15

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