Fixed #4481 (Simplify %str% [ %num% ])
This commit is contained in:
parent
f0ce26a2aa
commit
723d95597b
|
@ -741,6 +741,34 @@ std::size_t Token::getStrLength(const Token *tok)
|
|||
return len;
|
||||
}
|
||||
|
||||
std::string Token::getCharAt(const Token *tok, std::size_t index)
|
||||
{
|
||||
assert(tok != NULL);
|
||||
|
||||
const std::string strValue(tok->strValue());
|
||||
const char *str = strValue.c_str();
|
||||
|
||||
while (*str) {
|
||||
if (index == 0) {
|
||||
std::string ret;
|
||||
if (*str == '\\') {
|
||||
ret = *str;
|
||||
++str;
|
||||
}
|
||||
ret += *str;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (*str == '\\')
|
||||
++str;
|
||||
++str;
|
||||
--index;
|
||||
}
|
||||
assert(index == 0);
|
||||
|
||||
return "\\0";
|
||||
}
|
||||
|
||||
void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation)
|
||||
{
|
||||
/**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */
|
||||
|
|
10
lib/token.h
10
lib/token.h
|
@ -178,6 +178,16 @@ public:
|
|||
**/
|
||||
static std::size_t getStrLength(const Token *tok);
|
||||
|
||||
/**
|
||||
* Return char of C-string at index (possible escaped "\\n")
|
||||
*
|
||||
* Should be called for %str% tokens only.
|
||||
*
|
||||
* @param tok token with C-string
|
||||
* @param index position of character
|
||||
**/
|
||||
static std::string getCharAt(const Token *tok, std::size_t index);
|
||||
|
||||
Type type() const {
|
||||
return _type;
|
||||
}
|
||||
|
|
|
@ -3244,6 +3244,8 @@ bool Tokenizer::simplifyTokenList()
|
|||
// clear the _functionList so it can't contain dead pointers
|
||||
deleteSymbolDatabase();
|
||||
|
||||
simplifyCharAt();
|
||||
|
||||
// simplify references
|
||||
simplifyReference();
|
||||
|
||||
|
@ -6661,6 +6663,21 @@ bool Tokenizer::simplifyRedundantParenthesis()
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyCharAt()
|
||||
{
|
||||
// Replace "string"[0] with 's'
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%str% [ %num% ]")) {
|
||||
const MathLib::bigint index = MathLib::toLongNumber(tok->tokAt(2)->str());
|
||||
// Check within range
|
||||
if (index >= 0 && index <= (MathLib::bigint)Token::getStrLength(tok)) {
|
||||
tok->str(std::string("'" + Token::getCharAt(tok, (size_t)index) + "'"));
|
||||
tok->deleteNext(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyReference()
|
||||
{
|
||||
if (isC())
|
||||
|
|
|
@ -400,6 +400,8 @@ public:
|
|||
*/
|
||||
bool simplifyRedundantParenthesis();
|
||||
|
||||
void simplifyCharAt();
|
||||
|
||||
/** Simplify references */
|
||||
void simplifyReference();
|
||||
|
||||
|
|
|
@ -433,6 +433,7 @@ private:
|
|||
TEST_CASE(undefinedSizeArray);
|
||||
|
||||
TEST_CASE(simplifyArrayAddress); // Replace "&str[num]" => "(str + num)"
|
||||
TEST_CASE(simplifyCharAt);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Unspecified) {
|
||||
|
@ -8046,6 +8047,18 @@ private:
|
|||
// Don't crash
|
||||
tok("int", true);
|
||||
}
|
||||
|
||||
void simplifyCharAt() { // ticket #4481
|
||||
ASSERT_EQUALS("'h' ;", tok("\"hello\"[0] ;"));
|
||||
ASSERT_EQUALS("'\n' ;", tok("\"\n\"[0] ;"));
|
||||
ASSERT_EQUALS("'\\0' ;", tok("\"hello\"[5] ;"));
|
||||
ASSERT_EQUALS("'\\0' ;", tok("\"\"[0] ;"));
|
||||
ASSERT_EQUALS("'\\0' ;", tok("\"\\0\"[0] ;"));
|
||||
ASSERT_EQUALS("'\\n' ;", tok("\"hello\\nworld\"[5] ;"));
|
||||
ASSERT_EQUALS("'w' ;", tok("\"hello\nworld\"[6] ;"));
|
||||
ASSERT_EQUALS("\"hello\" [ 7 ] ;", tok("\"hello\"[7] ;"));
|
||||
ASSERT_EQUALS("\"hello\" [ -1 ] ;", tok("\"hello\"[-1] ;"));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyTokens)
|
||||
|
|
Loading…
Reference in New Issue