Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions lib/token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,29 +729,10 @@ nonneg int Token::getStrLength(const Token *tok)
assert(tok != nullptr);
assert(tok->mTokType == eString);

int len = 0;
// cppcheck-suppress shadowFunction - TODO: fix this
const std::string str(getStringLiteral(tok->str()));
std::string::const_iterator it = str.cbegin();
const std::string::const_iterator end = str.cend();

while (it != end) {
if (*it == '\\') {
++it;

// string ends at '\0'
if (*it == '0')
return len;
}

if (*it == '\0')
return len;

++it;
++len;
}
const std::string s(replaceEscapeSequences(getStringLiteral(tok->str())));

return len;
const auto pos = s.find('\0');
return pos < s.size() ? pos : s.size();
}

nonneg int Token::getStrArraySize(const Token *tok)
Expand Down
7 changes: 3 additions & 4 deletions lib/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,13 @@ class CPPCHECKLIB Token {

bool isCChar() const {
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', emptyString)) ||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && mStr.length() == 3) ||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && mStr.compare(0, 2, "\'\\") == 0 && mStr.length() == 4));
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && (replaceEscapeSequences(getCharLiteral(mStr)).size() == 1)));
}

bool isCMultiChar() const {
return (((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString)) && (mStr.compare(0, 2, "\'\\") != 0 || mStr.length() > 4) &&
(mStr.length() > 3));
return (mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', emptyString) && (replaceEscapeSequences(getCharLiteral(mStr)).size() > 1);
}

/**
* @brief Is current token a template argument?
*
Expand Down
37 changes: 37 additions & 0 deletions lib/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,40 @@ void findAndReplace(std::string &source, const std::string &searchFor, const std
index += replaceWith.length();
}
}

std::string replaceEscapeSequences(const std::string &source) {
std::string result;
result.reserve(source.size());
for (std::size_t i = 0; i < source.size(); ++i) {
if (source[i] != '\\' || i + 1 >= source.size())
result += source[i];
else {
++i;
if (source[i] == 'n') {
result += '\n';
} else if (source[i] == 'r') {
result += '\r';
} else if (source[i] == 't') {
result += '\t';
} else if (source[i] == 'x') {
std::string value = "0";
if (i + 1 < source.size() && std::isxdigit(source[i+1]))
value += source[i++ + 1];
if (i + 1 < source.size() && std::isxdigit(source[i+1]))
value += source[i++ + 1];
result += static_cast<char>(std::stoi(value, nullptr, 16));
} else if (source[i] == '0') {
std::string value = "0";
if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7')
value += source[i++ + 1];
if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7')
value += source[i++ + 1];
result += static_cast<char>(std::stoi(value, nullptr, 8));
} else {
result += source[i];
}
}
}
return result;
}

6 changes: 6 additions & 0 deletions lib/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@ CPPCHECKLIB std::string trim(const std::string& s, const std::string& t = " \t")
*/
CPPCHECKLIB void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith);

/**
* Replace all escape sequences in the given string.
* @param source The string that contains escape sequences
*/
CPPCHECKLIB std::string replaceEscapeSequences(const std::string &source);

namespace cppcheck
{
NORETURN inline void unreachable()
Expand Down
8 changes: 8 additions & 0 deletions test/testtoken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ class TestToken : public TestFixture {
ASSERT_EQUALS(false, tok.isUtf32());
ASSERT_EQUALS(false, tok.isLong());
ASSERT_EQUALS(true, tok.isCMultiChar());

tok.str("'\\x10'");
ASSERT_EQUALS(true, tok.isCChar());
ASSERT_EQUALS(false, tok.isUtf8());
ASSERT_EQUALS(false, tok.isUtf16());
ASSERT_EQUALS(false, tok.isUtf32());
ASSERT_EQUALS(false, tok.isLong());
ASSERT_EQUALS(false, tok.isCMultiChar());
}

void stringTypes() const {
Expand Down
11 changes: 11 additions & 0 deletions test/testutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class TestUtils : public TestFixture {
TEST_CASE(startsWith);
TEST_CASE(trim);
TEST_CASE(findAndReplace);
TEST_CASE(replaceEscapeSequences);
}

void isValidGlobPattern() const {
Expand Down Expand Up @@ -427,6 +428,16 @@ class TestUtils : public TestFixture {
ASSERT_EQUALS("", s);
}
}

void replaceEscapeSequences() const {
ASSERT_EQUALS("\x30", ::replaceEscapeSequences("\\x30"));
ASSERT_EQUALS("\030", ::replaceEscapeSequences("\\030"));
ASSERT_EQUALS("\r", ::replaceEscapeSequences("\\r"));
ASSERT_EQUALS("\n", ::replaceEscapeSequences("\\n"));
ASSERT_EQUALS("\t", ::replaceEscapeSequences("\\t"));
ASSERT_EQUALS("\\", ::replaceEscapeSequences("\\\\"));
ASSERT_EQUALS("\"", ::replaceEscapeSequences("\\\""));
}
};

REGISTER_TEST(TestUtils)