Skip to content

Commit 6741f77

Browse files
carlatcrownCarl Morgan
andauthored
Support integer Z suffix and user defined literals with _ suffix (#10807, #11438) (cppcheck-opensource#5130)
Co-authored-by: Carl Morgan <[email protected]>
1 parent d490210 commit 6741f77

2 files changed

Lines changed: 74 additions & 8 deletions

File tree

lib/mathlib.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ bool MathLib::isDecimalFloat(const std::string &str)
546546
if (str.empty())
547547
return false;
548548
enum class State {
549-
START, BASE_DIGITS1, LEADING_DECIMAL, TRAILING_DECIMAL, BASE_DIGITS2, E, MANTISSA_PLUSMINUS, MANTISSA_DIGITS, SUFFIX_F, SUFFIX_L
549+
START, BASE_DIGITS1, LEADING_DECIMAL, TRAILING_DECIMAL, BASE_DIGITS2, E, MANTISSA_PLUSMINUS, MANTISSA_DIGITS, SUFFIX_F, SUFFIX_L, SUFFIX_LITERAL_LEADER, SUFFIX_LITERAL
550550
} state = State::START;
551551
std::string::const_iterator it = str.cbegin();
552552
if ('+' == *it || '-' == *it)
@@ -582,6 +582,8 @@ bool MathLib::isDecimalFloat(const std::string &str)
582582
state = State::SUFFIX_F;
583583
else if (*it=='l' || *it=='L')
584584
state = State::SUFFIX_L;
585+
else if (*it == '_')
586+
state = State::SUFFIX_LITERAL_LEADER;
585587
else if (std::isdigit(static_cast<unsigned char>(*it)))
586588
state = State::BASE_DIGITS2;
587589
else
@@ -594,6 +596,8 @@ bool MathLib::isDecimalFloat(const std::string &str)
594596
state = State::SUFFIX_F;
595597
else if (*it=='l' || *it=='L')
596598
state = State::SUFFIX_L;
599+
else if (*it == '_')
600+
state = State::SUFFIX_LITERAL_LEADER;
597601
else if (!std::isdigit(static_cast<unsigned char>(*it)))
598602
return false;
599603
break;
@@ -619,13 +623,18 @@ bool MathLib::isDecimalFloat(const std::string &str)
619623
else if (!std::isdigit(static_cast<unsigned char>(*it)))
620624
return false;
621625
break;
626+
// Ensure at least one post _ char for user defined literals
627+
case State::SUFFIX_LITERAL:
628+
case State::SUFFIX_LITERAL_LEADER:
629+
state = State::SUFFIX_LITERAL;
630+
break;
622631
case State::SUFFIX_F:
623632
return false;
624633
case State::SUFFIX_L:
625634
return false;
626635
}
627636
}
628-
return (state==State::BASE_DIGITS2 || state==State::MANTISSA_DIGITS || state==State::TRAILING_DECIMAL || state==State::SUFFIX_F || state==State::SUFFIX_L);
637+
return (state==State::BASE_DIGITS2 || state==State::MANTISSA_DIGITS || state==State::TRAILING_DECIMAL || state==State::SUFFIX_F || state==State::SUFFIX_L || (state==State::SUFFIX_LITERAL));
629638
}
630639

631640
bool MathLib::isNegative(const std::string &str)
@@ -644,22 +653,28 @@ bool MathLib::isPositive(const std::string &str)
644653

