116 #include <functional>
117 #include <initializer_list>
126 #include <type_traits>
127 #include <unordered_map>
128 #include <unordered_set>
133 if (
function.find(
"operator") != std::string::npos)
134 function =
"(valueFlow)";
138 (file.empty() ?
"" : location) +
function +
" bailout: " + what, type,
Certainty::normal);
142 #define bailout2(type, tokenlist, errorLogger, tok, what) bailoutInternal((type), (tokenlist), (errorLogger), (tok), (what), __FILE__, __LINE__, __func__)
144 #define bailout(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailout", (tokenlist), (errorLogger), (tok), (what))
146 #define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailoutInternal("valueFlowBailoutIncompleteVar", (tokenlist), (errorLogger), (tok), (what), "", 0, __func__)
158 kind =
"inconclusive";
176 " => " + local.function_name() +
": " +
debugString(v);
177 v.
debugPath.emplace_back(tok, std::move(s));
183 if (indirect >= 0 && v.
indirect != indirect)
192 if (indirect >= 0 && v.
indirect != indirect)
207 if (indirect >= 0 && v.
indirect != indirect)
263 const char* greaterThan =
">=";
264 const char* lessThan =
"<=";
266 std::swap(greaterThan, lessThan);
275 const char* greaterThan =
">";
276 const char* lessThan =
"<";
278 std::swap(greaterThan, lessThan);
293 return value == std::numeric_limits<MathLib::bigint>::max() || value == std::numeric_limits<MathLib::bigint>::min();
299 const std::function<std::vector<ValueFlow::Value>(
const Token*)>&
evaluate)
306 if (!value1.empty() && !value2.empty()) {
318 each(tok->
astOperand2(), std::move(true_value), std::move(false_value));
326 each(tok->
astOperand1(), std::move(true_value), std::move(false_value));
337 return {t->values().front()};
338 std::vector<ValueFlow::Value> result;
342 if (!isNonConditionalPossibleIntValue(v))
353 const std::function<std::vector<MathLib::bigint>(
const Token*)>&
evaluate)
355 const Token* result =
nullptr;
362 true_value = std::move(true_value2);
363 false_value = std::move(false_value2);
365 [&](
const Token* t) -> std::vector<ValueFlow::Value> {
366 std::vector<ValueFlow::Value> r;
367 std::vector<MathLib::bigint> v =
evaluate(t);
369 std::transform(v.cbegin(), v.cend(), std::back_inserter(r), [&](
MathLib::bigint i) {
370 return ValueFlow::Value{i};
379 return parseCompareInt(tok, true_value, false_value, [](
const Token* t) -> std::vector<MathLib::bigint> {
381 return {t->values().front().intvalue};
382 return std::vector<MathLib::bigint>{};
392 if (termTok && termTok->
scope() == tok->
scope())
394 std::string unknownFunction;
396 return unknownFunction.empty() || unknown;
404 if (value.
floatValue >= std::numeric_limits<int>::min() && value.
floatValue <= std::numeric_limits<int>::max()) {
413 if (
sign == ValueType::Sign::SIGNED && value.
intvalue & (one << (bit - 1))) {
414 value.
intvalue |= ~((one << bit) - 1ULL);
476 if (parent->
str() !=
"(")
485 ftok = ftok->
tokAt(2);
487 return parent->
next();
527 return f->containerYield;
539 std::unordered_set<ValueFlow::Value::ValueType, EnumClassHash>,
553 auto it = compatibleTypes.find(x);
554 if (it == compatibleTypes.end())
556 return it->second.count(y) > 0;
609 const MathLib::biguint unsignedMaxValue = (1ULL << (value_size * 8)) - 1ULL;
611 value &= unsignedMaxValue;
612 if (dst_sign == ValueType::Sign::SIGNED && (value & signBit))
613 value |= ~unsignedMaxValue;
668 if (value1.isImpossible())
671 if (value2.isImpossible())
673 if (value1.path != value2.path)
681 if (value1.isContainerSizeValue() && value2.isContainerSizeValue())
683 else if (value1.isContainerSizeValue() && value2.isTokValue() && value2.tokvalue->tokType() ==
Token::eString)
685 else if (value2.isContainerSizeValue() && value1.isTokValue() && value1.tokvalue->tokType() ==
Token::eString)
701 Token* next =
nullptr;
785 else if (parent->
str() ==
":") {
800 const std::list<ValueFlow::Value> &values = op->
values();
801 if (std::find(values.cbegin(), values.cend(), value) != values.cend())
810 [&](
const Token *t) {
812 if (varId > 0 || value.varId != 0)
830 else if (parent->str() ==
"?" && value.
isIntValue() && tok == parent->astOperand1() && value.
isKnown() &&
831 parent->astOperand2() && parent->astOperand2()->astOperand1() && parent->astOperand2()->astOperand2()) {
832 const std::list<ValueFlow::Value> &values = (value.
intvalue == 0
833 ? parent->astOperand2()->astOperand2()->values()
834 : parent->astOperand2()->astOperand1()->values());
841 else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() ==
Token::eBitOp) || (parent->tokType() ==
Token::eLogicalOp)) &&
842 parent->astOperand1() &&
843 parent->astOperand2()) {
874 if (value1.path != value2.path)
878 if (value1.isIteratorValue() && value2.isIteratorValue())
885 if (!result.isIntValue() && !result.isFloatValue())
889 const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue;
890 const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue;
892 return value1.isFloatValue() ?
static_cast<MathLib::bigint>(value1.floatValue) : value1.intvalue;
895 return value2.isFloatValue() ?
static_cast<MathLib::bigint>(value2.floatValue) : value2.intvalue;
897 if ((value1.isFloatValue() || value2.isFloatValue()) &&
Token::Match(parent,
"&|^|%|<<|>>|==|!=|%or%"))
900 if ((value1.isIntValue() && value2.isTokValue()) || (value1.isTokValue() && value2.isIntValue())) {
901 if (parent->str() ==
"==")
903 else if (parent->str() ==
"!=")
905 }
else if (value1.isIntValue() && value2.isIntValue()) {
907 result.intvalue =
calculate(parent->str(), intValue1(), intValue2(), &error);
910 }
else if (value1.isTokValue() && value2.isTokValue() &&
912 const Token* tok1 = value1.tokvalue;
913 const Token* tok2 = value2.tokvalue;
916 equal = tok1->
str() == tok2->
str();
920 if (args1.size() == args2.size()) {
925 equal = std::equal(args1.begin(),
929 return atok->values().front().intvalue ==
930 btok->values().front().intvalue;
938 result.intvalue = parent->str() ==
"==" ? equal : !equal;
945 if (!result.isFloatValue() && !value1.isIntValue() && !value2.isIntValue())
948 if (value1.isTokValue() || value2.isTokValue())
952 if (result.isFloatValue()) {
953 result.floatValue =
calculate(parent->str(), floatValue1, floatValue2, &error);
955 result.intvalue =
calculate(parent->str(), intValue1(), intValue2(), &error);
962 result.invertBound();
970 else if (parent->str() ==
"!") {
972 if (!val.isIntValue())
974 if (val.isImpossible() && val.intvalue != 0)
977 if (val.isImpossible())
986 else if (parent->str() ==
"~") {
988 if (!val.isIntValue())
1008 else if (parent->isUnaryOp(
"-")) {
1010 if (!val.isIntValue() && !val.isFloatValue())
1026 else if (parent->str() ==
"++") {
1028 if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
1042 else if (parent->str() ==
"--") {
1044 if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
1067 else if (
Token::Match(parent,
":: %name%") && parent->astOperand2() == tok) {
1094 else if (valueType.
type == ValueType::Type::CHAR)
1096 else if (valueType.
type == ValueType::Type::SHORT)
1098 else if (valueType.
type == ValueType::Type::INT)
1100 else if (valueType.
type == ValueType::Type::LONG)
1102 else if (valueType.
type == ValueType::Type::LONGLONG)
1124 std::set<const Scope*> anonScopes;
1129 if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
1132 return i1 * dim.num;
1137 total = f(total, *vt, dim);
1140 total = f(total, *vt, dim);
1164 if (maxRecursion == 100)
1168 return align == 0 ? 0 :
bitCeil(align);
1171 auto accHelper = [&](
size_t max,
const ValueType& vt2,
size_t ) {
1172 size_t a =
getAlignOf(vt2, settings, ++maxRecursion);
1173 return std::max(max, a);
1177 total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](
size_t v,
const Type::BaseInfo& bi) {
1178 if (bi.type && bi.type->classScope)
1179 v += accumulateStructMembers(bi.type->classScope, accHelper);
1185 if (vt.
type == ValueType::Type::CONTAINER)
1199 if (maxRecursion == 100)
1203 if (vt.
type == ValueType::Type::BOOL || vt.
type == ValueType::Type::CHAR)
1205 if (vt.
type == ValueType::Type::SHORT)
1207 if (vt.
type == ValueType::Type::WCHAR_T)
1209 if (vt.
type == ValueType::Type::INT)
1211 if (vt.
type == ValueType::Type::LONG)
1213 if (vt.
type == ValueType::Type::LONGLONG)
1215 if (vt.
type == ValueType::Type::FLOAT)
1217 if (vt.
type == ValueType::Type::DOUBLE)
1219 if (vt.
type == ValueType::Type::LONGDOUBLE)
1221 if (vt.
type == ValueType::Type::CONTAINER)
1224 auto accHelper = [&](
size_t total,
const ValueType& vt2,
size_t dim) ->
size_t {
1227 if (n == 0 || a == 0)
1230 size_t padding = (a - (total % a)) % a;
1235 total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](
size_t v,
const Type::BaseInfo& bi) {
1236 if (bi.type && bi.type->classScope)
1237 v += accumulateStructMembers(bi.type->classScope, accHelper);
1246 total += (align - (total % align)) % align;
1265 signedValue += maxValue + 1;
1271 }
catch (
const std::exception & ) {
1286 }
else if (tok->
str() ==
"NULL" || (tok->
isCpp() && tok->
str() ==
"nullptr")) {
1308 if (tok2->
next()->
str() ==
"[")
1311 tok2 = tok2->
tokAt(2);
1335 }
else if (tok2->
type() && tok2->
type()->isEnumType()) {
1337 if (tok2->
type()->classScope) {
1338 const Token * type = tok2->
type()->classScope->enumType;
1357 !sz1->
variable()->dimensions().empty() &&
1358 sz1->
variable()->dimensionKnown(0) &&
1377 }
else if (!var->
type()) {
1382 for (
size_t i = 0; i < var->
dimensions().size(); ++i) {
1388 if (size && count > 0) {
1390 if (settings.
platform.
type != Platform::Type::Unspecified)
1423 }
else if (!tok2->
type()) {
1436 catch (
const std::exception& ) {
1454 (tok->
variable()->isPointer() || (tok->
variable()->valueType() && tok->
variable()->valueType()->isIntegral()))))) {
1476 if (tokenlist.
isCPP()) {
1510 std::map<nonneg int, const Token *> constantArrays;
1513 if (tok->
varId() > 0) {
1515 const std::map<nonneg int, const Token *>::const_iterator it = constantArrays.find(tok->
varId());
1516 if (it != constantArrays.end()) {
1528 constantArrays[tok->
varId()] = rhstok;
1529 tok = rhstok->
link();
1535 tok->
astParent()->astOperand1()->variable() &&
1536 tok->
astParent()->astOperand1()->variable()->isPointer()) {
1546 if (
Token::Match(tok,
"const %type% %var% [ %num%| ] = {")) {
1549 constantArrays[vartok->
varId()] = rhstok;
1550 tok = rhstok->
link();
1554 if (
Token::Match(tok,
"const char %var% [ %num%| ] = %str% ;")) {
1557 constantArrays[vartok->
varId()] = strtok;
1558 tok = strtok->
next();
1575 if (tok->
astParent()->astOperand1() != tok)
1577 if (tok->
astParent()->astOperand2() != tok)
1589 const std::list<ValueFlow::Value>::const_iterator val =
1591 if (val == tok->
values().end()) {
1595 var = val->tokvalue->variable();
1596 known = val->isKnown();
1620 const Token* indexTok =
nullptr;
1621 const Token* arrayTok =
nullptr;
1636 if (!indexTok || !arrayTok)
1640 if (!arrayValue.isTokValue())
1642 if (arrayValue.isImpossible())
1645 if (!indexValue.isIntValue())
1647 if (indexValue.isImpossible())
1649 if (!arrayValue.isKnown() && !indexValue.isKnown() && arrayValue.varId != 0 && indexValue.varId != 0 &&
1650 !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue))
1654 result.
condition = arrayValue.condition ? arrayValue.condition : indexValue.condition;
1655 result.
setInconclusive(arrayValue.isInconclusive() || indexValue.isInconclusive());
1656 result.
varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId;
1657 result.
varvalue = (result.
varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue;
1658 if (arrayValue.valueKind == indexValue.valueKind)
1659 result.
valueKind = arrayValue.valueKind;
1661 result.
errorPath.insert(result.
errorPath.end(), arrayValue.errorPath.cbegin(), arrayValue.errorPath.cend());
1662 result.
errorPath.insert(result.
errorPath.end(), indexValue.errorPath.cbegin(), indexValue.errorPath.cend());
1667 const std::string s = arrayValue.tokvalue->strValue();
1668 if (index == s.size()) {
1671 }
else if (index >= 0 && index < s.size()) {
1676 std::vector<const Token*> args =
getArguments(arrayValue.tokvalue);
1677 if (index < 0 || index >= args.size())
1679 const Token* arg = args[index];
1706 if (vartok->
str() ==
"[")
1708 else if (vartok->
str() ==
"." || vartok->
str() ==
"::")
1726 if (tok->
str() !=
"&")
1794 *minvalue = expr->
values().front().intvalue;
1796 *maxvalue = expr->
values().front().intvalue;
1804 if (!lhsHasKnownRange && !rhsHasKnownRange)
1806 if (!lhsHasKnownRange || !rhsHasKnownRange) {
1808 *minvalue = lhsHasKnownRange ? vals[0] : vals[2];
1810 *maxvalue = lhsHasKnownRange ? vals[1] : vals[3];
1813 *minvalue = vals[0] & vals[2];
1815 *maxvalue = vals[1] & vals[3];
1827 if (lhsHasKnownRange && vals[0] < 0)
1830 if (!lhsHasKnownRange && (!expr->
astOperand1()->valueType() || expr->
astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED))
1835 *maxvalue = vals[3] - 1;
1845 if (tok->
str() !=
">>")
1873 if ((tok->
astOperand1()->valueType()->type == ValueType::Type::CHAR) ||
1874 (tok->
astOperand1()->valueType()->type == ValueType::Type::SHORT) ||
1875 (tok->
astOperand1()->valueType()->type == ValueType::Type::WCHAR_T) ||
1876 (tok->
astOperand1()->valueType()->type == ValueType::Type::BOOL) ||
1877 (tok->
astOperand1()->valueType()->type == ValueType::Type::INT))
1879 else if (tok->
astOperand1()->valueType()->type == ValueType::Type::LONG)
1881 else if (tok->
astOperand1()->valueType()->type == ValueType::Type::LONGLONG)
1896 std::vector<MathLib::bigint> result;
1902 result = {tok->
values().front().intvalue};
1906 if (!
op1.empty() && !
op2.empty()) {
1907 result = calculate<std::vector<MathLib::bigint>>(tok->
str(),
op1.front(),
op2.front());
1920 if (parentTypes.empty())
1922 const ValueType& vt = parentTypes.front();
1933 return tok1->
values().front().intvalue == tok2->
values().front().intvalue;
1947 lower.setImpossible();
1952 upper.setImpossible();
1956 if (minvalue.empty())
1958 ValueFlow::Value value{std::max<MathLib::bigint>(0, minvalue.front()) - 1};
1969 bool flipped =
false;
1970 if (std::equal(tokens.cbegin(), tokens.cend(), branches.crbegin(), &
isSameToken))
1972 else if (!std::equal(tokens.cbegin(), tokens.cend(), branches.cbegin(), &
isSameToken))
1974 const bool isMin =
Token::Match(condTok,
"<|<=") ^ flipped;
1975 std::vector<ValueFlow::Value> values;
1976 for (
const Token* tok2 : tokens) {
1978 values.emplace_back(tok2->
values().front());
1982 symValue.tokvalue = tok2;
1983 values.push_back(symValue);
1984 std::copy_if(tok2->
values().cbegin(),
1986 std::back_inserter(values),
1990 return v.isSymbolicValue();
2011 }
else if (
Token::Match(tok,
"abs|labs|llabs|fabs|fabsf|fabsl (")) {
2022 if (container->
view)
2050 bool prev_enum_is_known =
true;
2053 if (enumerator.
start) {
2057 enumerator.
value = rhs->
values().front().intvalue;
2059 value = enumerator.
value + 1;
2060 prev_enum_is_known =
true;
2062 prev_enum_is_known =
false;
2063 }
else if (prev_enum_is_known) {
2064 enumerator.
value = value++;
2074 std::map<const Variable*, ValueFlow::Value> vars;
2075 for (
const Token* tok = tokenList.
front(); tok; tok = tok->
next()) {
2079 if (tok == tok->
variable()->nameToken() &&
2098 const std::map<const Variable*, ValueFlow::Value>::const_iterator var = vars.find(tok->
variable());
2099 if (var == vars.end())
2108 std::map<const Variable *, ValueFlow::Value> vars;
2109 for (
const Token *tok = tokenList.
front(); tok; tok = tok->
next()) {
2113 if (tok == tok->
variable()->nameToken() &&
2130 else if (tok->
astParent()->isAssignmentOp()) {
2131 if (tok == tok->
astParent()->astOperand1())
2146 const std::map<const Variable *, ValueFlow::Value>::const_iterator var = vars.find(tok->
variable());
2147 if (var == vars.end())
2157 const Token* endToken,
2158 const Token* exprTok,
2169 makeAnalyzer(exprTok, std::move(value), tokenlist, settings),
2176 const Token* endToken,
2177 const Token* exprTok,
2178 std::list<ValueFlow::Value> values,
2186 result.
update(
valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc));
2191 template<
class ValueOrValues>
2193 const Token* exprTok,
2200 const Token* endToken =
nullptr;
2204 return valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc);
2208 const Token* exprTok,
2209 std::list<ValueFlow::Value> values,
2226 const Token*
const endToken,
2227 const Token*
const varToken,
2228 std::list<ValueFlow::Value> values,
2244 const Token*
const varToken,
2250 valueFlowReverse(tok,
nullptr, varToken, {std::move(val)}, tokenlist, errorLogger, settings, loc);
2255 const char* op =
"||";
2259 while (parent && (parent->
str() == op || parent->
str() ==
"!" || parent->
isCast()))
2264 return parent && parent->
str() != op;
2269 static std::unordered_map<std::string, std::string> lookup = {{
"=",
"="},
2277 auto it = lookup.find(assign);
2278 if (it == lookup.end()) {
2285 return std::string{assign.cbegin(), assign.cend() - 1};
2288 template<
class T,
class U>
2289 static T
calculateAssign(
const std::string& assign,
const T& x,
const U& y,
bool* error =
nullptr)
2291 if (assign.empty() || assign.back() !=
'=') {
2301 template<
class T,
class U>
2307 template<
class T,
class U>
2311 template<
class Value,
REQUIRES(
"Value must ValueFlow::Value", std::is_convertible<Value&, const ValueFlow::Value&> )>
2315 if (lhsValue.isSymbolicValue() && rhsValue.
isIntValue()) {
2316 if (assign !=
"+=" && assign !=
"-=")
2319 }
else if (lhsValue.isIntValue() && rhsValue.
isIntValue()) {
2321 }
else if (lhsValue.isFloatValue() && rhsValue.
isIntValue()) {
2366 using M = std::unordered_map<nonneg int, ValueFlow::Value>;
2383 return &
mIt->second;
2420 template<
typename V>
2423 if (tok->
varId() == varid)
2425 if (tok->
varId() == 0)
2432 return std::any_of(values.begin(), values.end(), [&](
const ValueFlow::Value& val) {
2433 if (!val.isNonValue())
2435 if (val.isInconclusive())
2437 if (val.isLifetimeValue() && !val.isLocalLifetimeValue())
2439 if (val.isLifetimeValue() && val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
2441 if (!Token::Match(val.tokvalue,
".|&|*|%var%"))
2443 return astHasVar(val.tokvalue, tok->varId());
2447 static bool bifurcate(
const Token* tok,
const std::set<nonneg int>& varids,
const Settings& settings,
int depth = 20);
2450 const std::set<nonneg int>& varids,
2456 bool result =
false;
2457 const Token* tok = start;
2480 if (tok->
varId() != 0) {
2481 if (varids.count(tok->
varId()) > 0)
2489 if (start->
strAt(-1) ==
")" || start->
strAt(-1) ==
"}")
2492 start = start->
tokAt(2);
2576 std::unordered_map<nonneg int, const Token*> result;
2580 if (!v.isSymbolicValue())
2582 if (v.isImpossible())
2586 if (v.tokvalue->exprId() == 0)
2588 if (
match(v.tokvalue))
2590 result[v.tokvalue->exprId()] = v.tokvalue;
2636 result.
dependent = std::any_of(args.cbegin(), args.cend(), [&](
const Token* arg) {
2637 ConditionState cs = analyzeCondition(arg, depth - 1);
2638 return cs.dependent;
2648 std::unordered_map<nonneg int, const Token*> symbols =
getSymbols(tok);
2650 for (
auto&& p : symbols) {
2651 const Token* arg = p.second;
2692 if (!result.empty() && value->
equalTo(result.front()))
2705 if (indirect == -1) {
2708 indirect = vt->pointer;
2713 for (
int i = 0; i <= indirect; ++i)
2730 }
else if (
getSettings().library.getFunction(tok)) {
2771 std::vector<MathLib::bigint> result =
evaluateInt(rhs);
2772 if (!result.empty()) {
2779 if (parent->
str() !=
"=") {
2784 if (tok->
exprId() != 0 &&
2809 if (tok->
astParent()->isAssignmentOp()) {
2811 std::vector<MathLib::bigint> result =
evaluateInt(rhs);
2812 assert(!result.empty());
2815 std::string info(
"Compound assignment '" + tok->
astParent()->str() +
"', assigned value is " +
2819 value->
errorPath.emplace_back(tok, std::move(info));
2821 assert(
false &&
"Writable value cannot be evaluated");
2826 bool inc = tok->
astParent()->str() ==
"++";
2827 const std::string opName(inc ?
"incremented" :
"decremented");
2836 if (sz > 0 && sz < 8)
2839 value->
errorPath.emplace_back(tok, tok->
str() +
" is " + opName +
"', new value is " + value->
infoString());
2851 return match(child);
2867 return v.isSymbolicValue() && currValue->equalValue(v);
2878 if (!v.
isKnown() && !toImpossible)
2880 if (exact && v.
intvalue != 0 && !isPoint)
2882 std::vector<MathLib::bigint> r;
2897 value->
bound = bound;
2928 assert(!inconclusiveRef || ref != tok);
2931 if (inconclusiveRef) {
2939 const Token* lifeTok =
nullptr;
2941 if (!v.isLocalLifetimeValue())
2945 lifeTok = v.tokvalue;
2983 const bool inconclusiveRefs = refs.size() != 1;
2984 if (std::none_of(refs.cbegin(), refs.cend(), [&](
const ReferenceToken& ref) {
2985 return tok == ref.token;
3010 return {
static_cast<int>(tok->
values().front().intvalue)};
3011 std::vector<MathLib::bigint> result;
3015 result.push_back(1);
3017 result.push_back(0);
3023 result.push_back(out);
3043 return v.isKnown() && v.isContainerSizeValue();
3050 return {
static_cast<int>(out)};
3056 void assume(
const Token* tok,
bool state,
unsigned int flags)
override {
3062 bool isCondBlock =
false;
3069 const Token* startBlock = parent->
link()->next();
3071 startBlock = parent->
linkAt(-2);
3072 const Token* endBlock = startBlock->
link();
3084 std::string s = state ?
"empty" :
"not empty";
3104 assert(
false &&
"Internal update unimplemented.");
3114 localValue = *value;
3115 value = &localValue;
3139 std::unordered_map<nonneg int, const Variable*>
varids;
3140 std::unordered_map<nonneg int, const Variable*>
aliases;
3145 const std::unordered_map<nonneg int, const Variable*>&
getVars()
const {
3180 for (
const auto& m: {
3183 for (
const auto& p:m.get()) {
3184 nonneg int const varid = p.first;
3186 if (tok->
varId() == varid)
3197 return std::any_of(vars.cbegin(), vars.cend(), [] (
const std::pair<nonneg int, const Variable*>& p) {
3198 const Variable* var = p.second;
3199 return !var->isLocal() && !var->isArgument() && !var->isConst();
3253 std::set<nonneg int> varids2;
3263 newValue.
errorPath.emplace_back(tok, msg);
3280 assert(e && e->
exprId() != 0 &&
"Not a valid expression");
3297 constexpr
int maxDepth = 4;
3298 if (depth > maxDepth)
3301 const bool top = depth == 0 && tok == start;
3305 if (!(v.isLocalLifetimeValue() || (ispointer && v.isSymbolicValue() && v.isKnown())))
3309 if (v.tokvalue == tok)
3321 if (tok->
varId() > 0) {
3474 result =
"iterator";
3497 std::string msg = type;
3500 errorPath.emplace_back(vartok,
"Variable created here.");
3503 std::string submessage;
3508 if (type ==
"pointer")
3509 submessage =
" to local variable";
3511 submessage =
" that points to local variable";
3514 submessage =
" that captures local variable";
3517 submessage =
" to local container";
3521 submessage.replace(submessage.find(
"local"), 5,
"member");
3522 msg += submessage +
" '" + var->
name() +
"'";
3530 std::vector<ValueFlow::Value> result;
3532 if (!v.isLocalLifetimeValue() && !(path != 0 && v.isSubFunctionLifetimeValue()))
3538 if (path >= 0 && v.path != 0 && v.path != path)
3542 std::copy_if(tok->
values().cbegin(), tok->
values().cend(), std::back_inserter(result), pred);
3579 if (values.size() != 1)
3581 return values.front();
3584 template<
class Predicate>
3593 return std::vector<ValueFlow::LifetimeToken> {};
3595 return std::vector<ValueFlow::LifetimeToken>{};
3598 return {{tok, std::move(errorPath)}};
3600 return {{tok, std::move(errorPath)}};
3604 if (!varDeclEndToken)
3605 return {{tok,
true, std::move(errorPath)}};
3607 errorPath.emplace_back(varDeclEndToken,
"Passed to reference.");
3608 return {{tok,
true, std::move(errorPath)}};
3611 errorPath.emplace_back(varDeclEndToken,
"Assigned to reference.");
3613 const bool temporary =
isTemporary(vartok,
nullptr,
true);
3615 if (vartok == tok || (nonlocal && temporary) ||
3617 return {{tok,
true, std::move(errorPath)}};
3619 return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
3623 errorPath.emplace_back(var->
nameToken(),
"Assigned to reference.");
3626 return {{tok,
true, std::move(errorPath)}};
3629 return getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1);
3630 return std::vector<ValueFlow::LifetimeToken>{};
3632 return std::vector<ValueFlow::LifetimeToken> {};
3639 return {{tok, std::move(errorPath)}};
3640 std::vector<ValueFlow::LifetimeToken> result;
3642 for (
const Token* returnTok : returns) {
3643 if (returnTok == tok)
3646 const Token* argvarTok = lt.token;
3650 const Token* argTok =
nullptr;
3654 return std::vector<ValueFlow::LifetimeToken> {};
3657 if (n >= args.size())
3658 return std::vector<ValueFlow::LifetimeToken> {};
3660 lt.errorPath.emplace_back(returnTok,
"Return reference.");
3665 lt.errorPath.emplace_back(returnTok,
"Return reference that depends on 'this'.");
3666 lt.errorPath.emplace_back(tok->
previous(),
3671 getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()),
3672 returns.size() > 1);
3673 result.insert(result.end(), arglts.cbegin(), arglts.cend());
3683 errorPath.emplace_back(tok->
previous(),
"Accessing container.");
3691 const Token *vartok = tok;
3695 else if (vartok->
str() ==
".") {
3701 else if (vartok->
str() ==
"::")
3708 return {{tok, std::move(errorPath)}};
3711 if (!v.isLocalLifetimeValue())
3713 if (v.tokvalue == tok)
3715 errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
3716 return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1);
3726 auto it = std::find_if(vts.cbegin(), vts.cend(), [&](
const ValueType& vt) {
3727 return vt.isTypeEqual(vartok->valueType());
3729 if (it != vts.end())
3730 return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1);
3732 return {{tok, std::move(errorPath)}};
3744 bool result =
false;
3755 if (lts.size() != 1)
3757 if (lts.front().inconclusive)
3760 *addressOf = lts.front().addressOf;
3761 errorPath.insert(errorPath.end(), lts.front().errorPath.cbegin(), lts.front().errorPath.cend());
3762 return lts.front().token;
3831 if (vtParent->
str() == vt->
str())
3840 while (tok != endTok &&
Token::Match(tok,
"const|volatile|auto|&|&&"))
3845 static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const Token*, const Token*> y)
3847 const Token* start1 = x.first;
3848 const Token* start2 = y.first;
3849 if (start1 ==
nullptr || start2 ==
nullptr)
3851 while (start1 != x.second && start2 != y.second) {
3853 if (tok1 != start1) {
3858 if (tok2 != start2) {
3862 if (start1->
str() != start2->
str())
3864 start1 = start1->
next();
3865 start2 = start2->
next();
3869 return !(start1 == x.second && start2 == y.second);
3871 static bool isNotEqual(std::pair<const Token*, const Token*> x,
const std::string& y,
bool cpp)
3874 std::istringstream istr(y);
3875 tokenList.
createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C);
3896 std::pair<const Token*, const Token*> parentdecl =
Token::typeDecl(dst);
3911 if (tok->
str() ==
",")
3915 const Token* parent =
nullptr;
3918 for (
const ValueType& vtParent : vtParents) {
3956 const Scope* outerScope = innerScope;
3959 if (!innerScope && outerScope)
3960 innerScope = outerScope;
3961 if (!innerScope || !outerScope)
3976 const Token* end =
nullptr;
3980 local |= var->isLocal();
3981 if (var->isLocal() || var->isArgument()) {
3982 const Token* varEnd = getEndOfVarScope(var);
3983 if (!end || (smallest ? precedes(varEnd, end) : succeeds(varEnd, end)))
3986 const Token* top = var->nameToken()->astTop();
3987 if (top && Token::simpleMatch(top->tokAt(-1),
"if (")) {
3988 const Token* elseTok = top->link()->linkAt(1);
3989 if (Token::simpleMatch(elseTok,
"} else {") && tok->scope()->isNestedIn(elseTok->tokAt(2)->scope()))
3990 end = tok->scope()->bodyEnd;
3996 if (!end && defaultScope)
3997 end = defaultScope->bodyEnd;
4004 while (scope && scope->
isLocal())
4017 std::list<ValueFlow::Value> values = tok->
values();
4023 while (parent && parent->
str() ==
",")
4046 std::list<ValueFlow::Value> values = parent->
astOperand2()->values();
4051 return child->exprId() == expr->exprId();
4058 if (expr->
exprId() > 0) {
4059 valueFlowForward(nextExpression, endOfVarScope->
next(), expr, values, tokenlist, errorLogger, settings);
4067 const Token* parentLifetime =
4069 if (parentLifetime && parentLifetime->
exprId() > 0) {
4070 valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings);
4087 std::list<ValueFlow::Value> values = tok->
values();
4091 valueFlowForward(nextExpression, endOfVarScope, tok, std::move(values), tokenlist, errorLogger, settings);
4093 }
else if (parent->
isCast()) {
4094 std::list<ValueFlow::Value> values = tok->
values();
4127 const std::vector<const Token*>& argtoks,
4131 std::set<Token*> forwardToks;
4132 for (
const Token* arg : argtoks) {
4137 forwardToks.emplace(ls.forwardTok);
4139 for (
auto* tok : forwardToks) {
4153 if (n >= args.size()) {
4158 "Argument mismatch: Function '" + tok->
str() +
"' returning lifetime from argument index " +
4159 std::to_string(n) +
" but only " + std::to_string(args.size()) +
4160 " arguments are available.");
4163 const Token *argtok2 = args[n];
4167 template<
class Predicate>
4177 bool update =
false;
4182 er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
4185 if (!pred(lt.token))
4197 if (std::find(tok->
values().cbegin(), tok->
values().cend(), value) != tok->
values().cend())
4226 template<
class Predicate>
4236 bool update =
false;
4250 const Variable* var = lt.token->variable();
4257 if (std::find(tok->
values().cbegin(), tok->
values().cend(), value) != tok->
values().cend())
4266 if (!v.isLifetimeValue())
4268 const Token *tok3 = v.tokvalue;
4273 er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend());
4276 if (!pred(lt.token))
4284 value.
path = v.path;
4291 if (std::find(tok->
values().cbegin(), tok->
values().cend(), value) != tok->
values().cend())
4321 template<
class Predicate>
4329 bool update =
false;
4337 if (!v.isLifetimeValue())
4339 const Token *tok2 = v.tokvalue;
4347 for (
const Token *tok3 = tok; tok3 && tok3 != varDeclEndToken; tok3 = tok3->
previous()) {
4350 .byVal(tok, tokenlist, errorLogger, settings, pred, loc);
4384 static bool hasBorrowingVariables(
const std::list<Variable>& vars,
const std::vector<const Token*>& args,
int depth = 10)
4388 return std::any_of(vars.cbegin(), vars.cend(), [&](
const Variable& var) {
4389 if (const ValueType* vt = var.valueType()) {
4390 if (vt->pointer > 0 &&
4391 std::none_of(args.begin(), args.end(), [vt](const Token* arg) {
4392 return arg->valueType() && arg->valueType()->type == vt->type;
4395 if (vt->pointer > 0)
4397 if (vt->reference != Reference::None)
4399 if (vt->isPrimitive())
4404 if (vt->type == ValueType::CONTAINER && vt->container)
4405 return vt->container->view;
4407 return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1);
4415 const std::string& name,
4416 const std::vector<const Token*>& args,
4423 std::unordered_map<const Token*, const Variable*> argToParam;
4424 for (std::size_t i = 0; i < args.size(); i++)
4427 std::unordered_map<const Variable*, LifetimeCapture> paramCapture;
4449 if (!v.isLifetimeValue())
4455 const Variable* lifeVar = v.tokvalue->variable();
4461 else if (v.isArgumentLifetimeValue())
4464 paramCapture[lifeVar] = c;
4468 if (!found && argvar && argvar->
isArgument())
4477 "Passed to constructor of '" + name +
"'.",
4481 if (paramCapture.count(paramVar) == 0)
4485 ls.
byRef(tok, tokenlist, errorLogger, settings);
4487 ls.
byVal(tok, tokenlist, errorLogger, settings);
4494 "Passed to constructor of '" + name +
"'.",
4500 ls.
byRef(tok, tokenlist, errorLogger, settings);
4502 ls.
byVal(tok, tokenlist, errorLogger, settings);
4511 Token* memtok =
nullptr;
4513 memtok = tok->
astParent()->astOperand1();
4515 if (returnContainer >= 0) {
4517 for (
int argnr = 1; argnr <= args.size(); ++argnr) {
4523 const Token *
const argTok = args[argnr - 1];
4524 bool forward =
false;
4528 val.
errorPath.emplace_back(argTok,
"Passed to '" + tok->
str() +
"'.");
4538 }
else if (
Token::Match(tok->
tokAt(-2),
"std :: ref|cref|tie|front_inserter|back_inserter")) {
4541 tok->
next(), tokenlist, errorLogger, settings);
4543 }
else if (
Token::Match(tok->
tokAt(-2),
"std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind")) {
4546 tok->
next(), tokenlist, errorLogger, settings);
4551 const std::size_t n = args.size();
4557 .byDerefCopy(memtok, tokenlist, errorLogger, settings);
4561 .byVal(memtok, tokenlist, errorLogger, settings);
4573 bool update =
false;
4574 for (
const Token* returnTok : returns) {
4575 if (returnTok == tok)
4582 update |= ls.
byVal(tok->
next(), tokenlist, errorLogger, settings);
4585 if (!v.isLifetimeValue())
4603 if (thisIndirect == -1)
4604 update |= ls.
byDerefCopy(tok->
next(), tokenlist, errorLogger, settings);
4605 else if (thisIndirect == 0)
4606 update |= ls.
byVal(tok->
next(), tokenlist, errorLogger, settings);
4607 else if (thisIndirect == 1)
4608 update |= ls.
byRef(tok->
next(), tokenlist, errorLogger, settings);
4611 const Variable *var = v.tokvalue->variable();
4620 update |= ls.
byRef(tok->
next(), tokenlist, errorLogger, settings);
4621 }
else if (v.isArgumentLifetimeValue()) {
4622 update |= ls.
byVal(tok->
next(), tokenlist, errorLogger, settings);
4640 iArg = strToInt<std::size_t>(retVal.substr(3));
4645 if (iArg > 0 && iArg <= args.size()) {
4646 const Token* varTok = args[iArg - 1];
4649 tok->
next(), tokenlist, errorLogger, settings);
4679 std::vector<const Function*> candidates;
4681 if (
function.minArgCount() > args.size())
4683 if (!
function.isConstructor())
4685 candidates.push_back(&
function);
4688 if (candidates.size() == 1)
4689 f = candidates.front();
4718 "Passed to initializer list.",
4722 ls.
byVal(tok, tokenlist, errorLogger, settings);
4733 auto it = scope->
varlist.cbegin();
4739 "Passed to constructor of '" + t->
name() +
"'.",
4743 it = std::find_if(it, scope->varlist.cend(), [](const Variable& var) {
4744 return !var.isStatic();
4746 if (it == scope->
varlist.cend())
4750 ls.
byRef(tok, tokenlist, errorLogger, settings);
4752 ls.
byVal(tok, tokenlist, errorLogger, settings);
4769 std::vector<ValueType> vts;
4780 if (vt.pointer > 0) {
4786 "Passed to initializer list.",
4789 ls.
byVal(tok, tokenlist, errorLogger, settings);
4795 .byRef(tok, tokenlist, errorLogger, settings);
4802 "Passed to initializer list.",
4805 ls.
byDerefCopy(tok, tokenlist, errorLogger, settings);
4807 }
else if (vt.container->hasInitializerListConstructor) {
4812 "Passed to initializer list.",
4815 ls.
byVal(tok, tokenlist, errorLogger, settings);
4819 const Type* t =
nullptr;
4820 if (vt.typeScope && vt.typeScope->definedType)
4821 t = vt.typeScope->definedType;
4840 if (afterArguments && afterArguments->
originalName() ==
"->") {
4851 }
else if (c->variable()) {
4853 }
else if (c->isUnaryOp(
"&") &&
Token::Match(c->astOperand1(),
"%var%")) {
4857 const std::string& s = c->expressionString();
4870 std::unordered_map<const Variable*, std::pair<const Token*, LifetimeCapture>>
explicitCaptures;
4900 return std::any_of(vtParents.cbegin(), vtParents.cend(), [&](
const ValueType& vt) {
4903 return vt.container->view;
4930 std::set<const Scope *> scopes;
4932 std::set<nonneg int> varids;
4933 bool capturedThis =
false;
4935 auto isImplicitCapturingVariable = [&](
const Token *varTok) {
4946 if (scopes.count(scope) > 0)
4950 scopes.insert(scope);
4955 bool update =
false;
4957 if (varids.count(tok->
varId()) > 0)
4963 update |= ls.byRef(tok, tokenlist, errorLogger, settings, pred);
4968 update |= ls.byVal(tok, tokenlist, errorLogger, settings, pred);
4981 value.
errorPath.emplace_back(tok2,
"Lambda captures the 'this' variable here.");
4983 capturedThis =
true;
4985 if (std::find(tok->
values().cbegin(), tok->
values().cend(), value) != tok->
values().cend())
4994 const Token* tok2 = p.second.first;
4997 captureThisVariable(tok2, c);
4999 captureVariable(tok2, c, [](
const Token*) {
5006 auto isImplicitCapturingThis = [&](
const Token* tok2) {
5027 if (isImplicitCapturingThis(tok2)) {
5030 captureVariable(tok2, lam.
implicitCapture, isImplicitCapturingVariable);
5044 errorPath.emplace_back(tok,
"Address of variable taken here.");
5063 ls.
byRef(tok, tokenlist, errorLogger, settings);
5085 master.
errorPath.emplace_back(parent->
tokAt(2),
"Iterator to container is created here.");
5090 master.
errorPath.emplace_back(parent,
"Iterator to container is created here.");
5095 master.
errorPath.emplace_back(parent->
tokAt(2),
"Pointer to container is created here.");
5101 std::vector<const Token*> toks;
5104 if (!v.isLocalLifetimeValue())
5110 toks.push_back(v.tokvalue);
5114 if (!v.isLocalLifetimeValue())
5120 toks.push_back(v.tokvalue);
5126 for (
const Token* tok2 : toks) {
5130 value.
errorPath.insert(value.
errorPath.begin(), rt.errors.cbegin(), rt.errors.cend());
5136 if (!rt.token->variable()) {
5139 ls.
byRef(parent->
tokAt(2), tokenlist, errorLogger, settings);
5156 ErrorPath errorPath = {{ptok,
"Raw pointer to smart pointer created here."}};
5175 errorPath.emplace_back(tok,
"Array decayed to pointer here.");
5196 if (tok->
str() !=
"std")
5199 Token * variableToken =
nullptr;
5201 variableToken = tok->
tokAt(4);
5207 variableToken = rightAngle->
tokAt(2);
5213 if (variableToken->
strAt(2) ==
".")
5217 if (moveKind !=
nullptr)
5219 if (varTok !=
nullptr)
5220 *varTok = variableToken;
5226 const Token * varTok = openParenthesisToken->
tokAt(-3);
5227 return Token::Match(varTok,
"%varid% . %name% (", varId) &&
5233 Token* tok = moveVarTok;
5234 while (tok && tok->
str() !=
"(")
5241 if (!parameterToken)
5261 if (memberInitializationTok)
5262 start = memberInitializationTok;
5265 for (
auto* tok =
const_cast<Token*
>(start); tok != scope->
bodyEnd; tok = tok->
next()) {
5283 valueFlowForward(tok->
next(), endOfVarScope, tok, std::move(value), tokenlist, errorLogger, settings);
5293 while (parent && parent->
str() !=
"=" && parent->
str() !=
"return" &&
5297 (parent->
str() ==
"return" ||
5298 parent->
str() ==
"("))
5306 if (endOfFunctionCall) {
5307 if (endOfFunctionCall->
str() ==
")") {
5308 Token* ternaryColon = endOfFunctionCall->
link()->astParent();
5310 ternaryColon = ternaryColon->
astParent();
5314 endOfFunctionCall = endOfFunctionCall->
link();
5321 value.
errorPath.emplace_back(tok,
"Calling std::move(" + varTok->
str() +
")");
5323 value.
errorPath.emplace_back(tok,
"Calling std::forward(" + varTok->
str() +
")");
5326 valueFlowForward(endOfFunctionCall, endOfVarScope, varTok, std::move(value), tokenlist, errorLogger, settings);
5334 for (
const Token* tok = start; tok != end; tok = tok->
next()) {
5342 const Token* condTok,
5366 std::vector<const Token*> conds = {tok};
5367 if (tok->
str() == op) {
5368 std::vector<const Token*> args =
astFlatten(tok, op);
5369 std::copy_if(args.cbegin(), args.cend(), std::back_inserter(conds), [&](
const Token* tok2) {
5370 if (tok2->exprId() == 0)
5372 if (tok2->hasKnownIntValue())
5374 if (Token::Match(tok2,
"%var%|.") && !astIsBool(tok2))
5415 bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok,
"Skipping function due to incomplete variable " + incompleteTok->str());
5428 Token * blockTok = parenTok->
link()->tokAt(1);
5430 if (condTok->
exprId() == 0)
5438 Token* startTok = blockTok;
5453 std::vector<const Token*> conds =
getConditions(condTok,
"||");
5457 startTok = startTok->
link()->tokAt(2);
5458 for (
const Token* condTok2:conds) {
5471 const Scope* scope2 = scope;
5478 for (
const Token* condTok2:conds) {
5501 if (srcSize > dstSize)
5503 if (srcSize == dstSize && src->
sign != dst->
sign)
5505 }
else if (src->
type == dst->
type) {
5506 if (src->
type == ValueType::Type::RECORD)
5516 assert(tok && tok->
exprId() > 0 &&
"Missing expr id for symbolic value");
5532 std::set<nonneg int> result;
5534 if (child->
varId() > 0)
5535 result.insert(child->
varId());
5572 if (std::any_of(vars.cbegin(), vars.cend(), [&](
const Variable* var) {
5573 if (rhsVarIds.count(var->declarationId()) > 0)
5576 return var->isStatic();
5577 return !var->isArgument();
5591 tok->
astOperand1()->expressionString() +
" is assigned '" +
5592 tok->
astOperand2()->expressionString() +
"' here.");
5597 tok->
astOperand1()->expressionString() +
" is assigned '" +
5598 tok->
astOperand2()->expressionString() +
"' here.");
5619 if (!v.isSymbolicValue())
5623 if (v.intvalue != 0)
5641 if (
Token::Match(tok,
"abs|labs|llabs|fabs|fabsf|fabsl (")) {
5653 v.
errorPath.emplace_back(tok,
"Passed to " + tok->
str());
5659 }
else if (
Token::Match(tok,
"*|/|<<|>>|^|+|-|%or%")) {
5667 const Token* vartok =
nullptr;
5680 if (vartok->
exprId() == 0)
5688 std::vector<ValueFlow::Value> values = {
makeSymbolic(vartok)};
5689 std::unordered_set<nonneg int> ids = {vartok->
exprId()};
5690 std::copy_if(vartok->
values().cbegin(),
5692 std::back_inserter(values),
5694 if (!v.isSymbolicValue())
5698 return ids.insert(v.tokvalue->exprId()).second;
5720 v.
errorPath.emplace_back(strlenTok,
"Return index of first '\\0' character in string");
5773 std::vector<ValueFlow::Value> values =
infer(leftModel, tok->
str(), 0, tok->
astOperand2()->values());
5774 if (values.empty()) {
5785 template<
class ContainerOfValue>
5789 const ContainerOfValue& values,
5794 throw InternalError(var->
nameToken(),
"valueFlowForwardConst: start token does not precede the end token.");
5795 for (
Token* tok = start; tok != end; tok = tok->
next()) {
5803 auto it = std::find_if(refs.cbegin(), refs.cend(), [&](
const ReferenceToken& ref) {
5804 return ref.token->varId() == var->declarationId();
5806 if (it != refs.end()) {
5808 if (refs.size() > 1)
5810 value.
errorPath.insert(value.
errorPath.end(), it->errors.cbegin(), it->errors.cend());
5817 if (!v.isSymbolicValue())
5826 if (v.intvalue != 0) {
5833 value.
bound = v.bound;
5834 value.
errorPath.insert(value.
errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend());
5846 const std::initializer_list<ValueFlow::Value>& values,
5858 const Token* next = start;
5872 else if (result != b)
5884 if (tok->
variable()->nameToken() == tok)
5894 std::vector<const Variable*> vars,
5895 std::list<ValueFlow::Value> values,
5909 vars.cbegin(), vars.cend(), [&](
const Variable* var) {
5910 return !var->isPointer() && !var->isSmartPointer();
5915 std::string valueKind;
5918 valueKind =
"never ";
5920 valueKind =
"less than ";
5922 valueKind =
"greater than ";
5924 std::string info =
"Assignment '" + tok->
astParent()->expressionString() +
"', assigned value is " + valueKind + value.
infoString();
5925 value.
errorPath.emplace_back(tok, std::move(info));
5929 if (tokenlist.
isCPP() && vars.size() == 1 &&
Token::Match(vars.front()->typeStartToken(),
"bool|_Bool")) {
5941 if (vars.size() == 1 && vars.front()->isStatic() && init)
5945 if (std::any_of(vars.cbegin(), vars.cend(), [&](
const Variable* var) {
5946 return var->isVolatile();
5952 if (!nextExpression)
5964 auto it = std::remove_if(values.begin(), values.end(), [](
const ValueFlow::Value& value) {
5965 if (!value.isKnown())
5967 if (value.isIntValue())
5969 if (value.isFloatValue())
5971 if (value.isContainerSizeValue())
5973 if (value.isIteratorValue())
5977 std::list<ValueFlow::Value> constValues;
5978 constValues.splice(constValues.end(), values, it, values.end());
5985 auto knownValueIt = std::find_if(values.begin(), values.end(), [](
const ValueFlow::Value& value) {
5986 if (!value.isKnown())
5988 return value.isIntValue();
5990 if (knownValueIt != values.end()) {
5999 valueFlowForward(nextExpression, endOfVarScope, expr, std::move(values), tokenlist, errorLogger, settings);
6004 const std::list<ValueFlow::Value>& values,
6014 static std::list<ValueFlow::Value>
truncateValues(std::list<ValueFlow::Value> values,
6026 if (osz >= sz && dst->
sign == ValueType::Sign::SIGNED && src->
sign == ValueType::Sign::UNSIGNED) {
6034 if (osz == sz && value.
intvalue < 0)
6060 return (tok->
str() ==
"(" || tok->
str() ==
"{") &&
6065 tok->
astOperand1()->variable()->valueType()->type >= ValueType::Type::VOID &&
6070 template<
class C1,
class C2>
6073 if (c1.size() > c2.size())
6076 for (
auto&& x : c1) {
6077 if (c2.find(x) != c2.end())
6087 const std::set<const Scope*>& skippedFunctions)
6090 if (skippedFunctions.count(scope))
6092 std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
6095 bool isInit =
false;
6111 if (!rhs || rhs->
values().empty())
6117 std::set<ValueFlow::Value::ValueType> types;
6125 return types.count(value.
valueType) > 0;
6139 auto isIncremental = [&](
const Token* tok2) ->
bool {
6141 [&](
const Token* child) {
6146 const bool incremental = isIncremental(tok->
astOperand2()) ||
6147 std::any_of(values.cbegin(), values.cend(), [&](
const ValueFlow::Value& value) {
6148 if (!value.isSymbolicValue())
6150 return isIncremental(value.tokvalue);
6170 rhs, tok->
astOperand1(), std::move(vars), values, init, tokenlist, errorLogger, settings);
6176 std::unordered_set<nonneg int> ids;
6197 s.insert(expr->
exprId());
6200 tok->
astOperand1()->expressionString() +
" is assigned '" +
6201 tok->
astOperand2()->expressionString() +
"' here.");
6202 valueFlowForward(start, end, expr, std::move(value), tokenlist, errorLogger, settings);
6211 std::vector<const Variable*> result;
6214 result.push_back(child->
variable());
6232 if (args.size() != 2)
6234 if (args[0]->exprId() == 0)
6236 if (args[1]->exprId() == 0)
6238 for (
int i = 0; i < 2; i++) {
6239 std::vector<const Variable*> vars =
getVariables(args[0]);
6240 const std::list<ValueFlow::Value>& values = args[0]->values();
6241 valueFlowForwardAssign(args[0], args[1], std::move(vars), values,
false, tokenlist, errorLogger, settings);
6242 std::swap(args[0], args[1]);
6276 static void insertImpossible(std::list<ValueFlow::Value>& values,
const std::list<ValueFlow::Value>& input)
6281 static void insertNegateKnown(std::list<ValueFlow::Value>& values,
const std::list<ValueFlow::Value>& input)
6288 values.push_back(std::move(value));
6307 auto it = std::find_if(values.cbegin(), values.cend(), [](
const ValueFlow::Value& v) {
6310 if (it == values.end())
6313 return v.path == 0 || v.path == it->path;
6325 std::list<ValueFlow::Value>& thenValues,
6326 std::list<ValueFlow::Value>& elseValues,
6327 bool known =
false)
const
6330 const bool allowKnown = path == 0;
6331 const bool allowImpossible =
impossible && allowKnown;
6335 bool then = !
inverted || !inverted2;
6352 std::swap(thenValues, elseValues);
6362 const Token* exprTok,
6363 const std::list<ValueFlow::Value>& values,
6369 return valueFlowForward(start->
next(), stop, exprTok, values, tokenlist, errorLogger, settings, loc);
6373 const Token* exprTok,
6374 const std::list<ValueFlow::Value>& values,
6384 const Token* endToken,
6385 const Token* exprTok,
6386 const std::list<ValueFlow::Value>& values,
6392 valueFlowReverse(start, endToken, exprTok, values, tokenlist, errorLogger, settings, loc);
6397 const std::set<const Scope*>& skippedFunctions,
6398 const std::function<
void(
const Condition& cond,
Token* tok,
const Scope* scope)>& f)
const
6401 if (skippedFunctions.count(scope))
6426 f(cond, tok, scope);
6436 const std::set<const Scope*>& skippedFunctions)
const {
6453 if (settings.debugwarnings)
6457 "variable '" + cond.vartok->expressionString() +
"', condition is defined in macro");
6463 if (settings.debugwarnings)
6467 "variable '" + cond.vartok->expressionString() +
"', condition is defined in macro");
6471 std::list<ValueFlow::Value> values = cond.
true_values;
6492 if (Token::simpleMatch(top->previous(),
"for (")) {
6493 if (top->astOperand2() && top->astOperand2()->astOperand2() &&
6494 findExpressionChanged(
6495 cond.vartok, top->astOperand2()->astOperand2(), top->link(), settings)) {
6496 if (settings.debugwarnings)
6500 "variable '" + cond.vartok->expressionString() +
"' used in loop");
6506 const Token*
const start = top;
6507 const Token*
const block = top->
link()->next();
6512 if (!Token::Match(tok,
"%assign%|++|--") &&
6513 findExpression(cond.vartok->exprId(), start, end, [&](const Token* tok2) {
6514 return Token::Match(tok2->astParent(),
"%assign%") && astIsLHS(tok2);
6518 reverse(bodyTok->
link(), bodyTok, cond.
vartok, values, tokenlist, errorLogger, settings);
6529 Token* startTok =
nullptr;
6537 reverse(startTok,
nullptr, cond.vartok, values, tokenlist, errorLogger, settings);
6552 const bool value = sibling->
values().front().intvalue;
6571 return v.path == path && isNonConditionalPossibleIntValue(v);
6584 const std::set<const Scope*>& skippedFunctions)
const {
6585 traverseCondition(symboldatabase, settings, skippedFunctions, [&](
const Condition& cond,
Token* condTok,
const Scope* scope) {
6589 const bool allowKnown = path == 0;
6591 std::list<ValueFlow::Value> thenValues;
6592 std::list<ValueFlow::Value> elseValues;
6597 Token* parent = ctx->astParent();
6598 if (astIsRHS(ctx) && astIsLHS(parent) && parent->astParent() &&
6599 parent->str() == parent->astParent()->str())
6600 parent = parent->astParent();
6601 else if (!astIsLHS(ctx)) {
6605 std::vector<Token*> nextExprs = {parent->
astOperand2()};
6606 if (
astIsLHS(parent) && parent->astParent() && parent->astParent()->str() == parent->str()) {
6607 nextExprs.push_back(parent->astParent()->astOperand2());
6609 std::list<ValueFlow::Value> andValues;
6610 std::list<ValueFlow::Value> orValues;
6613 const std::string& op(parent->str());
6614 std::list<ValueFlow::Value> values;
6616 values = std::move(andValues);
6617 else if (op ==
"||")
6618 values = std::move(orValues);
6623 std::all_of(values.cbegin(), values.cend(), [](
const ValueFlow::Value& v) {
6624 return v.isIntValue() || v.isFloatValue();
6627 return v.isImpossible();
6629 for (
Token* start:nextExprs) {
6638 const Token* tok2 = condTok;
6640 bool mixedOperators =
false;
6646 }
else if (op != parent->
str()) {
6647 mixedOperators =
true;
6651 if (parent->
str() ==
"!") {
6652 op = (op ==
"&&" ?
"||" :
"&&");
6657 if (mixedOperators) {
6666 for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
6672 Token* condTop = ctx->astParent();
6674 bool inverted2 =
false;
6676 Token* parent = skipNotAndCasts(condTop, &inverted2)->
astParent();
6682 std::swap(thenValues, elseValues);
6690 forward(colon->
astOperand1(), cond.
vartok, thenValues, tokenlist, errorLogger, settings);
6691 forward(colon->
astOperand2(), cond.
vartok, elseValues, tokenlist, errorLogger, settings);
6696 if (condTop != top && condTop->
str() !=
";")
6714 std::set<ValueFlow::Value::Bound> bounds;
6718 bounds.insert(v.bound);
6731 const Token* startBlock = top->
link()->next();
6741 fillFromPath(pm, initTok, path, settings);
6742 fillFromPath(pm, condTok, path, settings);
6743 execute(initTok, pm,
nullptr,
nullptr, settings);
6745 execute(condTok, pm, &result,
nullptr, settings);
6749 for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
6751 v.condition =
nullptr;
6752 v.conditional =
true;
6757 bool deadBranch[] = {
false,
false};
6759 Token* startTokens[] = {
nullptr,
nullptr};
6762 startTokens[0] = top->
link()->next();
6764 startTokens[1] = top->
link()->linkAt(1)->tokAt(2);
6766 int changeBlock = -1;
6769 for (
int i = 0; i < 2; i++) {
6770 const Token*
const startToken = startTokens[i];
6773 std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
6777 Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.
vartok, values, tokenlist, errorLogger, settings);
6790 startTokens[changeBlock]->link(),
6792 " is changed in conditional block");
6795 if (bailBlock >= 0) {
6799 startTokens[bailBlock]->link(),
6800 "valueFlowAfterCondition: bailing in conditional block");
6807 bool dead_if = deadBranch[0];
6808 bool dead_else = deadBranch[1];
6809 const Token* unknownFunction =
nullptr;
6815 if (!dead_if && unknownFunction) {
6817 bailout(tokenlist, errorLogger, unknownFunction,
"possible noreturn scope");
6822 after = after->
linkAt(2);
6823 unknownFunction =
nullptr;
6826 if (!dead_else && unknownFunction) {
6828 bailout(tokenlist, errorLogger, unknownFunction,
"possible noreturn scope");
6833 if (dead_if && dead_else)
6836 std::list<ValueFlow::Value> values;
6838 values = std::move(elseValues);
6839 }
else if (dead_else) {
6840 values = std::move(thenValues);
6842 std::copy_if(thenValues.cbegin(),
6844 std::back_inserter(values),
6846 std::copy_if(elseValues.cbegin(),
6848 std::back_inserter(values),
6855 if (dead_if || dead_else) {
6860 bool possible =
false;
6862 const std::string& op(parent->
str());
6863 while (parent && parent->
str() == op)
6866 possible = op ==
"||";
6868 possible = op ==
"&&";
6873 }
else if (allowKnown) {
6880 const bool isKnown = std::any_of(values.cbegin(), values.cend(), [&](
const ValueFlow::Value& v) {
6881 return v.isKnown() || v.isImpossible();
6893 start = start->
tokAt(2);
6894 forward(start, start->
link(), cond.
vartok, values, tokenlist, errorLogger, settings);
6895 start = start->
link();
6916 const std::set<const Scope*>& skippedFunctions)
6918 handler->beforeCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
6919 handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions);
6925 std::vector<Condition> conds;
6932 cond.
true_values.push_back(std::move(true_value));
6933 cond.false_values.push_back(std::move(false_value));
6934 cond.vartok = vartok;
6935 conds.push_back(std::move(cond));
6940 const Token* vartok =
nullptr;
6942 if (tok->
str() ==
"!") {
6960 return {std::move(cond)};
6988 if (r.size() == 1 && r.front().isKnown())
7058 std::vector<ValueFlow::Value> result =
7066 std::vector<ValueFlow::Value> result =
7076 if (result.size() != 1)
7113 std::vector<Condition> result;
7114 auto addCond = [&](
const Token* lhsTok,
const Token* rhsTok,
bool inverted) {
7115 for (
int i = 0; i < 2; i++) {
7116 const bool lhs = i == 0;
7117 const Token* vartok = lhs ? lhsTok : rhsTok;
7118 const Token* valuetok = lhs ? rhsTok : lhsTok;
7119 if (valuetok->
exprId() == 0)
7136 result.push_back(std::move(cond));
7163 execute(firstExpression, programMemory, &result, &
error, settings);
7166 execute(secondExpression, programMemory, &result, &
error, settings);
7171 bool reassign =
false;
7173 [&](
const Token *t) {
7186 int maxcount = 10000;
7187 while (result != 0 && !
error && --maxcount > 0) {
7188 endMemory = programMemory;
7189 execute(thirdExpression, programMemory, &result, &
error, settings);
7191 execute(secondExpression, programMemory, &result, &
error, settings);
7195 memory1->
swap(startMemory);
7198 memory2->
swap(endMemory);
7200 memoryAfter->
swap(programMemory);
7215 assert(expr->
varId() > 0);
7216 const Token *
const bodyEnd = bodyStart->
link();
7222 for (
Token *tok2 = bodyStart->
next(); tok2 != bodyEnd; tok2 = tok2->
next()) {
7226 const Token *
const p = parent;
7228 if (!parent || parent->
str() ==
":")
7230 if (parent->
str() ==
"?") {
7238 bailout(tokenlist, errorLogger, tok2,
"For loop variable " + tok2->
str() +
" stopping on ?");
7252 Token *parent = tok2;
7253 while (parent && parent->
str() == tok2->
str())
7256 if (parent && parent->
str() ==
"(") {
7257 tok2 = parent->
link();
7264 const Token* vartok = expr;
7267 vartok = rml->
str() ==
"]" ? rml : rml->
previous();
7268 if (vartok->
str() ==
"]" && vartok->
link()->previous())
7269 vartok = vartok->
link()->previous();
7271 if ((tok2->
str() ==
"&&" &&
7275 (tok2->
str() ==
"||" &&
7285 bailout(tokenlist, errorLogger, tok2,
"For loop variable bailout on conditional continue|break|return");
7289 bailout(tokenlist, errorLogger, tok2,
"For loop variable skipping conditional scope");
7294 bailout(tokenlist, errorLogger, tok2,
"For loop variable bailout on conditional continue|break|return");
7302 bailout(tokenlist, errorLogger, tok2,
"For loop skipping {} code");
7313 const Token *vartok =
nullptr;
7314 for (
const Token *tok = fortok; tok; tok = tok->
next()) {
7315 if (tok->
varId() == varid) {
7320 if (!vartok || !vartok->
variable())
7324 const Token *endToken =
nullptr;
7328 endToken = fortok->
scope()->bodyEnd;
7331 if (blockTok != endToken) {
7333 v.
errorPath.emplace_back(fortok,
"After for loop, " + var->
name() +
" has value " + v.infoString());
7335 valueFlowForward(blockTok->
next(), endToken, vartok, std::move(v), tokenlist, errorLogger, settings);
7353 bool knownInitValue, partialCond;
7356 if (
extractForLoopValues(tok, varid, knownInitValue, initValue, partialCond, stepValue, lastValue)) {
7357 const bool executeBody = !knownInitValue || initValue <= lastValue;
7359 if (executeBody && vartok) {
7360 std::list<ValueFlow::Value> initValues;
7366 std::list<ValueFlow::Value> lastValues;
7368 lastValues.back().conditional =
true;
7371 lastValues.pop_front();
7372 valueFlowForward(bodyStart, bodyStart->link(), vartok, std::move(lastValues), tokenlist, errorLogger, settings);
7375 const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
7380 for (
const auto& p : mem1) {
7381 if (!p.second.isIntValue())
7383 if (p.second.isImpossible())
7385 if (p.first.tok->varId() == 0)
7389 for (
const auto& p : mem2) {
7390 if (!p.second.isIntValue())
7392 if (p.second.isImpossible())
7394 if (p.first.tok->varId() == 0)
7398 for (
const auto& p : memAfter) {
7399 if (!p.second.isIntValue())
7401 if (p.second.isImpossible())
7403 if (p.first.tok->varId() == 0)
7413 std::unordered_map<nonneg int, ValueFlow::Value>
values;
7414 std::unordered_map<nonneg int, const Variable*>
vars;
7418 for (
const auto& p:args) {
7419 values[p.first->declarationId()] = p.second;
7420 vars[p.first->declarationId()] = p.first;
7424 virtual const std::unordered_map<nonneg int, const Variable*>&
getVars()
const {
7429 if (tok->
varId() == 0)
7437 if (tok->
varId() == 0)
7447 p.second.conditional =
true;
7453 p.second.errorPath.emplace_back(tok, s);
7460 for (
const auto& p:
getVars()) {
7461 nonneg int const varid = p.first;
7463 if (tok->
varId() == varid)
7473 if (p.second.isImpossible())
7475 p.second.changeKnownToPossible();
7481 if (p.second.isImpossible())
7483 p.second.setInconclusive();
7490 if (p.second.conditional)
7492 if (p.second.condition)
7493 return !p.second.isImpossible();
7502 const auto& values_ = condTok->
values();
7503 return std::any_of(values_.cbegin(), values_.cend(), [](
const ValueFlow::Value& v) {
7504 return v.isSymbolicValue() && Token::Match(v.tokvalue,
"%oror%|&&");
7515 return std::all_of(
values.cbegin(),
values.cend(), [](
const std::pair<nonneg int, ValueFlow::Value>& p) {
7516 return p.second.isLifetimeValue();
7535 std::set<nonneg int> varids;
7549 for (
const auto& p :
values) {
7559 template<
class Key,
class F>
7560 static bool productParams(
const Settings& settings,
const std::unordered_map<Key, std::list<ValueFlow::Value>>& vars, F f)
7562 using Args = std::vector<std::unordered_map<Key, ValueFlow::Value>>;
7565 for (
const auto& p:vars) {
7566 if (p.second.empty())
7568 args.back()[p.first] = p.second.front();
7572 for (
const auto& p:vars) {
7573 if (args.size() > max) {
7577 if (p.second.empty())
7579 std::for_each(std::next(p.second.begin()), p.second.end(), [&](
const ValueFlow::Value& value) {
7581 for (auto arg:args) {
7582 if (value.path != 0) {
7583 for (const auto& q:arg) {
7584 if (q.first == p.first)
7586 if (q.second.path == 0)
7588 if (q.second.path != value.path)
7592 arg[p.first] = value;
7593 new_args.push_back(std::move(arg));
7595 std::copy(new_args.cbegin(), new_args.cend(), std::back_inserter(args));
7599 if (args.size() > max) {
7604 for (
const auto& arg:args) {
7609 if (std::any_of(arg.cbegin(), arg.cend(), [&](
const std::pair<Key, ValueFlow::Value>& p) {
7610 return p.second.path != path;
7621 const Scope* functionScope,
7622 const std::unordered_map<
const Variable*, std::list<ValueFlow::Value>>& vars)
7624 const bool r =
productParams(settings, vars, [&](
const std::unordered_map<const Variable*, ValueFlow::Value>& arg) {
7629 std::string fname =
"<unknown>";
7633 bailout(tokenlist, errorLogger, functionScope->
bodyStart,
"Too many argument passed to " + fname);
7641 const Scope* functionScope,
7642 const std::list<ValueFlow::Value>& argvalues)
7665 if (scope.
type != Scope::ScopeType::eSwitch)
7677 bailout(tokenlist, errorLogger, vartok,
"switch variable " + var->
name() +
" is global");
7682 if (tok->
str() ==
"{") {
7687 std::list<ValueFlow::Value> values;
7689 values.back().condition = tok;
7690 values.back().errorPath.emplace_back(tok,
"case " + tok->
next()->
str() +
": " + vartok->
str() +
" is " + tok->
next()->
str() +
" here.");
7696 tok = tok->
tokAt(3);
7700 values.back().condition = tok;
7701 values.back().errorPath.emplace_back(tok,
"case " + tok->
next()->
str() +
": " + vartok->
str() +
" is " + tok->
next()->
str() +
" here.");
7703 for (std::list<ValueFlow::Value>::const_iterator val = values.cbegin(); val != values.cend(); ++val) {
7713 values.back().setKnown();
7736 std::list<ValueFlow::Value> argvalues(argtok->
values());
7738 if (argvalues.empty() &&
Token::Match(argtok,
"%comp%|%oror%|&&|!")) {
7739 argvalues.emplace_back(0);
7740 argvalues.emplace_back(1);
7747 std::unordered_map<nonneg int, std::list<ValueFlow::Value>> argValues;
7753 if (returnValue.find(
"arg") != std::string::npos && argValues.empty())
7755 productParams(settings, argValues, [&](
const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
7760 for (
auto&& p : arg) {
7761 if (p.second.isPossible())
7762 kind = p.second.valueKind;
7763 if (p.second.isInconclusive()) {
7764 kind = p.second.valueKind;
7776 template<
class Iterator>
7791 template<
class Iterator>
7794 return {start, last};
7809 if (!calledFunction) {
7812 if (!returnValue.empty())
7818 if (!calledFunctionScope)
7822 std::unordered_map<const Variable*, std::list<ValueFlow::Value>> argvars;
7824 const std::vector<const Token *> &callArguments =
getArguments(tok);
7825 for (
int argnr = 0U; argnr < callArguments.size(); ++argnr) {
7826 const Token *argtok = callArguments[argnr];
7842 if (argtok->
variable() && !argtok->
variable()->isPointer() && argvalues.size() == 1 && argvalues.front().isUninitValue()) {
7847 if (argvalues.empty())
7852 const std::string nr = std::to_string(argnr + 1) +
getOrdinalText(argnr + 1);
7855 "Calling function '" +
7856 calledFunction->
name() +
7872 argvars[argvar] = std::move(argvalues);
7881 if (!tokenlist.
isCPP())
7888 for (std::size_t arg = function->minArgCount(); arg < function->argCount(); arg++) {
7889 const Variable* var =
function->getArgumentVar(arg);
7892 std::list<ValueFlow::Value> argvalues;
7898 argvalues.push_back(std::move(v));
7900 if (!argvalues.empty())
7912 return (v.isIntValue() || v.isContainerSizeValue() || v.isFloatValue()) && v.isKnown();
7914 if (it == tok->
values().end())
7916 return std::addressof(*it);
7926 if (!std::all_of(std::next(toks.begin()), toks.end(), [&](
const Token* tok) {
7927 return std::any_of(tok->values().begin(), tok->values().end(), [&](const ValueFlow::Value& v) {
7928 return v.equalValue(*result) && v.valueKind == result->valueKind;
7954 const Function*
function =
nullptr;
7962 if (function->isImplicitlyVirtual() && !function->hasFinalSpecifier())
7969 if (returns.empty())
7978 std::vector<const Token*> arguments =
getArguments(tok);
7981 for (std::size_t i = 0; i < arguments.size(); ++i) {
7982 const Variable *
const arg =
function->getArgumentVar(i);
7985 bailout(tokenlist, errorLogger, tok,
"function return; unhandled argument type");
7986 programMemory.
clear();
7994 if (programMemory.
empty() && !arguments.empty())
7996 std::vector<ValueFlow::Value> values =
execute(function->functionScope, programMemory, settings);
7998 if (v.isUninitValue())
8032 std::unordered_set<const Token*> locations;
8033 std::transform(value.
errorPath.cbegin(),
8035 std::inserter(locations, locations.begin()),
8045 return locations.insert(e.first).second;
8058 return tok->varId() == var->declarationId();
8064 std::vector<Token*> uses =
findAllUsages(var, start, library);
8067 Token* first = uses.front();
8072 Token* temp = first;
8079 if (uses.size() == 1)
8083 if (scope == var->
scope()) {
8084 bool isLoopExpression =
false;
8085 for (
const Token* parent = first; parent; parent = parent->
astParent()) {
8089 Token::simpleMatch(parent->astParent()->astParent()->astParent()->astOperand1(),
"for (") &&
8090 parent == parent->astParent()->astParent()->astParent()->astOperand2()->astOperand2()->astOperand2()) {
8091 isLoopExpression =
true;
8094 return isLoopExpression ? start : first->
previous();
8097 if (std::all_of(uses.begin() + 1, uses.end(), [&](
const Token* tok) {
8098 return tok->scope() == scope;
8119 if (!tok->
scope()->isExecutable())
8140 bool partial =
false;
8144 std::map<Token*, ValueFlow::Value> partialReads;
8163 Token* tok2 = p.first;
8166 auto pp = partialReads.insert(std::make_pair(tok2, v));
8168 const bool inserted = pp.second;
8180 for (
auto&& p : partialReads) {
8181 Token* tok2 = p.first;
8230 const bool isPointer = addressOf || indirect > 0;
8233 if (!isPointer && arg->
isConst())
8246 addressOf ? indirect + 1 : indirect,
8289 return rhsval.isKnown() && rhsval.isContainerSizeValue();
8297 if (args.size() < 2)
8324 return rhsval.isKnown() && rhsval.isContainerSizeValue();
8326 if (it != rhs->
values().end())
8366 const std::function<std::vector<MathLib::bigint>(
const Token*)>& eval,
8375 std::vector<MathLib::bigint> x1 = eval(expr->
astOperand1());
8376 std::vector<MathLib::bigint> x2 = eval(expr->
astOperand2());
8377 if (expr->
astOperand1()->exprId() == 0 && x1.empty())
8379 if (expr->
astOperand2()->exprId() == 0 && x2.empty())
8381 const Token* varTok =
nullptr;
8382 if (!x1.empty() && x2.empty()) {
8385 }
else if (x1.empty() && !x2.empty()) {
8393 const std::function<std::vector<MathLib::bigint>(
const Token*)>& eval,
8402 const bool rhs =
astIsRHS(binaryTok);
8406 if (binaryTok && expr->
str().size() == 1) {
8407 switch (expr->
str()[0]) {
8438 [](
const Token* tok) -> std::vector<MathLib::bigint> {
8440 return {tok->values().front().intvalue};
8504 for (
const Token *tok = start; tok != end; tok = tok->
next()) {
8518 if (!tok->
scope()->isExecutable())
8530 const std::list<ValueFlow::Value>& values = inTok->
values();
8531 const bool constValue = inTok->
isNumber();
8541 tok->
astParent()->originalName() !=
"->") {
8548 valueFlowForwardAssign(ftok, tok, std::move(vars), {std::move(v)},
false, tokenlist, errorLogger, settings);
8554 const std::list<ValueFlow::Value>& values = inTok->
values();
8559 bool hasParentReset =
false;
8563 hasParentReset =
true;
8572 valueFlowForwardAssign(ftok, tok, std::move(vars), {std::move(v)},
false, tokenlist, errorLogger, settings);
8606 if (!tok->
scope()->isExecutable())
8610 Token* ftok =
nullptr;
8646 if (!values.empty()) {
8650 if (!values.empty())
8655 v.assumeCondition(tok);
8661 return {std::move(cond)};
8670 if (!tok->
scope()->isExecutable())
8699 std::vector<ValueFlow::Value> values;
8701 std::copy_if(tok->
values().cbegin(),
8703 std::back_inserter(values),
8730 if (args.size() == 1 || (args.size() > 1 && !
astIsIntegral(args[1],
false)))
8736 if (!result.empty())
8742 if (args[0]->exprId() == args[1]->exprId())
8746 nonneg int const eid = args[0]->exprId();
8749 if (sizetok->
exprId() == eid)
8750 std::swap(vartok, sizetok);
8761 if (args.size() == 1)
8763 if (args.size() == 3)
8777 return contType.
isTypeEqual(&tokType) || tokType.
type == ValueType::Type::UNKNOWN_TYPE;
8788 bool initList =
true;
8790 if (args.size() < 4) {
8795 }
else if (containerTypeToken) {
8839 valueFlowForward(start, tok, std::move(value), tokenlist, errorLogger, settings);
8844 while (scope && scope->
type != Scope::ScopeType::eFunction)
8858 if (v->tokvalue != tok)
8868 const std::set<const Scope*>& skippedFunctions)
8874 if (!var->scope() || !var->scope()->bodyEnd || !var->scope()->bodyStart)
8876 if (!var->valueType() || !var->valueType()->container)
8885 const bool nonLocal = !var->isLocal() || var->isPointer() || var->isReference() || var->isStatic();
8886 bool constSize = var->isConst() && !
nonLocal;
8887 bool staticSize =
false;
8888 if (var->valueType()->container->size_templateArgNo >= 0) {
8892 if (var->dimensions().size() == 1) {
8893 const Dimension& dim = var->dimensions().front();
8897 size = dim.
tok->
values().front().intvalue;
8905 Token* nameToken =
const_cast<Token*
>(var->nameToken());
8919 values.back().setKnown();
8926 const Token* constructorArgs = nameToken->
next();
8937 valueFlowForward(nameToken->
next(), var->nameToken(), value, tokenlist, errorLogger, settings);
8944 if (
Token::Match(tok,
"%name%|;|{|} %var% = %str% ;")) {
8946 if (containerTok->
exprId() == 0)
8957 std::vector<ValueFlow::Value> values;
8964 values.push_back(value);
8966 const Token* constructorArgs = tok;
8973 if (containerTok->
exprId() == 0)
8976 std::vector<ValueFlow::Value> values =
8985 if (containerTok->
exprId() == 0)
8992 valueFlowForward(tok->
next(), containerTok, std::move(value), tokenlist, errorLogger, settings);
9018 valueFlowForward(next, containerTok, value, tokenlist, errorLogger, settings);
9027 std::vector<Condition> conds;
9035 cond.
true_values.push_back(std::move(true_value));
9038 conds.push_back(std::move(cond));
9043 const Token* vartok =
nullptr;
9046 if (tok->
str() ==
"(") {
9064 return {std::move(cond)};
9068 const Token *strtok =
nullptr;
9087 return {std::move(cond)};
9103 const std::vector<const Token*> args =
getArguments(funcTok);
9133 if (newTok && newTok->astOperand1()) {
9134 const Token* bracTok =
nullptr, *typeTok =
nullptr;
9135 if (newTok->astOperand1()->str() ==
"[")
9138 if (newTok->astOperand1()->astOperand1() && newTok->astOperand1()->astOperand1()->str() ==
"[")
9141 typeTok = newTok->astOperand1()->astOperand1();
9144 typeTok = newTok->astOperand1();
9146 numElem = bracTok->
astOperand2()->getKnownIntValue();
9151 if (numElem >= 0 && newTok->astParent() && newTok->astParent()->isAssignmentOp()) {
9153 if (!typeTok || !typeTok->
varId())
9154 typeTok = newTok->
astParent()->previous();
9158 sizeValue = numElem * typeSize;
9173 while (rhs && rhs->
isCast())
9178 const bool isNew = rhs->
isCpp() && rhs->
str() ==
"new";
9182 const MathLib::bigint sizeValue = isNew ? getBufferSizeFromNew(rhs) : getBufferSizeFromAllocFunc(rhs->
previous());
9187 value.
errorPath.emplace_back(tok->
tokAt(2),
"Assign " + tok->
strAt(1) +
", buffer with size " + std::to_string(sizeValue));
9202 case ValueType::Type::BOOL:
9205 case ValueType::Type::CHAR:
9208 case ValueType::Type::SHORT:
9211 case ValueType::Type::INT:
9214 case ValueType::Type::LONG:
9217 case ValueType::Type::LONGLONG:
9227 }
else if (bits < 62) {
9228 if (vt->
sign == ValueType::Sign::UNSIGNED) {
9230 maxValue = (1LL << bits) - 1;
9232 minValue = -(1LL << (bits - 1));
9233 maxValue = (1LL << (bits - 1)) - 1;
9235 }
else if (bits == 64) {
9236 if (vt->
sign == ValueType::Sign::UNSIGNED) {
9238 maxValue = LLONG_MAX;
9240 minValue = LLONG_MIN;
9241 maxValue = LLONG_MAX;
9253 std::istringstream istr(typestr+
";");
9254 if (!typeTokens.
createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C))
9271 const bool safe =
function->
isSafe(settings);
9272 const bool all = safe && settings.
platform.
type != Platform::Type::Unspecified;
9274 for (
const Variable &arg : function->argumentList) {
9281 std::list<ValueFlow::Value> argValues;
9282 argValues.emplace_back(0);
9284 argValues.back().errorPath.emplace_back(arg.
nameToken(),
"Assuming " + arg.
name() +
" is empty");
9285 argValues.back().safe =
true;
9286 argValues.emplace_back(1000000);
9288 argValues.back().errorPath.emplace_back(arg.
nameToken(),
"Assuming " + arg.
name() +
" size is 1000000");
9289 argValues.back().safe =
true;
9299 if (!isLow && !isHigh && !all)
9302 const bool safeLow = !isLow;
9303 const bool safeHigh = !isHigh;
9305 if ((!isLow || !isHigh) && all) {
9312 isLow = isHigh =
true;
9314 std::list<ValueFlow::Value> argValues;
9315 argValues.emplace_back(0);
9317 argValues.back().floatValue = isLow ? low : -1E25;
9318 argValues.back().errorPath.emplace_back(arg.
nameToken(),
"Safe checks: Assuming argument has value " +
MathLib::toString(argValues.back().floatValue));
9319 argValues.back().safe =
true;
9320 argValues.emplace_back(0);
9322 argValues.back().floatValue = isHigh ? high : 1E25;
9323 argValues.back().errorPath.emplace_back(arg.
nameToken(),
"Safe checks: Assuming argument has value " +
MathLib::toString(argValues.back().floatValue));
9324 argValues.back().safe =
true;
9328 std::move(argValues),
9336 std::list<ValueFlow::Value> argValues;
9338 argValues.emplace_back(low);
9339 argValues.back().errorPath.emplace_back(arg.
nameToken(), std::string(safeLow ?
"Safe checks: " :
"") +
"Assuming argument has value " + std::to_string(low));
9340 argValues.back().safe = safeLow;
9343 argValues.emplace_back(high);
9344 argValues.back().errorPath.emplace_back(arg.
nameToken(), std::string(safeHigh ?
"Safe checks: " :
"") +
"Assuming argument has value " + std::to_string(high));
9345 argValues.back().safe = safeHigh;
9348 if (!argValues.empty())
9352 std::move(argValues),
9370 if (unknownValues.empty())
9380 if (value < minvalue)
9382 else if (value > maxvalue)
9399 std::string msg =
"The value is " +
debugString(v);
9401 errorPath.insert(errorPath.end(), v.debugPath.cbegin(), v.debugPath.cend());
9402 errorPath.emplace_back(tok,
"");
9410 if (expr && expr->
values().empty()) {
9437 virtual const char*
name()
const = 0;
9446 using Clock = std::chrono::steady_clock;
9449 : state(std::move(state)), stop(
TimePoint::max()), timerResults(timerResults)
9451 setSkippedFunctions();
9464 std::size_t values = 0;
9465 std::size_t n = state.settings.valueFlowMaxIterations;
9466 while (n > 0 && values != getTotalValues()) {
9467 values = getTotalValues();
9474 if (state.settings.debugwarnings) {
9475 if (n == 0 && values != getTotalValues()) {
9480 "ValueFlow maximum iterations exceeded",
9481 "valueFlowMaxIterations",
9483 state.errorLogger.reportErr(errmsg);
9491 auto start = Clock::now();
9494 if (!state.tokenlist.isCPP() && pass->cpp())
9497 Timer t(pass->name(), state.settings.showtime, timerResults);
9508 for (
Token* tok = state.tokenlist.front(); tok; tok = tok->
next())
9509 n += tok->
values().size();
9515 if (state.settings.performanceValueFlowMaxIfCount > 0) {
9516 for (
const Scope* functionScope : state.symboldatabase.functionScopes) {
9517 int countIfScopes = 0;
9518 std::vector<const Scope*> scopes{functionScope};
9519 while (!scopes.empty()) {
9520 const Scope* s = scopes.back();
9523 scopes.emplace_back(s2);
9524 if (s2->
type == Scope::ScopeType::eIf)
9528 if (countIfScopes > state.settings.performanceValueFlowMaxIfCount) {
9529 state.skippedFunctions.emplace(functionScope);
9532 const std::string& functionName = functionScope->
className;
9533 const std::list<ErrorMessage::FileLocation> callstack(
9537 state.tokenlist.getSourceFilePath(),
9539 "Limiting ValueFlow analysis in function '" + functionName +
"' since it is too complex. "
9540 "Please specify --check-level=exhaustive to perform full analysis.",
9543 state.errorLogger.reportErr(errmsg);
9552 if (state.settings.performanceValueFlowMaxTime >= 0)
9553 stop = Clock::now() + std::chrono::seconds{state.settings.performanceValueFlowMaxTime};
9563 const char* mName =
nullptr;
9567 const char*
name()
const override {
9585 #define VALUEFLOW_ADAPTOR(cpp, ...) \
9586 makeValueFlowPassAdaptor(#__VA_ARGS__, \
9588 [](TokenList& tokenlist, \
9589 SymbolDatabase& symboldatabase, \
9590 ErrorLogger& errorLogger, \
9591 const Settings& settings, \
9592 const std::set<const Scope*>& skippedFunctions) { \
9594 (void)symboldatabase; \
9595 (void)errorLogger; \
9597 (void)skippedFunctions; \
9601 #define VFA(...) VALUEFLOW_ADAPTOR(false, __VA_ARGS__)
9602 #define VFA_CPP(...) VALUEFLOW_ADAPTOR(true, __VA_ARGS__)
9619 tok2 = tok2->
link();
9620 else if (tok2->
str() ==
",")
9683 return "Either the condition is redundant";
9684 if (condition->
str() ==
"case") {
9686 for (
const Token *tok = condition; tok && tok->
str() !=
":"; tok = tok->
next()) {
9691 return "Either the switch case '" + expr +
"' is redundant";
9693 return "Either the condition '" + condition->
expressionString() +
"' is redundant";
9720 const Token* indexTok,
9729 return {*indexValue};
9736 return v.isSymbolicValue() && v.isPossible() && v.bound == ValueFlow::Value::Bound::Upper;
9753 return {std::move(value)};
9762 std::vector<ValueFlow::Value> result =
isOutOfBoundsImpl(size, indexTok,
false);
9763 if (!result.empty())
bool astIsContainer(const Token *tok)
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
bool astIsPrimitive(const Token *tok)
bool astIsContainerView(const Token *tok)
bool astIsIntegral(const Token *tok, bool unknown)
Is expression of integral type?
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
bool isTemporary(const Token *tok, const Library *library, bool unknown)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
bool isUsedAsBool(const Token *const tok, const Settings &settings)
Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for.
bool extractForLoopValues(const Token *forToken, nonneg int &varid, bool &knownInitValue, MathLib::bigint &initValue, bool &partialCond, MathLib::bigint &stepValue, MathLib::bigint &lastValue)
Extract for loop values: loopvar varid, init value, step value, last value (inclusive)
bool astIsPointer(const Token *tok)
bool isLikelyStreamRead(const Token *op)
do we see a likely write of rhs through overloaded operator s >> x; a & x;
bool astIsContainerOwned(const Token *tok)
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
bool astIsLHS(const Token *tok)
bool isGlobalData(const Token *expr)
bool isConstFunctionCall(const Token *ftok, const Library &library)
bool astIsBool(const Token *tok)
Is expression of boolean type?
const Token * getArgumentStart(const Token *ftok)
bool isScopeBracket(const Token *tok)
bool isVariableDecl(const Token *tok)
static int getArgumentPos(const Token *ftok, const Token *tokToFind)
bool astIsGenericChar(const Token *tok)
Is expression a char according to valueType?
Token * getInitTok(Token *tok)
bool astIsUniqueSmartPointer(const Token *tok)
Library::Container::Action astContainerAction(const Token *tok, const Token **ftok)
Library::Container::Yield astFunctionYield(const Token *tok, const Settings &settings, const Token **ftok)
std::vector< const Token * > astFlatten(const Token *tok, const char *op)
bool astIsSmartPointer(const Token *tok)
Token * getCondTokFromEnd(Token *endBlock)
const Token * astParentSkipParens(const Token *tok)
bool isOppositeCond(bool isNot, const Token *const cond1, const Token *const cond2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Are two conditions opposite.
bool astIsContainerString(const Token *tok)
bool astIsRHS(const Token *tok)
std::vector< ValueType > getParentValueTypes(const Token *tok, const Settings &settings, const Token **parent)
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
const Token * nextAfterAstRightmostLeaf(const Token *tok)
bool isThisChanged(const Token *tok, int indirect, const Settings &settings)
bool astIsNonStringContainer(const Token *tok)
Token * getStepTok(Token *tok)
bool isIteratorPair(const std::vector< const Token * > &args)
Are the arguments a pair of iterators/pointers?
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
Is variable changed by function call? In case the answer of the question is inconclusive,...
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
Token * findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
bool astIsUnsigned(const Token *tok)
bool astIsIterator(const Token *tok)
const Token * previousBeforeAstLeftmostLeaf(const Token *tok)
const Token * findExpressionChangedSkipDeadCode(const Token *expr, const Token *start, const Token *end, const Settings &settings, const std::function< std::vector< MathLib::bigint >(const Token *tok)> &evaluate, int depth)
std::vector< const Variable * > getLHSVariables(const Token *tok)
bool isConstExpression(const Token *tok, const Library &library)
const Token * getLHSVariableToken(const Token *tok)
const Token * getParentLifetime(const Token *tok)
SmallVector< ReferenceToken > followAllReferences(const Token *tok, bool temporary, bool inconclusive, ErrorPath errors, int depth)
bool isLikelyStream(const Token *stream)
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
const Token * findParent(const Token *tok, const TFunc &pred)
const Token * findAstNode(const Token *ast, const TFunc &pred)
R calculate(const std::string &s, const T &x, const T &y, bool *error=nullptr)
static bool isBool(const Variable *var)
static int sign(const T v)
static const Token * isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect=0)
This is an interface, which the class responsible of error logging should implement.
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
File name and line number.
Wrapper for error messages, provided by reportErr()
static std::vector< const Token * > findReturns(const Function *f)
const std::string & name() const
const Scope * functionScope
scope of function body
bool isSafe(const Settings &settings) const
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
const Variable * getArgumentVar(nonneg int num) const
bool isImplicitlyVirtual(bool defaultVal=false) const
check if this function is virtual in the base classes
const Token * constructorMemberInitialization() const
const Scope * nestedIn
Scope the function is declared in.
bool hasVirtualSpecifier() const
bool isConstructor() const
Action getAction(const std::string &function) const
Yield getYield(const std::string &function) const
Library definitions handling.
std::vector< MathLib::bigint > unknownReturnValues(const Token *ftok) const
const Token * getContainerFromYield(const Token *tok, Container::Yield yield) const
const std::string & returnValue(const Token *ftok) const
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const
const AllocFunc * getReallocFuncInfo(const Token *tok) const
get reallocation info for function
const Function * getFunction(const Token *ftok) const
int returnValueContainer(const Token *ftok) const
const ArgumentChecks::IteratorInfo * getArgIteratorInfo(const Token *ftok, int argnr) const
bool isNotLibraryFunction(const Token *ftok) const
const std::string & returnValueType(const Token *ftok) const
static std::string toString(T value)=delete
static biguint toBigUNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
static const int bigint_bits
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
static bool isFloat(const std::string &str)
static bool isInt(const std::string &str)
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
unsigned long long biguint
static std::string stripDirectoryPart(const std::string &file)
Get filename without a directory path part.
std::list< Function > functionList
bool isNestedIn(const Scope *outer) const
std::list< Variable > varlist
std::vector< Scope * > nestedList
static Function * nestedInFunction(const Scope *scope)
std::vector< Enumerator > enumeratorList
Function * function
function info for this function
const Token * classDef
class/struct/union/namespace token
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
bool isExecutable() const
SelectValueFromVarIdMapRange(const M *m)
std::unordered_map< nonneg int, ValueFlow::Value > M
This is just a container for general settings so that we don't need to pass individual values to func...
int performanceValueFlowMaxSubFunctionArgs
max number of sets of arguments to pass to subfuncions in valueflow
bool debugnormal
Is –debug-normal given?
bool daca
Are we running from DACA script?
std::set< std::string > checkUnknownFunctionReturn
check unknown function return values
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool debugwarnings
Is –debug-warnings given?
Standards standards
Struct contains standards settings.
bool isEnabled(T flag) const
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
const Token * back() const
get last token of list
void simplifyPlatformTypes()
Convert platform dependent types to standard types.
const std::string & getSourceFilePath() const
void simplifyStdType()
Collapse compound standard types into a single token.
const Token * front() const
get first token of list
bool createTokens(std::istream &code, const std::string &file0)
Create tokens from code.
The token list that the TokenList generates is a linked-list of this class.
bool hasKnownValue() const
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
nonneg int exprId() const
const std::string & originalName() const
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
bool addValue(const ValueFlow::Value &value)
Add token value.
bool hasKnownIntValue() const
const ValueFlow::Value * getMaxValue(bool condition, MathLib::bigint path=0) const
MathLib::bigint getKnownIntValue() const
void removeValues(std::function< bool(const ValueFlow::Value &)> pred)
bool isExpandedMacro() const
bool isTemplateArg() const
Is current token a template argument?
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
bool isArithmeticalOp() const
static nonneg int getStrSize(const Token *tok, const Settings &settings)
bool isIncompleteVar() const
bool isUniqueExprId() const
static nonneg int getStrLength(const Token *tok)
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
const ValueType * valueType() const
const std::string & strAt(int index) const
bool hasKnownSymbolicValue(const Token *tok) const
const Enumerator * enumerator() const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
bool isCMultiChar() const
std::string expressionString() const
bool isUnaryOp(const std::string &s) const
TokenDebug getTokenDebug() const
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
Token::Type tokType() const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
void type(const ::Type *t)
Associate this token with given type.
static std::string typeStr(const Token *tok)
bool isAssignmentOp() const
bool isSplittedVarDeclEq() const
bool isStandardType() const
void variable(const Variable *v)
Associate this token with given variable.
bool isComparisonOp() const
const std::list< ValueFlow::Value > & values() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint &value) const
void astParent(Token *tok)
Information about a class type.
bool isStructType() const
const Token * classDef
Points to "class" token.
std::vector< BaseInfo > derivedFrom
enum Type::NeedInitialization needInitialization
bool equalTo(const T &x) const
bool isSymbolicValue() const
Bound bound
The value bound
std::string toString() const
enum ValueFlow::Value::ValueType valueType
void changeKnownToPossible()
MathLib::bigint path
Path id.
bool isIteratorValue() const
std::string infoString() const
bool isMovedValue() const
bool isFloatValue() const
bool conditional
Conditional value.
ValueKind
How known is this value.
@ Inconclusive
Inconclusive.
@ Impossible
Listed values are impossible.
@ Known
Only listed values are possible.
@ Possible
This value is possible, other unlisted values may also be possible.
bool isLifetimeValue() const
long long varvalue
For calculated values - variable value that calculated value depends on.
bool defaultArg
Is this value passed as default parameter to the function?
bool isImpossible() const
double floatValue
float value
bool isUninitValue() const
const Token * condition
Condition that this value depends on.
const Token * tokvalue
token value - the token that has the value.
long long intvalue
int value (or sometimes bool value?)
nonneg int varId
For calculated values - varId that calculated value depends on.
enum ValueFlow::Value::ValueKind valueKind
bool equalValue(const ValueFlow::Value &rhs) const
bool isLocalLifetimeValue() const
bool isContainerSizeValue() const
std::list< ErrorPathItem > ErrorPath
enum ValueFlow::Value::LifetimeKind lifetimeKind
enum ValueFlow::Value::MoveKind moveKind
void setInconclusive(bool inconclusive=true)
void assumeCondition(const Token *tok)
enum ValueFlow::Value::LifetimeScope lifetimeScope
long long wideintvalue
int value before implicit truncation
bool isSubFunctionLifetimeValue() const
bool isIteratorStartValue() const
bool isIteratorEndValue() const
bool isInconclusive() const
std::vector< std::string > subexpressions
bool safe
value relies on safe checking
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
bool isTypeEqual(const ValueType *that) const
Check if type is the same ignoring const and references.
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Reference reference
Is the outermost indirection of this type a reference or rvalue.
const Library::SmartPointer * smartPointer
Smart pointer.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
std::string originalTypeName
original type name as written in the source code.
const Token * containerTypeToken
The container type token.
const Scope * typeScope
if the type definition is seen this point out the type scope
static ValueType parseDecl(const Token *type, const Settings &settings)
enum ValueType::Sign sign
Information about a member variable.
bool hasDefault() const
Does variable have a default value.
bool isArgument() const
Is variable a function argument.
bool isEnumType() const
Determine whether it's an enumeration type.
bool isClass() const
Is variable a user defined (or unknown) type.
bool isExtern() const
Is variable extern.
bool isReference() const
Is reference variable.
bool dimensionKnown(nonneg int index_) const
Get array dimension known.
bool isRValueReference() const
Is reference variable.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
bool isSmartPointer() const
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isThrow() const
Is variable a throw type.
const Scope * typeScope() const
Get Scope pointer of known type.
bool isGlobal() const
Is variable global.
bool isPublic() const
Is variable public.
const std::string & name() const
Get name string.
const Token * typeEndToken() const
Get type end token.
bool isConst() const
Is variable const.
MathLib::bigint dimension(nonneg int index_) const
Get array dimension length.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
bool isInit() const
Is variable initialized in its declaration.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
#define REQUIRES(msg,...)
static const std::string emptyString
std::vector< MathLib::bigint > evaluateKnownValues(const Token *tok)
std::vector< T * > findTokensSkipDeadCode(const Library &library, T *start, const Token *end, const Predicate &pred, const Evaluate &evaluate)
Analyzer::Result valueFlowGenericForward(Token *start, const Token *end, const ValuePtr< Analyzer > &a, const TokenList &tokenList, ErrorLogger &errorLogger, const Settings &settings)
static bool nonLocal(const Variable *var, bool deref)
std::pair< const Token *, std::string > ErrorPathItem
const Library::Container * getLibraryContainer(const Token *tok)
std::list< ErrorPathItem > ErrorPath
@ information
Checking information.
@ error
Programming error.
std::vector< ValueFlow::Value > infer(const ValuePtr< InferModel > &model, const std::string &op, std::list< ValueFlow::Value > lhsValues, std::list< ValueFlow::Value > rhsValues)
const Token * parseCompareInt(const Token *tok, Value &true_value, Value &false_value, const std::function< std::vector< MathLib::bigint >(const Token *)> &evaluate)
bool isContainerSizeChanged(const Token *tok, int indirect, const Settings &settings, int depth=20)
std::string eitherTheConditionIsRedundant(const Token *condition)
CPPCHECKLIB Value getLifetimeObjValue(const Token *tok, bool inconclusive=false)
const Value * valueFlowConstantFoldAST(Token *expr, const Settings &settings)
Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFl...
CPPCHECKLIB ValuePtr< InferModel > makeIntegralInferModel()
const Value * findValue(const std::list< Value > &values, const Settings &settings, const std::function< bool(const Value &)> &pred)
std::vector< LifetimeToken > getLifetimeTokens(const Token *tok, const Settings &settings, bool escape=false, Value::ErrorPath errorPath=Value::ErrorPath{})
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath)
void combineValueProperties(const Value &value1, const Value &value2, Value &result)
bool isLifetimeBorrowed(const Token *tok, const Settings &settings)
const Token * getEndOfExprScope(const Token *tok, const Scope *defaultScope=nullptr, bool smallest=true)
const Variable * getLifetimeVariable(const Token *tok, Value::ErrorPath &errorPath, const Settings &settings, bool *addressOf=nullptr)
bool hasLifetimeToken(const Token *tok, const Token *lifetime, const Settings &settings)
const Token * solveExprValue(const Token *expr, const std::function< std::vector< MathLib::bigint >(const Token *)> &eval, Value &value)
std::vector< Value > isOutOfBounds(const Value &size, const Token *indexTok, bool possible=true)
size_t getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
Value asImpossible(Value v)
CPPCHECKLIB std::vector< Value > getLifetimeObjValues(const Token *tok, bool inconclusive=false, MathLib::bigint path=0)
void setValues(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, TimerResultsIntf *timerResults)
Perform valueflow analysis.
bool conditionIsFalse(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always false when variable has given value?
static ValueFlow::Value execute(const Token *expr, ProgramMemory &pm, const Settings &settings)
static ValueFlow::Value evaluate(const std::string &op, const ValueFlow::Value &lhs, const ValueFlow::Value &rhs)
ProgramMemory getProgramMemory(const Token *tok, const Token *expr, const ValueFlow::Value &value, const Settings &settings)
Get program memory by looking backwards from given token.
ValueFlow::Value evaluateLibraryFunction(const std::unordered_map< nonneg int, ValueFlow::Value > &args, const std::string &returnValue, const Settings &settings, bool cpp)
bool conditionIsTrue(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always true when variable has given value?
void valueFlowGenericReverse(Token *start, const Token *end, const ValuePtr< Analyzer > &a, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
bool isInconclusive() const
bool isSymbolicMatch() const
virtual bool lowerToInconclusive()=0
Lower any values to inconclusive.
virtual bool invalid() const
std::list< ValueFlow::Value > true_values
Token * getContextAndValues(Token *condTok, std::list< ValueFlow::Value > &thenValues, std::list< ValueFlow::Value > &elseValues, bool known=false) const
MathLib::bigint getPath() const
std::list< ValueFlow::Value > false_values
static MathLib::bigint findPath(const std::list< ValueFlow::Value > &values)
void beforeCondition(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions) const
virtual void reverse(Token *start, const Token *endToken, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
ConditionHandler(const ConditionHandler &)=default
void afterCondition(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions) const
static Token * skipNotAndCasts(Token *tok, bool *inverted=nullptr)
virtual std::vector< Condition > parse(const Token *tok, const Settings &settings) const =0
virtual Analyzer::Result forward(Token *start, const Token *stop, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
ConditionHandler()=default
void traverseCondition(const SymbolDatabase &symboldatabase, const Settings &settings, const std::set< const Scope * > &skippedFunctions, const std::function< void(const Condition &cond, Token *tok, const Scope *scope)> &f) const
virtual Analyzer::Result forward(Token *top, const Token *exprTok, const std::list< ValueFlow::Value > &values, TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
virtual ~ConditionHandler()=default
static void fillFromPath(ProgramMemory &pm, const Token *top, MathLib::bigint path, const Settings &settings)
std::vector< Condition > parse(const Token *tok, const Settings &settings) const override
Action isModified(const Token *tok) const override
void writeValue(ValueFlow::Value *val, const Token *tok, Direction d) const override
bool match(const Token *tok) const override
int getIndirect(const Token *tok) const override
ContainerExpressionAnalyzer(const Token *expr, ValueFlow::Value val, const TokenList &t, const Settings &s)
Action isWritable(const Token *tok, Direction) const override
Array dimension information.
const Token * tok
size token
MathLib::bigint num
(assumed) dimension length when size is a number, 0 if not known
ValueFlow::Value::ValueType getType() const override
void setupExprVarIds(const Token *start, int depth=0)
ExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
bool isVariable() const override
bool isGlobal() const override
static bool nonLocal(const Variable *var, bool deref)
Action isAliasModified(const Token *tok, int indirect) const override
bool invalid() const override
bool match(const Token *tok) const override
bool dependsOnThis() const override
virtual bool skipUniqueExprIds() const
ProgramState getProgramState() const override
ValueFlow::Value yield(MathLib::bigint value) const override
bool match(const ValueFlow::Value &value) const override
Simple container to be thrown when internal error is detected.
std::vector< Condition > parse(const Token *tok, const Settings &) const override
bool match(const ValueFlow::Value &value) const override
virtual ValueFlow::Value::ValueType getType() const =0
ValueFlow::Value yield(MathLib::bigint value) const override
std::vector< const Token * > getCaptures() const
std::unordered_map< const Variable *, std::pair< const Token *, LifetimeCapture > > explicitCaptures
LifetimeCapture implicitCapture
ValueFlow::Value::LifetimeKind type
bool byRef(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
static void forEach(const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const std::vector< const Token * > &argtoks, const std::string &message, ValueFlow::Value::LifetimeKind type, F f)
bool byVal(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current())
bool byDerefCopy(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current()) const
bool byRef(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current())
void forwardLifetime(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
LifetimeStore(const Token *argtok, std::string message, ValueFlow::Value::LifetimeKind type=ValueFlow::Value::LifetimeKind::Object, bool inconclusive=false)
bool byDerefCopy(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, Predicate pred, SourceLocation loc=SourceLocation::current()) const
bool byVal(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
static LifetimeStore fromFunctionArg(const Function *f, const Token *tok, const Variable *var, const TokenList &tokenlist, const Settings &settings, ErrorLogger &errorLogger)
bool submatch(const Token *tok, bool exact) const override
MemberExpressionAnalyzer(std::string varname, const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
void addErrorPath(const Token *tok, const std::string &s) override
virtual const std::unordered_map< nonneg int, const Variable * > & getVars() const
MultiValueFlowAnalyzer(const std::unordered_map< const Variable *, ValueFlow::Value > &args, const TokenList &t, const Settings &set)
bool match(const Token *tok) const override
bool stopOnCondition(const Token *condTok) const override
If analysis should stop on the condition.
std::unordered_map< nonneg int, const Variable * > vars
ProgramState getProgramState() const override
void makeConditional() override
const ValueFlow::Value * getValue(const Token *tok) const override
bool updateScope(const Token *endBlock, bool) const override
If the analysis is unsure whether to update a scope, this will return true if the analysis should bif...
std::unordered_map< nonneg int, ValueFlow::Value > values
bool lowerToInconclusive() override
Lower any values to inconclusive.
bool isConditional() const override
If the value is conditional.
bool lowerToPossible() override
Lower any values to possible.
bool isAlias(const Token *tok, bool &inconclusive) const override
ValueFlow::Value * getValue(const Token *tok) override
bool skipUniqueExprIds() const override
OppositeExpressionAnalyzer(bool pIsNot, const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
bool match(const Token *tok) const override
void assume(const Token *tok, bool b, bool isEmpty=false)
void removeModifiedVars(const Token *tok)
ProgramMemory get(const Token *tok, const Token *ctx, const ProgramMemory::Map &vars) const
void addState(const Token *tok, const ProgramMemory::Map &vars)
void setValue(const Token *expr, const ValueFlow::Value &value)
bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint &result) const
std::unordered_map< ExprIdToken, ValueFlow::Value, ExprIdToken::Hash > Map
bool hasValue(nonneg int exprid)
void swap(ProgramMemory &pm)
bool skipUniqueExprIds() const override
bool match(const Token *tok) const override
SameExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
Iterator(const M::const_iterator &it)
friend bool operator!=(const Iterator &a, const Iterator &b)
pointer operator->() const
reference operator*() const
friend bool operator==(const Iterator &a, const Iterator &b)
std::forward_iterator_tag iterator_category
std::ptrdiff_t difference_type
std::vector< Condition > parse(const Token *tok, const Settings &) const override
const std::unordered_map< nonneg int, const Variable * > & getVars() const
void addErrorPath(const Token *tok, const std::string &s) override
void makeConditional() override
bool useSymbolicValues() const override
std::unordered_map< nonneg int, const Variable * > varids
const std::unordered_map< nonneg int, const Variable * > & getAliasedVars() const
bool isAlias(const Token *tok, bool &inconclusive) const override
bool stopOnCondition(const Token *condTok) const override
If analysis should stop on the condition.
const ValueFlow::Value * getValue(const Token *) const override
bool lowerToPossible() override
Lower any values to possible.
bool lowerToInconclusive() override
Lower any values to inconclusive.
ValuePtr< Analyzer > reanalyze(Token *tok, const std::string &msg) const override
Return analyzer for expression at token.
SingleValueFlowAnalyzer(ValueFlow::Value v, const TokenList &t, const Settings &s)
bool isConditional() const override
If the value is conditional.
bool isGlobal() const override
std::unordered_map< nonneg int, const Variable * > aliases
ValueFlow::Value * getValue(const Token *) override
bool updateScope(const Token *endBlock, bool) const override
If the analysis is unsure whether to update a scope, this will return true if the analysis should bif...
static SourceLocation current()
const char * function_name() const
const char * file_name() const
std::uint_least32_t line() const
enum Standards::cppstd_t cpp
ValueFlow::Value::ValueType getType() const override
SubExpressionAnalyzer(const Token *e, ValueFlow::Value val, const TokenList &t, const Settings &s)
virtual bool submatch(const Token *tok, bool exact=true) const =0
bool internalMatch(const Token *tok) const override
bool match(const Token *tok) const override
std::vector< std::pair< Token *, ValueFlow::Value > > PartialReadContainer
void internalUpdate(Token *tok, const ValueFlow::Value &v, Direction) override
ValuePtr< Analyzer > reanalyze(Token *, const std::string &) const override
Return analyzer for expression at token.
std::shared_ptr< PartialReadContainer > partialReads
bool isAlias(const Token *tok, bool &inconclusive) const override
static const Token * skipNot(const Token *tok)
static bool isNegatedBool(const Token *tok)
std::vector< Condition > parse(const Token *tok, const Settings &settings) const override
SymbolicInferModel(const Token *tok)
bool match(const ValueFlow::Value &value) const override
ValueFlow::Value yield(MathLib::bigint value) const override
bool isUnknownDependent() const
virtual void internalUpdate(Token *, const ValueFlow::Value &, Direction)
virtual bool useSymbolicValues() const
virtual Action isModified(const Token *tok) const
Action analyzeLifetime(const Token *tok) const
void update(Token *tok, Action a, Direction d) override
Update the state of the value.
Action analyzeMatch(const Token *tok, Direction d) const
Action analyze(const Token *tok, Direction d) const override
Analyze a token.
ValueFlowAnalyzer(const TokenList &t, const Settings &s)
std::unordered_map< nonneg int, const Token * > getSymbols(const Token *tok) const
void assume(const Token *tok, bool state, unsigned int flags) override
The condition that will be assumed during analysis.
virtual ProgramState getProgramState() const =0
virtual bool isAlias(const Token *tok, bool &inconclusive) const =0
virtual Action isAliasModified(const Token *tok, int indirect=-1) const
virtual bool match(const Token *tok) const =0
virtual bool internalMatch(const Token *) const
static const std::string & getAssign(const Token *tok, Direction d)
bool isSameSymbolicValue(const Token *tok, ValueFlow::Value *value=nullptr) const
virtual ValueFlow::Value * getValue(const Token *tok)=0
virtual const ValueFlow::Value * getValue(const Token *tok) const =0
ValuePtr< Analyzer > reanalyze(Token *, const std::string &) const override
Return analyzer for expression at token.
virtual void addErrorPath(const Token *tok, const std::string &s)=0
std::vector< MathLib::bigint > evaluate(Evaluate e, const Token *tok, const Token *ctx=nullptr) const override
Try to evaluate the value of a token(most likely a condition)
virtual bool isVariable() const
const TokenList & tokenlist
virtual void makeConditional()=0
ConditionState analyzeCondition(const Token *tok, int depth=20) const
const Token * findMatch(const Token *tok) const
virtual void writeValue(ValueFlow::Value *value, const Token *tok, Direction d) const
std::vector< MathLib::bigint > evaluateInt(const Token *tok) const
const Settings & settings
Action isGlobalModified(const Token *tok) const
virtual int getIndirect(const Token *tok) const
virtual bool dependsOnThis() const
Action analyzeToken(const Token *ref, const Token *tok, Direction d, bool inconclusiveRef) const
virtual bool isGlobal() const
std::vector< MathLib::bigint > evaluateInt(const Token *tok, F getProgramMemory) const
virtual Action isWritable(const Token *tok, Direction d) const
ProgramMemory::Map ProgramState
virtual Action isThisModified(const Token *tok) const
const Settings & getSettings() const
void updateState(const Token *tok) override
Update the state of the program at the token.
bool cpp() const override
ValueFlowPassAdaptor(const char *pname, bool pcpp, F prun)
const char * name() const override
void run(const ValueFlowState &state) const override
bool run(std::initializer_list< ValuePtr< ValueFlowPass >> passes) const
std::chrono::steady_clock Clock
bool run(const ValuePtr< ValueFlowPass > &pass) const
void setSkippedFunctions()
std::size_t getTotalValues() const
bool run_once(std::initializer_list< ValuePtr< ValueFlowPass >> passes) const
TimerResultsIntf * timerResults
std::chrono::time_point< Clock > TimePoint
ValueFlowPassRunner(ValueFlowState state, TimerResultsIntf *timerResults=nullptr)
virtual bool cpp() const =0
virtual ~ValueFlowPass() noexcept=default
virtual const char * name() const =0
ValueFlowPass(const ValueFlowPass &)=default
virtual void run(const ValueFlowState &state) const =0
ErrorLogger & errorLogger
ValueFlowState(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
SymbolDatabase & symboldatabase
const Settings & settings
std::set< const Scope * > skippedFunctions
static std::vector< LifetimeToken > setInconclusive(std::vector< LifetimeToken > v, bool b)
static std::vector< LifetimeToken > setAddressOf(std::vector< LifetimeToken > v, bool b)
static const char * getOrdinalText(int i)
std::array< T, sizeof...(Ts)+1 > makeArray(T x, Ts... xs)
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
static const char * bool_to_string(bool b)
bool contains(const Range &r, const T &x)
static bool valueFlowForLoop2(const Token *tok, ProgramMemory *memory1, ProgramMemory *memory2, ProgramMemory *memoryAfter, const Settings &settings)
static void changeKnownToPossible(std::list< ValueFlow::Value > &values, int indirect=-1)
static void valueFlowSetConditionToKnown(const Token *tok, std::list< ValueFlow::Value > &values, bool then)
static std::vector< ValueFlow::Value > isOutOfBoundsImpl(const ValueFlow::Value &size, const Token *indexTok, bool condition)
static bool isStdMoveOrStdForwarded(Token *tok, ValueFlow::Value::MoveKind *moveKind, Token **varTok=nullptr)
static bool isVariableInit(const Token *tok)
static void valueFlowBitAnd(TokenList &tokenlist, const Settings &settings)
static void valueFlowSymbolicOperators(const SymbolDatabase &symboldatabase, const Settings &settings)
static bool isTruncated(const ValueType *src, const ValueType *dst, const Settings &settings)
static void setValueUpperBound(ValueFlow::Value &value, bool upper)
static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token *openParenthesisToken, nonneg int varId)
static void valueFlowDebug(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowGlobalConstVar(TokenList &tokenList, const Settings &settings)
static bool productParams(const Settings &settings, const std::unordered_map< Key, std::list< ValueFlow::Value >> &vars, F f)
static std::set< nonneg int > getVarIds(const Token *tok)
static std::vector< const Token * > getConditions(const Token *tok, const char *op)
static bool isCompatibleValues(const ValueFlow::Value &value1, const ValueFlow::Value &value2)
static void valueFlowInjectParameter(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const Scope *functionScope, const std::unordered_map< const Variable *, std::list< ValueFlow::Value >> &vars)
static const ValueFlow::Value * getKnownValueFromToken(const Token *tok)
static std::vector< ValueFlow::LifetimeToken > getLifetimeTokens(const Token *tok, bool escape, ValueFlow::Value::ErrorPath errorPath, Predicate pred, const Settings &settings, int depth=20)
static bool isComputableValue(const Token *parent, const ValueFlow::Value &value)
static void valueFlowArrayElement(TokenList &tokenlist, const Settings &settings)
static bool isBreakOrContinueScope(const Token *endToken)
static const Token * parseBinaryIntOp(const Token *expr, const std::function< std::vector< MathLib::bigint >(const Token *)> &eval, MathLib::bigint &known)
static bool isContainerOfPointers(const Token *tok, const Settings &settings)
static SingleRange< T > MakeSingleRange(T &x)
static void valueFlowRightShift(TokenList &tokenList, const Settings &settings)
static void valueFlowAfterMove(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static ValueFlow::Value::Bound findVarBound(const Variable *var, const Token *start, const Token *end, const Settings &settings)
static bool isCompatibleValueTypes(ValueFlow::Value::ValueType x, ValueFlow::Value::ValueType y)
static void valueFlowGlobalStaticVar(TokenList &tokenList, const Settings &settings)
static const Token * findIncompleteVar(const Token *start, const Token *end)
static std::vector< const Variable * > getVariables(const Token *tok)
static const Token * getCastTypeStartToken(const Token *parent, const Settings &settings)
static void valueFlowForLoopSimplify(Token *const bodyStart, const Token *expr, bool globalvar, const MathLib::bigint value, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowAfterAssign(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
static const Token * getLifetimeToken(const Token *tok, ValueFlow::Value::ErrorPath &errorPath, const Settings &settings, bool *addressOf=nullptr)
static std::vector< MathLib::bigint > minUnsignedValue(const Token *tok, int depth=8)
static MathLib::bigint valueFlowGetStrLength(const Token *tok)
static bool isSaturated(MathLib::bigint value)
static bool isDifferentType(const Token *src, const Token *dst)
static void valueFlowAfterSwap(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowEnumValue(SymbolDatabase &symboldatabase, const Settings &settings)
static void valueFlowString(TokenList &tokenlist, const Settings &settings)
static Token * findOpenParentesisOfMove(Token *moveVarTok)
static bool isNonZero(const Token *tok)
static bool derefShared(const Token *tok)
static Analyzer::Result valueFlowForward(Token *startToken, const Token *endToken, const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
static nonneg int getSizeOfType(const Token *typeTok, const Settings &settings)
static void setSymbolic(ValueFlow::Value &value, const Token *tok)
static void valueFlowSafeFunctions(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static bool isNumeric(const ValueFlow::Value &value)
static void valueFlowCondition(const ValuePtr< ConditionHandler > &handler, TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
static void valueFlowNumber(TokenList &tokenlist, const Settings &settings)
static ValueFlowPassAdaptor< F > makeValueFlowPassAdaptor(const char *name, bool cpp, F run)
static void setConditionalValues(const Token *tok, bool lhs, MathLib::bigint value, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
static void removeImpossible(std::list< ValueFlow::Value > &values, int indirect=-1)
static void valueFlowLifetimeConstructor(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static bool bifurcateVariableChanged(const Variable *var, const std::set< nonneg int > &varids, const Token *start, const Token *end, const Settings &settings, int depth=20)
static void valueFlowSymbolic(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void insertImpossible(std::list< ValueFlow::Value > &values, const std::list< ValueFlow::Value > &input)
static void assignValueIfMutable(T &x, const U &y)
static std::string removeAssign(const std::string &assign)
static Library::Container::Yield findIteratorYield(Token *tok, const Token **ftok, const Settings &settings)
static void valueFlowDynamicBufferSize(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowForwardConst(Token *start, const Token *end, const Variable *var, const ContainerOfValue &values, const Settings &settings, int=0)
static bool isContainerSizeChangedByFunction(const Token *tok, int indirect, const Settings &settings, int depth=20)
static size_t accumulateStructMembers(const Scope *scope, F f)
static void valueFlowSymbolicInfer(const SymbolDatabase &symboldatabase, const Settings &settings)
static ValueFlow::Value truncateImplicitConversion(Token *parent, const ValueFlow::Value &value, const Settings &settings)
static bool isContainerSizeChanged(const Token *expr, const Token *start, const Token *end, int indirect, const Settings &settings, int depth=20)
static const Function * findConstructor(const Scope *scope, const Token *tok, const std::vector< const Token * > &args)
static ValueFlow::Value makeConditionValue(long long val, const Token *condTok, bool assume, bool impossible, const Settings &settings, SourceLocation loc=SourceLocation::current())
static std::vector< ValueFlow::Value > getContainerSizeFromConstructorArgs(const std::vector< const Token * > &args, const Library::Container *container, bool known)
static void valueFlowUnknownFunctionReturn(TokenList &tokenlist, const Settings &settings)
static void valueFlowIteratorInfer(TokenList &tokenlist, const Settings &settings)
static const Token * isStrlenOf(const Token *tok, const Token *expr, int depth=10)
static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings &settings)
Set token value for cast.
static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known=true)
static void setConditionalValue(ValueFlow::Value &value, const Token *tok, MathLib::bigint i)
static void valueFlowFunctionDefaultParameter(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowLifetimeUserConstructor(Token *tok, const Function *constructor, const std::string &name, const std::vector< const Token * > &args, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static bool isRangeForScope(const Scope *scope)
static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
static bool isNonInvertibleOperation(const Token *tok)
static void valueFlowIterators(TokenList &tokenlist, const Settings &settings)
static void valueFlowContainerSize(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, const std::set< const Scope * > &skippedFunctions)
static ValueFlow::Value makeSymbolic(const Token *tok, MathLib::bigint delta=0)
static bool isLifetimeOwned(const ValueType *vtParent)
static void setValueBound(ValueFlow::Value &value, const Token *tok, bool invert)
static void valueFlowSmartPointer(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowContainerSetTokValue(const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, const Token *tok, Token *initList)
static void setTokenValue(Token *tok, ValueFlow::Value value, const Settings &settings, SourceLocation loc=SourceLocation::current())
set ValueFlow value and perform calculations if possible
static size_t getAlignOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
static bool hasUniqueOwnership(const Token *tok)
static void addToErrorPath(ValueFlow::Value &value, const ValueFlow::Value &from)
static bool isIntegralOrPointer(const Token *tok)
static void valueFlowArrayBool(TokenList &tokenlist, const Settings &settings)
static void valueFlowForLoop(TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static std::list< ValueFlow::Value > getIteratorValues(std::list< ValueFlow::Value > values, const ValueFlow::Value::ValueKind *kind=nullptr)
static Analyzer::Result valueFlowForwardRecursive(Token *top, const Token *exprTok, std::list< ValueFlow::Value > values, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
static bool isSameToken(const Token *tok1, const Token *tok2)
static ValueFlow::Value::MoveKind isMoveOrForward(const Token *tok)
static bool isBreakScope(const Token *const endToken)
static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
static bool valueFlowIsSameContainerType(const ValueType &contType, const Token *tok, const Settings &settings)
static bool isConvertedToIntegral(const Token *tok, const Settings &settings)
static const Scope * getLoopScope(const Token *tok)
static bool isConvertedToView(const Token *tok, const Settings &settings)
static void setFunctionReturnValue(const Function *f, Token *tok, ValueFlow::Value v, const Settings &settings)
static void parseCompareEachInt(const Token *tok, const std::function< void(const Token *varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)> &each, const std::function< std::vector< ValueFlow::Value >(const Token *)> &evaluate)
static const Token * getOtherOperand(const Token *tok)
static void valueFlowForwardLifetime(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowUninit(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowPointerAlias(TokenList &tokenlist, const Settings &settings)
static bool isNotLifetimeValue(const ValueFlow::Value &val)
static bool needsInitialization(const Variable *var)
static bool bifurcate(const Token *tok, const std::set< nonneg int > &varids, const Settings &settings, int depth=20)
static ValueFlow::Value inferCondition(const std::string &op, const Token *varTok, MathLib::bigint val)
static std::string debugString(const ValueFlow::Value &v)
static void lowerToPossible(std::list< ValueFlow::Value > &values, int indirect=-1)
static bool isScope(const Token *tok)
static bool hasBorrowingVariables(const std::list< Variable > &vars, const std::vector< const Token * > &args, int depth=10)
static void valueFlowReverse(Token *tok, const Token *const endToken, const Token *const varToken, std::list< ValueFlow::Value > values, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings, SourceLocation loc=SourceLocation::current())
static std::list< ValueFlow::Value > truncateValues(std::list< ValueFlow::Value > values, const ValueType *dst, const ValueType *src, const Settings &settings)
static void valueFlowSwitchVariable(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static ValuePtr< Analyzer > makeReverseAnalyzer(const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, const Settings &settings)
static void changePossibleToKnown(std::list< ValueFlow::Value > &values, int indirect=-1)
static void valueFlowForwardAssign(Token *const tok, const Token *expr, std::vector< const Variable * > vars, std::list< ValueFlow::Value > values, const bool init, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static const Token * skipCVRefs(const Token *tok, const Token *endTok)
static bool isConditionKnown(const Token *tok, bool then)
static void valueFlowLifetimeClassConstructor(Token *tok, const Type *t, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowImpossibleValues(TokenList &tokenList, const Settings &settings)
static void valueFlowLifetime(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static T calculateAssign(const std::string &assign, const T &x, const U &y, bool *error=nullptr)
static bool evalAssignment(Value &lhsValue, const std::string &assign, const ValueFlow::Value &rhsValue)
static void valueFlowForLoopSimplifyAfter(Token *fortok, nonneg int varid, const MathLib::bigint num, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowFunctionReturn(TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings)
static Token * findEndOfFunctionCallForParameter(Token *parameterToken)
static Token * valueFlowSetConstantValue(Token *tok, const Settings &settings)
static bool intersects(const C1 &c1, const C2 &c2)
static const std::string & invertAssign(const std::string &assign)
static Token * findStartToken(const Variable *var, Token *start, const Library &library)
static void setSourceLocation(ValueFlow::Value &v, SourceLocation ctx, const Token *tok, SourceLocation local=SourceLocation::current())
static bool getExpressionRange(const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
static const Token * getEndOfVarScope(const Variable *var)
static size_t bitCeil(size_t x)
static long long truncateIntValue(long long value, size_t value_size, const ValueType::Sign dst_sign)
static std::vector< ValueFlow::Value > getContainerSizeFromConstructor(const Token *tok, const ValueType *valueType, const Settings &settings, bool known=true)
static void valueFlowSameExpressions(TokenList &tokenlist, const Settings &settings)
static bool isDecayedPointer(const Token *tok)
static bool isNotEqual(std::pair< const Token *, const Token * > x, std::pair< const Token *, const Token * > y)
static void valueFlowArray(TokenList &tokenlist, const Settings &settings)
static const ValueFlow::Value * getKnownValueFromTokens(const std::vector< const Token * > &toks)
static std::vector< Token * > findAllUsages(const Variable *var, Token *start, const Library &library)
static const Token * solveExprValue(const Token *expr, ValueFlow::Value &value)
static void valueFlowInferCondition(TokenList &tokenlist, const Settings &settings)
#define bailout(tokenlist, errorLogger, tok, what)
static const Scope * getFunctionScope(const Scope *scope)
static void valueFlowSubFunction(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, const Settings &settings)
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)
This is the ValueFlow component in Cppcheck.
static ValuePtr< Analyzer > makeAnalyzer(const Token *exprTok, ValueFlow::Value value, const TokenList &tokenlist, const Settings &settings)
static bool isEscapeScope(const Token *tok, const Settings &settings, bool unknown=false)
static std::list< ValueFlow::Value > getFunctionArgumentValues(const Token *argtok)
static bool isIntegralOnlyOperator(const Token *tok)
static bool isAliasOf(const Variable *var, const Token *tok, nonneg int varid, const V &values, bool *inconclusive=nullptr)
static IteratorRange< Iterator > MakeIteratorRange(Iterator start, Iterator last)
static Library::Container::Yield getContainerYield(Token *tok, const Settings &settings, Token **parent=nullptr)
static std::vector< ValueFlow::Value > getContainerValues(const Token *tok)
static bool isInitialVarAssign(const Token *tok)
#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what)
static bool getMinMaxValues(const ValueType *vt, const Platform &platform, MathLib::bigint &minValue, MathLib::bigint &maxValue)
static bool isNonConditionalPossibleIntValue(const ValueFlow::Value &v)
static ValueFlow::Value castValue(ValueFlow::Value value, const ValueType::Sign sign, nonneg int bit)
static void insertNegateKnown(std::list< ValueFlow::Value > &values, const std::list< ValueFlow::Value > &input)
static std::vector< ValueFlow::Value > getInitListSize(const Token *tok, const ValueType *valueType, const Settings &settings, bool known=true)