diff --git a/lib/calculate.h b/lib/calculate.h index c33e37fd3b7..470000f95ad 100644 --- a/lib/calculate.h +++ b/lib/calculate.h @@ -60,12 +60,16 @@ R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr) constexpr MathLib::bigint maxBitsSignedShift = maxBitsShift - 1; switch (MathLib::encodeMultiChar(s)) { case '+': + case '+=': return wrap(x + y); case '-': + case '-=': return wrap(x - y); case '*': + case '*=': return wrap(x * y); case '/': + case '/=': if (isZero(y) || (std::is_signed{} && y < 0)) { if (error) *error = true; @@ -73,6 +77,7 @@ R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr) } return wrap(x / y); case '%': + case '%=': if (isZero(MathLib::bigint(y)) || (std::is_signed{} && MathLib::bigint(y) < 0)) { if (error) *error = true; @@ -80,16 +85,20 @@ R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr) } return wrap(MathLib::bigint(x) % MathLib::bigint(y)); case '&': + case '&=': return wrap(MathLib::bigint(x) & MathLib::bigint(y)); case '|': + case '|=': return wrap(MathLib::bigint(x) | MathLib::bigint(y)); case '^': + case '^=': return wrap(MathLib::bigint(x) ^ MathLib::bigint(y)); case '>': return wrap(x > y); case '<': return wrap(x < y); case '<<': + case '<<=': if (y >= maxBitsSignedShift || y < 0 || x < 0) { if (error) *error = true; @@ -97,6 +106,7 @@ R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr) } return wrap(MathLib::bigint(x) << MathLib::bigint(y)); case '>>': + case '>>=': if (y >= maxBitsSignedShift || y < 0 || x < 0) { if (error) *error = true; diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index e7b715ab36b..2e5b229c0a7 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -486,7 +486,7 @@ namespace ValueFlow } // Calculations.. - else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp) || + else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp) || (Token::Match(parent, "%assign%") && parent->str().size() > 1) || (parent->tokType() == Token::eLogicalOp)) && parent->astOperand1() && parent->astOperand2()) { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index b8496c863d5..cfb64b0f121 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1403,6 +1403,12 @@ class TestValueFlow : public TestFixture { "}\n"; ASSERT_NO_THROW(tokenValues(code, "<=>")); + code = "int f() {\n" // #15184 + " int i = -1;\n" + " return 1 / (i += 1);\n" + "}\n"; + ASSERT_EQUALS(true, testKnownValueOfTok(code, "+=", 0)); + // Comparison of string values = removeImpossible(tokenValues("f(\"xyz\" == \"xyz\");\n", "==")); // implementation defined ASSERT_EQUALS(0U, values.size()); // <- no value