diff --git a/lib/importproject.cpp b/lib/importproject.cpp index d81c95ab6fd..dea408f4fbe 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1381,9 +1381,12 @@ std::string ImportProject::applyMSBuildStaticFunction(const std::string &classNa // Format a double as an integer string when the value is whole, // otherwise use std::to_string (which gives 6 decimal places). const auto fmtDouble = [](double d) -> std::string { - const auto i = static_cast(d); - if (!(static_cast(i) < d) && !(static_cast(i) > d)) - return std::to_string(i); + // Converting a double outside the long long range is undefined behaviour + if (d >= static_cast(LLONG_MIN) && d < -static_cast(LLONG_MIN)) { + const auto i = static_cast(d); + if (!(static_cast(i) < d) && !(static_cast(i) > d)) + return std::to_string(i); + } return std::to_string(d); }; if (args.size() == 1) { @@ -1400,16 +1403,14 @@ std::string ImportProject::applyMSBuildStaticFunction(const std::string &classNa // not round-half-away-from-zero. const double fl = std::floor(x); const double frac = x - fl; - long long rounded; + double rounded; if (frac < 0.5) - rounded = static_cast(fl); + rounded = fl; else if (frac > 0.5) - rounded = static_cast(fl) + 1; - else { // exactly 0.5 -- round to nearest even integer - const auto ifl = static_cast(fl); - rounded = ((ifl % 2) == 0) ? ifl : ifl + 1; - } - return std::to_string(rounded); + rounded = fl + 1; + else // exactly 0.5 -- round to nearest even integer + rounded = (std::fabs(std::fmod(fl, 2.0)) < 1) ? fl : fl + 1; + return fmtDouble(rounded); } if (caseInsensitiveStringCompare(member, "Sqrt") == 0 && x >= 0) return fmtDouble(std::sqrt(x)); diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index a9b756ff17a..86d2467b45c 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -1319,6 +1319,12 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("5", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Abs(5))")); ASSERT_EQUALS("2", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Floor(2.9))")); ASSERT_EQUALS("3", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Ceiling(2.1))")); + ASSERT_EQUALS("2", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Round(2.5))")); + ASSERT_EQUALS("4", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Round(3.5))")); + ASSERT_EQUALS("-2", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Round(-2.5))")); + ASSERT_EQUALS("1000000000000000019884624838656.000000", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Pow(10, 30))")); + ASSERT_EQUALS("1000000000000000019884624838656.000000", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Round(1e30))")); + ASSERT_EQUALS("-1000000000000000019884624838656.000000", cppcheck::testing::expandMSBuildExpression("$([System.Math]::Floor(-1e30))")); // --- $([System.IO.Path]::...) --- ASSERT_EQUALS("bar.cpp", cppcheck::testing::expandMSBuildExpression("$([System.IO.Path]::GetFileName('C:/foo/bar.cpp'))"));