diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index e2fe8ec3c..3d49ed42c 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1,817 +1,831 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "cppcheck.h" - -#include "preprocessor.h" // preprocessor. -#include "tokenize.h" // <- Tokenizer - -#include "filelister.h" - -#include "check.h" - -#include -#include -#include -#include -#include -#include -#include - -/* - TODO: - - handle SHOWTIME_TOP5 and SHOWTIME_AVERAGE (show time per result average) in TimerResults - - sort list by time - - list number of results? - - find way to store number of results per entry - - do not sort the results alphabetically -*/ -enum -{ - SHOWTIME_NONE = 0, - SHOWTIME_FILE, - SHOWTIME_SUMMARY, - SHOWTIME_TOP5, - SHOWTIME_AVERAGE -}; - -class TimerResultsIntf -{ -public: - virtual ~TimerResultsIntf() { } - - virtual void AddResults(const std::string& str, clock_t clocks) = 0; -}; - -class TimerResults : public TimerResultsIntf -{ -public: - TimerResults() - // : _numerOfResults(0) - { - } - - void ShowResults() - { - std::map::const_iterator I = _results.begin(); - const std::map::const_iterator E = _results.end(); - - while (I != E) - { - double sec = (double)I->second / CLOCKS_PER_SEC; - std::cout << I->first << ": " << sec << "s" << std::endl; - - ++I; - } - } - - virtual void AddResults(const std::string& str, clock_t clocks) - { - if (_results.find(str) != _results.end()) - _results[str] += clocks; - else - _results[str] = clocks; - - //_numerOfResults++; - } - -private: - std::map _results; - //unsigned int _numerOfResults; -}; - -static TimerResults S_timerResults; - -class Timer -{ -public: - Timer(const std::string& str, unsigned int showtimeMode, TimerResultsIntf* timerResults = NULL) - : _str(str) - , _showtimeMode(showtimeMode) - , _stopped(false) - , _start(0) - , _timerResults(timerResults) - { - if (showtimeMode != SHOWTIME_NONE) - _start = clock(); - } - - ~Timer() - { - Stop(); - } - - void Stop() - { - if ((_showtimeMode != SHOWTIME_NONE) && !_stopped) - { - clock_t end = clock(); - clock_t diff = end - _start; - - if ((_showtimeMode == SHOWTIME_SUMMARY) || (_showtimeMode == SHOWTIME_TOP5)) - { - if (_timerResults) - _timerResults->AddResults(_str, diff); - } - - if (_showtimeMode == SHOWTIME_FILE) - { - double sec = (double)diff / CLOCKS_PER_SEC; - std::cout << _str << ": " << sec << "s" << std::endl; - } - } - - _stopped = true; - } - -private: - Timer& operator=(const Timer&); // disallow assignments - - const std::string _str; - unsigned int _showtimeMode; - clock_t _start; - bool _stopped; - TimerResultsIntf* _timerResults; -}; - -//--------------------------------------------------------------------------- - -CppCheck::CppCheck(ErrorLogger &errorLogger) - : _errorLogger(errorLogger) -{ - exitcode = 0; -} - -CppCheck::~CppCheck() -{ - S_timerResults.ShowResults(); -} - -void CppCheck::settings(const Settings ¤tSettings) -{ - _settings = currentSettings; -} - -void CppCheck::addFile(const std::string &path) -{ - getFileLister()->recursiveAddFiles(_filenames, path.c_str(), true); -} - -void CppCheck::addFile(const std::string &path, const std::string &content) -{ - _filenames.push_back(path); - _fileContents[ path ] = content; -} - -void CppCheck::clearFiles() -{ - _filenames.clear(); - _fileContents.clear(); -} - -const char * CppCheck::version() -{ - return "1.42"; -} - - -static void AddFilesToList(const std::string& FileList, std::vector& PathNames) -{ - // to keep things initially simple, if the file can't be opened, just be - // silent and move on - // ideas : we could also require this should be an xml file, with the filenames - // specified in an xml structure - // we could elaborate this then, to also include the I-paths, ... - // basically for everything that makes the command line very long - // xml is a bonus then, since we can easily extend it - // we need a good parser then -> suggestion : TinyXml - // drawback : creates a dependency - std::ifstream Files(FileList.c_str()); - if (Files) - { - std::string FileName; - while (std::getline(Files, FileName)) // next line - { - if (!FileName.empty()) - { - PathNames.push_back(FileName); - } - } - } -} - -bool CppCheck::parseFromArgs(int argc, const char* const argv[]) -{ - std::vector pathnames; - bool showHelp = false; - for (int i = 1; i < argc; i++) - { - if (strcmp(argv[i], "--version") == 0) - { - reportOut(std::string("Cppcheck ") + version()); - return true; - } - - // Flag used for various purposes during debugging - else if (strcmp(argv[i], "--debug") == 0) - _settings._debug = true; - - // Inconclusive checking - keep this for compatibility but don't - // handle it - else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0) - ; - - // Only print something when there are errors - else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) - _settings._errorsOnly = true; - - // Checking coding style - else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--style") == 0) - _settings.addEnabled("style"); - - // Filter errors - else if (strcmp(argv[i], "--suppressions") == 0) - { - ++i; - - if (i >= argc) - { - reportOut("cppcheck: No file specified for the --suppressions option"); - return false; - } - - std::ifstream f(argv[i]); - if (!f.is_open()) - { - reportOut("cppcheck: Couldn't open the file \"" + std::string(argv[i]) + "\""); - return false; - } - _settings.nomsg.parseFile(f); - } - - // Filter errors - else if (strcmp(argv[i], "--exitcode-suppressions") == 0) - { - ++i; - - if (i >= argc) - { - reportOut("cppcheck: No file specified for the --exitcode-suppressions option"); - return false; - } - - std::ifstream f(argv[i]); - if (!f.is_open()) - { - reportOut("cppcheck: Couldn't open the file \"" + std::string(argv[i]) + "\""); - return false; - } - _settings.nofail.parseFile(f); - } - - // Enables inline suppressions. - else if (strcmp(argv[i], "--inline-suppr") == 0) - _settings._inlineSuppressions = true; - - // Verbose error messages (configuration info) - else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) - _settings._verbose = true; - - // Force checking of files that have "too many" configurations - else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--force") == 0) - _settings._force = true; - - // Write results in results.xml - else if (strcmp(argv[i], "--xml") == 0) - _settings._xml = true; - - // Check if there are unused functions - else if (strcmp(argv[i], "--unused-functions") == 0) - _settings.addEnabled("unusedFunctions"); - - // Append userdefined code to checked source code - else if (strncmp(argv[i], "--append=", 9) == 0) - _settings.append(9 + argv[i]); - - // show timing information.. - else if (strncmp(argv[i], "--showtime=", 11) == 0) - { - const std::string showtimeMode = argv[i] + 11; - if (showtimeMode == "file") - _settings._showtime = SHOWTIME_FILE; - else if (showtimeMode == "summary") - _settings._showtime = SHOWTIME_SUMMARY; - else if (showtimeMode == "top5") - _settings._showtime = SHOWTIME_TOP5; - else if (showtimeMode == "average") - _settings._showtime = SHOWTIME_AVERAGE; - else - _settings._showtime = SHOWTIME_NONE; - } - - // Print help - else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) - { - pathnames.clear(); - _filenames.clear(); - showHelp = true; - break; - } - - - else if (strncmp(argv[i], "--enable=", 9) == 0) - { - _settings.addEnabled(argv[i] + 9); - } - - // --error-exitcode=1 - else if (strncmp(argv[i], "--error-exitcode=", 17) == 0) - { - std::string temp = argv[i]; - temp = temp.substr(17); - std::istringstream iss(temp); - if (!(iss >> _settings._exitCode)) - { - _settings._exitCode = 0; - reportOut("cppcheck: Argument must be an integer. Try something like '--error-exitcode=1'"); - return false; - } - } - - // Include paths - else if (strcmp(argv[i], "-I") == 0 || strncmp(argv[i], "-I", 2) == 0) - { - std::string path; - - // "-I path/" - if (strcmp(argv[i], "-I") == 0) - { - ++i; - if (i >= argc) - { - reportOut("cppcheck: argument to '-I' is missing"); - return false; - } - - path = argv[i]; - } - - // "-Ipath/" - else - { - path = argv[i]; - path = path.substr(2); - } - - // If path doesn't end with / or \, add it - if (path[path.length()-1] != '/' && path[path.length()-1] != '\\') - path += '/'; - - _settings._includePaths.push_back(path); - } - - // file list specified - else if (strncmp(argv[i], "--file-list=", 12) == 0) - { - // open this file and read every input file (1 file name per line) - AddFilesToList(12 + argv[i], pathnames); - } - - // Output formatter - else if (strcmp(argv[i], "--template") == 0) - { - // "--template path/" - ++i; - if (i >= argc) - { - reportOut("cppcheck: argument to '--template' is missing"); - return false; - } - - _settings._outputFormat = argv[i]; - if (_settings._outputFormat == "gcc") - _settings._outputFormat = "{file}:{line}: {severity}: {message}"; - else if (_settings._outputFormat == "vs") - _settings._outputFormat = "{file}({line}): {severity}: {message}"; - } - - // Checking threads - else if (strcmp(argv[i], "-j") == 0 || - strncmp(argv[i], "-j", 2) == 0) - { - std::string numberString; - - // "-j 3" - if (strcmp(argv[i], "-j") == 0) - { - ++i; - if (i >= argc) - { - reportOut("cppcheck: argument to '-j' is missing"); - return false; - } - - numberString = argv[i]; - } - - // "-j3" - else if (strncmp(argv[i], "-j", 2) == 0) - { - numberString = argv[i]; - numberString = numberString.substr(2); - } - - std::istringstream iss(numberString); - if (!(iss >> _settings._jobs)) - { - reportOut("cppcheck: argument to '-j' is not a number"); - return false; - } - - if (_settings._jobs > 1000) - { - reportOut("cppcheck: argument for '-j' is allowed to be 1000 at max"); - return false; - } - } - - // auto deallocated classes.. - else if (strcmp(argv[i], "--auto-dealloc") == 0) - { - ++i; - - if (i >= argc || !strstr(argv[i], ".lst")) - { - reportOut("cppcheck: No .lst file specified for the --auto-dealloc option"); - return false; - } - - std::ifstream f(argv[i]); - if (!f.is_open()) - { - reportOut("cppcheck: couldn't open the file \"" + std::string(argv[i+1]) + "\""); - return false; - } - - _settings.autoDealloc(f); - } - - // print all possible error messages.. - else if (strcmp(argv[i], "--errorlist") == 0) - { - getErrorMessages(); - } - - // documentation.. - else if (strcmp(argv[i], "--doc") == 0) - { - std::ostringstream doc; - // Get documentation.. - for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) - { - doc << "===" << (*it)->name() << "===\n" - << (*it)->classInfo() << "\n\n"; - } - - std::string doc2(doc.str()); - while (doc2.find("\n\n\n") != std::string::npos) - doc2.erase(doc2.find("\n\n\n"), 1); - reportOut(doc2); - return true; - } - - else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0) - { - reportOut("cppcheck: error: unrecognized command line option \"" + std::string(argv[i]) + "\""); - return false; - } - - else - pathnames.push_back(argv[i]); - } - - if (_settings.isEnabled("unusedFunctions") && _settings._jobs > 1) - { - reportOut("unusedFunctions check can't be used with -j option, so it was disabled."); - } - - if (!pathnames.empty()) - { - // Execute recursiveAddFiles() to each given file parameter - std::vector::const_iterator iter; - for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) - getFileLister()->recursiveAddFiles(_filenames, iter->c_str(), true); - } - - if (argc <= 1 || showHelp) - { - std::ostringstream oss; - oss << "Cppcheck - A tool for static C/C++ code analysis\n" - "\n" - "Syntax:\n" - " cppcheck [--append=file] [--enable=]\n" - " [--error-exitcode=[n]] [--exitcode-suppressions file] [--force]\n" - " [--help] [-Idir] [-j [jobs]] [--quiet] [--style]\n" - " [--suppressions file.txt] [--inline-suppr] [--file-list=file.txt]\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" - "Options:\n" - " --append=file This allows you to provide information about\n" - " functions by providing an implementation for these.\n" - " --enable=id Enable specific checks. The available ids are:\n" - " * all - enable all checks\n" - " * exceptNew - exception safety when using new\n" - " * exceptRealloc - exception safety when reallocating\n" - " * style - Check coding style\n" - " * unusedFunctions - check for unused functions\n" - " Several ids can be given if you separate them with commas\n" - " --error-exitcode=[n] If errors are found, integer [n] is returned instead\n" - " of default 0. EXIT_FAILURE is returned\n" - " if arguments are not valid or if no input files are\n" - " provided. Note that your operating system can\n" - " modify this value, e.g. 256 can become 0.\n" - " --exitcode-suppressions file\n" - " Used when certain messages should be displayed but\n" - " should not cause a non-zero exitcode.\n" - " -f, --force Force checking on files that have \"too many\"\n" - " configurations\n" - " -h, --help Print this help\n" - " -I [dir] Give include path. Give several -I parameters to give\n" - " several paths. First given path is checked first. If\n" - " paths are relative to source files, this is not needed\n" - " -j [jobs] Start [jobs] threads to do the checking simultaneously.\n" - " -q, --quiet Only print error messages\n" - " -s, --style deprecated, use --enable=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" - " --inline-suppr Enable inline suppressions. Use them by placing one or\n" - " more comments in the form: // cppcheck-suppress memleak\n" - " on the lines before the warning to suppress.\n" - " --file-list=file Specify the files to check in a text file. One Filename per line.\n" - " --template '[text]' Format the error messages. E.g.\n" - " '{file}:{line},{severity},{id},{message}' or\n" - " '{file}({line}):({severity}) {message}'\n" - " Pre-defined templates: gcc, vs\n" - " --unused-functions deprecated, use --enable=unusedFunctions\n" - " -v, --verbose More detailed error reports\n" - " --version Print out version number\n" - " --xml Write results in xml to error stream.\n" - "\n" - "Example usage:\n" - " # Recursively check the current folder. Print the progress on the screen and\n" - " write errors in a file:\n" - " cppcheck . 2> err.txt\n" - " # Recursively check ../myproject/ and don't print progress:\n" - " cppcheck --quiet ../myproject/\n" - " # Check only files one.cpp and two.cpp and give all information there is:\n" - " cppcheck -v -s one.cpp two.cpp\n" - " # Check f.cpp and search include files from inc1/ and inc2/:\n" - " cppcheck -I inc1/ -I inc2/ f.cpp\n"; - reportOut(oss.str()); - } - else if (_filenames.empty()) - { - reportOut("cppcheck: No C or C++ source files found."); - return false; - } - - return true; -} - -unsigned int CppCheck::check() -{ - exitcode = 0; - - _checkUnusedFunctions.setErrorLogger(this); - std::sort(_filenames.begin(), _filenames.end()); - for (unsigned int c = 0; c < _filenames.size(); c++) - { - _errout.str(""); - const std::string fname = _filenames[c]; - - if (_settings.terminated()) - break; - - if (_settings._errorsOnly == false) - _errorLogger.reportOut(std::string("Checking ") + fname + std::string("...")); - - try - { - Preprocessor preprocessor(&_settings, this); - std::list configurations; - std::string filedata = ""; - - if (_fileContents.size() > 0 && _fileContents.find(_filenames[c]) != _fileContents.end()) - { - // File content was given as a string - std::istringstream iss(_fileContents[ _filenames[c] ]); - preprocessor.preprocess(iss, filedata, configurations, fname, _settings._includePaths); - } - else - { - // Only file name was given, read the content from file - std::ifstream fin(fname.c_str()); - Timer t("Preprocessor::preprocess", _settings._showtime, &S_timerResults); - preprocessor.preprocess(fin, filedata, configurations, fname, _settings._includePaths); - } - - int checkCount = 0; - for (std::list::const_iterator it = configurations.begin(); it != configurations.end(); ++it) - { - // Check only 12 first configurations, after that bail out, unless --force - // was used. - if (!_settings._force && checkCount > 11) - { - if (_settings._errorsOnly == false) - _errorLogger.reportOut(std::string("Bailing out from checking ") + fname + ": Too many configurations. Recheck this file with --force if you want to check them all."); - - break; - } - - cfg = *it; - Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults); - const std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, fname, &_errorLogger); - t.Stop(); - - // If only errors are printed, print filename after the check - if (_settings._errorsOnly == false && it != configurations.begin()) - _errorLogger.reportOut(std::string("Checking ") + fname + ": " + cfg + std::string("...")); - - checkFile(codeWithoutCfg + _settings.append(), _filenames[c].c_str()); - ++checkCount; - } - } - catch (std::runtime_error &e) - { - // Exception was thrown when checking this file.. - _errorLogger.reportOut("Bailing out from checking " + fname + ": " + e.what()); - } - - _errorLogger.reportStatus(c + 1, (unsigned int)_filenames.size()); - } - - // This generates false positives - especially for libraries - _settings._verbose = false; - if (_settings.isEnabled("unusedFunctions") && _settings._jobs == 1) - { - _errout.str(""); - if (_settings._errorsOnly == false) - _errorLogger.reportOut("Checking usage of global functions.."); - - _checkUnusedFunctions.check(); - } - - _errorList.clear(); - return exitcode; -} - - -//--------------------------------------------------------------------------- -// CppCheck - A function that checks a specified file -//--------------------------------------------------------------------------- - -void CppCheck::checkFile(const std::string &code, const char FileName[]) -{ - if (_settings.terminated()) - return; - - Tokenizer _tokenizer(&_settings, this); - bool result; - - // Tokenize the file - std::istringstream istr(code); - - Timer timer("Tokenizer::tokenize", _settings._showtime, &S_timerResults); - result = _tokenizer.tokenize(istr, FileName, cfg); - timer.Stop(); - if (!result) - { - // File had syntax errors, abort - return; - } - - Timer timer2("Tokenizer::fillFunctionList", _settings._showtime, &S_timerResults); - _tokenizer.fillFunctionList(); - timer2.Stop(); - - // call all "runChecks" in all registered Check classes - for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) - { - if (_settings.terminated()) - return; - - Timer timerRunChecks((*it)->name() + "::runChecks", _settings._showtime, &S_timerResults); - (*it)->runChecks(&_tokenizer, &_settings, this); - } - - Timer timer3("Tokenizer::simplifyTokenList", _settings._showtime, &S_timerResults); - result = _tokenizer.simplifyTokenList(); - timer3.Stop(); - if (!result) - return; - - Timer timer4("Tokenizer::fillFunctionList", _settings._showtime, &S_timerResults); - _tokenizer.fillFunctionList(); - timer4.Stop(); - - if (_settings.isEnabled("unusedFunctions") && _settings._jobs == 1) - _checkUnusedFunctions.parseTokens(_tokenizer); - - // call all "runSimplifiedChecks" in all registered Check classes - for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) - { - if (_settings.terminated()) - return; - - Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings._showtime, &S_timerResults); - (*it)->runSimplifiedChecks(&_tokenizer, &_settings, this); - } -} - -Settings CppCheck::settings() const -{ - return _settings; -} - -//--------------------------------------------------------------------------- - -void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) -{ - std::string errmsg = msg.toText(); - - // Alert only about unique errors - 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.nomsg.isSuppressed(msg._id, file, line)) - return; - - if (!_settings.nofail.isSuppressed(msg._id, file, line)) - exitcode = 1; - - _errorList.push_back(errmsg); - std::string errmsg2(errmsg); - if (_settings._verbose) - { - errmsg2 += "\n Defines=\'" + cfg + "\'\n"; - } - - _errorLogger.reportErr(msg); - - _errout << errmsg2 << std::endl; -} - -void CppCheck::reportOut(const std::string &outmsg) -{ - _errorLogger.reportOut(outmsg); -} - -const std::vector &CppCheck::filenames() const -{ - return _filenames; -} - -void CppCheck::reportStatus(unsigned int /*index*/, unsigned int /*max*/) -{ - -} - -void CppCheck::getErrorMessages() -{ - // call all "getErrorMessages" in all registered Check classes - std::cout << ErrorLogger::ErrorMessage::getXMLHeader(); - for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) - { - (*it)->getErrorMessages(); - } - - Tokenizer tokenizer(&_settings, 0); - tokenizer.getErrorMessages(); - - std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl; -} +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "cppcheck.h" + +#include "preprocessor.h" // preprocessor. +#include "tokenize.h" // <- Tokenizer + +#include "filelister.h" + +#include "check.h" + +#include +#include +#include +#include +#include +#include +#include + +/* + TODO: + - handle SHOWTIME_TOP5 in TimerResults + - sort list by time + - do not sort the results alphabetically + - rename "file" to "single" + - synchronise map access in multithreaded mode or disable timing + - add unit tests + - for --showtime + - for Timer* classes + - move timer stuff to seperate source/header +*/ +enum +{ + SHOWTIME_NONE = 0, + SHOWTIME_FILE, + SHOWTIME_SUMMARY, + SHOWTIME_TOP5 +}; + +class TimerResultsIntf +{ +public: + virtual ~TimerResultsIntf() { } + + virtual void AddResults(const std::string& str, clock_t clocks) = 0; +}; + +struct TimerResultsData +{ + clock_t _clocks; + unsigned int _numberOfResults; + + TimerResultsData() + : _clocks(0) + , _numberOfResults(0) + { + } +}; + +class TimerResults : public TimerResultsIntf +{ +public: + TimerResults() + { + } + + void ShowResults() + { + clock_t overallClocks = 0; + + std::map::const_iterator I = _results.begin(); + const std::map::const_iterator E = _results.end(); + + while (I != E) + { + const double sec = (double)I->second._clocks / CLOCKS_PER_SEC; + const double secAverage = (double)(I->second._clocks / I->second._numberOfResults) / CLOCKS_PER_SEC; + std::cout << I->first << ": " << sec << "s (avg. " << secAverage << "s - " << I->second._numberOfResults << " result(s))" << std::endl; + + overallClocks += I->second._clocks; + + ++I; + } + + const double secOverall = (double)overallClocks / CLOCKS_PER_SEC; + std::cout << "Overall time: " << secOverall << "s" << std::endl; + } + + virtual void AddResults(const std::string& str, clock_t clocks) + { + _results[str]._clocks += clocks; + _results[str]._numberOfResults++; + } + +private: + std::map _results; +}; + +static TimerResults S_timerResults; + +class Timer +{ +public: + Timer(const std::string& str, unsigned int showtimeMode, TimerResultsIntf* timerResults = NULL) + : _str(str) + , _showtimeMode(showtimeMode) + , _start(0) + , _stopped(false) + , _timerResults(timerResults) + { + if (showtimeMode != SHOWTIME_NONE) + _start = clock(); + } + + ~Timer() + { + Stop(); + } + + void Stop() + { + if ((_showtimeMode != SHOWTIME_NONE) && !_stopped) + { + const clock_t end = clock(); + const clock_t diff = end - _start; + + if (_showtimeMode == SHOWTIME_FILE) + { + double sec = (double)diff / CLOCKS_PER_SEC; + std::cout << _str << ": " << sec << "s" << std::endl; + } + else + { + if (_timerResults) + _timerResults->AddResults(_str, diff); + } + } + + _stopped = true; + } + +private: + Timer& operator=(const Timer&); // disallow assignments + + const std::string _str; + const unsigned int _showtimeMode; + clock_t _start; + bool _stopped; + TimerResultsIntf* _timerResults; +}; + +//--------------------------------------------------------------------------- + +CppCheck::CppCheck(ErrorLogger &errorLogger) + : _errorLogger(errorLogger) +{ + exitcode = 0; +} + +CppCheck::~CppCheck() +{ + S_timerResults.ShowResults(); +} + +void CppCheck::settings(const Settings ¤tSettings) +{ + _settings = currentSettings; +} + +void CppCheck::addFile(const std::string &path) +{ + getFileLister()->recursiveAddFiles(_filenames, path.c_str(), true); +} + +void CppCheck::addFile(const std::string &path, const std::string &content) +{ + _filenames.push_back(path); + _fileContents[ path ] = content; +} + +void CppCheck::clearFiles() +{ + _filenames.clear(); + _fileContents.clear(); +} + +const char * CppCheck::version() +{ + return "1.42"; +} + + +static void AddFilesToList(const std::string& FileList, std::vector& PathNames) +{ + // to keep things initially simple, if the file can't be opened, just be + // silent and move on + // ideas : we could also require this should be an xml file, with the filenames + // specified in an xml structure + // we could elaborate this then, to also include the I-paths, ... + // basically for everything that makes the command line very long + // xml is a bonus then, since we can easily extend it + // we need a good parser then -> suggestion : TinyXml + // drawback : creates a dependency + std::ifstream Files(FileList.c_str()); + if (Files) + { + std::string FileName; + while (std::getline(Files, FileName)) // next line + { + if (!FileName.empty()) + { + PathNames.push_back(FileName); + } + } + } +} + +bool CppCheck::parseFromArgs(int argc, const char* const argv[]) +{ + std::vector pathnames; + bool showHelp = false; + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "--version") == 0) + { + reportOut(std::string("Cppcheck ") + version()); + return true; + } + + // Flag used for various purposes during debugging + else if (strcmp(argv[i], "--debug") == 0) + _settings._debug = true; + + // Inconclusive checking - keep this for compatibility but don't + // handle it + else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0) + ; + + // Only print something when there are errors + else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) + _settings._errorsOnly = true; + + // Checking coding style + else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--style") == 0) + _settings.addEnabled("style"); + + // Filter errors + else if (strcmp(argv[i], "--suppressions") == 0) + { + ++i; + + if (i >= argc) + { + reportOut("cppcheck: No file specified for the --suppressions option"); + return false; + } + + std::ifstream f(argv[i]); + if (!f.is_open()) + { + reportOut("cppcheck: Couldn't open the file \"" + std::string(argv[i]) + "\""); + return false; + } + _settings.nomsg.parseFile(f); + } + + // Filter errors + else if (strcmp(argv[i], "--exitcode-suppressions") == 0) + { + ++i; + + if (i >= argc) + { + reportOut("cppcheck: No file specified for the --exitcode-suppressions option"); + return false; + } + + std::ifstream f(argv[i]); + if (!f.is_open()) + { + reportOut("cppcheck: Couldn't open the file \"" + std::string(argv[i]) + "\""); + return false; + } + _settings.nofail.parseFile(f); + } + + // Enables inline suppressions. + else if (strcmp(argv[i], "--inline-suppr") == 0) + _settings._inlineSuppressions = true; + + // Verbose error messages (configuration info) + else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) + _settings._verbose = true; + + // Force checking of files that have "too many" configurations + else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--force") == 0) + _settings._force = true; + + // Write results in results.xml + else if (strcmp(argv[i], "--xml") == 0) + _settings._xml = true; + + // Check if there are unused functions + else if (strcmp(argv[i], "--unused-functions") == 0) + _settings.addEnabled("unusedFunctions"); + + // Append userdefined code to checked source code + else if (strncmp(argv[i], "--append=", 9) == 0) + _settings.append(9 + argv[i]); + + // show timing information.. + else if (strncmp(argv[i], "--showtime=", 11) == 0) + { + const std::string showtimeMode = argv[i] + 11; + if (showtimeMode == "file") + _settings._showtime = SHOWTIME_FILE; + else if (showtimeMode == "summary") + _settings._showtime = SHOWTIME_SUMMARY; + else if (showtimeMode == "top5") + _settings._showtime = SHOWTIME_TOP5; + else + _settings._showtime = SHOWTIME_NONE; + } + + // Print help + else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + { + pathnames.clear(); + _filenames.clear(); + showHelp = true; + break; + } + + + else if (strncmp(argv[i], "--enable=", 9) == 0) + { + _settings.addEnabled(argv[i] + 9); + } + + // --error-exitcode=1 + else if (strncmp(argv[i], "--error-exitcode=", 17) == 0) + { + std::string temp = argv[i]; + temp = temp.substr(17); + std::istringstream iss(temp); + if (!(iss >> _settings._exitCode)) + { + _settings._exitCode = 0; + reportOut("cppcheck: Argument must be an integer. Try something like '--error-exitcode=1'"); + return false; + } + } + + // Include paths + else if (strcmp(argv[i], "-I") == 0 || strncmp(argv[i], "-I", 2) == 0) + { + std::string path; + + // "-I path/" + if (strcmp(argv[i], "-I") == 0) + { + ++i; + if (i >= argc) + { + reportOut("cppcheck: argument to '-I' is missing"); + return false; + } + + path = argv[i]; + } + + // "-Ipath/" + else + { + path = argv[i]; + path = path.substr(2); + } + + // If path doesn't end with / or \, add it + if (path[path.length()-1] != '/' && path[path.length()-1] != '\\') + path += '/'; + + _settings._includePaths.push_back(path); + } + + // file list specified + else if (strncmp(argv[i], "--file-list=", 12) == 0) + { + // open this file and read every input file (1 file name per line) + AddFilesToList(12 + argv[i], pathnames); + } + + // Output formatter + else if (strcmp(argv[i], "--template") == 0) + { + // "--template path/" + ++i; + if (i >= argc) + { + reportOut("cppcheck: argument to '--template' is missing"); + return false; + } + + _settings._outputFormat = argv[i]; + if (_settings._outputFormat == "gcc") + _settings._outputFormat = "{file}:{line}: {severity}: {message}"; + else if (_settings._outputFormat == "vs") + _settings._outputFormat = "{file}({line}): {severity}: {message}"; + } + + // Checking threads + else if (strcmp(argv[i], "-j") == 0 || + strncmp(argv[i], "-j", 2) == 0) + { + std::string numberString; + + // "-j 3" + if (strcmp(argv[i], "-j") == 0) + { + ++i; + if (i >= argc) + { + reportOut("cppcheck: argument to '-j' is missing"); + return false; + } + + numberString = argv[i]; + } + + // "-j3" + else if (strncmp(argv[i], "-j", 2) == 0) + { + numberString = argv[i]; + numberString = numberString.substr(2); + } + + std::istringstream iss(numberString); + if (!(iss >> _settings._jobs)) + { + reportOut("cppcheck: argument to '-j' is not a number"); + return false; + } + + if (_settings._jobs > 1000) + { + reportOut("cppcheck: argument for '-j' is allowed to be 1000 at max"); + return false; + } + } + + // auto deallocated classes.. + else if (strcmp(argv[i], "--auto-dealloc") == 0) + { + ++i; + + if (i >= argc || !strstr(argv[i], ".lst")) + { + reportOut("cppcheck: No .lst file specified for the --auto-dealloc option"); + return false; + } + + std::ifstream f(argv[i]); + if (!f.is_open()) + { + reportOut("cppcheck: couldn't open the file \"" + std::string(argv[i+1]) + "\""); + return false; + } + + _settings.autoDealloc(f); + } + + // print all possible error messages.. + else if (strcmp(argv[i], "--errorlist") == 0) + { + getErrorMessages(); + } + + // documentation.. + else if (strcmp(argv[i], "--doc") == 0) + { + std::ostringstream doc; + // Get documentation.. + for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) + { + doc << "===" << (*it)->name() << "===\n" + << (*it)->classInfo() << "\n\n"; + } + + std::string doc2(doc.str()); + while (doc2.find("\n\n\n") != std::string::npos) + doc2.erase(doc2.find("\n\n\n"), 1); + reportOut(doc2); + return true; + } + + else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0) + { + reportOut("cppcheck: error: unrecognized command line option \"" + std::string(argv[i]) + "\""); + return false; + } + + else + pathnames.push_back(argv[i]); + } + + if (_settings.isEnabled("unusedFunctions") && _settings._jobs > 1) + { + reportOut("unusedFunctions check can't be used with -j option, so it was disabled."); + } + + if (!pathnames.empty()) + { + // Execute recursiveAddFiles() to each given file parameter + std::vector::const_iterator iter; + for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) + getFileLister()->recursiveAddFiles(_filenames, iter->c_str(), true); + } + + if (argc <= 1 || showHelp) + { + std::ostringstream oss; + oss << "Cppcheck - A tool for static C/C++ code analysis\n" + "\n" + "Syntax:\n" + " cppcheck [--append=file] [--enable=]\n" + " [--error-exitcode=[n]] [--exitcode-suppressions file] [--force]\n" + " [--help] [-Idir] [-j [jobs]] [--quiet] [--style]\n" + " [--suppressions file.txt] [--inline-suppr] [--file-list=file.txt]\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" + "Options:\n" + " --append=file This allows you to provide information about\n" + " functions by providing an implementation for these.\n" + " --enable=id Enable specific checks. The available ids are:\n" + " * all - enable all checks\n" + " * exceptNew - exception safety when using new\n" + " * exceptRealloc - exception safety when reallocating\n" + " * style - Check coding style\n" + " * unusedFunctions - check for unused functions\n" + " Several ids can be given if you separate them with commas\n" + " --error-exitcode=[n] If errors are found, integer [n] is returned instead\n" + " of default 0. EXIT_FAILURE is returned\n" + " if arguments are not valid or if no input files are\n" + " provided. Note that your operating system can\n" + " modify this value, e.g. 256 can become 0.\n" + " --exitcode-suppressions file\n" + " Used when certain messages should be displayed but\n" + " should not cause a non-zero exitcode.\n" + " -f, --force Force checking on files that have \"too many\"\n" + " configurations\n" + " -h, --help Print this help\n" + " -I [dir] Give include path. Give several -I parameters to give\n" + " several paths. First given path is checked first. If\n" + " paths are relative to source files, this is not needed\n" + " -j [jobs] Start [jobs] threads to do the checking simultaneously.\n" + " -q, --quiet Only print error messages\n" + " -s, --style deprecated, use --enable=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" + " --inline-suppr Enable inline suppressions. Use them by placing one or\n" + " more comments in the form: // cppcheck-suppress memleak\n" + " on the lines before the warning to suppress.\n" + " --file-list=file Specify the files to check in a text file. One Filename per line.\n" + " --template '[text]' Format the error messages. E.g.\n" + " '{file}:{line},{severity},{id},{message}' or\n" + " '{file}({line}):({severity}) {message}'\n" + " Pre-defined templates: gcc, vs\n" + " --unused-functions deprecated, use --enable=unusedFunctions\n" + " -v, --verbose More detailed error reports\n" + " --version Print out version number\n" + " --xml Write results in xml to error stream.\n" + "\n" + "Example usage:\n" + " # Recursively check the current folder. Print the progress on the screen and\n" + " write errors in a file:\n" + " cppcheck . 2> err.txt\n" + " # Recursively check ../myproject/ and don't print progress:\n" + " cppcheck --quiet ../myproject/\n" + " # Check only files one.cpp and two.cpp and give all information there is:\n" + " cppcheck -v -s one.cpp two.cpp\n" + " # Check f.cpp and search include files from inc1/ and inc2/:\n" + " cppcheck -I inc1/ -I inc2/ f.cpp\n"; + reportOut(oss.str()); + } + else if (_filenames.empty()) + { + reportOut("cppcheck: No C or C++ source files found."); + return false; + } + + return true; +} + +unsigned int CppCheck::check() +{ + exitcode = 0; + + _checkUnusedFunctions.setErrorLogger(this); + std::sort(_filenames.begin(), _filenames.end()); + for (unsigned int c = 0; c < _filenames.size(); c++) + { + _errout.str(""); + const std::string fname = _filenames[c]; + + if (_settings.terminated()) + break; + + if (_settings._errorsOnly == false) + _errorLogger.reportOut(std::string("Checking ") + fname + std::string("...")); + + try + { + Preprocessor preprocessor(&_settings, this); + std::list configurations; + std::string filedata = ""; + + if (_fileContents.size() > 0 && _fileContents.find(_filenames[c]) != _fileContents.end()) + { + // File content was given as a string + std::istringstream iss(_fileContents[ _filenames[c] ]); + preprocessor.preprocess(iss, filedata, configurations, fname, _settings._includePaths); + } + else + { + // Only file name was given, read the content from file + std::ifstream fin(fname.c_str()); + Timer t("Preprocessor::preprocess", _settings._showtime, &S_timerResults); + preprocessor.preprocess(fin, filedata, configurations, fname, _settings._includePaths); + } + + int checkCount = 0; + for (std::list::const_iterator it = configurations.begin(); it != configurations.end(); ++it) + { + // Check only 12 first configurations, after that bail out, unless --force + // was used. + if (!_settings._force && checkCount > 11) + { + if (_settings._errorsOnly == false) + _errorLogger.reportOut(std::string("Bailing out from checking ") + fname + ": Too many configurations. Recheck this file with --force if you want to check them all."); + + break; + } + + cfg = *it; + Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults); + const std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, fname, &_errorLogger); + t.Stop(); + + // If only errors are printed, print filename after the check + if (_settings._errorsOnly == false && it != configurations.begin()) + _errorLogger.reportOut(std::string("Checking ") + fname + ": " + cfg + std::string("...")); + + checkFile(codeWithoutCfg + _settings.append(), _filenames[c].c_str()); + ++checkCount; + } + } + catch (std::runtime_error &e) + { + // Exception was thrown when checking this file.. + _errorLogger.reportOut("Bailing out from checking " + fname + ": " + e.what()); + } + + _errorLogger.reportStatus(c + 1, (unsigned int)_filenames.size()); + } + + // This generates false positives - especially for libraries + _settings._verbose = false; + if (_settings.isEnabled("unusedFunctions") && _settings._jobs == 1) + { + _errout.str(""); + if (_settings._errorsOnly == false) + _errorLogger.reportOut("Checking usage of global functions.."); + + _checkUnusedFunctions.check(); + } + + _errorList.clear(); + return exitcode; +} + + +//--------------------------------------------------------------------------- +// CppCheck - A function that checks a specified file +//--------------------------------------------------------------------------- + +void CppCheck::checkFile(const std::string &code, const char FileName[]) +{ + if (_settings.terminated()) + return; + + Tokenizer _tokenizer(&_settings, this); + bool result; + + // Tokenize the file + std::istringstream istr(code); + + Timer timer("Tokenizer::tokenize", _settings._showtime, &S_timerResults); + result = _tokenizer.tokenize(istr, FileName, cfg); + timer.Stop(); + if (!result) + { + // File had syntax errors, abort + return; + } + + Timer timer2("Tokenizer::fillFunctionList", _settings._showtime, &S_timerResults); + _tokenizer.fillFunctionList(); + timer2.Stop(); + + // call all "runChecks" in all registered Check classes + for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) + { + if (_settings.terminated()) + return; + + Timer timerRunChecks((*it)->name() + "::runChecks", _settings._showtime, &S_timerResults); + (*it)->runChecks(&_tokenizer, &_settings, this); + } + + Timer timer3("Tokenizer::simplifyTokenList", _settings._showtime, &S_timerResults); + result = _tokenizer.simplifyTokenList(); + timer3.Stop(); + if (!result) + return; + + Timer timer4("Tokenizer::fillFunctionList", _settings._showtime, &S_timerResults); + _tokenizer.fillFunctionList(); + timer4.Stop(); + + if (_settings.isEnabled("unusedFunctions") && _settings._jobs == 1) + _checkUnusedFunctions.parseTokens(_tokenizer); + + // call all "runSimplifiedChecks" in all registered Check classes + for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) + { + if (_settings.terminated()) + return; + + Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings._showtime, &S_timerResults); + (*it)->runSimplifiedChecks(&_tokenizer, &_settings, this); + } +} + +Settings CppCheck::settings() const +{ + return _settings; +} + +//--------------------------------------------------------------------------- + +void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) +{ + std::string errmsg = msg.toText(); + + // Alert only about unique errors + 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.nomsg.isSuppressed(msg._id, file, line)) + return; + + if (!_settings.nofail.isSuppressed(msg._id, file, line)) + exitcode = 1; + + _errorList.push_back(errmsg); + std::string errmsg2(errmsg); + if (_settings._verbose) + { + errmsg2 += "\n Defines=\'" + cfg + "\'\n"; + } + + _errorLogger.reportErr(msg); + + _errout << errmsg2 << std::endl; +} + +void CppCheck::reportOut(const std::string &outmsg) +{ + _errorLogger.reportOut(outmsg); +} + +const std::vector &CppCheck::filenames() const +{ + return _filenames; +} + +void CppCheck::reportStatus(unsigned int /*index*/, unsigned int /*max*/) +{ + +} + +void CppCheck::getErrorMessages() +{ + // call all "getErrorMessages" in all registered Check classes + std::cout << ErrorLogger::ErrorMessage::getXMLHeader(); + for (std::list::iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) + { + (*it)->getErrorMessages(); + } + + Tokenizer tokenizer(&_settings, 0); + tokenizer.getErrorMessages(); + + std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl; +} diff --git a/lib/settings.h b/lib/settings.h index d30b1bb7f..819dbbb67 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -1,194 +1,194 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SETTINGS_H -#define SETTINGS_H - -#include -#include -#include -#include -#include - -/// @addtogroup Core -/// @{ - - -/** - * @brief This is just a container for general settings so that we don't need - * to pass individual values to functions or constructors now or in the - * future when we might have even more detailed settings. - */ -class Settings -{ -private: - /** @brief classes that are automaticly deallocated */ - std::set _autoDealloc; - - /** @brief Code to append in the checks */ - std::string _append; - - /** @brief enable extra checks by id */ - std::map _enabled; - - /** @brief terminate checking */ - bool _terminate; - - Settings(bool all); - -public: - Settings(); - Settings(const Settings &s); - const Settings &operator=(const Settings &s); - virtual ~Settings(); - - /** @brief Return test settings where inconclusive is true */ - static Settings testSettings() - { - return Settings(true); - } - - /** @brief Is --debug given? */ - bool _debug; - - /** @brief Inconclusive checks - for debugging of Cppcheck */ - const bool inconclusive; - - /** @brief Is --style given? */ - bool _checkCodingStyle; - - /** @brief Is --quiet given? */ - bool _errorsOnly; - - /** @brief Is --inline-suppr given? */ - bool _inlineSuppressions; - - /** @brief Is --verbose given? */ - bool _verbose; - - /** @brief Request termination of checking */ - void terminate() - { - _terminate = true; - } - - /** @brief termination requested? */ - bool terminated() const - { - return _terminate; - } - - /** @brief Force checking the files with "too many" configurations (--force). */ - bool _force; - - /** @brief write xml results (--xml) */ - bool _xml; - - /** @brief How many processes/threads should do checking at the same - time. Default is 1. (-j N) */ - unsigned int _jobs; - - /** @brief If errors are found, this value is returned from main(). - Default value is 0. */ - int _exitCode; - - /** @brief The output format in which the errors are printed in text mode, - e.g. "{severity} {file}:{line} {message} {id}" */ - std::string _outputFormat; - - /** @brief show timing information (--showtime=file|summary|top5|average) */ - unsigned int _showtime; - - /** @brief List of include paths, e.g. "my/includes/" which should be used - for finding include files inside source files. (-I) */ - std::list _includePaths; - - /** @brief Fill list of automaticly deallocated classes (--auto-dealloc) */ - void autoDealloc(std::istream &istr); - - /** @brief Add class to list of automatically deallocated classes */ - void addAutoAllocClass(const std::string &name); - - /** @brief is a class automaticly deallocated? */ - bool isAutoDealloc(const std::string &classname) const; - - /** @brief assign append code (--append) */ - void append(const std::string &filename); - - /** @brief get append code (--append) */ - std::string append() const; - - /** - * @brief Returns true if given id is in the list of - * enabled extra checks (--enable) - * @param str id for the extra check, e.g. "style" - * @return true if the check is enabled. - */ - bool isEnabled(const std::string &str) const; - - /** - * @brief Enable extra checks by id. See isEnabled() - * @param str single id or list of id values to be enabled - * or empty string to enable all. e.g. "style,possibleError" - */ - void addEnabled(const std::string &str); - - /** @brief class for handling suppressions */ - class Suppressions - { - private: - /** @brief List of error which the user doesn't want to see. */ - std::map > > _suppressions; - public: - /** - * @brief 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 parseFile(std::istream &istr); - - /** - * @brief 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); - - /** - * @brief Returns true if this message should not be shown to the user. - * @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" - * @return true if this error is suppressed. - */ - bool isSuppressed(const std::string &errorId, const std::string &file, unsigned int line); - - }; - - /** @brief suppress message (--suppressions) */ - Suppressions nomsg; - - /** @brief suppress exitcode */ - Suppressions nofail; -}; - -/// @} - -#endif // SETTINGS_H +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include +#include +#include +#include + +/// @addtogroup Core +/// @{ + + +/** + * @brief This is just a container for general settings so that we don't need + * to pass individual values to functions or constructors now or in the + * future when we might have even more detailed settings. + */ +class Settings +{ +private: + /** @brief classes that are automaticly deallocated */ + std::set _autoDealloc; + + /** @brief Code to append in the checks */ + std::string _append; + + /** @brief enable extra checks by id */ + std::map _enabled; + + /** @brief terminate checking */ + bool _terminate; + + Settings(bool all); + +public: + Settings(); + Settings(const Settings &s); + const Settings &operator=(const Settings &s); + virtual ~Settings(); + + /** @brief Return test settings where inconclusive is true */ + static Settings testSettings() + { + return Settings(true); + } + + /** @brief Is --debug given? */ + bool _debug; + + /** @brief Inconclusive checks - for debugging of Cppcheck */ + const bool inconclusive; + + /** @brief Is --style given? */ + bool _checkCodingStyle; + + /** @brief Is --quiet given? */ + bool _errorsOnly; + + /** @brief Is --inline-suppr given? */ + bool _inlineSuppressions; + + /** @brief Is --verbose given? */ + bool _verbose; + + /** @brief Request termination of checking */ + void terminate() + { + _terminate = true; + } + + /** @brief termination requested? */ + bool terminated() const + { + return _terminate; + } + + /** @brief Force checking the files with "too many" configurations (--force). */ + bool _force; + + /** @brief write xml results (--xml) */ + bool _xml; + + /** @brief How many processes/threads should do checking at the same + time. Default is 1. (-j N) */ + unsigned int _jobs; + + /** @brief If errors are found, this value is returned from main(). + Default value is 0. */ + int _exitCode; + + /** @brief The output format in which the errors are printed in text mode, + e.g. "{severity} {file}:{line} {message} {id}" */ + std::string _outputFormat; + + /** @brief show timing information (--showtime=file|summary|top5) */ + unsigned int _showtime; + + /** @brief List of include paths, e.g. "my/includes/" which should be used + for finding include files inside source files. (-I) */ + std::list _includePaths; + + /** @brief Fill list of automaticly deallocated classes (--auto-dealloc) */ + void autoDealloc(std::istream &istr); + + /** @brief Add class to list of automatically deallocated classes */ + void addAutoAllocClass(const std::string &name); + + /** @brief is a class automaticly deallocated? */ + bool isAutoDealloc(const std::string &classname) const; + + /** @brief assign append code (--append) */ + void append(const std::string &filename); + + /** @brief get append code (--append) */ + std::string append() const; + + /** + * @brief Returns true if given id is in the list of + * enabled extra checks (--enable) + * @param str id for the extra check, e.g. "style" + * @return true if the check is enabled. + */ + bool isEnabled(const std::string &str) const; + + /** + * @brief Enable extra checks by id. See isEnabled() + * @param str single id or list of id values to be enabled + * or empty string to enable all. e.g. "style,possibleError" + */ + void addEnabled(const std::string &str); + + /** @brief class for handling suppressions */ + class Suppressions + { + private: + /** @brief List of error which the user doesn't want to see. */ + std::map > > _suppressions; + public: + /** + * @brief 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 parseFile(std::istream &istr); + + /** + * @brief 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); + + /** + * @brief Returns true if this message should not be shown to the user. + * @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" + * @return true if this error is suppressed. + */ + bool isSuppressed(const std::string &errorId, const std::string &file, unsigned int line); + + }; + + /** @brief suppress message (--suppressions) */ + Suppressions nomsg; + + /** @brief suppress exitcode */ + Suppressions nofail; +}; + +/// @} + +#endif // SETTINGS_H