diff --git a/man/cppcheck.1.xml b/man/cppcheck.1.xml index 9bdca39f0..80766539a 100644 --- a/man/cppcheck.1.xml +++ b/man/cppcheck.1.xml @@ -112,6 +112,7 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ + @@ -208,6 +209,12 @@ files, this is not needed. Check coding style. + + + + Suppress warnings listed in the file. Filename and line as optional. The format of the single line in file is: [error id]:[filename]:[line] + + diff --git a/src/cppcheck.cpp b/src/cppcheck.cpp index 302fe4086..8ba3d3e98 100644 --- a/src/cppcheck.cpp +++ b/src/cppcheck.cpp @@ -98,6 +98,20 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[]) else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--style") == 0) _settings._checkCodingStyle = true; + // Filter errors + else if (strcmp(argv[i], "--suppressions") == 0) + { + ++i; + + if (i >= argc) + return "No file specified for the --suppressions option\n"; + + std::ifstream f(argv[i]); + if (!f.is_open()) + return "couldn't open the file \"" + std::string(argv[i]) + "\"\n"; + _settings.suppressions(f); + } + // Verbose error messages (configuration info) else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) _settings._verbose = true; @@ -301,8 +315,8 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[]) "Syntax:\n" " cppcheck [--all] [--append=file] [--auto-dealloc file.lst]\n" " [--error-exitcode=[n]] [--force] [--help] [-Idir] [-j [jobs]]\n" - " [--quiet] [--style] [--unused-functions] [--verbose] [--version]\n" - " [--xml] [file or path1] [file or path] ...\n" + " [--quiet] [--style] [--suppressions file.txt] [--unused-functions]\n" + " [--verbose] [--version] [--xml] [file or path1] [file or path] ...\n" "\n" "If path is given instead of filename, *.cpp, *.cxx, *.cc, *.c++ and *.c files\n" "are checked recursively from given directory.\n\n" @@ -331,6 +345,9 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[]) " -j [jobs] Start [jobs] threads to do the checking simultaneously.\n" " -q, --quiet Only print error messages\n" " -s, --style Check coding style\n" + " --suppressions file Suppress warnings listed in the file. Filename and line\n" + " are optional. The format of the single line in file is:\n" + " [error id]:[filename]:[line]\n" " --template '[text]' Format the error messages. E.g.\n" " '{file}:{line},{severity},{id},{message}' or\n" " '{file}({line}):({severity}) {message}'\n" @@ -528,6 +545,17 @@ void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) if (std::find(_errorList.begin(), _errorList.end(), errmsg) != _errorList.end()) return; + std::string file; + unsigned int line(0); + if (!msg._callStack.empty()) + { + file = msg._callStack.back().getfile(); + line = msg._callStack.back().line; + } + + if (_settings.isSuppressed(msg._id, file, line)) + return; + _errorList.push_back(errmsg); std::string errmsg2(errmsg); if (_settings._verbose) diff --git a/src/settings.cpp b/src/settings.cpp index ac49b2737..34dcf8ed4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -20,6 +20,7 @@ #include #include +#include Settings::Settings() { @@ -59,6 +60,62 @@ void Settings::autoDealloc(std::istream &istr) } } +bool Settings::suppressions(std::istream &istr) +{ + std::string line; + while (getline(istr, line)) + { + // Skip empty lines + if (line.empty()) + continue; + + std::istringstream lineStream(line); + std::string id; + std::string file; + unsigned int lineNumber = 0; + if (std::getline(lineStream, id, ':')) + { + if (std::getline(lineStream, file, ':')) + { + lineStream >> lineNumber; + } + } + + // We could perhaps check if the id is valid and return error if it is not + addSuppression(id, file, lineNumber); + } + + return true; +} + +void Settings::addSuppression(const std::string &errorId, const std::string &file, unsigned int line) +{ + _suppressions[errorId][file].push_back(line); + _suppressions[errorId][file].sort(); +} + +bool Settings::isSuppressed(const std::string &errorId, const std::string &file, unsigned int line) +{ + if (_suppressions.find(errorId) == _suppressions.end()) + return false; + + // Check are all errors of this type filtered out + if (_suppressions[errorId].find("") != _suppressions[errorId].end()) + return true; + + if (_suppressions[errorId].find(file) == _suppressions[errorId].end()) + return false; + + // Check should all errors in this file be filtered out + if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), 0) != _suppressions[errorId][file].end()) + return true; + + if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), line) == _suppressions[errorId][file].end()) + return false; + + return true; +} + void Settings::addAutoAllocClass(const std::string &name) { _autoDealloc.push_back(name); diff --git a/src/settings.h b/src/settings.h index 99a4bf96b..20219257d 100644 --- a/src/settings.h +++ b/src/settings.h @@ -22,6 +22,7 @@ #include #include #include +#include /// @addtogroup Core /// @{ @@ -41,6 +42,9 @@ private: /** Code to append in the checks */ std::string _append; + /** List of error which the user doesn't want to see. */ + std::map > > _suppressions; + public: Settings(); virtual ~Settings(); @@ -87,6 +91,28 @@ public: /** Add class to list of automatically deallocated classes */ void addAutoAllocClass(const std::string &name); + /** + * Don't show errors listed in the file. + * @param istr Open file stream where errors can be read. + * @return true on success, false in syntax error is noticed. + */ + bool suppressions(std::istream &istr); + + /** + * Don't show this error. If file and/or line are optional. In which case + * the errorId alone is used for filtering. + * @param errorId, the id for the error, e.g. "arrayIndexOutOfBounds" + * @param file File name with the path, e.g. "src/main.cpp" + * @param line number, e.g. "123" + */ + void addSuppression(const std::string &errorId, const std::string &file = "", unsigned int line = 0); + + /** + * Returns true if this message should not be shown to the user. + * @return true if this error is suppressed. + */ + bool isSuppressed(const std::string &errorId, const std::string &file, unsigned int line); + /** is a class automaticly deallocated? */ bool isAutoDealloc(const char classname[]) const;