diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index cd55145b9..9c63d6de3 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -687,6 +687,58 @@ static void compileExpression(Token *&tok, std::stack &op) void TokenList::createAst() { for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) { + if (Token::simpleMatch(tok,"for (")) { + std::stack operands; + Token *tok2 = tok->tokAt(2); + Token *init1 = 0; + while (tok2 && tok2->str() != ";") { + if (tok2->str() == "<" && tok2->link()) { + tok2 = tok2->link(); + if (!tok2) + break; + } else if (Token::Match(tok2, "%var% %op%|(|[|.|=|::") || Token::Match(tok2->previous(), "[;{}] %cop%|(")) { + init1 = tok2; + compileExpression(tok2, operands); + if (tok2->str() == ";") + break; + init1 = 0; + } + tok2 = tok2->next(); + } + if (!tok2 || tok2->str() != ";") { + tok = tok->next(); + continue; + } + + Token * const init = init1 ? init1 : tok2; + + Token * const semicolon1 = tok2; + tok2 = tok2->next(); + compileExpression(tok2, operands); + + Token * const semicolon2 = tok2; + tok2 = tok2->next(); + compileExpression(tok2, operands); + + if (init != semicolon1) + semicolon1->astOperand1(init); + tok2 = semicolon1->next(); + while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber()) + tok2 = tok2->next(); + if (tok2 != semicolon2) + semicolon2->astOperand1(tok2); + tok2 = tok->linkAt(1); + while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber()) + tok2 = tok2->previous(); + if (tok2 != semicolon2) + semicolon2->astOperand2(tok2); + + semicolon1->astOperand2(semicolon2); + tok->next()->astOperand1(tok); + tok->next()->astOperand2(semicolon1); + + tok = tok->linkAt(1); + } if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|(")) { std::stack operands; compileExpression(tok, operands); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 51a70bd3b..1c081d0c8 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -159,33 +159,26 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog } // bailout: while-condition, variable is changed in while loop - for (const Token *tok2 = tok; tok2; tok2 = tok2->previous()) { - if (tok2->str() == ")") - tok2 = tok2->link(); + for (const Token *tok2 = tok; tok2; tok2 = tok2->astParent()) { + if (tok2->astParent() || tok2->str() != "(" || !Token::simpleMatch(tok2->link(), ") {")) + continue; - else if (tok2->str() == "(" && Token::simpleMatch(tok2->link(), ") {")) { - if (Token::Match(tok2->previous(), "for|while (")) { - const Token *start = tok2->link()->next(); - const Token *end = start->link(); - if (Token::findmatch(start,"++|--| %varid% ++|--|=",end,varid)) { - varid = 0U; - if (settings->debugwarnings) - bailout(tokenlist, errorLogger, tok, "variable " + var->nameToken()->str() + " used in loop"); - } - } - - // if,macro => bailout - else if (Token::simpleMatch(tok2->previous(), "if (") && tok2->previous()->isExpandedMacro()) { + if (Token::Match(tok2->previous(), "for|while (")) { + const Token *start = tok2->link()->next(); + const Token *end = start->link(); + if (Token::findmatch(start,"++|--| %varid% ++|--|=",end,varid)) { varid = 0U; if (settings->debugwarnings) - bailout(tokenlist, errorLogger, tok, "variable " + var->nameToken()->str() + ", condition is defined in macro"); + bailout(tokenlist, errorLogger, tok, "variable " + var->nameToken()->str() + " used in loop"); } - - break; } - else if (Token::Match(tok2, "[{}]")) - break; + // if,macro => bailout + else if (Token::simpleMatch(tok2->previous(), "if (") && tok2->previous()->isExpandedMacro()) { + varid = 0U; + if (settings->debugwarnings) + bailout(tokenlist, errorLogger, tok, "variable " + var->nameToken()->str() + ", condition is defined in macro"); + } } if (varid == 0U) continue; diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 445361ece..f8321a2d1 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -10098,6 +10098,10 @@ private: ASSERT_EQUALS("a0>bc/?d:", testAst("(a>0) ? (b/(c)) : d;")); ASSERT_EQUALS("abc/+d+", testAst("a + (b/(c)) + d;")); + + // for + ASSERT_EQUALS("for;;(", testAst("for(;;)")); + ASSERT_EQUALS("fora0=a8