Fixed #5982 (Add xml dump)

This commit is contained in:
Daniel Marjamäki 2014-07-14 15:51:45 +02:00
parent bf5b4d9ece
commit 8db5836e3f
10 changed files with 207 additions and 46 deletions

View File

@ -134,6 +134,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
else if (std::strcmp(argv[i], "--debug-fp") == 0)
_settings->debugFalsePositive = true;
// dump cppcheck data
else if (std::strcmp(argv[i], "--dump") == 0)
_settings->dump = true;
// (Experimental) exception handling inside cppcheck client
else if (std::strcmp(argv[i], "--exception-handling") == 0)
_settings->exceptionHandling = true;
@ -843,6 +847,9 @@ void CmdLineParser::PrintHelp()
" analysis is disabled by this flag.\n"
" --check-library Show information messages when library files have\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"
" --force is used, Cppcheck will only check the given\n"
" configuration when -D is used.\n"

View File

@ -363,6 +363,19 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
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
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
if (_settings.terminated())

View File

@ -25,7 +25,11 @@
Settings::Settings()
: _terminate(false),
debug(false), debugwarnings(false), debugFalsePositive(false), exceptionHandling(false),
debug(false),
debugwarnings(false),
debugFalsePositive(false),
dump(false),
exceptionHandling(false),
inconclusive(false), experimental(false),
_errorsOnly(false),
_inlineSuppressions(false),

View File

@ -63,6 +63,9 @@ public:
/** @brief Is --debug-fp given? */
bool debugFalsePositive;
/** @brief Is --dump given? */
bool dump;
/** @brief Is --exception-handling given */
bool exceptionHandling;

View File

@ -2074,18 +2074,62 @@ void SymbolDatabase::printOut(const char *title) const
}
}
void SymbolDatabase::printXml() const
void SymbolDatabase::printXml(std::ostream &out) const
{
// Scopes..
out << " <scopes>" << std::endl;
for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
std::cout << "<scope";
std::cout << " id=\"" << &*scope << "\"";
std::cout << " type=\"" << scope->type << "\"";
out << " <scope";
out << " id=\"" << &*scope << "\"";
out << " type=\"" << scope->type << "\"";
if (!scope->className.empty())
std::cout << " className=\"" << scope->className << "\"";
std::cout << " nestedIn=\"" << scope->nestedIn << "\"";
std::cout << "/>" << std::endl;
out << " className=\"" << scope->className << "\"";
if (scope->nestedIn)
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;
}
//---------------------------------------------------------------------------

View File

@ -839,7 +839,7 @@ public:
void printOut(const char * title = NULL) const;
void printVariable(const Variable *var, const char *indent) const;
void printXml() const;
void printXml(std::ostream &out) const;
bool isCPP() const;

View File

@ -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, ' ');
out << strindent << "<token str=\"" << tok->str() << '\"';
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->astOperand1() && !tok->astOperand2()) {
std::ostringstream ret;
ret << strindent << "<token text=\"" << tok->str() << "\"";
if (tok->varId() > 0U)
ret << " varId=\"" << MathLib::toString(tok->varId()) << "\"";
ret << "/>";
return ret.str();
out << "/>" << std::endl;
}
std::string ret = strindent + "<token text=\"" + tok->str() + "\">\n";
if (tok->astOperand1())
ret += astStringXml(tok->astOperand1(),indent+2U) + '\n';
if (tok->astOperand2())
ret += astStringXml(tok->astOperand2(),indent+2U) + '\n';
return ret + strindent + "</token>";
else {
out << '>' << std::endl;
if (tok->astOperand1())
astStringXml(tok->astOperand1(), indent+2U, out);
if (tok->astOperand2())
astStringXml(tok->astOperand2(), indent+2U, out);
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;
@ -1112,16 +1119,16 @@ void Token::printAst(bool verbose, bool xml) const
for (const Token *tok = this; tok; tok = tok->next()) {
if (print && tok->_astOperand1) {
if (!title && !xml)
std::cout << "\n\n##AST" << std::endl;
out << "\n\n##AST" << std::endl;
title = true;
if (xml) {
std::cout << "<ast scope=\"" << tok->scope() << "\">" << std::endl;
std::cout << astStringXml(tok->astTop(), 2U) << std::endl;
std::cout << "</ast>" << std::endl;
out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr() << "\">" << std::endl;
astStringXml(tok->astTop(), 2U, out);
out << "</ast>" << std::endl;
} else if (verbose)
std::cout << tok->astTop()->astStringVerbose(0,0) << std::endl;
out << tok->astTop()->astStringVerbose(0,0) << std::endl;
else
std::cout << tok->astTop()->astString(" ") << std::endl;
out << tok->astTop()->astString(" ") << std::endl;
print = false;
if (tok->str() == "(")
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;
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()) {
if (tok->values.empty())
continue;
if (line != tok->linenr())
std::cout << "Line " << tok->linenr() << std::endl;
if (xml)
out << " <values id=\"" << &tok->values << "\">" << std::endl;
else if (line != tok->linenr())
out << "Line " << tok->linenr() << std::endl;
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) {
if (it != tok->values.begin())
std::cout << ",";
std::cout << it->intvalue;
if (xml) {
out << " <value intvalue=\"" << it->intvalue << "\"";
if (it->condition) {
out << " condition-line=\"" << it->condition->linenr() << '\"';
}
out << "/>" << std::endl;
}
else {
out << (it == tok->values.begin() ? "" : ",") << it->intvalue << std::endl;
}
}
std::cout << "}" << 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

View File

@ -811,9 +811,9 @@ public:
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;
};
/// @}

View File

@ -3739,21 +3739,21 @@ void Tokenizer::printDebugOutput() const
list.front()->printOut(0, list.getFiles());
if (_settings->_xml)
std::cout << "<dump>" << std::endl;
std::cout << "<debug>" << std::endl;
if (_symbolDatabase) {
if (_settings->_xml)
_symbolDatabase->printXml();
_symbolDatabase->printXml(std::cout);
else if (_settings->_verbose)
_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)
std::cout << "</dump>" << std::endl;
list.front()->printValueFlow();
std::cout << "</debug>" << std::endl;
}
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 << "&lt;";
break;
case '>':
xml << "&gt;";
break;
case '&':
xml << "&amp;";
break;
case '\"':
xml << "&quot;";
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()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {

View File

@ -719,6 +719,8 @@ public:
void printDebugOutput() const;
void dump(std::ostream &out) const;
Token *deleteInvalidTypedef(Token *typeDef);
/**