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)
|
||||
_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"
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -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 << "<";
|
||||
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()
|
||||
{
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
|
|
|
@ -719,6 +719,8 @@ public:
|
|||
|
||||
void printDebugOutput() const;
|
||||
|
||||
void dump(std::ostream &out) const;
|
||||
|
||||
Token *deleteInvalidTypedef(Token *typeDef);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue