From d1bfae989ea226dfd772082da08ad52d016504e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sun, 9 Oct 2022 11:19:19 +0200 Subject: [PATCH] fixed handling of incomplete char/string literals in `isPrefixStringCharLiteral()` - also optimized it a bit (#4541) * fixed handling of incomplete char/string literals in `isPrefixStringCharLiteral()` - also optimized it a bit / added tests for `isStringLiteral()` and `isCharLiteral()` * utils.h: early out in `isStringCharLiteral()` to avoid the loop --- lib/utils.h | 22 +++++++-- test/testutils.cpp | 110 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/lib/utils.h b/lib/utils.h index c8e7e6816..e70b7de35 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -89,15 +89,31 @@ bool endsWith(const std::string& str, const char (&end)[N]) inline static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string& p) { + // str must be at least the prefix plus the start and end quote + if (str.length() < p.length() + 2) + return false; + + // check for end quote if (!endsWith(str, q)) return false; - if ((str.length() + 1) > p.length() && (str.compare(0, p.size() + 1, p + q) == 0)) - return true; - return false; + + // check for start quote + if (str[p.size()] != q) + return false; + + // check for prefix + if (str.compare(0, p.size(), p) != 0) + return false; + + return true; } inline static bool isStringCharLiteral(const std::string &str, char q) { + // early out to avoid the loop + if (!endsWith(str, q)) + return false; + static const std::array suffixes{"", "u8", "u", "U", "L"}; for (const std::string & p: suffixes) { if (isPrefixStringCharLiteral(str, q, p)) diff --git a/test/testutils.cpp b/test/testutils.cpp index 230b220f4..bdc12b217 100644 --- a/test/testutils.cpp +++ b/test/testutils.cpp @@ -30,6 +30,8 @@ private: void run() override { TEST_CASE(isValidGlobPattern); TEST_CASE(matchglob); + TEST_CASE(isStringLiteral); + TEST_CASE(isCharLiteral); } void isValidGlobPattern() const { @@ -68,6 +70,114 @@ private: ASSERT_EQUALS(true, ::matchglob("?y?", "xyz")); ASSERT_EQUALS(true, ::matchglob("?/?/?", "x/y/z")); } + + void isStringLiteral() const { + // empty + ASSERT_EQUALS(false, ::isStringLiteral("")); + + // no literals + ASSERT_EQUALS(false, ::isStringLiteral("u8")); + ASSERT_EQUALS(false, ::isStringLiteral("u")); + ASSERT_EQUALS(false, ::isStringLiteral("U")); + ASSERT_EQUALS(false, ::isStringLiteral("L")); + + // incomplete string literals + ASSERT_EQUALS(false, ::isStringLiteral("\"")); + ASSERT_EQUALS(false, ::isStringLiteral("u8\"")); + ASSERT_EQUALS(false, ::isStringLiteral("u\"")); + ASSERT_EQUALS(false, ::isStringLiteral("U\"")); + ASSERT_EQUALS(false, ::isStringLiteral("L\"")); + + // valid string literals + ASSERT_EQUALS(true, ::isStringLiteral("\"\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u8\"\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u\"\"")); + ASSERT_EQUALS(true, ::isStringLiteral("U\"\"")); + ASSERT_EQUALS(true, ::isStringLiteral("L\"\"")); + ASSERT_EQUALS(true, ::isStringLiteral("\"t\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u8\"t\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u\"t\"")); + ASSERT_EQUALS(true, ::isStringLiteral("U\"t\"")); + ASSERT_EQUALS(true, ::isStringLiteral("L\"t\"")); + ASSERT_EQUALS(true, ::isStringLiteral("\"test\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u8\"test\"")); + ASSERT_EQUALS(true, ::isStringLiteral("u\"test\"")); + ASSERT_EQUALS(true, ::isStringLiteral("U\"test\"")); + ASSERT_EQUALS(true, ::isStringLiteral("L\"test\"")); + + // incomplete char literals + ASSERT_EQUALS(false, ::isStringLiteral("'")); + ASSERT_EQUALS(false, ::isStringLiteral("u8'")); + ASSERT_EQUALS(false, ::isStringLiteral("u'")); + ASSERT_EQUALS(false, ::isStringLiteral("U'")); + ASSERT_EQUALS(false, ::isStringLiteral("L'")); + + // valid char literals + ASSERT_EQUALS(false, ::isStringLiteral("'t'")); + ASSERT_EQUALS(false, ::isStringLiteral("u8't'")); + ASSERT_EQUALS(false, ::isStringLiteral("u't'")); + ASSERT_EQUALS(false, ::isStringLiteral("U't'")); + ASSERT_EQUALS(false, ::isStringLiteral("L't'")); + ASSERT_EQUALS(false, ::isStringLiteral("'test'")); + ASSERT_EQUALS(false, ::isStringLiteral("u8'test'")); + ASSERT_EQUALS(false, ::isStringLiteral("u'test'")); + ASSERT_EQUALS(false, ::isStringLiteral("U'test'")); + ASSERT_EQUALS(false, ::isStringLiteral("L'test'")); + } + + void isCharLiteral() const { + // empty + ASSERT_EQUALS(false, ::isCharLiteral("")); + + // no literals + ASSERT_EQUALS(false, ::isCharLiteral("u8")); + ASSERT_EQUALS(false, ::isCharLiteral("u")); + ASSERT_EQUALS(false, ::isCharLiteral("U")); + ASSERT_EQUALS(false, ::isCharLiteral("L")); + + // incomplete string literals + ASSERT_EQUALS(false, ::isCharLiteral("\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u8\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u\"")); + ASSERT_EQUALS(false, ::isCharLiteral("U\"")); + ASSERT_EQUALS(false, ::isCharLiteral("L\"")); + + // valid string literals + ASSERT_EQUALS(false, ::isCharLiteral("\"\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u8\"\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u\"\"")); + ASSERT_EQUALS(false, ::isCharLiteral("U\"\"")); + ASSERT_EQUALS(false, ::isCharLiteral("L\"\"")); + ASSERT_EQUALS(false, ::isCharLiteral("\"t\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u8\"t\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u\"t\"")); + ASSERT_EQUALS(false, ::isCharLiteral("U\"t\"")); + ASSERT_EQUALS(false, ::isCharLiteral("L\"t\"")); + ASSERT_EQUALS(false, ::isCharLiteral("\"test\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u8\"test\"")); + ASSERT_EQUALS(false, ::isCharLiteral("u\"test\"")); + ASSERT_EQUALS(false, ::isCharLiteral("U\"test\"")); + ASSERT_EQUALS(false, ::isCharLiteral("L\"test\"")); + + // incomplete char literals + ASSERT_EQUALS(false, ::isCharLiteral("'")); + ASSERT_EQUALS(false, ::isCharLiteral("u8'")); + ASSERT_EQUALS(false, ::isCharLiteral("u'")); + ASSERT_EQUALS(false, ::isCharLiteral("U'")); + ASSERT_EQUALS(false, ::isCharLiteral("L'")); + + // valid char literals + ASSERT_EQUALS(true, ::isCharLiteral("'t'")); + ASSERT_EQUALS(true, ::isCharLiteral("u8't'")); + ASSERT_EQUALS(true, ::isCharLiteral("u't'")); + ASSERT_EQUALS(true, ::isCharLiteral("U't'")); + ASSERT_EQUALS(true, ::isCharLiteral("L't'")); + ASSERT_EQUALS(true, ::isCharLiteral("'test'")); + ASSERT_EQUALS(true, ::isCharLiteral("u8'test'")); + ASSERT_EQUALS(true, ::isCharLiteral("u'test'")); + ASSERT_EQUALS(true, ::isCharLiteral("U'test'")); + ASSERT_EQUALS(true, ::isCharLiteral("L'test'")); + } }; REGISTER_TEST(TestUtils)