39 #include <unordered_map>
51 "premium-internalError",
52 "premium-invalidArgument",
53 "premium-invalidLicense",
54 "preprocessorErrorDirective",
65 callStack(std::move(callStack)),
67 file0(std::move(file1)),
80 callStack(std::move(callStack)),
82 file0(std::move(file1)),
93 : id(std::move(id)), severity(severity), cwe(0U), certainty(certainty), hash(0)
96 for (std::list<const Token *>::const_iterator it = callstack.cbegin(); it != callstack.cend(); ++it) {
104 if (list && !list->
getFiles().empty())
112 : id(std::move(id)), severity(severity), cwe(cwe.id), certainty(certainty)
115 for (
const Token *tok: callstack) {
123 if (list && !list->
getFiles().empty())
132 : id(id), severity(severity), cwe(cwe.id), certainty(certainty)
136 const Token *tok = e.first;
141 std::string info = e.second;
143 if (
startsWith(info,
"$symbol:") && info.find(
'\n') < info.size()) {
144 const std::string::size_type pos = info.find(
'\n');
145 const std::string &symbolName = info.substr(8, pos - 8);
146 info =
replaceStr(info.substr(pos+1),
"$symbol", symbolName);
149 callStack.emplace_back(tok, info, tokenList);
152 if (tokenList && !tokenList->
getFiles().empty())
165 const char *
const unknown =
"<UNKNOWN>";
167 const char *attr = errmsg->Attribute(
"id");
168 id = attr ? attr : unknown;
170 attr = errmsg->Attribute(
"severity");
173 attr = errmsg->Attribute(
"cwe");
175 cwe.
id = attr ? strToInt<unsigned short>(attr) : 0;
177 attr = errmsg->Attribute(
"inconclusive");
180 attr = errmsg->Attribute(
"msg");
183 attr = errmsg->Attribute(
"verbose");
186 attr = errmsg->Attribute(
"hash");
187 hash = attr ? strToInt<std::size_t>(attr) : 0;
189 for (
const tinyxml2::XMLElement *e = errmsg->FirstChildElement(); e; e = e->NextSiblingElement()) {
190 if (std::strcmp(e->Name(),
"location")==0) {
191 const char *strfile = e->Attribute(
"file");
192 const char *strinfo = e->Attribute(
"info");
193 const char *strline = e->Attribute(
"line");
194 const char *strcolumn = e->Attribute(
"column");
196 const char *file = strfile ? strfile : unknown;
197 const char *info = strinfo ? strinfo :
"";
198 const int line = strline ? strToInt<int>(strline) : 0;
199 const int column = strcolumn ? strToInt<int>(strcolumn) : 0;
200 callStack.emplace_front(file, info, line, column);
201 }
else if (std::strcmp(e->Name(),
"symbol")==0) {
219 const std::string::size_type pos = msg.find(
'\n');
221 if (pos == std::string::npos) {
226 setmsg(msg.substr(pos + 1));
235 oss += std::to_string(str.length());
242 if (internalError.
token)
243 assert(tokenList !=
nullptr);
245 std::list<ErrorMessage::FileLocation> locationList;
246 if (tokenList && internalError.
token) {
247 locationList.emplace_back(internalError.
token, tokenList);
249 locationList.emplace_back(filename, 0, 0);
257 (msg.empty() ?
"" : (msg +
": ")) + internalError.
errorMessage,
261 if (!internalError.
details.empty())
276 const std::string text(
"inconclusive");
288 for (std::list<ErrorMessage::FileLocation>::const_iterator loc =
callStack.cbegin(); loc !=
callStack.cend(); ++loc) {
290 frame += std::to_string(loc->line);
292 frame += std::to_string(loc->column);
294 frame += loc->getfile(
false);
296 frame += loc->getOrigFile(
false);
298 frame += loc->getinfo();
311 std::istringstream iss(data);
312 std::array<std::string, 7> results;
313 std::size_t elem = 0;
314 while (iss.good() && elem < 7) {
315 unsigned int len = 0;
317 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid length");
319 if (iss.get() !=
' ')
320 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator");
323 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
328 iss.read(&temp[0], len);
331 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
333 if (temp ==
"inconclusive") {
339 results[elem++] = std::move(temp);
343 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
346 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - insufficient elements");
348 id = std::move(results[0]);
351 if (!results[2].empty()) {
354 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid CWE ID - " + err);
357 if (!results[3].empty()) {
360 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid hash - " + err);
362 file0 = std::move(results[4]);
366 unsigned int stackSize = 0;
367 if (!(iss >> stackSize))
368 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid stack size");
370 if (iss.get() !=
' ')
371 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator");
377 unsigned int len = 0;
379 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid length (stack)");
381 if (iss.get() !=
' ')
382 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator (stack)");
387 iss.read(&temp[0], len);
390 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data (stack)");
393 std::vector<std::string> substrings;
394 substrings.reserve(5);
395 for (std::string::size_type pos = 0; pos < temp.size() && substrings.size() < 5; ++pos) {
396 if (substrings.size() == 4) {
397 substrings.push_back(temp.substr(pos));
400 const std::string::size_type start = pos;
401 pos = temp.find(
'\t', pos);
402 if (pos == std::string::npos) {
403 substrings.push_back(temp.substr(start));
406 substrings.push_back(temp.substr(start, pos - start));
408 if (substrings.size() < 4)
409 throw InternalError(
nullptr,
"Internal Error: Deserializing of error message failed");
414 loc.
setfile(std::move(substrings[2]));
415 if (substrings.size() == 5)
428 productName = nameAndVersion.first;
429 const std::string version = nameAndVersion.first.empty() ?
CppCheck::version() : nameAndVersion.second;
431 tinyxml2::XMLPrinter printer;
434 printer.PushDeclaration(
"xml version=\"1.0\" encoding=\"UTF-8\"");
437 printer.OpenElement(
"results",
false);
439 printer.PushAttribute(
"version", 2);
440 printer.OpenElement(
"cppcheck",
false);
441 if (!productName.empty())
442 printer.PushAttribute(
"product-name", productName.c_str());
443 printer.PushAttribute(
"version", version.c_str());
444 printer.CloseElement(
false);
445 printer.OpenElement(
"errors",
false);
447 return std::string(printer.CStr()) +
'>';
452 return " </errors>\n</results>";
460 result.reserve(raw.length());
461 std::string::const_iterator from=raw.cbegin();
462 while (from!=raw.cend()) {
463 if (std::isprint(
static_cast<unsigned char>(*from))) {
464 result.push_back(*from);
466 std::ostringstream es;
468 const unsigned uFrom = (
unsigned char)*from;
469 es <<
'\\' << std::setbase(8) << std::setw(3) << std::setfill(
'0') << uFrom;
479 tinyxml2::XMLPrinter printer(
nullptr,
false, 2);
480 printer.OpenElement(
"error",
false);
481 printer.PushAttribute(
"id",
id.c_str());
486 printer.PushAttribute(
"cwe",
cwe.
id);
488 printer.PushAttribute(
"hash", std::to_string(
hash).c_str());
490 printer.PushAttribute(
"inconclusive",
"true");
493 printer.PushAttribute(
"file0",
file0.c_str());
495 for (std::list<FileLocation>::const_reverse_iterator it =
callStack.crbegin(); it !=
callStack.crend(); ++it) {
496 printer.OpenElement(
"location",
false);
497 printer.PushAttribute(
"file", it->getfile().c_str());
498 printer.PushAttribute(
"line", std::max(it->line,0));
499 printer.PushAttribute(
"column", it->column);
500 if (!it->getinfo().empty())
502 printer.CloseElement(
false);
504 for (std::string::size_type pos = 0; pos <
mSymbolNames.size();) {
505 const std::string::size_type pos2 =
mSymbolNames.find(
'\n', pos);
506 std::string symbolName;
507 if (pos2 == std::string::npos) {
514 printer.OpenElement(
"symbol",
false);
515 printer.PushText(symbolName.c_str());
516 printer.CloseElement(
false);
518 printer.CloseElement(
false);
519 return printer.CStr();
529 static void findAndReplace(std::string &source,
const std::string &searchFor,
const std::string &replaceWith)
531 std::string::size_type index = 0;
532 while ((index = source.find(searchFor, index)) != std::string::npos) {
533 source.replace(index, searchFor.length(), replaceWith);
534 index += replaceWith.length();
539 static std::string
readCode(
const std::string &file,
int linenr,
int column,
const char endl[])
541 std::ifstream fin(file);
543 while (linenr > 0 && std::getline(fin,line)) {
546 const std::string::size_type endPos = line.find_last_not_of(
"\r\n\t ");
547 if (endPos + 1 < line.size())
548 line.erase(endPos + 1);
549 std::string::size_type pos = 0;
550 while ((pos = line.find(
'\t', pos)) != std::string::npos)
552 return line + endl + std::string((column>0 ? column-1 : 0),
' ') +
'^';
559 static const std::unordered_map<char, std::string> substitutionMap = {
566 std::string::size_type index = 0;
567 while ((index = source.find(
'\\', index)) != std::string::npos) {
568 const char searchFor = source[index+1];
569 const auto it = substitutionMap.find(searchFor);
570 if (it == substitutionMap.end()) {
574 const std::string& replaceWith = it->second;
575 source.replace(index, 2, replaceWith);
576 index += replaceWith.length();
580 static void replace(std::string& source,
const std::unordered_map<std::string, std::string> &substitutionMap)
582 std::string::size_type index = 0;
583 while ((index = source.find(
'{', index)) != std::string::npos) {
584 const std::string::size_type end = source.find(
'}', index);
585 if (end == std::string::npos)
587 const std::string searchFor = source.substr(index, end-index+1);
588 const auto it = substitutionMap.find(searchFor);
589 if (it == substitutionMap.end()) {
593 const std::string& replaceWith = it->second;
594 source.replace(index, searchFor.length(), replaceWith);
595 index += replaceWith.length();
601 static const std::unordered_map<std::string, std::string> substitutionMap =
612 replace(source, substitutionMap);
616 std::string
ErrorMessage::toString(
bool verbose,
const std::string &templateFormat,
const std::string &templateLocation)
const
623 if (templateFormat.empty()) {
633 text +=
", inconclusive";
641 std::string result = templateFormat;
645 std::string::size_type pos1 = result.find(
"{inconclusive:");
646 while (pos1 != std::string::npos) {
647 const std::string::size_type pos2 = result.find(
'}', pos1+1);
648 const std::string replaceFrom = result.substr(pos1,pos2-pos1+1);
651 pos1 = result.find(
"{inconclusive:", pos1);
657 if (result.find(
"{callstack}") != std::string::npos)
662 if (result.find(
"{code}") != std::string::npos) {
663 const std::string::size_type pos = result.find(
'\r');
665 if (pos == std::string::npos)
667 else if (pos+1 < result.size() && result[pos+1] ==
'\n')
674 static const std::unordered_map<std::string, std::string> callStackSubstitutionMap =
677 {
"{file}",
"nofile"},
682 replace(result, callStackSubstitutionMap);
685 if (!templateLocation.empty() &&
callStack.size() >= 2U) {
687 std::string text = templateLocation;
690 findAndReplace(text,
"{line}", std::to_string(fileLocation.line));
691 findAndReplace(text,
"{column}", std::to_string(fileLocation.column));
693 if (text.find(
"{code}") != std::string::npos) {
694 const std::string::size_type pos = text.find(
'\r');
696 if (pos == std::string::npos)
698 else if (pos+1 < text.size() && text[pos+1] ==
'\n')
702 findAndReplace(text,
"{code}",
readCode(fileLocation.getOrigFile(), fileLocation.line, fileLocation.column, endl));
704 result +=
'\n' + text;
714 for (std::list<ErrorMessage::FileLocation>::const_iterator tok = callStack.cbegin(); tok != callStack.cend(); ++tok) {
715 str += (tok == callStack.cbegin() ?
"" :
" -> ");
716 str += tok->stringify();
723 : fileIndex(tok->fileIndex()), line(tok->linenr()), column(tok->column()), mOrigFileName(tokenList->getOrigFile(tok)), mFileName(tokenList->file(tok))
727 : fileIndex(tok->fileIndex()), line(tok->linenr()), column(tok->column()), mOrigFileName(tokenList->getOrigFile(tok)), mFileName(tokenList->file(tok)), mInfo(std::move(info))
741 return mOrigFileName;
757 str += std::to_string(line);
766 for (
const unsigned char c : str) {
787 if (c >=
' ' && c <= 0x7f)
799 std::ostringstream ostr;
800 ostr <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
801 <<
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n"
802 <<
"<plist version=\"1.0\">\r\n"
804 <<
" <key>clang_version</key>\r\n"
805 <<
"<string>cppcheck version " << version <<
"</string>\r\n"
806 <<
" <key>files</key>\r\n"
808 for (
const std::string & file : files)
810 ostr <<
" </array>\r\n"
811 <<
" <key>diagnostics</key>\r\n"
818 std::ostringstream ostr;
819 ostr <<
indent <<
"<dict>\r\n"
820 <<
indent <<
' ' <<
"<key>line</key><integer>" << loc.
line <<
"</integer>\r\n"
821 <<
indent <<
' ' <<
"<key>col</key><integer>" << loc.
column <<
"</integer>\r\n"
822 <<
indent <<
' ' <<
"<key>file</key><integer>" << loc.
fileIndex <<
"</integer>\r\n"
823 <<
indent <<
"</dict>\r\n";
829 std::ostringstream plist;
830 plist <<
" <dict>\r\n"
831 <<
" <key>path</key>\r\n"
834 std::list<ErrorMessage::FileLocation>::const_iterator prev = msg.
callStack.cbegin();
836 for (std::list<ErrorMessage::FileLocation>::const_iterator it = msg.
callStack.cbegin(); it != msg.
callStack.cend(); ++it) {
838 plist <<
" <dict>\r\n"
839 <<
" <key>kind</key><string>control</string>\r\n"
840 <<
" <key>edges</key>\r\n"
843 <<
" <key>start</key>\r\n"
848 <<
" <key>end</key>\r\n"
859 std::list<ErrorMessage::FileLocation>::const_iterator next = it;
861 const std::string message = (it->getinfo().empty() && next == msg.
callStack.cend() ? msg.
shortMessage() : it->getinfo());
863 plist <<
" <dict>\r\n"
864 <<
" <key>kind</key><string>event</string>\r\n"
865 <<
" <key>location</key>\r\n"
867 <<
" <key>ranges</key>\r\n"
874 <<
" <key>depth</key><integer>0</integer>\r\n"
875 <<
" <key>extended_message</key>\r\n"
877 <<
" <key>message</key>\r\n"
882 plist <<
" </array>\r\n"
886 <<
" <key>check_name</key><string>" << msg.
id <<
"</string>\r\n"
887 <<
" <!-- This hash is experimental and going to change! -->\r\n"
888 <<
" <key>issue_hash_content_of_line_in_context</key><string>" << 0 <<
"</string>\r\n"
889 <<
" <key>issue_context_kind</key><string></string>\r\n"
890 <<
" <key>issue_context</key><string></string>\r\n"
891 <<
" <key>issue_hash_function_offset</key><string></string>\r\n"
892 <<
" <key>location</key>\r\n"
899 std::string
replaceStr(std::string s,
const std::string &from,
const std::string &to)
901 std::string::size_type pos1 = 0;
902 while (pos1 < s.size()) {
903 pos1 = s.find(from, pos1);
904 if (pos1 == std::string::npos)
906 if (pos1 > 0 && (s[pos1-1] ==
'_' || std::isalnum(s[pos1-1]))) {
910 const std::string::size_type pos2 = pos1 + from.size();
911 if (pos2 >= s.size())
912 return s.substr(0,pos1) + to;
913 if (s[pos2] ==
'_' || std::isalnum(s[pos2])) {
917 s.replace(pos1, from.size(), to);
static const char * version()
Returns current version number as a string.
static std::string plistData(const ErrorMessage &msg)
static std::string toxml(const std::string &str)
Convert XML-sensitive characters into XML entities.
static const std::set< std::string > mCriticalErrorIds
static std::string callStackToString(const std::list< ErrorMessage::FileLocation > &callStack)
static std::string plistHeader(const std::string &version, const std::vector< std::string > &files)
File name and line number.
void setfile(std::string file)
Set the filename.
void setinfo(const std::string &i)
std::string getfile(bool convert=true) const
Return the filename.
FileLocation(const std::string &file, int line, unsigned int column)
std::string stringify() const
std::string getOrigFile(bool convert=true) const
Filename with the whole path (no –rp)
Wrapper for error messages, provided by reportErr()
static std::string getXMLFooter()
static std::string getXMLHeader(std::string productName)
std::string mSymbolNames
symbol names
std::string mVerboseMessage
Verbose message.
std::size_t hash
Warning hash.
std::string toString(bool verbose, const std::string &templateFormat=emptyString, const std::string &templateLocation=emptyString) const
Format the error message into a string.
const std::string & shortMessage() const
Short message (single line short message)
std::string mShortMessage
Short message.
static std::string fixInvalidChars(const std::string &raw)
std::string file0
For GUI rechecking; source file (not header)
std::list< FileLocation > callStack
std::string serialize() const
void deserialize(const std::string &data)
std::string toXML() const
Format the error message in XML format.
static ErrorMessage fromInternalError(const InternalError &internalError, const TokenList *tokenList, const std::string &filename, const std::string &msg=emptyString)
void setmsg(const std::string &msg)
set short and verbose messages
static std::string simplifyPath(std::string originalPath)
Simplify path "foo/bar/.." => "foo".
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
static std::string toNativeSeparators(std::string path)
Convert path to use native separators.
static std::pair< std::string, std::string > getNameAndVersion(const std::string &productName)
const std::string & getSourceFilePath() const
const std::vector< std::string > & getFiles() const
Get filenames (the sourcefile + the files it include).
The token list that the TokenList generates is a linked-list of this class.
std::string toString(Color c)
static void serializeString(std::string &oss, const std::string &str)
static void replaceSpecialChars(std::string &source)
static void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith)
Replace all occurrences of searchFor with replaceWith in the given source.
static std::string readCode(const std::string &file, int linenr, int column, const char endl[])
static void replaceColors(std::string &source)
static void replace(std::string &source, const std::unordered_map< std::string, std::string > &substitutionMap)
static std::string plistLoc(const char indent[], const ErrorMessage::FileLocation &loc)
Severity
enum class for severity.
std::pair< const Token *, std::string > ErrorPathItem
void substituteTemplateFormatStatic(std::string &templateFormat)
replaces the static parts of the location template
std::string replaceStr(std::string s, const std::string &from, const std::string &to)
Replace substring.
void substituteTemplateLocationStatic(std::string &templateLocation)
replaces the static parts of the location template
Severity severityFromString(const std::string &severity)
std::string severityToString(Severity severity)
std::list< ErrorPathItem > ErrorPath
@ none
No severity (default value).
@ error
Programming error.
Simple container to be thrown when internal error is detected.
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
bool strToInt(const std::string &str, T &num, std::string *err=nullptr)
bool endsWith(const std::string &str, char c)