diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f5838dbcc..6e5589042 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -125,6 +125,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) else if (std::strcmp(argv[i], "--debug-fp") == 0) _settings->debugFalsePositive = true; + // Experimental AST handling + else if (std::strcmp(argv[i], "--ast") == 0) + _settings->ast = true; + // Inconclusive checking (still in testing phase) else if (std::strcmp(argv[i], "--inconclusive") == 0) _settings->inconclusive = true; diff --git a/lib/settings.cpp b/lib/settings.cpp index 89faedc54..56f714dba 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -26,7 +26,7 @@ Settings::Settings() : _terminate(false), debug(false), debugwarnings(false), debugFalsePositive(false), - inconclusive(false), experimental(false), + ast(false), inconclusive(false), experimental(false), _errorsOnly(false), _inlineSuppressions(false), _verbose(false), diff --git a/lib/settings.h b/lib/settings.h index 23d02651e..eafaa0994 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -62,6 +62,9 @@ public: /** @brief Is --debug-fp given? */ bool debugFalsePositive; + /** @brief Experimental AST handling */ + bool ast; + /** @brief Inconclusive checks */ bool inconclusive; diff --git a/lib/token.cpp b/lib/token.cpp index 3c1b26527..26811549d 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1166,13 +1166,30 @@ void Token::astHandleParentheses() innerTop = innerTop->_astParent; if (_astParent) { - if (_str == "(" && _astParent->_astOperand2 != NULL) + if (_astParent->_astOperand2 == this) _astParent->_astOperand2 = innerTop; - else + else if (_astParent->_astOperand1 == this) _astParent->_astOperand1 = innerTop; innerTop->_astParent = _astParent; - } else { - _astParent = innerTop; + _astParent = NULL; } } + +void Token::printAst() const +{ + bool title = false; + + bool print = true; + for (const Token *tok = this; tok; tok = tok->next()) { + if (print && tok->_astOperand1) { + if (!title) + std::cout << "\n\n##AST" << std::endl; + title = true; + std::cout << tok->astTop()->astString(" ") << std::endl; + print = false; + } + if (Token::Match(tok, "[;{}]")) + print = true; + } +} diff --git a/lib/token.h b/lib/token.h index 86e8ab084..e6e24741d 100644 --- a/lib/token.h +++ b/lib/token.h @@ -671,14 +671,16 @@ public: return ret; } - std::string astString() const { + std::string astString(const char *sep = "") const { std::string ret; if (_astOperand1) - ret = _astOperand1->astString(); + ret = _astOperand1->astString(sep); if (_astOperand2) - ret += _astOperand2->astString(); - return ret+_str; + ret += _astOperand2->astString(sep); + return ret + sep + _str; } + + void printAst() const; }; /// @} diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 18236c602..d61b06f21 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3645,6 +3645,12 @@ bool Tokenizer::simplifyTokenList() tok->deleteNext(); } + // Experimental AST handling. Only for C code now since + // uninstantiated C++ templates are not handled well. Fix + // TestTokenize::asttemplate + if (_settings->ast && isC()) + list.createAst(); + if (_settings->terminated()) return false; @@ -3653,6 +3659,9 @@ bool Tokenizer::simplifyTokenList() if (_settings->_verbose) _symbolDatabase->printOut("Symbol database"); + + if (_settings->ast) + list.front()->printAst(); } if (_settings->debugwarnings) { diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index d9b172126..635836ed4 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -392,7 +392,7 @@ void TokenList::createAst() const while (tok->next()) tok = tok->next(); for (; tok; tok = tok->previous()) { - if ((!tok->previous() || tok->previous()->isOp()) && + if (tok->isOp() && (!tok->previous() || tok->previous()->isOp() || tok->previous()->type() == Token::eOther) && op.find(" "+tok->str()+" ")!=std::string::npos) { tok->astOperand1(tok->next()); } @@ -401,6 +401,13 @@ void TokenList::createAst() const const std::string op(operators[i]); for (Token *tok = _front; tok; tok = tok->next()) { if (tok->astOperand1()==NULL && op.find(" "+tok->str()+" ")!=std::string::npos) { + // Don't create AST for "..." + if (tok->str() == "." && (tok->previous()->str() == "." || tok->next()->str() == ".")) + continue; + + if (Token::Match(tok, "* [)]]")) + continue; + if (tok->type() != Token::eIncDecOp) { tok->astOperand1(tok->previous()); tok->astOperand2(tok->next()); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index bb6609d8b..1d7624f91 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -9929,7 +9929,13 @@ private: // Create AST.. tokenList.createAst(); - return tokenList.front()->astTop()->astString(); + for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { + if (tok->astOperand1()) + return tok->astTop()->astString(); + } + + // No AST found + return ""; } void astexpr() const { // simple expressions with arithmetical ops