56 mValues[expr] = value;
60 [&](
const Token*
tok) -> std::vector<MathLib::bigint> {
62 return {tok->values().front().intvalue};
70 mValues[subexpr] = std::move(subvalue);
74 const ProgramMemory::Map::const_iterator it = mValues.find(
exprid);
75 const bool found = it != mValues.cend() && (impossible || !it->second.isImpossible());
151 return mValues.find(
exprid) != mValues.end();
155 return mValues.at(
exprid);
158 return mValues.at(
exprid);
163 for (
auto it = mValues.begin(); it != mValues.end();) {
165 it = mValues.erase(it);
183 return mValues.empty();
189 mValues[p.first] = std::move(p.second);
208 return !
error && result == r;
221 static bool frontIs(
const std::vector<MathLib::bigint>& v,
bool i)
276 auto eval = [&](
const Token* t) -> std::vector<MathLib::bigint> {
278 return std::vector<MathLib::bigint>{};
279 if (t->hasKnownIntValue())
280 return {t->values().front().intvalue};
286 return std::vector<MathLib::bigint>{};
294 if (vartok->
exprId() == 0)
300 const bool impossible = (
tok->
str() ==
"==" && !then) || (
tok->
str() ==
"!=" && then);
317 if (lhs.empty() || rhs.empty()) {
365 tok2->astOperand2()) {
368 for (
const auto& p:vars) {
369 if (p.first != vartok->
exprId())
382 }
else if (tok2->exprId() > 0 &&
Token::Match(tok2,
".|(|[|*|%var%") && !pm.
hasValue(tok2->exprId()) &&
387 if (tok2->str() ==
"{") {
388 if (indentlevel <= 0) {
397 tok2 = tok2->linkAt(-2)->previous();
399 if (tok2->str() ==
"}" && !
Token::Match(tok2->link()->previous(),
"%var% {")) {
410 tok2 = tok2->link()->tokAt(-2);
451 origins.insert(std::make_pair(p.first.getExpressionId(), origin));
458 for (
const auto& p : pm)
459 origins[p.first.getExpressionId()] = origin;
465 for (
const auto& p:vars) {
489 const Token* origin = tok;
492 origin = top->
link()->next();
493 if (!b && origin->
link()) {
494 origin = origin->
link();
497 replace(std::move(pm), origin);
503 auto eval = [&](
const Token* cond) -> std::vector<MathLib::bigint> {
545 programMemory.
setValue(expr, value);
548 return programMemory;
561 return std::string{assign.cbegin(), assign.cend() - 1};
566 template<
class T,
class U>
567 void operator()(T& x,
const U& y)
const
587 if (
contains({
"%",
"/",
"&",
"|"}, op))
607 const bool compareOp =
contains({
"==",
"!=",
"<",
">",
">=",
"<="}, op);
650 std::unordered_map<std::string, BuiltinLibraryFunction> functions;
651 functions[
"strlen"] = [](
const std::vector<ValueFlow::Value>& args) {
652 if (args.size() != 1)
662 functions[
"strcmp"] = [](
const std::vector<ValueFlow::Value>& args) {
663 if (args.size() != 2)
675 functions[
"strncmp"] = [](
const std::vector<ValueFlow::Value>& args) {
676 if (args.size() != 3)
692 functions[
"sin"] = [](
const std::vector<ValueFlow::Value>& args) {
693 if (args.size() != 1)
698 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
703 functions[
"lgamma"] = [](
const std::vector<ValueFlow::Value>& args) {
704 if (args.size() != 1)
709 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
714 functions[
"cos"] = [](
const std::vector<ValueFlow::Value>& args) {
715 if (args.size() != 1)
720 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
725 functions[
"tan"] = [](
const std::vector<ValueFlow::Value>& args) {
726 if (args.size() != 1)
731 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
736 functions[
"asin"] = [](
const std::vector<ValueFlow::Value>& args) {
737 if (args.size() != 1)
742 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
747 functions[
"acos"] = [](
const std::vector<ValueFlow::Value>& args) {
748 if (args.size() != 1)
753 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
758 functions[
"atan"] = [](
const std::vector<ValueFlow::Value>& args) {
759 if (args.size() != 1)
764 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
769 functions[
"atan2"] = [](
const std::vector<ValueFlow::Value>& args) {
770 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
771 return v.isFloatValue() || v.isIntValue();
774 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
777 v.
floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
781 functions[
"remainder"] = [](
const std::vector<ValueFlow::Value>& args) {
782 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
783 return v.isFloatValue() || v.isIntValue();
786 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
789 v.
floatValue = std::remainder(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
793 functions[
"nextafter"] = [](
const std::vector<ValueFlow::Value>& args) {
794 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
795 return v.isFloatValue() || v.isIntValue();
798 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
801 v.
floatValue = std::nextafter(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
805 functions[
"nexttoward"] = [](
const std::vector<ValueFlow::Value>& args) {
806 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
807 return v.isFloatValue() || v.isIntValue();
810 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
813 v.
floatValue = std::nexttoward(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
817 functions[
"hypot"] = [](
const std::vector<ValueFlow::Value>& args) {
818 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
819 return v.isFloatValue() || v.isIntValue();
822 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
825 v.
floatValue = std::hypot(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
829 functions[
"fdim"] = [](
const std::vector<ValueFlow::Value>& args) {
830 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
831 return v.isFloatValue() || v.isIntValue();
834 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
837 v.
floatValue = std::fdim(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
841 functions[
"fmax"] = [](
const std::vector<ValueFlow::Value>& args) {
842 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
843 return v.isFloatValue() || v.isIntValue();
846 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
849 v.
floatValue = std::fmax(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
853 functions[
"fmin"] = [](
const std::vector<ValueFlow::Value>& args) {
854 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
855 return v.isFloatValue() || v.isIntValue();
858 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
861 v.
floatValue = std::fmin(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
865 functions[
"fmod"] = [](
const std::vector<ValueFlow::Value>& args) {
866 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
867 return v.isFloatValue() || v.isIntValue();
870 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
873 v.
floatValue = std::fmod(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
877 functions[
"pow"] = [](
const std::vector<ValueFlow::Value>& args) {
878 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
879 return v.isFloatValue() || v.isIntValue();
882 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
885 v.
floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
889 functions[
"scalbln"] = [](
const std::vector<ValueFlow::Value>& args) {
890 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
891 return v.isFloatValue() || v.isIntValue();
894 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
897 v.
floatValue = std::scalbln(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
901 functions[
"ldexp"] = [](
const std::vector<ValueFlow::Value>& args) {
902 if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](
const ValueFlow::Value& v) {
903 return v.isFloatValue() || v.isIntValue();
906 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
909 v.
floatValue = std::ldexp(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
913 functions[
"ilogb"] = [](
const std::vector<ValueFlow::Value>& args) {
914 if (args.size() != 1)
919 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
924 functions[
"erf"] = [](
const std::vector<ValueFlow::Value>& args) {
925 if (args.size() != 1)
930 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
935 functions[
"erfc"] = [](
const std::vector<ValueFlow::Value>& args) {
936 if (args.size() != 1)
941 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
946 functions[
"floor"] = [](
const std::vector<ValueFlow::Value>& args) {
947 if (args.size() != 1)
952 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
957 functions[
"sqrt"] = [](
const std::vector<ValueFlow::Value>& args) {
958 if (args.size() != 1)
963 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
968 functions[
"cbrt"] = [](
const std::vector<ValueFlow::Value>& args) {
969 if (args.size() != 1)
974 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
979 functions[
"ceil"] = [](
const std::vector<ValueFlow::Value>& args) {
980 if (args.size() != 1)
985 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
990 functions[
"exp"] = [](
const std::vector<ValueFlow::Value>& args) {
991 if (args.size() != 1)
996 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1001 functions[
"exp2"] = [](
const std::vector<ValueFlow::Value>& args) {
1002 if (args.size() != 1)
1007 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1012 functions[
"expm1"] = [](
const std::vector<ValueFlow::Value>& args) {
1013 if (args.size() != 1)
1018 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1023 functions[
"fabs"] = [](
const std::vector<ValueFlow::Value>& args) {
1024 if (args.size() != 1)
1029 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1034 functions[
"log"] = [](
const std::vector<ValueFlow::Value>& args) {
1035 if (args.size() != 1)
1040 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1045 functions[
"log10"] = [](
const std::vector<ValueFlow::Value>& args) {
1046 if (args.size() != 1)
1051 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1056 functions[
"log1p"] = [](
const std::vector<ValueFlow::Value>& args) {
1057 if (args.size() != 1)
1062 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1067 functions[
"log2"] = [](
const std::vector<ValueFlow::Value>& args) {
1068 if (args.size() != 1)
1073 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1078 functions[
"logb"] = [](
const std::vector<ValueFlow::Value>& args) {
1079 if (args.size() != 1)
1084 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1089 functions[
"nearbyint"] = [](
const std::vector<ValueFlow::Value>& args) {
1090 if (args.size() != 1)
1095 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1100 functions[
"sinh"] = [](
const std::vector<ValueFlow::Value>& args) {
1101 if (args.size() != 1)
1106 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1111 functions[
"cosh"] = [](
const std::vector<ValueFlow::Value>& args) {
1112 if (args.size() != 1)
1117 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1122 functions[
"tanh"] = [](
const std::vector<ValueFlow::Value>& args) {
1123 if (args.size() != 1)
1128 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1133 functions[
"asinh"] = [](
const std::vector<ValueFlow::Value>& args) {
1134 if (args.size() != 1)
1139 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1144 functions[
"acosh"] = [](
const std::vector<ValueFlow::Value>& args) {
1145 if (args.size() != 1)
1150 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1155 functions[
"atanh"] = [](
const std::vector<ValueFlow::Value>& args) {
1156 if (args.size() != 1)
1161 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1166 functions[
"round"] = [](
const std::vector<ValueFlow::Value>& args) {
1167 if (args.size() != 1)
1172 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1177 functions[
"tgamma"] = [](
const std::vector<ValueFlow::Value>& args) {
1178 if (args.size() != 1)
1183 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1188 functions[
"trunc"] = [](
const std::vector<ValueFlow::Value>& args) {
1189 if (args.size() != 1)
1194 const double value = args[0].
isFloatValue() ? args[0].floatValue : args[0].intvalue;
1205 auto it = functions.find(name);
1206 if (it == functions.end())
1217 static std::vector<const Token*>
setDifference(
const std::vector<const Token*>& v1,
const std::vector<const Token*>& v2)
1219 std::vector<const Token*> result;
1220 std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result), &
TokenExprIdCompare);
1225 const Token* storedValue,
1239 const std::unordered_map<nonneg int, ValueFlow::Value>& state)
1241 conds.erase(std::remove_if(conds.begin(),
1243 [&](
const Token* cond) {
1244 if (cond->exprId() == 0)
1246 auto it = state.find(cond->exprId());
1247 if (it == state.end())
1249 const ValueFlow::Value& v = it->second;
1250 return isTrueOrFalse(v, !b);
1258 const Settings* settings =
nullptr;
1264 assert(settings !=
nullptr);
1271 std::unordered_map<nonneg int, ValueFlow::Value> executeAll(
const std::vector<const Token*>& toks,
1272 const bool* b =
nullptr)
const
1274 std::unordered_map<nonneg int, ValueFlow::Value> result;
1276 for (
const Token* tok : toks) {
1281 result.emplace(tok->
exprId(), std::move(r));
1289 static std::vector<const Token*> flattenConditions(
const Token* tok)
1293 static bool sortConditions(std::vector<const Token*>& conditions)
1295 if (std::any_of(conditions.begin(), conditions.end(), [](
const Token* child) {
1296 return Token::Match(child,
"&&|%oror%");
1300 conditions.erase(std::unique(conditions.begin(), conditions.end(), &
TokenExprIdCompare), conditions.end());
1301 return !conditions.empty() && conditions.front()->exprId() != 0;
1329 std::vector<const Token*> conditions1 = flattenConditions(expr);
1330 if (conditions1.empty())
1332 std::unordered_map<nonneg int, ValueFlow::Value> condValues = executeAll(conditions1, &b);
1333 bool allNegated =
true;
1335 for (
const auto& p : condValues) {
1343 if (condValues.size() == conditions1.size() && allNegated)
1344 return negatedValue;
1347 if (!sortConditions(conditions1))
1350 for (
const auto& p : *pm) {
1351 const Token* tok = p.first.tok;
1360 std::vector<const Token*> conditions2 = flattenConditions(tok);
1361 if (!sortConditions(conditions2))
1363 if (conditions1.size() == conditions2.size() &&
1364 std::equal(conditions1.begin(), conditions1.end(), conditions2.begin(), &
TokenExprIdEqual))
1366 std::vector<const Token*> diffConditions1 =
setDifference(conditions1, conditions2);
1367 std::vector<const Token*> diffConditions2 =
setDifference(conditions2, conditions1);
1370 if (diffConditions1.size() != diffConditions2.size())
1372 if (diffConditions1.size() == conditions1.size())
1374 for (
const Token* cond1 : diffConditions1) {
1375 auto it = std::find_if(diffConditions2.begin(), diffConditions2.end(), [&](
const Token* cond2) {
1376 return evalSameCondition(*pm, cond2, cond1, *settings);
1378 if (it == diffConditions2.end())
1380 diffConditions2.erase(it);
1382 if (diffConditions2.empty())
1395 return expr->
values().front();
1437 if (expr->
str() !=
"=") {
1446 std::bind(assign{}, std::ref(lhs.
floatValue), std::placeholders::_1));
1454 return executeMultiCondition(
false, expr);
1456 return executeMultiCondition(
true, expr);
1470 if (expr->
str() ==
"++")
1476 const Token* tokvalue =
nullptr;
1477 if (!pm->getTokValue(expr->
astOperand1()->exprId(), tokvalue)) {
1478 auto tokvalue_it = std::find_if(expr->
astOperand1()->values().cbegin(),
1481 if (tokvalue_it == expr->
astOperand1()->values().cend() || !tokvalue_it->isKnown()) {
1484 tokvalue = tokvalue_it->tokvalue;
1486 if (!tokvalue || !tokvalue->
isLiteral()) {
1489 const std::string strValue = tokvalue->
strValue();
1494 if (index >= 0 && index < strValue.size())
1496 if (index == strValue.size())
1506 std::vector<ValueFlow::Value> result =
1508 if (!result.empty() && result.front().isKnown())
1509 return result.front();
1512 std::vector<ValueFlow::Value> result =
1514 if (!result.empty() && result.front().isKnown())
1515 return result.front();
1526 if (expr->
str() ==
"!") {
1537 if (expr->
str() ==
"-")
1551 }
else if (expr->
str() ==
"(" && expr->
isCast()) {
1556 if (expr->
exprId() > 0 && pm->hasValue(expr->
exprId())) {
1569 if (settings && expr->
str() ==
"(") {
1570 std::vector<const Token*> tokArgs =
getArguments(expr);
1571 std::vector<ValueFlow::Value> args(tokArgs.size());
1573 tokArgs.cbegin(), tokArgs.cend(), args.begin(), [&](
const Token* tok) {
1574 return execute(tok);
1579 for (std::size_t i = 0; i < args.size(); ++i) {
1586 ex.pm = &functionState;
1598 if (!returnValue.empty()) {
1599 std::unordered_map<nonneg int, ValueFlow::Value> arg_map;
1612 if (child->exprId() > 0 && pm->hasValue(child->exprId())) {
1613 ValueFlow::Value& v = pm->at(child->exprId());
1614 assert(settings != nullptr);
1615 if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) {
1616 if (ValueFlow::isContainerSizeChanged(child, v.indirect, *settings))
1618 } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) {
1619 if (isVariableChanged(child, v.indirect, *settings))
1634 std::vector<const ValueFlow::Value*> values;
1639 values.push_back(std::addressof(v));
1644 return x->intvalue < y->intvalue;
1646 if (it == values.end())
1668 if (updateValue(v, executeImpl(expr)))
1672 if (expr->
exprId() > 0 && pm->hasValue(expr->
exprId())) {
1673 if (updateValue(v, pm->at(expr->
exprId())))
1697 std::vector<ValueFlow::Value>
execute(
const Scope* scope)
1712 if (
execute(top).isUninitValue())
1723 const Token* thenStart = top->
link()->next();
1725 const Token* elseStart =
nullptr;
1727 elseStart = thenStart->
link()->tokAt(2);
1728 next = elseStart->
link();
1730 std::vector<ValueFlow::Value> result;
1739 if (!result.empty())
1754 return ex.execute(expr);
1760 return ex.execute(scope);
1764 const std::string& returnValue,
1768 thread_local
static std::unordered_map<std::string,
1769 std::function<
ValueFlow::Value(
const std::unordered_map<nonneg int, ValueFlow::Value>& arg)>>
1771 if (functions.count(returnValue) == 0) {
1773 std::unordered_map<nonneg int, const Token*> lookupVarId;
1776 functions[returnValue] =
1777 [lookupVarId, expr, settings](
const std::unordered_map<nonneg int, ValueFlow::Value>& xargs) {
1781 for (
const auto& p : xargs) {
1782 auto it = lookupVarId.find(p.first);
1783 if (it != lookupVarId.end())
1786 return execute(expr.get(), pm, settings);
1789 return functions.at(returnValue)(args);
bool astIsContainer(const Token *tok)
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
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.
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
bool astHasExpr(const Token *tok, nonneg int exprid)
std::vector< const Token * > astFlatten(const Token *tok, const char *op)
Token * getCondTokFromEnd(Token *endBlock)
const Token * nextAfterAstRightmostLeaf(const Token *tok)
bool astIsUnsigned(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)
nonneg int astCount(const Token *tok, const char *op, int depth)
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
R calculate(const std::string &s, const T &x, const T &y, bool *error=nullptr)
This class will take a list of filenames and settings and check then all files using threads.
Executor(const std::list< FileWithDetails > &files, const std::list< FileSettings > &fileSettings, const Settings &settings, SuppressionList &suppressions, ErrorLogger &errorLogger)
const Scope * functionScope
scope of function body
const Variable * getArgumentVar(nonneg int num) const
bool isImplicitlyVirtual(bool defaultVal=false) const
check if this function is virtual in the base classes
Yield getYield(const std::string &function) const
const Token * getContainerFromYield(const Token *tok, Container::Yield yield) const
const std::string & returnValue(const Token *ftok) const
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)
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
This is just a container for general settings so that we don't need to pass individual values to func...
The token list that the TokenList generates is a linked-list of this class.
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
bool hasKnownIntValue() const
static nonneg int getStrLength(const Token *tok)
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
const ValueType * valueType() const
const std::string & strAt(int index) const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
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
std::string strValue() const
This can be called only for tokens that are strings, else the assert() is called.
bool isAssignmentOp() const
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.
void astParent(Token *tok)
bool isSymbolicValue() const
Bound bound
The value bound
enum ValueFlow::Value::ValueType valueType
bool isIteratorValue() const
bool isFloatValue() const
@ Impossible
Listed values are impossible.
bool isImpossible() const
double floatValue
float value
bool isUninitValue() const
static void visitValue(T &self, F f)
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?)
enum ValueFlow::Value::ValueKind valueKind
bool isContainerSizeValue() const
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
Information about a member variable.
const Token * nameToken() const
Get name token.
std::shared_ptr< Token > createTokenFromExpression(const std::string &returnValue, const Settings &settings, bool cpp, std::unordered_map< nonneg int, const Token * > *lookupVarId)
@ 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)
CPPCHECKLIB ValuePtr< InferModel > makeIntegralInferModel()
void combineValueProperties(const Value &value1, const Value &value2, Value &result)
Value asImpossible(Value v)
static BuiltinLibraryFunction getBuiltinLibraryFunction(const std::string &name)
bool conditionIsFalse(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always false when variable has given value?
static bool frontIs(const std::vector< MathLib::bigint > &v, bool i)
static bool isTrueOrFalse(const ValueFlow::Value &v, bool b)
static ValueFlow::Value execute(const Token *expr, ProgramMemory &pm, const Settings &settings)
static bool isFalse(const ValueFlow::Value &v)
static ValueFlow::Value evaluate(const std::string &op, const ValueFlow::Value &lhs, const ValueFlow::Value &rhs)
static void programMemoryParseCondition(ProgramMemory &pm, const Token *tok, const Token *endTok, const Settings &settings, bool then)
static bool evalSameCondition(const ProgramMemory &state, const Token *storedValue, const Token *cond, const Settings &settings)
static bool isNumericValue(const ValueFlow::Value &value)
static bool isTrue(const ValueFlow::Value &v)
static std::string removeAssign(const std::string &assign)
static std::vector< const Token * > setDifference(const std::vector< const Token * > &v1, const std::vector< const Token * > &v2)
ProgramMemory getProgramMemory(const Token *tok, const Token *expr, const ValueFlow::Value &value, const Settings &settings)
Get program memory by looking backwards from given token.
static bool isIntegralValue(const ValueFlow::Value &value)
static bool evaluateCondition(MathLib::bigint r, const Token *condition, ProgramMemory &pm, const Settings &settings)
ValueFlow::Value evaluateLibraryFunction(const std::unordered_map< nonneg int, ValueFlow::Value > &args, const std::string &returnValue, const Settings &settings, bool cpp)
static void removeModifiedVars(ProgramMemory &pm, const Token *tok, const Token *origin, const Settings &settings)
static bool isBasicForLoop(const Token *tok)
static void fillProgramMemoryFromConditions(ProgramMemory &pm, const Scope *scope, const Token *endTok, const Settings &settings)
static bool TokenExprIdCompare(const Token *tok1, const Token *tok2)
static void addVars(ProgramMemory &pm, const ProgramMemory::Map &vars)
static std::unordered_map< std::string, BuiltinLibraryFunction > createBuiltinLibraryFunctions()
std::function< ValueFlow::Value(const std::vector< ValueFlow::Value > &)> BuiltinLibraryFunction
bool conditionIsTrue(const Token *condition, ProgramMemory pm, const Settings &settings)
Is condition always true when variable has given value?
static bool TokenExprIdEqual(const Token *tok1, const Token *tok2)
static void pruneConditions(std::vector< const Token * > &conds, bool b, const std::unordered_map< nonneg int, ValueFlow::Value > &state)
static double asFloat(const ValueFlow::Value &value)
static void fillProgramMemoryFromAssignments(ProgramMemory &pm, const Token *tok, const Settings &settings, const ProgramMemory &state, const ProgramMemory::Map &vars)
static ProgramMemory getInitialProgramState(const Token *tok, const Token *origin, const Settings &settings, const ProgramMemory::Map &vars=ProgramMemory::Map {})
std::size_t operator()(ExprIdToken etok) const
nonneg int getExpressionId() const
ProgramMemoryState(const Settings *s)
void assume(const Token *tok, bool b, bool isEmpty=false)
std::map< nonneg int, const Token * > origins
void replace(ProgramMemory pm, const Token *origin=nullptr)
void removeModifiedVars(const Token *tok)
ProgramMemory get(const Token *tok, const Token *ctx, const ProgramMemory::Map &vars) const
void insert(const ProgramMemory &pm, const Token *origin=nullptr)
void addState(const Token *tok, const ProgramMemory::Map &vars)
const Settings * settings
void setValue(const Token *expr, const ValueFlow::Value &value)
bool getIntValue(nonneg int exprid, MathLib::bigint &result) const
void insert(const ProgramMemory &pm)
bool getTokValue(nonneg int exprid, const Token *&result) const
void setUnknown(const Token *expr)
const ValueFlow::Value * getValue(nonneg int exprid, bool impossible=false) const
void erase_if(const std::function< bool(const ExprIdToken &)> &pred)
bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint &result) const
bool getContainerSizeValue(nonneg int exprid, MathLib::bigint &result) const
const ValueFlow::Value & at(nonneg int exprid) const
void setContainerSizeValue(const Token *expr, MathLib::bigint value, bool isEqual=true)
std::unordered_map< ExprIdToken, ValueFlow::Value, ExprIdToken::Hash > Map
void replace(ProgramMemory pm)
bool hasValue(nonneg int exprid)
void swap(ProgramMemory &pm)
void setIntValue(const Token *expr, MathLib::bigint value, bool impossible=false)
static std::string getStringLiteral(const std::string &str)
bool contains(const Range &r, const T &x)
static const Token * solveExprValue(const Token *expr, ValueFlow::Value &value)