Fixed #5982 (Add xml dump)
This commit is contained in:
parent
bf5b4d9ece
commit
8db5836e3f
|
@ -134,6 +134,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
||||||
else if (std::strcmp(argv[i], "--debug-fp") == 0)
|
else if (std::strcmp(argv[i], "--debug-fp") == 0)
|
||||||
_settings->debugFalsePositive = true;
|
_settings->debugFalsePositive = true;
|
||||||
|
|
||||||
|
// dump cppcheck data
|
||||||
|
else if (std::strcmp(argv[i], "--dump") == 0)
|
||||||
|
_settings->dump = true;
|
||||||
|
|
||||||
// (Experimental) exception handling inside cppcheck client
|
// (Experimental) exception handling inside cppcheck client
|
||||||
else if (std::strcmp(argv[i], "--exception-handling") == 0)
|
else if (std::strcmp(argv[i], "--exception-handling") == 0)
|
||||||
_settings->exceptionHandling = true;
|
_settings->exceptionHandling = true;
|
||||||
|
@ -843,6 +847,9 @@ void CmdLineParser::PrintHelp()
|
||||||
" analysis is disabled by this flag.\n"
|
" analysis is disabled by this flag.\n"
|
||||||
" --check-library Show information messages when library files have\n"
|
" --check-library Show information messages when library files have\n"
|
||||||
" incomplete info.\n"
|
" incomplete info.\n"
|
||||||
|
" --dump Dump xml data for each translation unit. The dump\n"
|
||||||
|
" files have the extension .dump and contain ast,\n"
|
||||||
|
" tokenlist, symboldatabase, valueflow.\n"
|
||||||
" -D<ID> Define preprocessor symbol. Unless --max-configs or\n"
|
" -D<ID> Define preprocessor symbol. Unless --max-configs or\n"
|
||||||
" --force is used, Cppcheck will only check the given\n"
|
" --force is used, Cppcheck will only check the given\n"
|
||||||
" configuration when -D is used.\n"
|
" configuration when -D is used.\n"
|
||||||
|
|
|
@ -363,6 +363,19 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dump
|
||||||
|
if (_settings.dump) {
|
||||||
|
std::string dumpfile = std::string(FileName) + ".dump";
|
||||||
|
std::ofstream fdump(dumpfile.c_str());
|
||||||
|
if (fdump.is_open()) {
|
||||||
|
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
||||||
|
fdump << "<dump cfg=\"" << cfg << "\">" << std::endl;
|
||||||
|
_tokenizer.dump(fdump);
|
||||||
|
fdump << "</dump>" << std::endl;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// call all "runChecks" in all registered Check classes
|
// call all "runChecks" in all registered Check classes
|
||||||
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
|
|
|
@ -25,7 +25,11 @@
|
||||||
|
|
||||||
Settings::Settings()
|
Settings::Settings()
|
||||||
: _terminate(false),
|
: _terminate(false),
|
||||||
debug(false), debugwarnings(false), debugFalsePositive(false), exceptionHandling(false),
|
debug(false),
|
||||||
|
debugwarnings(false),
|
||||||
|
debugFalsePositive(false),
|
||||||
|
dump(false),
|
||||||
|
exceptionHandling(false),
|
||||||
inconclusive(false), experimental(false),
|
inconclusive(false), experimental(false),
|
||||||
_errorsOnly(false),
|
_errorsOnly(false),
|
||||||
_inlineSuppressions(false),
|
_inlineSuppressions(false),
|
||||||
|
|
|
@ -63,6 +63,9 @@ public:
|
||||||
/** @brief Is --debug-fp given? */
|
/** @brief Is --debug-fp given? */
|
||||||
bool debugFalsePositive;
|
bool debugFalsePositive;
|
||||||
|
|
||||||
|
/** @brief Is --dump given? */
|
||||||
|
bool dump;
|
||||||
|
|
||||||
/** @brief Is --exception-handling given */
|
/** @brief Is --exception-handling given */
|
||||||
bool exceptionHandling;
|
bool exceptionHandling;
|
||||||
|
|
||||||
|
|
|
@ -2074,18 +2074,62 @@ void SymbolDatabase::printOut(const char *title) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolDatabase::printXml() const
|
void SymbolDatabase::printXml(std::ostream &out) const
|
||||||
{
|
{
|
||||||
// Scopes..
|
// Scopes..
|
||||||
|
out << " <scopes>" << std::endl;
|
||||||
for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
|
for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
|
||||||
std::cout << "<scope";
|
out << " <scope";
|
||||||
std::cout << " id=\"" << &*scope << "\"";
|
out << " id=\"" << &*scope << "\"";
|
||||||
std::cout << " type=\"" << scope->type << "\"";
|
out << " type=\"" << scope->type << "\"";
|
||||||
if (!scope->className.empty())
|
if (!scope->className.empty())
|
||||||
std::cout << " className=\"" << scope->className << "\"";
|
out << " className=\"" << scope->className << "\"";
|
||||||
std::cout << " nestedIn=\"" << scope->nestedIn << "\"";
|
if (scope->nestedIn)
|
||||||
std::cout << "/>" << std::endl;
|
out << " nestedIn=\"" << scope->nestedIn << "\"";
|
||||||
|
if (scope->functionList.empty() && scope->varlist.empty()) {
|
||||||
|
out << "/>" << std::endl;
|
||||||
|
} else {
|
||||||
|
out << '>' << std::endl;
|
||||||
|
if (!scope->functionList.empty()) {
|
||||||
|
out << " <functionList>" << std::endl;
|
||||||
|
for (std::list<Function>::const_iterator function = scope->functionList.begin(); function != scope->functionList.end(); ++function) {
|
||||||
|
out << " <function id=\"" << &*function << '\"';
|
||||||
|
if (function->argCount() == 0U)
|
||||||
|
out << "/>" << std::endl;
|
||||||
|
else {
|
||||||
|
out << ">" << std::endl;
|
||||||
|
for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
|
||||||
|
const Variable *arg = function->getArgumentVar(argnr);
|
||||||
|
out << " <arg nr=\"" << argnr << "\" variable=\"" << arg << "\"/>" << std::endl;
|
||||||
}
|
}
|
||||||
|
out << " </function>" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << " </functionList>" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!scope->varlist.empty()) {
|
||||||
|
out << " <varlist>" << std::endl;
|
||||||
|
for (std::list<Variable>::const_iterator var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
|
||||||
|
out << " <var id=\"" << &*var << '\"';
|
||||||
|
out << " nameToken=\"" << var->nameToken() << '\"';
|
||||||
|
out << " typeStartToken=\"" << var->typeStartToken() << '\"';
|
||||||
|
out << " typeEndToken=\"" << var->typeEndToken() << '\"';
|
||||||
|
out << " typeEndToken=\"" << var->typeEndToken() << '\"';
|
||||||
|
out << " isArgument=\"" << (var->isArgument() ? "true" : "false") << '\"';
|
||||||
|
out << " isArray=\"" << (var->isArray() ? "true" : "false") << '\"';
|
||||||
|
out << " isClass=\"" << (var->isClass() ? "true" : "false") << '\"';
|
||||||
|
out << " isLocal=\"" << (var->isLocal() ? "true" : "false") << '\"';
|
||||||
|
out << " isPointer=\"" << (var->isPointer() ? "true" : "false") << '\"';
|
||||||
|
out << " isReference=\"" << (var->isReference() ? "true" : "false") << '\"';
|
||||||
|
out << " isStatic=\"" << (var->isStatic() ? "true" : "false") << '\"';
|
||||||
|
out << "/>" << std::endl;
|
||||||
|
}
|
||||||
|
out << " </varlist>" << std::endl;
|
||||||
|
}
|
||||||
|
out << " </scope>" << std::endl;
|
||||||
|
}
|
||||||
|
out << " </scopes>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -839,7 +839,7 @@ public:
|
||||||
|
|
||||||
void printOut(const char * title = NULL) const;
|
void printOut(const char * title = NULL) const;
|
||||||
void printVariable(const Variable *var, const char *indent) const;
|
void printVariable(const Variable *var, const char *indent) const;
|
||||||
void printXml() const;
|
void printXml(std::ostream &out) const;
|
||||||
|
|
||||||
bool isCPP() const;
|
bool isCPP() const;
|
||||||
|
|
||||||
|
|
|
@ -1083,28 +1083,35 @@ std::string Token::expressionString() const
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string astStringXml(const Token *tok, std::size_t indent)
|
static void astStringXml(const Token *tok, std::size_t indent, std::ostream &out)
|
||||||
{
|
{
|
||||||
const std::string strindent(indent, ' ');
|
const std::string strindent(indent, ' ');
|
||||||
|
|
||||||
if (!tok->astOperand1() && !tok->astOperand2()) {
|
out << strindent << "<token str=\"" << tok->str() << '\"';
|
||||||
std::ostringstream ret;
|
|
||||||
ret << strindent << "<token text=\"" << tok->str() << "\"";
|
|
||||||
if (tok->varId() > 0U)
|
if (tok->varId() > 0U)
|
||||||
ret << " varId=\"" << MathLib::toString(tok->varId()) << "\"";
|
out << " varId=\"" << MathLib::toString(tok->varId()) << '\"';
|
||||||
ret << "/>";
|
if (tok->variable())
|
||||||
return ret.str();
|
out << " variable=\"" << tok->variable() << '\"';
|
||||||
|
if (tok->function())
|
||||||
|
out << " function=\"" << tok->function() << '\"';
|
||||||
|
if (!tok->values.empty())
|
||||||
|
out << " values=\"" << &tok->values << '\"';
|
||||||
|
|
||||||
|
if (!tok->astOperand1() && !tok->astOperand2()) {
|
||||||
|
out << "/>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ret = strindent + "<token text=\"" + tok->str() + "\">\n";
|
else {
|
||||||
|
out << '>' << std::endl;
|
||||||
if (tok->astOperand1())
|
if (tok->astOperand1())
|
||||||
ret += astStringXml(tok->astOperand1(),indent+2U) + '\n';
|
astStringXml(tok->astOperand1(), indent+2U, out);
|
||||||
if (tok->astOperand2())
|
if (tok->astOperand2())
|
||||||
ret += astStringXml(tok->astOperand2(),indent+2U) + '\n';
|
astStringXml(tok->astOperand2(), indent+2U, out);
|
||||||
return ret + strindent + "</token>";
|
out << strindent << "</token>" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Token::printAst(bool verbose, bool xml) const
|
void Token::printAst(bool verbose, bool xml, std::ostream &out) const
|
||||||
{
|
{
|
||||||
bool title = false;
|
bool title = false;
|
||||||
|
|
||||||
|
@ -1112,16 +1119,16 @@ void Token::printAst(bool verbose, bool xml) const
|
||||||
for (const Token *tok = this; tok; tok = tok->next()) {
|
for (const Token *tok = this; tok; tok = tok->next()) {
|
||||||
if (print && tok->_astOperand1) {
|
if (print && tok->_astOperand1) {
|
||||||
if (!title && !xml)
|
if (!title && !xml)
|
||||||
std::cout << "\n\n##AST" << std::endl;
|
out << "\n\n##AST" << std::endl;
|
||||||
title = true;
|
title = true;
|
||||||
if (xml) {
|
if (xml) {
|
||||||
std::cout << "<ast scope=\"" << tok->scope() << "\">" << std::endl;
|
out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr() << "\">" << std::endl;
|
||||||
std::cout << astStringXml(tok->astTop(), 2U) << std::endl;
|
astStringXml(tok->astTop(), 2U, out);
|
||||||
std::cout << "</ast>" << std::endl;
|
out << "</ast>" << std::endl;
|
||||||
} else if (verbose)
|
} else if (verbose)
|
||||||
std::cout << tok->astTop()->astStringVerbose(0,0) << std::endl;
|
out << tok->astTop()->astStringVerbose(0,0) << std::endl;
|
||||||
else
|
else
|
||||||
std::cout << tok->astTop()->astString(" ") << std::endl;
|
out << tok->astTop()->astString(" ") << std::endl;
|
||||||
print = false;
|
print = false;
|
||||||
if (tok->str() == "(")
|
if (tok->str() == "(")
|
||||||
tok = tok->link();
|
tok = tok->link();
|
||||||
|
@ -1158,24 +1165,43 @@ std::string Token::astStringVerbose(const unsigned int indent1, const unsigned i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Token::printValueFlow() const
|
void Token::printValueFlow(bool xml, std::ostream &out) const
|
||||||
{
|
{
|
||||||
unsigned int line = 0;
|
unsigned int line = 0;
|
||||||
std::cout << "\n\n##Value flow" << std::endl;
|
if (xml)
|
||||||
|
out << " <valueflow>" << std::endl;
|
||||||
|
else
|
||||||
|
out << "\n\n##Value flow" << std::endl;
|
||||||
for (const Token *tok = this; tok; tok = tok->next()) {
|
for (const Token *tok = this; tok; tok = tok->next()) {
|
||||||
if (tok->values.empty())
|
if (tok->values.empty())
|
||||||
continue;
|
continue;
|
||||||
if (line != tok->linenr())
|
if (xml)
|
||||||
std::cout << "Line " << tok->linenr() << std::endl;
|
out << " <values id=\"" << &tok->values << "\">" << std::endl;
|
||||||
|
else if (line != tok->linenr())
|
||||||
|
out << "Line " << tok->linenr() << std::endl;
|
||||||
line = tok->linenr();
|
line = tok->linenr();
|
||||||
std::cout << " " << tok->str() << ":{";
|
if (!xml)
|
||||||
|
out << " " << tok->str() << ":{";
|
||||||
for (std::list<ValueFlow::Value>::const_iterator it=tok->values.begin(); it!=tok->values.end(); ++it) {
|
for (std::list<ValueFlow::Value>::const_iterator it=tok->values.begin(); it!=tok->values.end(); ++it) {
|
||||||
if (it != tok->values.begin())
|
if (xml) {
|
||||||
std::cout << ",";
|
out << " <value intvalue=\"" << it->intvalue << "\"";
|
||||||
std::cout << it->intvalue;
|
if (it->condition) {
|
||||||
|
out << " condition-line=\"" << it->condition->linenr() << '\"';
|
||||||
}
|
}
|
||||||
std::cout << "}" << std::endl;
|
out << "/>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
out << (it == tok->values.begin() ? "" : ",") << it->intvalue << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (xml)
|
||||||
|
out << " </values>" << std::endl;
|
||||||
|
else
|
||||||
|
out << "}" << std::endl;
|
||||||
|
}
|
||||||
|
if (xml)
|
||||||
|
out << " </valueflow>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings *settings) const
|
const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings *settings) const
|
||||||
|
|
|
@ -811,9 +811,9 @@ public:
|
||||||
|
|
||||||
std::string expressionString() const;
|
std::string expressionString() const;
|
||||||
|
|
||||||
void printAst(bool verbose, bool xml) const;
|
void printAst(bool verbose, bool xml, std::ostream &out) const;
|
||||||
|
|
||||||
void printValueFlow() const;
|
void printValueFlow(bool xml, std::ostream &out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -3739,21 +3739,21 @@ void Tokenizer::printDebugOutput() const
|
||||||
list.front()->printOut(0, list.getFiles());
|
list.front()->printOut(0, list.getFiles());
|
||||||
|
|
||||||
if (_settings->_xml)
|
if (_settings->_xml)
|
||||||
std::cout << "<dump>" << std::endl;
|
std::cout << "<debug>" << std::endl;
|
||||||
|
|
||||||
if (_symbolDatabase) {
|
if (_symbolDatabase) {
|
||||||
if (_settings->_xml)
|
if (_settings->_xml)
|
||||||
_symbolDatabase->printXml();
|
_symbolDatabase->printXml(std::cout);
|
||||||
else if (_settings->_verbose)
|
else if (_settings->_verbose)
|
||||||
_symbolDatabase->printOut("Symbol database");
|
_symbolDatabase->printOut("Symbol database");
|
||||||
}
|
}
|
||||||
|
|
||||||
list.front()->printAst(_settings->_verbose, _settings->_xml);
|
list.front()->printAst(_settings->_verbose, _settings->_xml, std::cout);
|
||||||
|
|
||||||
|
list.front()->printValueFlow(_settings->_xml, std::cout);
|
||||||
|
|
||||||
if (_settings->_xml)
|
if (_settings->_xml)
|
||||||
std::cout << "</dump>" << std::endl;
|
std::cout << "</debug>" << std::endl;
|
||||||
|
|
||||||
list.front()->printValueFlow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings->debugwarnings) {
|
if (_settings->debugwarnings) {
|
||||||
|
@ -3781,6 +3781,68 @@ void Tokenizer::printDebugOutput() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string toxml(const std::string &str)
|
||||||
|
{
|
||||||
|
std::ostringstream xml;
|
||||||
|
for (std::size_t i = 0U; i < str.length(); i++) {
|
||||||
|
char c = str[i];
|
||||||
|
switch (c) {
|
||||||
|
case '<':
|
||||||
|
xml << "<";
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
xml << ">";
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
xml << "&";
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
xml << """;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xml << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xml.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tokenizer::dump(std::ostream &out) const
|
||||||
|
{
|
||||||
|
// Create a xml data dump.
|
||||||
|
// The idea is not that this will be readable for humans. It's a
|
||||||
|
// data dump that 3rd party tools could load and get useful info from.
|
||||||
|
|
||||||
|
// tokens..
|
||||||
|
out << " <tokenlist>" << std::endl;
|
||||||
|
for (const Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
|
out << " <token id=\"" << tok << "\" file=\"" << toxml(list.file(tok)) << "\" linenr=\"" << tok->linenr() << "\"";
|
||||||
|
out << " str=\"" << toxml(tok->str()) << "\"";
|
||||||
|
if (tok->link())
|
||||||
|
out << " link=\"" << tok->link() << '\"';
|
||||||
|
if (tok->varId() > 0U)
|
||||||
|
out << " varId=\"" << MathLib::toString(tok->varId()) << '\"';
|
||||||
|
if (tok->variable())
|
||||||
|
out << " variable=\"" << tok->variable() << '\"';
|
||||||
|
if (tok->function())
|
||||||
|
out << " function=\"" << tok->function() << '\"';
|
||||||
|
if (!tok->values.empty())
|
||||||
|
out << " values=\"" << &tok->values << '\"';
|
||||||
|
if (tok->astParent())
|
||||||
|
out << " astParent=\"" << tok->astParent() << '\"';
|
||||||
|
if (tok->astOperand1())
|
||||||
|
out << " astOperand1=\"" << tok->astOperand1() << '\"';
|
||||||
|
if (tok->astOperand1())
|
||||||
|
out << " astOperand2=\"" << tok->astOperand2() << '\"';
|
||||||
|
out << "/>" << std::endl;
|
||||||
|
}
|
||||||
|
out << " </tokenlist>" << std::endl;
|
||||||
|
|
||||||
|
_symbolDatabase->printXml(out);
|
||||||
|
list.front()->printValueFlow(true, out);
|
||||||
|
}
|
||||||
|
|
||||||
void Tokenizer::removeMacrosInGlobalScope()
|
void Tokenizer::removeMacrosInGlobalScope()
|
||||||
{
|
{
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
|
|
|
@ -719,6 +719,8 @@ public:
|
||||||
|
|
||||||
void printDebugOutput() const;
|
void printDebugOutput() const;
|
||||||
|
|
||||||
|
void dump(std::ostream &out) const;
|
||||||
|
|
||||||
Token *deleteInvalidTypedef(Token *typeDef);
|
Token *deleteInvalidTypedef(Token *typeDef);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue