diff --git a/lib/check.h b/lib/check.h index 605316d2a..3dcee68f8 100644 --- a/lib/check.h +++ b/lib/check.h @@ -45,7 +45,6 @@ namespace tinyxml2 { /// @addtogroup Core /// @{ - /** * @brief Interface class that cppcheck uses to communicate with the checks. * All checking classes must inherit from this class @@ -158,19 +157,27 @@ protected: reportError(errmsg); } - std::list getErrorPath(const Token *errtok, const ValueFlow::Value *value) const { - std::list errorPath; + void reportError(const ErrorPath &errorPath, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, bool inconclusive) { + const ErrorLogger::ErrorMessage errmsg(errorPath, _tokenizer ? &_tokenizer->list : nullptr, severity, id, msg, cwe, inconclusive); + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + reportError(errmsg); + } + + ErrorPath getErrorPath(const Token *errtok, const ValueFlow::Value *value) const { + ErrorPath errorPath; if (!value) { - errorPath.push_back(errtok); + errorPath.push_back(ErrorPathItem(errtok,"")); } else if (_settings->verbose) { - errorPath = value->callstack; - errorPath.push_back(errtok); + errorPath = value->errorPath; + errorPath.push_back(ErrorPathItem(errtok,"")); } else { if (value->condition) - errorPath.push_back(value->condition); + errorPath.push_back(ErrorPathItem(value->condition, "condition '" + value->condition->expressionString() + "'")); //else if (!value->isKnown() || value->defaultArg) // errorPath = value->callstack; - errorPath.push_back(errtok); + errorPath.push_back(ErrorPathItem(errtok,"")); } return errorPath; } diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index b6ea1589d..85b0ed751 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1780,7 +1780,7 @@ void CheckBufferOverrun::negativeIndexError(const Token *tok, MathLib::bigint in void CheckBufferOverrun::negativeIndexError(const Token *tok, const ValueFlow::Value &index) { - const std::list errorPath = getErrorPath(tok, &index); + const ErrorPath errorPath = getErrorPath(tok, &index); std::ostringstream errmsg; if (index.condition) errmsg << ValueFlow::eitherTheConditionIsRedundant(index.condition) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index c78464f81..9809d48b3 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -473,7 +473,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var if (!_settings->isEnabled(value, inconclusive)) return; - const std::list errorPath = getErrorPath(tok,value); + const ErrorPath errorPath = getErrorPath(tok,value); if (value->condition) { reportError(errorPath, Severity::warning, "nullPointerRedundantCheck", errmsgcond, CWE476, inconclusive || value->inconclusive); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8ed5cb916..b5595dfec 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1656,7 +1656,7 @@ void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value) return; } - const std::list errorPath = getErrorPath(tok, value); + const ErrorPath errorPath = getErrorPath(tok, value); std::ostringstream errmsg; if (value->condition) diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 209f255fd..a141fdf51 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -111,6 +111,25 @@ ErrorLogger::ErrorMessage::ErrorMessage(const std::list& callstack setmsg(msg); } +ErrorLogger::ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenList, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, bool inconclusive) + : _id(id), _severity(severity), _cwe(cwe.id), _inconclusive(inconclusive) +{ + // Format callstack + for (ErrorPath::const_iterator it = errorPath.begin(); it != errorPath.end(); ++it) { + const Token *tok = it->first; + const std::string &info = it->second; + + // --errorlist can provide null values here + if (tok) + _callStack.push_back(ErrorLogger::ErrorMessage::FileLocation(tok, info, tokenList)); + } + + if (tokenList && !tokenList->getFiles().empty()) + file0 = tokenList->getFiles()[0]; + + setmsg(msg); +} + ErrorLogger::ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errmsg) : _id(errmsg->Attribute("id")), _severity(Severity::fromString(errmsg->Attribute("severity"))), @@ -125,7 +144,10 @@ ErrorLogger::ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errms _inconclusive = attr && (std::strcmp(attr, "true") == 0); for (const tinyxml2::XMLElement *e = errmsg->FirstChildElement(); e; e = e->NextSiblingElement()) { if (std::strcmp(e->Name(),"location")==0) { - _callStack.push_back(ErrorLogger::ErrorMessage::FileLocation(e->Attribute("file"), std::atoi(e->Attribute("line")))); + const char *strfile = e->Attribute("file"); + const char *strinfo = e->Attribute("info"); + const char *strline = e->Attribute("line"); + _callStack.push_back(ErrorLogger::ErrorMessage::FileLocation(strfile, strinfo ? strinfo : "", std::atoi(strline))); } } } @@ -453,6 +475,11 @@ ErrorLogger::ErrorMessage::FileLocation::FileLocation(const Token* tok, const To { } +ErrorLogger::ErrorMessage::FileLocation::FileLocation(const Token* tok, const std::string &info, const TokenList* list) + : line(tok->linenr()), fileNumber(tok->fileIndex()), _file(list->file(tok)), _info(info) +{ +} + std::string ErrorLogger::ErrorMessage::FileLocation::getfile(bool convert) const { if (convert) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index da08e085c..c9cfe3e72 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -160,6 +160,10 @@ public: } }; + +typedef std::pair ErrorPathItem; +typedef std::list ErrorPath; + /** * @brief This is an interface, which the class responsible of error logging * should implement. @@ -190,6 +194,7 @@ public: } FileLocation(const Token* tok, const TokenList* list); + FileLocation(const Token* tok, const std::string &info, const TokenList* tokenList); /** * Return the filename. @@ -214,12 +219,14 @@ public: private: std::string _file; + std::string _info; }; ErrorMessage(const std::list &callStack, const std::string& file1, Severity::SeverityType severity, const std::string &msg, const std::string &id, bool inconclusive); ErrorMessage(const std::list &callStack, const std::string& file1, Severity::SeverityType severity, const std::string &msg, const std::string &id, const CWE &cwe, bool inconclusive); ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive); ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, const CWE &cwe, bool inconclusive); + ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenList, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, bool inconclusive); ErrorMessage(); explicit ErrorMessage(const tinyxml2::XMLElement * const errmsg); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index eba36f0a3..5ec5ea8ec 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -365,7 +365,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti result.inconclusive = value1->inconclusive | value2->inconclusive; result.varId = (value1->varId != 0U) ? value1->varId : value2->varId; result.varvalue = (result.varId == value1->varId) ? value1->varvalue : value2->varvalue; - result.callstack = (value1->callstack.empty() ? value2 : value1)->callstack; + result.errorPath = (value1->errorPath.empty() ? value2 : value1)->errorPath; if (value1->valueKind == value2->valueKind) result.valueKind = value1->valueKind; const float floatValue1 = value1->isIntValue() ? value1->intvalue : value1->floatValue; @@ -1972,7 +1972,7 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat std::list values = tok->astOperand2()->values(); for (std::list::iterator it = values.begin(); it != values.end(); ++it) - it->callstack.push_back(tok->astOperand2()); + it->errorPath.push_back(ErrorPathItem(tok->astOperand2(),"assignment")); const bool constValue = tok->astOperand2()->isNumber(); if (tokenlist->isCPP() && Token::Match(var->typeStartToken(), "bool|_Bool")) { @@ -2771,9 +2771,9 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, } } - // callstack.. + // Error path.. for (std::list::iterator it = argvalues.begin(); it != argvalues.end(); ++it) - it->callstack.push_back(argtok); + it->errorPath.push_back(ErrorPathItem(argtok, "function call argument")); // passed values are not "known".. for (std::list::iterator it = argvalues.begin(); it != argvalues.end(); ++it) { diff --git a/lib/valueflow.h b/lib/valueflow.h index 01a9fddff..e249e06a6 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -34,9 +34,12 @@ class Settings; namespace ValueFlow { class CPPCHECKLIB Value { public: + typedef std::pair ErrorPathItem; + typedef std::list ErrorPath; + explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} Value(const Token *c, long long val) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) { - callstack.push_back(c); + errorPath.push_back(ErrorPathItem(c, "condition")); } bool operator==(const Value &rhs) const { @@ -105,10 +108,10 @@ namespace ValueFlow { /** For calculated values - variable value that calculated value depends on */ long long varvalue; - /** Condition that this value depends on (TODO: replace with a 'callstack') */ + /** Condition that this value depends on */ const Token *condition; - std::list callstack; + ErrorPath errorPath; /** For calculated values - varId that calculated value depends on */ unsigned int varId;