diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 8daddc0ffdd..7894acb5cf9 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -1249,6 +1249,42 @@ bool MathLib::isOctalDigit(char c) return (c >= '0' && c <= '7'); } +bool MathLib::isDigitSeparator(const std::string& iCode, std::string::size_type iPos) { + if (iPos == 0 || iPos >= iCode.size() || iCode[iPos] != '\'') + return false; + std::string::size_type i = iPos - 1; + while (std::isxdigit(iCode[i])) { + if (i == 0) + return true; // Only xdigits before ' + --i; + } + if (i == iPos - 1) { // No xdigit before ' + return false; + } else { + switch(iCode[i]) { + case ' ': + case '.': + case ',': + case 'x': + case '(': + case '{': + case '+': + case '-': + case '*': + case '%': + case '/': + case '&': + case '|': + case '^': + case '~': + case '=': + return true; + default: + return false; + } + } +} + MathLib::value operator+(const MathLib::value &v1, const MathLib::value &v2) { return MathLib::value::calc('+',v1,v2); diff --git a/lib/mathlib.h b/lib/mathlib.h index 067eb639c49..5fc10f7ebba 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -122,6 +122,13 @@ class CPPCHECKLIB MathLib { * */ static MathLib::bigint characterLiteralToLongNumber(const std::string& str); + /** + * \param iCode Code being considered + * \param iPos A posision within iCode + * \return Whether iCode[iPos] is a C++14 digit separator + */ + static bool isDigitSeparator(const std::string& iCode, std::string::size_type iPos); + private: /* * \param iLiteral A character literal diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 737c717c643..d9082e4d8a2 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -697,7 +697,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } // C++14 digit separators - if (ch == '\'' && std::isxdigit(previous)) + if (MathLib::isDigitSeparator(str, i)) ; // Just skip it. // String or char constants.. diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index ca569e1034c..d47600f9f0d 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -59,6 +59,7 @@ class TestMathLib : public TestFixture { TEST_CASE(abs); TEST_CASE(toString); TEST_CASE(characterLiteralsNormalization); + TEST_CASE(CPP14DigitSeparators); } void isGreater() const { @@ -1143,6 +1144,23 @@ class TestMathLib : public TestFixture { // Unsupported single escape sequence ASSERT_THROW(MathLib::normalizeCharacterLiteral("\\c"), InternalError); } + + void CPP14DigitSeparators() { // Ticket #7137 + ASSERT(MathLib::isDigitSeparator("'", 0) == false); + ASSERT(MathLib::isDigitSeparator("123'0;", 3)); + ASSERT(MathLib::isDigitSeparator("foo(1'2);", 5)); + ASSERT(MathLib::isDigitSeparator("foo(1,1'2);", 7)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 7)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 13)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 16) == false); + ASSERT(MathLib::isDigitSeparator("int b=1+9'8;", 9)); + ASSERT(MathLib::isDigitSeparator("if (1'2) { char c = 'c'; }", 5)); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120&1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120|1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 24) == false); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 26) == false); + } }; REGISTER_TEST(TestMathLib) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index ee062dc5113..9a74bde1d68 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -352,6 +352,11 @@ class TestPreprocessor : public TestFixture { ASSERT_EQUALS("int i = 0x0F0FFFFF;", preprocessorRead("int i = 0x0F0F'FFFF;")); ASSERT_EQUALS("", errout.str()); + + // Ticket #7137 + const char code[] = "void t(char c) { switch (c) { case'M': break; } }"; + ASSERT_EQUALS(code, preprocessorRead(code)); + ASSERT_EQUALS("", errout.str()); }