diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9af60ffb1..10acc1fb8 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4755,6 +4755,9 @@ bool Tokenizer::simplifyTokenList() modified |= simplifyCalculations(); } + // simplify redundant for + removeRedundantFor(); + // Remove redundant parentheses in return.. for (Token *tok = _tokens; tok; tok = tok->next()) { @@ -5004,6 +5007,105 @@ bool Tokenizer::removeReduntantConditions() return ret; } +void Tokenizer::removeRedundantFor() +{ + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] for ( %var% = %num% ; %var% < %num% ; ++| %var% ++| ) {")) + { + // Same variable name.. + const std::string varname(tok->tokAt(3)->str()); + const unsigned int varid(tok->tokAt(3)->varId()); + if (varname != tok->tokAt(7)->str()) + continue; + const Token *vartok = tok->tokAt(11); + if (vartok->str() == "++") + vartok = vartok->next(); + if (varname != vartok->str()) + continue; + + // Check that the difference of the numeric values is 1 + const MathLib::bigint num1(MathLib::toLongNumber(tok->strAt(5))); + const MathLib::bigint num2(MathLib::toLongNumber(tok->strAt(9))); + if (num1 + 1 != num2) + continue; + + // check how loop variable is used in loop.. + bool read = false; + bool write = false; + unsigned int indentlevel = 0; + for (const Token *tok2 = tok->tokAt(2)->link(); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + ++indentlevel; + else if (tok2->str() == "}") + { + if (indentlevel <= 1) + break; + --indentlevel; + } + + if (tok2->str() == varname) + { + if (tok2->previous()->isArithmeticalOp() && + tok2->next() && + (tok2->next()->isArithmeticalOp() || tok2->next()->str() == ";")) + { + read = true; + } + else + { + read = write = true; + break; + } + } + } + + // Simplify loop if loop variable isn't written + if (!write) + { + // remove "for (" + tok->deleteNext(); + tok->deleteNext(); + + // If loop variable is read then keep assignment before + // loop body.. + if (read) + { + // goto ";" + tok = tok->tokAt(4); + } + else + { + // remove "x = 0 ;" + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + } + + // remove "x < 1 ; x ++ )" + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + tok->deleteNext(); + + // Add assignment after the loop body so the loop variable + // get the correct end value + Token *tok2 = tok->next()->link(); + tok2->insertToken(";"); + tok2->insertToken(MathLib::toString(num2)); + tok2->insertToken("="); + tok2->insertToken(varname); + tok2->next()->varId(varid); + } + } + } +} + void Tokenizer::removeRedundantSemicolons() { diff --git a/lib/tokenize.h b/lib/tokenize.h index 94a37c0c7..2573bd5f0 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -359,6 +359,13 @@ public: */ bool removeReduntantConditions(); + /** + * Remove redundant for: + * "for (x=0;x<1;x++) { }" => "{ x = 1; }" + */ + void removeRedundantFor(); + + /** * Reduces "; ;" to ";", except in "( ; ; )" */ diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index a34f70d62..68b30e749 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -376,6 +376,11 @@ private: TEST_CASE(simplifyVarDecl1); // ticket # 2682 segmentation fault TEST_CASE(simplifyVarDecl2); // ticket # 2834 segmentation fault TEST_CASE(return_strncat); // ticket # 2860 Returning value of strncat() reported as memory leak + + // #3069 : for loop with 1 iteration + // for (x=0;x<1;x++) { .. } + // The for is redundant + TEST_CASE(removeRedundantFor); } std::string tok(const char code[], bool simplify = true) @@ -7385,6 +7390,27 @@ private: "return temp ; " "}", tok(code, true)); } + + void removeRedundantFor() // ticket #3069 + { + { + const char code[] = "void f() {" + " for(x=0;x<1;x++) {" + " y = 1;" + " }" + "}"; + ASSERT_EQUALS("void f ( ) { { y = 1 ; } x = 1 ; }", tok(code, true)); + } + + { + const char code[] = "void f() {" + " for(x=0;x<1;x++) {" + " y = 1 + x;" + " }" + "}"; + ASSERT_EQUALS("void f ( ) { x = 0 ; { y = 1 + x ; } x = 1 ; }", tok(code, true)); + } + } }; REGISTER_TEST(TestSimplifyTokens)