Fixed #5406 (crash inside valueFlowBeforeCondition() on files from kernel-git)
This commit is contained in:
parent
2b8cf462c9
commit
c8a1424e10
|
@ -686,72 +686,92 @@ static void compileExpression(Token *&tok, std::stack<Token*> &op)
|
|||
compileComma(tok,op);
|
||||
}
|
||||
|
||||
static Token * createAstAtToken(Token *tok)
|
||||
{
|
||||
if (Token::simpleMatch(tok,"for (")) {
|
||||
Token *tok2 = tok->tokAt(2);
|
||||
Token *init1 = 0;
|
||||
const Token * const endPar = tok->next()->link();
|
||||
while (tok2 && tok2 != endPar && 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;
|
||||
std::stack<Token *> operands;
|
||||
compileExpression(tok2, operands);
|
||||
if (tok2->str() == ";" || tok2->str() == ")")
|
||||
break;
|
||||
init1 = 0;
|
||||
}
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
if (!tok2 || tok2->str() != ";") {
|
||||
if (tok2 == endPar && init1) {
|
||||
tok->next()->astOperand2(init1);
|
||||
tok->next()->astOperand1(tok);
|
||||
}
|
||||
return tok2;
|
||||
}
|
||||
|
||||
Token * const init = init1 ? init1 : tok2;
|
||||
|
||||
Token * const semicolon1 = tok2;
|
||||
tok2 = tok2->next();
|
||||
std::stack<Token *> operands2;
|
||||
compileExpression(tok2, operands2);
|
||||
|
||||
Token * const semicolon2 = tok2;
|
||||
tok2 = tok2->next();
|
||||
std::stack<Token *> operands3;
|
||||
compileExpression(tok2, operands3);
|
||||
|
||||
if (init != semicolon1)
|
||||
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
|
||||
tok2 = semicolon1->next();
|
||||
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
|
||||
tok2 = tok2->next();
|
||||
if (tok2 != semicolon2)
|
||||
semicolon2->astOperand1(const_cast<Token*>(tok2->astTop()));
|
||||
tok2 = tok->linkAt(1);
|
||||
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
|
||||
tok2 = tok2->previous();
|
||||
if (tok2 != semicolon2)
|
||||
semicolon2->astOperand2(const_cast<Token*>(tok2->astTop()));
|
||||
|
||||
semicolon1->astOperand2(semicolon2);
|
||||
tok->next()->astOperand1(tok);
|
||||
tok->next()->astOperand2(semicolon1);
|
||||
|
||||
return tok->linkAt(1);
|
||||
}
|
||||
|
||||
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) {
|
||||
std::stack<Token *> operands;
|
||||
Token * const tok1 = tok;
|
||||
compileExpression(tok, operands);
|
||||
Token * const endToken = tok;
|
||||
|
||||
// Compile inner expressions inside inner ({..})
|
||||
for (tok = tok1; tok && tok != endToken; tok = tok ? tok->next() : NULL) {
|
||||
if (!Token::simpleMatch(tok, "( {"))
|
||||
continue;
|
||||
const Token * const endToken2 = tok->linkAt(1);
|
||||
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : NULL)
|
||||
tok = createAstAtToken(tok);
|
||||
}
|
||||
|
||||
return endToken ? endToken->previous() : NULL;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
void TokenList::createAst()
|
||||
{
|
||||
for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) {
|
||||
if (Token::simpleMatch(tok,"for (")) {
|
||||
Token *tok2 = tok->tokAt(2);
|
||||
Token *init1 = 0;
|
||||
const Token * const endPar = tok->next()->link();
|
||||
while (tok2 && tok2 != endPar && 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;
|
||||
std::stack<Token *> operands;
|
||||
compileExpression(tok2, operands);
|
||||
if (tok2->str() == ";" || tok2->str() == ")")
|
||||
break;
|
||||
init1 = 0;
|
||||
}
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
if (!tok2 || tok2->str() != ";") {
|
||||
if (tok2 == endPar && init1) {
|
||||
tok->next()->astOperand2(init1);
|
||||
tok->next()->astOperand1(tok);
|
||||
}
|
||||
tok = tok2;
|
||||
continue;
|
||||
}
|
||||
|
||||
Token * const init = init1 ? init1 : tok2;
|
||||
|
||||
Token * const semicolon1 = tok2;
|
||||
tok2 = tok2->next();
|
||||
std::stack<Token *> operands2;
|
||||
compileExpression(tok2, operands2);
|
||||
|
||||
Token * const semicolon2 = tok2;
|
||||
tok2 = tok2->next();
|
||||
std::stack<Token *> operands3;
|
||||
compileExpression(tok2, operands3);
|
||||
|
||||
if (init != semicolon1)
|
||||
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
|
||||
tok2 = semicolon1->next();
|
||||
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
|
||||
tok2 = tok2->next();
|
||||
if (tok2 != semicolon2)
|
||||
semicolon2->astOperand1(const_cast<Token*>(tok2->astTop()));
|
||||
tok2 = tok->linkAt(1);
|
||||
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
|
||||
tok2 = tok2->previous();
|
||||
if (tok2 != semicolon2)
|
||||
semicolon2->astOperand2(const_cast<Token*>(tok2->astTop()));
|
||||
|
||||
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<Token *> operands;
|
||||
compileExpression(tok, operands);
|
||||
}
|
||||
tok = createAstAtToken(tok);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10065,13 +10065,18 @@ private:
|
|||
// Create AST..
|
||||
tokenList.createAst();
|
||||
|
||||
// Return stringified AST
|
||||
std::string ret;
|
||||
std::set<const Token *> astTop;
|
||||
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
|
||||
if (tok->astOperand1())
|
||||
return tok->astTop()->astString();
|
||||
if (tok->astOperand1() && astTop.find(tok->astTop()) == astTop.end()) {
|
||||
astTop.insert(tok->astTop());
|
||||
if (!ret.empty())
|
||||
ret = ret + " ";
|
||||
ret += tok->astTop()->astString();
|
||||
}
|
||||
}
|
||||
|
||||
// No AST found
|
||||
return "";
|
||||
return ret;
|
||||
}
|
||||
|
||||
void astexpr() const { // simple expressions with arithmetical ops
|
||||
|
@ -10108,6 +10113,11 @@ private:
|
|||
TODO_ASSERT_EQUALS("fori1=current0=,iNUM<=i++;;(", "fori1=current0=,i<NUM=i++;;(", testAst("for(i = (1), current = 0; i <= (NUM); ++i)"));
|
||||
ASSERT_EQUALS("foreachxy,((", testAst("for(each(x,y)){}")); // it's not well-defined what this ast should be
|
||||
ASSERT_EQUALS("forab:(", testAst("for (int a : b);"));
|
||||
|
||||
// problems with multiple expressions
|
||||
ASSERT_EQUALS("ax( whilex(", testAst("a(x) while (x)"));
|
||||
ASSERT_EQUALS("ifx( i0= whilei(", testAst("if (x) { ({ int i = 0; while(i); }) };"));
|
||||
ASSERT_EQUALS("ifx( BUG_ON{!( i0= whilei(", testAst("if (x) { BUG_ON(!({int i=0; while(i);})); }"));
|
||||
}
|
||||
|
||||
void astpar() const { // parentheses
|
||||
|
@ -10126,8 +10136,8 @@ private:
|
|||
ASSERT_EQUALS("ab::r&c(=", testAst("a::b& r = (a::b&)c;")); // #5261
|
||||
|
||||
// ({..})
|
||||
ASSERT_EQUALS("a{+d+", testAst("a+({b+c;})+d"));
|
||||
ASSERT_EQUALS("a{d*+", testAst("a+({b+c;})*d"));
|
||||
ASSERT_EQUALS("a{+d+ bc+", testAst("a+({b+c;})+d"));
|
||||
ASSERT_EQUALS("a{d*+ bc+", testAst("a+({b+c;})*d"));
|
||||
}
|
||||
|
||||
void astbrackets() const { // []
|
||||
|
@ -10162,7 +10172,7 @@ private:
|
|||
|
||||
void asttemplate() const { // uninstantiated templates will have <,>,etc..
|
||||
ASSERT_EQUALS("a(3==", testAst("a<int>()==3"));
|
||||
ASSERT_EQUALS("ab(==", testAst("a == b<c>(); f();"));
|
||||
ASSERT_EQUALS("ab(== f(", testAst("a == b<c>(); f();"));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue