Skip to content

Commit 8db5836

Browse files
committed
Fixed danmar#5982 (Add xml dump)
1 parent bf5b4d9 commit 8db5836

10 files changed

Lines changed: 207 additions & 46 deletions

File tree

cli/cmdlineparser.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
134134
else if (std::strcmp(argv[i], "--debug-fp") == 0)
135135
_settings->debugFalsePositive = true;
136136

137+
// dump cppcheck data
138+
else if (std::strcmp(argv[i], "--dump") == 0)
139+
_settings->dump = true;
140+
137141
// (Experimental) exception handling inside cppcheck client
138142
else if (std::strcmp(argv[i], "--exception-handling") == 0)
139143
_settings->exceptionHandling = true;
@@ -843,6 +847,9 @@ void CmdLineParser::PrintHelp()
843847
" analysis is disabled by this flag.\n"
844848
" --check-library Show information messages when library files have\n"
845849
" incomplete info.\n"
850+
" --dump Dump xml data for each translation unit. The dump\n"
851+
" files have the extension .dump and contain ast,\n"
852+
" tokenlist, symboldatabase, valueflow.\n"
846853
" -D<ID> Define preprocessor symbol. Unless --max-configs or\n"
847854
" --force is used, Cppcheck will only check the given\n"
848855
" configuration when -D is used.\n"

lib/cppcheck.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,19 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
363363
return;
364364
}
365365

366+
// dump
367+
if (_settings.dump) {
368+
std::string dumpfile = std::string(FileName) + ".dump";
369+
std::ofstream fdump(dumpfile.c_str());
370+
if (fdump.is_open()) {
371+
fdump << "<?xml version=\"1.0\"?>" << std::endl;
372+
fdump << "<dump cfg=\"" << cfg << "\">" << std::endl;
373+
_tokenizer.dump(fdump);
374+
fdump << "</dump>" << std::endl;
375+
}
376+
return;
377+
}
378+
366379
// call all "runChecks" in all registered Check classes
367380
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
368381
if (_settings.terminated())

lib/settings.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525

2626
Settings::Settings()
2727
: _terminate(false),
28-
debug(false), debugwarnings(false), debugFalsePositive(false), exceptionHandling(false),
28+
debug(false),
29+
debugwarnings(false),
30+
debugFalsePositive(false),
31+
dump(false),
32+
exceptionHandling(false),
2933
inconclusive(false), experimental(false),
3034
_errorsOnly(false),
3135
_inlineSuppressions(false),

lib/settings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class CPPCHECKLIB Settings {
6363
/** @brief Is --debug-fp given? */
6464
bool debugFalsePositive;
6565

66+
/** @brief Is --dump given? */
67+
bool dump;
68+
6669
/** @brief Is --exception-handling given */
6770
bool exceptionHandling;
6871

lib/symboldatabase.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,18 +2074,62 @@ void SymbolDatabase::printOut(const char *title) const
20742074
}
20752075
}
20762076

2077-
void SymbolDatabase::printXml() const
2077+
void SymbolDatabase::printXml(std::ostream &out) const
20782078
{
20792079
// Scopes..
2080+
out << " <scopes>" << std::endl;
20802081
for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
2081-
std::cout << "<scope";
2082-
std::cout << " id=\"" << &*scope << "\"";
2083-
std::cout << " type=\"" << scope->type << "\"";
2082+
out << " <scope";
2083+
out << " id=\"" << &*scope << "\"";
2084+
out << " type=\"" << scope->type << "\"";
20842085
if (!scope->className.empty())
2085-
std::cout << " className=\"" << scope->className << "\"";
2086-
std::cout << " nestedIn=\"" << scope->nestedIn << "\"";
2087-
std::cout << "/>" << std::endl;
2086+
out << " className=\"" << scope->className << "\"";
2087+
if (scope->nestedIn)
2088+
out << " nestedIn=\"" << scope->nestedIn << "\"";
2089+
if (scope->functionList.empty() && scope->varlist.empty()) {
2090+
out << "/>" << std::endl;
2091+
} else {
2092+
out << '>' << std::endl;
2093+
if (!scope->functionList.empty()) {
2094+
out << " <functionList>" << std::endl;
2095+
for (std::list<Function>::const_iterator function = scope->functionList.begin(); function != scope->functionList.end(); ++function) {
2096+
out << " <function id=\"" << &*function << '\"';
2097+
if (function->argCount() == 0U)
2098+
out << "/>" << std::endl;
2099+
else {
2100+
out << ">" << std::endl;
2101+
for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
2102+
const Variable *arg = function->getArgumentVar(argnr);
2103+
out << " <arg nr=\"" << argnr << "\" variable=\"" << arg << "\"/>" << std::endl;
2104+
}
2105+
out << " </function>" << std::endl;
2106+
}
2107+
}
2108+
out << " </functionList>" << std::endl;
2109+
}
2110+
}
2111+
if (!scope->varlist.empty()) {
2112+
out << " <varlist>" << std::endl;
2113+
for (std::list<Variable>::const_iterator var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
2114+
out << " <var id=\"" << &*var << '\"';
2115+
out << " nameToken=\"" << var->nameToken() << '\"';
2116+
out << " typeStartToken=\"" << var->typeStartToken() << '\"';
2117+
out << " typeEndToken=\"" << var->typeEndToken() << '\"';
2118+
out << " typeEndToken=\"" << var->typeEndToken() << '\"';
2119+
out << " isArgument=\"" << (var->isArgument() ? "true" : "false") << '\"';
2120+
out << " isArray=\"" << (var->isArray() ? "true" : "false") << '\"';
2121+
out << " isClass=\"" << (var->isClass() ? "true" : "false") << '\"';
2122+
out << " isLocal=\"" << (var->isLocal() ? "true" : "false") << '\"';
2123+
out << " isPointer=\"" << (var->isPointer() ? "true" : "false") << '\"';
2124+
out << " isReference=\"" << (var->isReference() ? "true" : "false") << '\"';
2125+
out << " isStatic=\"" << (var->isStatic() ? "true" : "false") << '\"';
2126+
out << "/>" << std::endl;
2127+
}
2128+
out << " </varlist>" << std::endl;
2129+
}
2130+
out << " </scope>" << std::endl;
20882131
}
2132+
out << " </scopes>" << std::endl;
20892133
}
20902134

20912135
//---------------------------------------------------------------------------

lib/symboldatabase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ class CPPCHECKLIB SymbolDatabase {
839839

840840
void printOut(const char * title = NULL) const;
841841
void printVariable(const Variable *var, const char *indent) const;
842-
void printXml() const;
842+
void printXml(std::ostream &out) const;
843843

844844
bool isCPP() const;
845845

lib/token.cpp

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,45 +1083,52 @@ std::string Token::expressionString() const
10831083

10841084
}
10851085

1086-
static std::string astStringXml(const Token *tok, std::size_t indent)
1086+
static void astStringXml(const Token *tok, std::size_t indent, std::ostream &out)
10871087
{
10881088
const std::string strindent(indent, ' ');
10891089

1090+
out << strindent << "<token str=\"" << tok->str() << '\"';
1091+
if (tok->varId() > 0U)
1092+
out << " varId=\"" << MathLib::toString(tok->varId()) << '\"';
1093+
if (tok->variable())
1094+
out << " variable=\"" << tok->variable() << '\"';
1095+
if (tok->function())
1096+
out << " function=\"" << tok->function() << '\"';
1097+
if (!tok->values.empty())
1098+
out << " values=\"" << &tok->values << '\"';
1099+
10901100
if (!tok->astOperand1() && !tok->astOperand2()) {
1091-
std::ostringstream ret;
1092-
ret << strindent << "<token text=\"" << tok->str() << "\"";
1093-
if (tok->varId() > 0U)
1094-
ret << " varId=\"" << MathLib::toString(tok->varId()) << "\"";
1095-
ret << "/>";
1096-
return ret.str();
1101+
out << "/>" << std::endl;
10971102
}
10981103

1099-
std::string ret = strindent + "<token text=\"" + tok->str() + "\">\n";
1100-
if (tok->astOperand1())
1101-
ret += astStringXml(tok->astOperand1(),indent+2U) + '\n';
1102-
if (tok->astOperand2())
1103-
ret += astStringXml(tok->astOperand2(),indent+2U) + '\n';
1104-
return ret + strindent + "</token>";
1104+
else {
1105+
out << '>' << std::endl;
1106+
if (tok->astOperand1())
1107+
astStringXml(tok->astOperand1(), indent+2U, out);
1108+
if (tok->astOperand2())
1109+
astStringXml(tok->astOperand2(), indent+2U, out);
1110+
out << strindent << "</token>" << std::endl;
1111+
}
11051112
}
11061113