645654
static bool isValidIntegerSuffixIt(std::string::const_iterator it, std::string::const_iterator end, bool supportMicrosoftExtensions=true)
646655
{
647-
enum class Status { START, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU, SUFFIX_I, SUFFIX_I6, SUFFIX_I64, SUFFIX_UI, SUFFIX_UI6, SUFFIX_UI64 } state = Status::START;
656+
enum class Status { START, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_UZ, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU, SUFFIX_I, SUFFIX_I6, SUFFIX_I64, SUFFIX_UI, SUFFIX_UI6, SUFFIX_UI64, SUFFIX_Z, SUFFIX_LITERAL_LEADER, SUFFIX_LITERAL } state = Status::START;
648657
for (; it != end; ++it) {
649658
switch (state) {
650659
case Status::START:
651660
if (*it == 'u' || *it == 'U')
652661
state = Status::SUFFIX_U;
653662
else if (*it == 'l' || *it == 'L')
654663
state = Status::SUFFIX_L;
664+
else if (*it == 'z' || *it == 'Z')
665+
state = Status::SUFFIX_Z;
655666
else if (supportMicrosoftExtensions && (*it == 'i' || *it == 'I'))
656667
state = Status::SUFFIX_I;
668+
else if (*it == '_')
669+
state = Status::SUFFIX_LITERAL_LEADER;
657670
else
658671
return false;
659672
break;
660673
case Status::SUFFIX_U:
661674
if (*it == 'l' || *it == 'L')
662675
state = Status::SUFFIX_UL; // UL
676+
else if (*it == 'z' || *it == 'Z')
677+
state = Status::SUFFIX_UZ; // UZ
663678
else if (supportMicrosoftExtensions && (*it == 'i' || *it == 'I'))
664679
state = Status::SUFFIX_UI;
665680
else
@@ -711,19 +726,33 @@ static bool isValidIntegerSuffixIt(std::string::const_iterator it, std::string::
711726
else
712727
return false;
713728
break;
729+
case Status::SUFFIX_Z:
730+
if (*it == 'u' || *it == 'U')
731+
state = Status::SUFFIX_UZ;
732+
else
733+
return false;
734+
break;
735+
// Ensure at least one post _ char for user defined literals
736+
case Status::SUFFIX_LITERAL:
737+
case Status::SUFFIX_LITERAL_LEADER:
738+
state = Status::SUFFIX_LITERAL;
739+
break;
714740
default:
715741
return false;
716742
}
717743
}
718744
return ((state == Status::SUFFIX_U) ||
719745
(state == Status::SUFFIX_L) ||
746+
(state == Status::SUFFIX_Z) ||
720747
(state == Status::SUFFIX_UL) ||
748+
(state == Status::SUFFIX_UZ) ||
721749
(state == Status::SUFFIX_LU) ||
722750
(state == Status::SUFFIX_LL) ||
723751
(state == Status::SUFFIX_ULL) ||
724752
(state == Status::SUFFIX_LLU) ||
725753
(state == Status::SUFFIX_I64) ||
726-
(state == Status::SUFFIX_UI64));
754+
(state == Status::SUFFIX_UI64) ||
755+
(state == Status::SUFFIX_LITERAL));
727756
}
728757

729758
// cppcheck-suppress unusedFunction

test/testmathlib.cpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,14 @@ class TestMathLib : public TestFixture {
960960
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0ULL"));
961961
ASSERT_EQUALS(true, MathLib::isIntHex("+0x0LLU"));
962962
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0LLU"));
963+
ASSERT_EQUALS(true, MathLib::isIntHex("+0x0Z"));
964+
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0Z"));
965+
ASSERT_EQUALS(true, MathLib::isIntHex("+0x0ZU"));
966+
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0ZU"));
967+
ASSERT_EQUALS(true, MathLib::isIntHex("+0x0UZ"));
968+
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0UZ"));
969+
ASSERT_EQUALS(true, MathLib::isIntHex("+0x0Uz"));
970+
ASSERT_EQUALS(true, MathLib::isIntHex("-0x0Uz"));
963971

964972
// negative testing
965973
ASSERT_EQUALS(false, MathLib::isIntHex("+0x"));
@@ -972,10 +980,6 @@ class TestMathLib : public TestFixture {
972980
ASSERT_EQUALS(false, MathLib::isIntHex(" "));
973981
ASSERT_EQUALS(false, MathLib::isIntHex(" "));
974982
ASSERT_EQUALS(false, MathLib::isIntHex("0"));
975-
ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Z"));
976-
ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Z"));
977-
ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Uz"));
978-
ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Uz"));
979983
ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Lz"));
980984
ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Lz"));
981985
ASSERT_EQUALS(false, MathLib::isIntHex("+0x0LUz"));
@@ -1018,12 +1022,19 @@ class TestMathLib : public TestFixture {
10181022
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("u"));
10191023
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ul"));
10201024
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ull"));
1025+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("uz"));
10211026
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("l"));
10221027
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("lu"));
10231028
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ll"));
10241029
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("llu"));
10251030
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("llU"));
10261031
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("LLU"));
1032+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("z"));
1033+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("Z"));
1034+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("zu"));
1035+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("UZ"));
1036+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("ZU"));
1037+
10271038
// Microsoft extensions:
10281039
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("i64"));
10291040
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("I64"));
@@ -1033,6 +1044,10 @@ class TestMathLib : public TestFixture {
10331044
ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("I64", false));
10341045
ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("ui64", false));
10351046
ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("UI64", false));
1047+
1048+
// User defined suffix literals
1049+
ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix("_"));
1050+
ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix("_MyUserDefinedLiteral"));
10361051
}
10371052

