diff --git a/lib/token.cpp b/lib/token.cpp index 9197668dc..a561ebe6c 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -535,6 +535,23 @@ bool Token::isStandardType() const return ret; } +void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation) +{ + /**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */ + + // Fix the gap, which tokens to be moved will leave + srcStart->previous()->next(srcEnd->next()); + srcEnd->next()->previous(srcStart->previous()); + + // Fix the tokens to be moved + srcEnd->next(newLocation->next()); + srcStart->previous(newLocation); + + // Fix the tokens at newLocation + newLocation->next()->previous(srcEnd); + newLocation->next(srcStart); +} + //--------------------------------------------------------------------------- const Token *Token::findmatch(const Token *tok, const char pattern[], unsigned int varId) diff --git a/lib/token.h b/lib/token.h index 34bd2ac60..cfe5ba0f1 100644 --- a/lib/token.h +++ b/lib/token.h @@ -274,6 +274,15 @@ public: */ std::string strValue() const; + /** + * Move srcStart and srcEnd tokens and all tokens between then + * into new a location. Only links between tokens are changed. + * @param srcStart This is the first token to be moved + * @param srcEnd The last token to be moved + * @param newLocation srcStart will be placed after this token. + */ + static void move(Token *srcStart, Token *srcEnd, Token *newLocation); + private: void next(Token *next) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 73b082552..a331415fb 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3983,9 +3983,6 @@ void Tokenizer::simplifyNestedStrcat() continue; } - // insert extracted function calls before first strcat call - Token *insertPos = tok; - // find inner strcat call Token *tok2 = tok->tokAt(3); while (Token::simpleMatch(tok2, "strcat ( strcat")) @@ -3993,52 +3990,21 @@ void Tokenizer::simplifyNestedStrcat() tok2 = tok2->tokAt(2); } - Token *end = tok2->next()->link()->next(); - Token *endOfFirstArg = NULL; - std::stack brackets; - unsigned int lineno = tok->next()->linenr(); + // If we have this code: + // strcat(strcat(dst, foo), bar); + // We move this part of code before all strcat() calls: strcat(dst, foo) + // And place "dst" token where the code was. + Token *prevTok = tok2->previous(); - // copy tokens to new place - for (Token *cur = tok2; cur != end; cur = cur->next()) - { - insertPos->insertToken(cur->strAt(0)); - insertPos = insertPos->next(); + // Move tokens to new place + Token::move(tok2, tok2->next()->link(), tok); + tok = tok2->next()->link(); - if (cur->str() == "," && endOfFirstArg == NULL) - { - endOfFirstArg = cur; - } + // Insert the "dst" token + prevTok->insertToken(tok2->strAt(2)); - // preserve varId - if (cur->varId()) - { - insertPos->varId(cur->varId()); - } - - // use line number of first strcat token for all new - // tokens - insertPos->linenr(lineno); - - // linkify braces - if (insertPos->str() == "(") - { - brackets.push(insertPos); - } - else if (insertPos->str() == ")") - { - Token::createMutualLinks(brackets.top(), insertPos); - brackets.pop(); - } - } - insertPos->insertToken(";"); - - // remove tokens at old place, but don't remove token with - // variable name (1st argument) - Token::eraseTokens(tok2->previous(), tok2->tokAt(2)); - Token::eraseTokens(endOfFirstArg->previous(), end); - - // skip just inserted tokens - tok = insertPos; + // Insert semicolon after the moved strcat() + tok->insertToken(";"); } } diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e9355d443..75cef138f 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -124,6 +124,7 @@ private: // Simplify nested strcat() calls TEST_CASE(strcat1); + TEST_CASE(strcat2); // Syntax error TEST_CASE(argumentsWithSameName) @@ -1940,6 +1941,15 @@ private: ASSERT_EQUALS(expect, tok(code)); } + void strcat2() + { + const char code[] = "; strcat(strcat(dst, foo[0]), \" \");"; + const char expect[] = "; " + "strcat ( dst , foo [ 0 ] ) ; " + "strcat ( dst , \" \" ) ;"; + + ASSERT_EQUALS(expect, tok(code)); + } void argumentsWithSameName() {