1107-
void Token::printAst(bool verbose, bool xml) const
1114+
void Token::printAst(bool verbose, bool xml, std::ostream &out) const
11081115
{
11091116
bool title = false;
11101117

11111118
bool print = true;
11121119
for (const Token *tok = this; tok; tok = tok->next()) {
11131120
if (print && tok->_astOperand1) {
11141121
if (!title && !xml)
1115-
std::cout << "\n\n##AST" << std::endl;
1122+
out << "\n\n##AST" << std::endl;
11161123
title = true;
11171124
if (xml) {
1118-
std::cout << "<ast scope=\"" << tok->scope() << "\">" << std::endl;
1119-
std::cout << astStringXml(tok->astTop(), 2U) << std::endl;
1120-
std::cout << "</ast>" << std::endl;
1125+
out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr() << "\">" << std::endl;
1126+
astStringXml(tok->astTop(), 2U, out);
1127+
out << "</ast>" << std::endl;
11211128
} else if (verbose)
1122-
std::cout << tok->astTop()->astStringVerbose(0,0) << std::endl;
1129+
out << tok->astTop()->astStringVerbose(0,0) << std::endl;
11231130
else
1124-
std::cout << tok->astTop()->astString(" ") << std::endl;
1131+
out << tok->astTop()->astString(" ") << std::endl;
11251132
print = false;
11261133
if (tok->str() == "(")
11271134
tok = tok->link();
@@ -1158,24 +1165,43 @@ std::string Token::astStringVerbose(const unsigned int indent1, const unsigned i
11581165
}
11591166

11601167

1161-
void Token::printValueFlow() const
1168+
void Token::printValueFlow(bool xml, std::ostream &out) const
11621169
{
11631170
unsigned int line = 0;
1164-
std::cout << "\n\n##Value flow" << std::endl;
1171+
if (xml)
1172+
out << " <valueflow>" << std::endl;
1173+
else
1174+
out << "\n\n##Value flow" << std::endl;
11651175
for (const Token *tok = this; tok; tok = tok->next()) {
11661176
if (tok->values.empty())
11671177
continue;
1168-
if (line != tok->linenr())
1169-
std::cout << "Line " << tok->linenr() << std::endl;
1178+
if (xml)
1179+
out << " <values id=\"" << &tok->values << "\">" << std::endl;
1180+
else if (line != tok->linenr())
1181+
out << "Line " << tok->linenr() << std::endl;
11701182
line = tok->linenr();
1171-
std::cout << " " << tok->str() << ":{";
1183+
if (!xml)
1184+
out << " " << tok->str() << ":{";
11721185
for (std::list<ValueFlow::Value>::const_iterator it=tok->values.begin(); it!=tok->values.end(); ++it) {
1173-
if (it != tok->values.begin())
1174-
std::cout << ",";
1175-
std::cout << it->intvalue;
1186+
if (xml) {
1187+
out << " <value intvalue=\"" << it->intvalue << "\"";
1188+
if (it->condition) {
1189+
out << " condition-line=\"" << it->condition->linenr() << '\"';
1190+
}
1191+
out << "/>" << std::endl;
1192+
}
1193+
1194+
else {
1195+
out << (it == tok->values.begin() ? "" : ",") << it->intvalue << std::endl;
1196+
}
11761197
}
1177-
std::cout << "}" << std::endl;
1198+
if (xml)
1199+
out << " </values>" << std::endl;
1200+
else
1201+
out << "}" << std::endl;
11781202
}
1203+
if (xml)
1204+
out << " </valueflow>" << std::endl;
11791205
}
11801206

11811207
const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings *settings) const

lib/token.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,9 +811,9 @@ class CPPCHECKLIB Token {
811811

812812
std::string expressionString() const;
813813

814-
void printAst(bool verbose, bool xml) const;
814+
void printAst(bool verbose, bool xml, std::ostream &out) const;
815815

816-
void printValueFlow() const;
816+
void printValueFlow(bool xml, std::ostream &out) const;
817817
};
818818

819819
/// @}

lib/tokenize.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3739,21 +3739,21 @@ void Tokenizer::printDebugOutput() const
37393739
list.front()->printOut(0, list.getFiles());
37403740

37413741
if (_settings->_xml)
3742-
std::cout << "<dump>" << std::endl;
3742+
std::cout << "<debug>" << std::endl;
37433743

37443744
if (_symbolDatabase) {
37453745
if (_settings->_xml)
3746-
_symbolDatabase->printXml();
3746+
_symbolDatabase->printXml(std::cout);
37473747
else if (_settings->_verbose)
37483748
_symbolDatabase->printOut("Symbol database");
37493749
}
37503750

3751-
list.front()->printAst(_settings->_verbose, _settings->_xml);
3751+
list.front()->printAst(_settings->_verbose, _settings->_xml, std::cout);
37523752

3753-
if (_settings->_xml)
3754-
std::cout << "</dump>" << std::endl;
3753+
list.front()->printValueFlow(_settings->_xml, std::cout);
37553754

3756-
list.front()->printValueFlow();
3755+
if (_settings->_xml)
3756+
std::cout << "</debug>" << std::endl;
37573757
}
37583758

37593759
if (_settings->debugwarnings) {
@@ -3781,6 +3781,68 @@ void Tokenizer::printDebugOutput() const
37813781
}
37823782
}
37833783
}
3784+
3785+
static std::string toxml(const std::string &str)
3786+
{
3787+
std::ostringstream xml;
3788+
for (std::size_t i = 0U; i < str.length(); i++) {
3789+
char c = str[i];
3790+
switch (c) {
3791+
case '<':
3792+
xml << "&lt;";
3793+
break;
3794+
case '>':
3795+
xml << "&gt;";
3796+
break;
3797+
case '&':
3798+
xml << "&amp;";
3799+
break;
3800+
case '\"':
3801+
xml << "&quot;";
3802+
break;
3803+
default:
3804+
xml << c;
3805+
break;
3806+
}
3807+
}
3808+
return xml.str();
3809+
}
3810+
3811+
void Tokenizer::dump(std::ostream &out) const
3812+
{
3813+
// Create a xml data dump.
3814+
// The idea is not that this will be readable for humans. It's a
3815+
// data dump that 3rd party tools could load and get useful info from.
3816+
3817+
// tokens..
3818+
out << " <tokenlist>" << std::endl;
3819+
for (const Token *tok = list.front(); tok; tok = tok->next()) {
3820+
out << " <token id=\"" << tok << "\" file=\"" << toxml(list.file(tok)) << "\" linenr=\"" << tok->linenr() << "\"";
3821+
out << " str=\"" << toxml(tok->str()) << "\"";
3822+
if (tok->link())
3823+
out << " link=\"" << tok->link() << '\"';
3824+
if (tok->varId() > 0U)
3825+
out << " varId=\"" << MathLib::toString(tok->varId()) << '\"';
3826+
if (tok->variable())
3827+
out << " variable=\"" << tok->variable() << '\"';
3828+
if (tok->function())
3829+
out << " function=\"" << tok->function() << '\"';
3830+
if (!tok->values.empty())
3831+
out << " values=\"" << &tok->values << '\"';
3832+
if (tok->astParent())
3833+
out << " astParent=\"" << tok->astParent() << '\"';
3834+
if (tok->astOperand1())
3835+
out << " astOperand1=\"" << tok->astOperand1() << '\"';
3836+
if (tok->astOperand1())
3837+
out << " astOperand2=\"" << tok->astOperand2() << '\"';
3838+
out << "/>" << std::endl;
3839+
}
3840+
out << " </tokenlist>" << std::endl;
3841+
3842+
_symbolDatabase->printXml(out);
3843+
list.front()->printValueFlow(true, out);
3844+
}
3845+
37843846
void Tokenizer::removeMacrosInGlobalScope()
37853847
{
37863848
for (Token *tok = list.front(); tok; tok = tok->next()) {

lib/tokenize.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ class CPPCHECKLIB Tokenizer {
719719

720720
void printDebugOutput() const;
721721

722+
void dump(std::ostream &out) const;
723+
722724
Token *deleteInvalidTypedef(Token *typeDef);
723725

724726
/**

0 commit comments

Comments
 (0)