10381053
void ispositive() const {
@@ -1057,6 +1072,13 @@ class TestMathLib : public TestFixture {
10571072
ASSERT_EQUALS(true, MathLib::isFloat("0.f"));
10581073
ASSERT_EQUALS(true, MathLib::isFloat("0.f"));
10591074
ASSERT_EQUALS(true, MathLib::isFloat("0xA.Fp-10"));
1075+
1076+
// User defined suffix literals
1077+
ASSERT_EQUALS(false, MathLib::isFloat("0_"));
1078+
ASSERT_EQUALS(false, MathLib::isFloat("0._"));
1079+
ASSERT_EQUALS(false, MathLib::isFloat("0.1_"));
1080+
ASSERT_EQUALS(true, MathLib::isFloat("0.0_MyUserDefinedLiteral"));
1081+
ASSERT_EQUALS(true, MathLib::isFloat("0._MyUserDefinedLiteral"));
10601082
}
10611083

10621084
void isDecimalFloat() const {
@@ -1164,6 +1186,13 @@ class TestMathLib : public TestFixture {
11641186
ASSERT_EQUALS(true, MathLib::isDecimalFloat("1.0E+1"));
11651187
ASSERT_EQUALS(true, MathLib::isDecimalFloat("1.0E-1"));
11661188
ASSERT_EQUALS(true, MathLib::isDecimalFloat("-1.0E+1"));
1189+
1190+
// User defined suffix literals
1191+
ASSERT_EQUALS(false, MathLib::isDecimalFloat("0_"));
1192+
ASSERT_EQUALS(false, MathLib::isDecimalFloat(".1_"));
1193+
ASSERT_EQUALS(false, MathLib::isDecimalFloat("0.1_"));
1194+
ASSERT_EQUALS(true, MathLib::isDecimalFloat("0.0_MyUserDefinedLiteral"));
1195+
ASSERT_EQUALS(true, MathLib::isDecimalFloat(".1_MyUserDefinedLiteral"));
11671196
}
11681197

11691198
void naninf() const {
@@ -1198,6 +1227,14 @@ class TestMathLib : public TestFixture {
11981227
ASSERT_EQUALS(false, MathLib::isDec("+x"));
11991228
ASSERT_EQUALS(false, MathLib::isDec("x"));
12001229
ASSERT_EQUALS(false, MathLib::isDec(""));
1230+
1231+
// User defined suffix literals
1232+
ASSERT_EQUALS(false, MathLib::isDec("0_"));
1233+
ASSERT_EQUALS(false, MathLib::isDec("+0_"));
1234+
ASSERT_EQUALS(false, MathLib::isDec("-1_"));
1235+
ASSERT_EQUALS(true, MathLib::isDec("0_MyUserDefinedLiteral"));
1236+
ASSERT_EQUALS(true, MathLib::isDec("+1_MyUserDefinedLiteral"));
1237+
ASSERT_EQUALS(true, MathLib::isDec("-1_MyUserDefinedLiteral"));
12011238
}
12021239

12031240
void isNullValue() const {

0 commit comments

Comments
 (0)