diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 1cc7188a6..9966a6832 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -83,6 +83,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) _exitAfterPrint = true; return true; } + // Flag used for various purposes during debugging else if (strcmp(argv[i], "--debug") == 0) _settings->debug = _settings->debugwarnings = true; @@ -91,6 +92,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) else if (strcmp(argv[i], "--debug-warnings") == 0) _settings->debugwarnings = true; + // Print out code that triggers false positive + else if (strcmp(argv[i], "--debug-fp") == 0) + _settings->debugFalsePositive = true; + // Enable all checks - will be removed in future else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0) { diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 774c3e32e..1e6d1e9f3 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -82,6 +82,73 @@ unsigned int CppCheck::check(const std::string &path, const std::string &content return retval; } +std::string CppCheck::replaceAll(std::string code, const std::string &from, const std::string &to) +{ + size_t pos = 0; + while ((pos = code.find(from, pos)) != std::string::npos) + { + code.replace(pos, from.length(), to); + pos += to.length(); + } + + return code; +} + +bool CppCheck::findError(std::string code, const char FileName[]) +{ + // First make sure that error occurs with the original code + checkFile(code, FileName); + if (_errorList.empty()) + { + // Error does not occur with this code + return false; + } + + std::string previousCode = code; + std::string error = _errorList.front(); + for (;;) + { + + // Try to remove included files from the source + size_t found=previousCode.rfind("\n#endfile"); + if (found == std::string::npos) + { + // No modifications can be done to the code + } + else + { + // Modify code and re-check it to see if error + // is still there. + code = previousCode.substr(found+9); + _errorList.clear(); + checkFile(code, FileName); + } + + if (_errorList.empty()) + { + // Latest code didn't fail anymore. Fall back + // to previous code + code = previousCode; + } + else + { + error = _errorList.front(); + } + + // Add '\n' so that "\n#file" on first line would be found + code = "// " + error + "\n" + code; + code = replaceAll(code, "\n#file", "\n// #file"); + code = replaceAll(code, "\n#endfile", "\n// #endfile"); + + // We have reduced the code as much as we can. Print out + // the code and quit. + _errorLogger.reportOut(code); + break; + } + + return true; +} + unsigned int CppCheck::processFile() { exitcode = 0; @@ -186,7 +253,18 @@ unsigned int CppCheck::processFile() if (!appendCode.empty()) Preprocessor::preprocessWhitespaces(appendCode); - checkFile(codeWithoutCfg + appendCode, _filename.c_str()); + if (_settings.debugFalsePositive) + { + if (findError(codeWithoutCfg + appendCode, _filename.c_str())) + { + return exitcode; + } + } + else + { + checkFile(codeWithoutCfg + appendCode, _filename.c_str()); + } + ++checkCount; } } @@ -204,6 +282,8 @@ unsigned int CppCheck::processFile() return exitcode; } + + void CppCheck::checkFunctionUsage() { // This generates false positives - especially for libraries @@ -409,6 +489,13 @@ void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) if (errmsg.empty()) return; + if (_settings.debugFalsePositive) + { + // Don't print out error + _errorList.push_back(errmsg); + return; + } + // Alert only about unique errors if (std::find(_errorList.begin(), _errorList.end(), errmsg) != _errorList.end()) return; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 301329a95..73a5ccc05 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -158,6 +158,19 @@ private: */ virtual void reportOut(const std::string &outmsg); + /** + * @brief Check given code. If error is found, return true + * and print out source of the file. Try to reduce the code + * while still showing the error. + */ + bool findError(std::string code, const char FileName[]); + + /** + * @brief Replace "from" strings with "to" strings in "code" + * and return it. + */ + std::string replaceAll(std::string code, const std::string &from, const std::string &to); + unsigned int exitcode; std::list _errorList; std::ostringstream _errout; diff --git a/lib/settings.cpp b/lib/settings.cpp index 43c630c07..efc6a37ad 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -31,6 +31,7 @@ Settings::Settings() { debug = debugwarnings = false; + debugFalsePositive = false; _errorsOnly = false; _inlineSuppressions = false; _verbose = false; diff --git a/lib/settings.h b/lib/settings.h index 80752171f..afe4b306f 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -55,6 +55,9 @@ public: /** @brief Is --debug-warnings given? */ bool debugwarnings; + /** @brief Is --debug-fp given? */ + bool debugFalsePositive; + /** @brief Inconclusive checks */ bool inconclusive;