Coverage Report

Created: 2024-02-11 06:44

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