39 #include <unordered_map>
50 "premium-internalError",
51 "premium-invalidArgument",
52 "premium-invalidLicense",
53 "preprocessorErrorDirective",
64 callStack(std::move(callStack)),
66 file0(std::move(file1)),
79 callStack(std::move(callStack)),
81 file0(std::move(file1)),
92 : id(std::move(id)), severity(severity), cwe(0U), certainty(certainty), hash(0)
95 for (std::list<const Token *>::const_iterator it = callstack.cbegin(); it != callstack.cend(); ++it) {
103 if (list && !list->
getFiles().empty())
111 : id(std::move(id)), severity(severity), cwe(cwe.id), certainty(certainty)
114 for (
const Token *tok: callstack) {
122 if (list && !list->
getFiles().empty())
131 : id(id), severity(severity), cwe(cwe.id), certainty(certainty)
135 const Token *tok = e.first;
140 const std::string& path_info = e.second;
143 if (
startsWith(path_info,
"$symbol:") && path_info.find(
'\n') < path_info.size()) {
144 const std::string::size_type pos = path_info.find(
'\n');
145 const std::string symbolName = path_info.substr(8, pos - 8);
146 info =
replaceStr(path_info.substr(pos+1),
"$symbol", symbolName);
152 callStack.emplace_back(tok, std::move(info), tokenList);
155 if (tokenList && !tokenList->
getFiles().empty())
168 const char *
const unknown =
"<UNKNOWN>";
170 const char *attr = errmsg->Attribute(
"id");
171 id = attr ? attr : unknown;
173 attr = errmsg->Attribute(
"severity");
176 attr = errmsg->Attribute(
"cwe");
178 cwe.
id = attr ? strToInt<unsigned short>(attr) : 0;
180 attr = errmsg->Attribute(
"inconclusive");
183 attr = errmsg->Attribute(
"msg");
186 attr = errmsg->Attribute(
"verbose");
189 attr = errmsg->Attribute(
"hash");
190 hash = attr ? strToInt<std::size_t>(attr) : 0;
192 for (
const tinyxml2::XMLElement *e = errmsg->FirstChildElement(); e; e = e->NextSiblingElement()) {
193 if (std::strcmp(e->Name(),
"location")==0) {
194 const char *strfile = e->Attribute(
"file");
195 const char *strinfo = e->Attribute(
"info");
196 const char *strline = e->Attribute(
"line");
197 const char *strcolumn = e->Attribute(
"column");
199 const char *file = strfile ? strfile : unknown;
200 const char *info = strinfo ? strinfo :
"";
201 const int line = strline ? strToInt<int>(strline) : 0;
202 const int column = strcolumn ? strToInt<int>(strcolumn) : 0;
203 callStack.emplace_front(file, info, line, column);
204 }
else if (std::strcmp(e->Name(),
"symbol")==0) {
222 const std::string::size_type pos = msg.find(
'\n');
224 if (pos == std::string::npos) {
229 setmsg(msg.substr(pos + 1));
238 oss += std::to_string(str.length());
245 if (internalError.
token)
246 assert(tokenList !=
nullptr);
248 std::list<ErrorMessage::FileLocation> locationList;
249 if (tokenList && internalError.
token) {
250 locationList.emplace_back(internalError.
token, tokenList);
252 locationList.emplace_back(filename, 0, 0);
260 (msg.empty() ?
"" : (msg +
": ")) + internalError.
errorMessage,
264 if (!internalError.
details.empty())
279 const std::string text(
"inconclusive");
291 for (std::list<ErrorMessage::FileLocation>::const_iterator loc =
callStack.cbegin(); loc !=
callStack.cend(); ++loc) {
293 frame += std::to_string(loc->line);
295 frame += std::to_string(loc->column);
297 frame += loc->getfile(
false);
299 frame += loc->getOrigFile(
false);
301 frame += loc->getinfo();
314 std::istringstream iss(data);
315 std::array<std::string, 7> results;
316 std::size_t elem = 0;
317 while (iss.good() && elem < 7) {
318 unsigned int len = 0;
320 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid length");
322 if (iss.get() !=
' ')
323 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator");
326 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
331 iss.read(&temp[0], len);
334 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
336 if (temp ==
"inconclusive") {
342 results[elem++] = std::move(temp);
346 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data");
349 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - insufficient elements");
351 id = std::move(results[0]);
354 if (!results[2].empty()) {
357 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid CWE ID - " + err);
360 if (!results[3].empty()) {
363 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid hash - " + err);
365 file0 = std::move(results[4]);
369 unsigned int stackSize = 0;
370 if (!(iss >> stackSize))
371 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid stack size");
373 if (iss.get() !=
' ')
374 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator");
380 unsigned int len = 0;
382 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid length (stack)");
384 if (iss.get() !=
' ')
385 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - invalid separator (stack)");
390 iss.read(&temp[0], len);
393 throw InternalError(
nullptr,
"Internal Error: Deserialization of error message failed - premature end of data (stack)");
396 std::vector<std::string> substrings;
397 substrings.reserve(5);
398 for (std::string::size_type pos = 0; pos < temp.size() && substrings.size() < 5; ++pos) {
399 if (substrings.size() == 4) {
400 substrings.push_back(temp.substr(pos));
403 const std::string::size_type start = pos;
404 pos = temp.find(
'\t', pos);
405 if (pos == std::string::npos) {
406 substrings.push_back(temp.substr(start));
409 substrings.push_back(temp.substr(start, pos - start));
411 if (substrings.size() < 4)
412 throw InternalError(
nullptr,
"Internal Error: Deserializing of error message failed");
417 if (substrings.size() == 5)
418 info = std::move(substrings[4]);
419 ErrorMessage::FileLocation loc(substrings[3], std::move(info), strToInt<int>(substrings[0]), strToInt<unsigned int>(substrings[1]));
420 loc.
setfile(std::move(substrings[2]));
432 productName = nameAndVersion.first;
433 const std::string version = nameAndVersion.first.empty() ?
CppCheck::version() : nameAndVersion.second;
435 tinyxml2::XMLPrinter printer;
438 printer.PushDeclaration(
"xml version=\"1.0\" encoding=\"UTF-8\"");
441 printer.OpenElement(
"results",
false);
443 printer.PushAttribute(
"version", 2);
444 printer.OpenElement(
"cppcheck",
false);
445 if (!productName.empty())
446 printer.PushAttribute(
"product-name", productName.c_str());
447 printer.PushAttribute(
"version", version.c_str());
448 printer.CloseElement(
false);
449 printer.OpenElement(
"errors",
false);
451 return std::string(printer.CStr()) +
'>';
456 return " </errors>\n</results>";
464 result.reserve(raw.length());
465 std::string::const_iterator from=raw.cbegin();
466 while (from!=raw.cend()) {
467 if (std::isprint(
static_cast<unsigned char>(*from))) {
468 result.push_back(*from);
470 std::ostringstream es;
472 const unsigned uFrom = (
unsigned char)*from;
473 es <<
'\\' << std::setbase(8) << std::setw(3) << std::setfill(
'0') << uFrom;
483 tinyxml2::XMLPrinter printer(
nullptr,
false, 2);
484 printer.OpenElement(
"error",
false);
485 printer.PushAttribute(
"id",
id.c_str());
490 printer.PushAttribute(
"cwe",
cwe.
id);
492 printer.PushAttribute(
"hash", std::to_string(
hash).c_str());
494 printer.PushAttribute(
"inconclusive",
"true");
497 printer.PushAttribute(
"file0",
file0.c_str());
499 for (std::list<FileLocation>::const_reverse_iterator it =
callStack.crbegin(); it !=
callStack.crend(); ++it) {
500 printer.OpenElement(
"location",
false);
501 printer.PushAttribute(
"file", it->getfile().c_str());
502 printer.PushAttribute(
"line", std::max(it->line,0));
503 printer.PushAttribute(
"column", it->column);
504 if (!it->getinfo().empty())
506 printer.CloseElement(
false);
508 for (std::string::size_type pos = 0; pos <
mSymbolNames.size();) {
509 const std::string::size_type pos2 =
mSymbolNames.find(
'\n', pos);
510 std::string symbolName;
511 if (pos2 == std::string::npos) {
518 printer.OpenElement(
"symbol",
false);
519 printer.PushText(symbolName.c_str());
520 printer.CloseElement(
false);
522 printer.CloseElement(
false);
523 return printer.CStr();
527 static std::string
readCode(
const std::string &file,
int linenr,
int column,
const char endl[])
529 std::ifstream fin(file);
531 while (linenr > 0 && std::getline(fin,line)) {
534 const std::string::size_type endPos = line.find_last_not_of(
"\r\n\t ");
535 if (endPos + 1 < line.size())
536 line.erase(endPos + 1);
537 std::string::size_type pos = 0;
538 while ((pos = line.find(
'\t', pos)) != std::string::npos)
540 return line + endl + std::string((column>0 ? column-1 : 0),
' ') +
'^';
547 static const std::unordered_map<char, std::string> substitutionMap = {
554 std::string::size_type index = 0;
555 while ((index = source.find(
'\\', index)) != std::string::npos) {
556 const char searchFor = source[index+1];
557 const auto it = substitutionMap.find(searchFor);
558 if (it == substitutionMap.end()) {
562 const std::string& replaceWith = it->second;
563 source.replace(index, 2, replaceWith);
564 index += replaceWith.length();
568 static void replace(std::string& source,
const std::unordered_map<std::string, std::string> &substitutionMap)
570 std::string::size_type index = 0;
571 while ((index = source.find(
'{', index)) != std::string::npos) {
572 const std::string::size_type end = source.find(
'}', index);
573 if (end == std::string::npos)
575 const std::string searchFor = source.substr(index, end-index+1);
576 const auto it = substitutionMap.find(searchFor);
577 if (it == substitutionMap.end()) {
581 const std::string& replaceWith = it->second;
582 source.replace(index, searchFor.length(), replaceWith);
583 index += replaceWith.length();
589 static const std::unordered_map<std::string, std::string> substitutionMap =
600 replace(source, substitutionMap);
604 std::string
ErrorMessage::toString(
bool verbose,
const std::string &templateFormat,
const std::string &templateLocation)
const
611 if (templateFormat.empty()) {
621 text +=
", inconclusive";
629 std::string result = templateFormat;
633 std::string::size_type pos1 = result.find(
"{inconclusive:");
634 while (pos1 != std::string::npos) {
635 const std::string::size_type pos2 = result.find(
'}', pos1+1);
636 const std::string replaceFrom = result.substr(pos1,pos2-pos1+1);
639 pos1 = result.find(
"{inconclusive:", pos1);
645 if (result.find(
"{callstack}") != std::string::npos)
650 if (result.find(
"{code}") != std::string::npos) {
651 const std::string::size_type pos = result.find(
'\r');
653 if (pos == std::string::npos)
655 else if (pos+1 < result.size() && result[pos+1] ==
'\n')
662 static const std::unordered_map<std::string, std::string> callStackSubstitutionMap =
665 {
"{file}",
"nofile"},
670 replace(result, callStackSubstitutionMap);
673 if (!templateLocation.empty() &&
callStack.size() >= 2U) {
675 std::string text = templateLocation;
678 findAndReplace(text,
"{line}", std::to_string(fileLocation.line));
679 findAndReplace(text,
"{column}", std::to_string(fileLocation.column));
681 if (text.find(
"{code}") != std::string::npos) {
682 const std::string::size_type pos = text.find(
'\r');
684 if (pos == std::string::npos)
686 else if (pos+1 < text.size() && text[pos+1] ==
'\n')
690 findAndReplace(text,
"{code}",
readCode(fileLocation.getOrigFile(), fileLocation.line, fileLocation.column, endl));
692 result +=
'\n' + text;
702 for (std::list<ErrorMessage::FileLocation>::const_iterator tok = callStack.cbegin(); tok != callStack.cend(); ++tok) {
703 str += (tok == callStack.cbegin() ?
"" :
" -> ");
704 str += tok->stringify();
711 : fileIndex(tok->fileIndex()), line(tok->linenr()), column(tok->column()), mOrigFileName(tokenList->getOrigFile(tok)), mFileName(tokenList->file(tok))
715 : fileIndex(tok->fileIndex()), line(tok->linenr()), column(tok->column()), mOrigFileName(tokenList->getOrigFile(tok)), mFileName(tokenList->file(tok)), mInfo(std::move(info))
729 return mOrigFileName;
745 str += std::to_string(line);
754 for (
const unsigned char c : str) {
775 if (c >=
' ' && c <= 0x7f)
787 std::ostringstream ostr;
788 ostr <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
789 <<
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n"
790 <<
"<plist version=\"1.0\">\r\n"
792 <<
" <key>clang_version</key>\r\n"
793 <<
"<string>cppcheck version " << version <<
"</string>\r\n"
794 <<
" <key>files</key>\r\n"
796 for (
const std::string & file : files)
798 ostr <<
" </array>\r\n"
799 <<
" <key>diagnostics</key>\r\n"
806 std::ostringstream ostr;
807 ostr <<
indent <<
"<dict>\r\n"
808 <<
indent <<
' ' <<
"<key>line</key><integer>" << loc.
line <<
"</integer>\r\n"
809 <<
indent <<
' ' <<
"<key>col</key><integer>" << loc.
column <<
"</integer>\r\n"
810 <<
indent <<
' ' <<
"<key>file</key><integer>" << loc.
fileIndex <<
"</integer>\r\n"
811 <<
indent <<
"</dict>\r\n";
817 std::ostringstream plist;
818 plist <<
" <dict>\r\n"
819 <<
" <key>path</key>\r\n"
822 std::list<ErrorMessage::FileLocation>::const_iterator prev = msg.
callStack.cbegin();
824 for (std::list<ErrorMessage::FileLocation>::const_iterator it = msg.
callStack.cbegin(); it != msg.
callStack.cend(); ++it) {
826 plist <<
" <dict>\r\n"
827 <<
" <key>kind</key><string>control</string>\r\n"
828 <<
" <key>edges</key>\r\n"
831 <<
" <key>start</key>\r\n"
836 <<
" <key>end</key>\r\n"
847 std::list<ErrorMessage::FileLocation>::const_iterator next = it;
849 const std::string message = (it->getinfo().empty() && next == msg.
callStack.cend() ? msg.
shortMessage() : it->getinfo());
851 plist <<
" <dict>\r\n"
852 <<
" <key>kind</key><string>event</string>\r\n"
853 <<
" <key>location</key>\r\n"
855 <<
" <key>ranges</key>\r\n"
862 <<
" <key>depth</key><integer>0</integer>\r\n"
863 <<
" <key>extended_message</key>\r\n"
865 <<
" <key>message</key>\r\n"
870 plist <<
" </array>\r\n"
874 <<
" <key>check_name</key><string>" << msg.
id <<
"</string>\r\n"
875 <<
" <!-- This hash is experimental and going to change! -->\r\n"
876 <<
" <key>issue_hash_content_of_line_in_context</key><string>" << 0 <<
"</string>\r\n"
877 <<
" <key>issue_context_kind</key><string></string>\r\n"
878 <<
" <key>issue_context</key><string></string>\r\n"
879 <<
" <key>issue_hash_function_offset</key><string></string>\r\n"
880 <<
" <key>location</key>\r\n"
887 std::string
replaceStr(std::string s,
const std::string &from,
const std::string &to)
889 std::string::size_type pos1 = 0;
890 while (pos1 < s.size()) {
891 pos1 = s.find(from, pos1);
892 if (pos1 == std::string::npos)
894 if (pos1 > 0 && (s[pos1-1] ==
'_' || std::isalnum(s[pos1-1]))) {
898 const std::string::size_type pos2 = pos1 + from.size();
899 if (pos2 >= s.size())
900 return s.substr(0,pos1) + to;
901 if (s[pos2] ==
'_' || std::isalnum(s[pos2])) {
905 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.
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 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)
void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith)
Replace all occurrences of searchFor with replaceWith in the given source.
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)