diff --git a/.gitignore b/.gitignore index 5de6f2ea9..e62fe2dbf 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,6 @@ gui/qrc_gui.cpp gui/*.qm # Doxygen output folder doxyoutput/ -htdocs/ # qmake generated *.sdf diff --git a/Makefile b/Makefile index 09aadde1c..5391b67ea 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ CLIOBJ = cli/cmdlineparser.o \ cli/filelister_unix.o \ cli/filelister_win32.o \ cli/main.o \ + cli/pathmatch.o \ cli/threadexecutor.o TESTOBJ = test/options.o \ @@ -74,6 +75,7 @@ TESTOBJ = test/options.o \ test/testoptions.o \ test/testother.o \ test/testpath.o \ + test/testpathmatch.o \ test/testpostfixoperator.o \ test/testpreprocessor.o \ test/testrunner.o \ @@ -103,8 +105,8 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ) all: cppcheck testrunner -testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o $(LDFLAGS) +testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o $(LDFLAGS) test: all ./testrunner @@ -206,7 +208,7 @@ lib/tokenize.o: lib/tokenize.cpp lib/tokenize.h lib/token.h lib/mathlib.h lib/se cli/cmdlineparser.o: cli/cmdlineparser.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/timer.h cli/cmdlineparser.h lib/path.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp -cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h cli/threadexecutor.h cli/cmdlineparser.h cli/filelister.h lib/path.h +cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h cli/threadexecutor.h cli/cmdlineparser.h cli/filelister.h lib/path.h cli/pathmatch.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp cli/filelister.o: cli/filelister.cpp cli/filelister.h cli/filelister_win32.h cli/filelister_unix.h @@ -221,6 +223,9 @@ cli/filelister_win32.o: cli/filelister_win32.cpp cli/filelister.h cli/filelister cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/main.o cli/main.cpp +cli/pathmatch.o: cli/pathmatch.cpp cli/pathmatch.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/pathmatch.o cli/pathmatch.cpp + cli/threadexecutor.o: cli/threadexecutor.cpp cli/threadexecutor.h lib/settings.h lib/errorlogger.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/threadexecutor.o cli/threadexecutor.cpp @@ -284,6 +289,9 @@ test/testother.o: test/testother.cpp lib/tokenize.h lib/checkother.h lib/check.h test/testpath.o: test/testpath.cpp test/testsuite.h lib/errorlogger.h test/redirect.h lib/path.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpath.o test/testpath.cpp +test/testpathmatch.o: test/testpathmatch.cpp test/testsuite.h lib/errorlogger.h test/redirect.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpathmatch.o test/testpathmatch.cpp + test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/tokenize.h lib/checkpostfixoperator.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpostfixoperator.o test/testpostfixoperator.cpp diff --git a/cli/cli.pro b/cli/cli.pro index 85702b9fb..e04e4e158 100644 --- a/cli/cli.pro +++ b/cli/cli.pro @@ -17,12 +17,15 @@ SOURCES += main.cpp \ filelister.cpp \ filelister_unix.cpp \ filelister_win32.cpp \ + pathmatch.cpp \ threadexecutor.cpp + HEADERS += cppcheckexecutor.h \ cmdlineparser.h \ filelister.h \ filelister_unix.h \ filelister_win32.h \ + pathmatch.h \ threadexecutor.h CONFIG(release, debug|release) { diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index c3eaa5764..b64229edf 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -26,6 +26,7 @@ #include "settings.h" #include "cmdlineparser.h" #include "path.h" +#include "filelister.h" // xml is used in rules #include "tinyxml/tinyxml.h" @@ -210,11 +211,28 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) else if (strcmp(argv[i], "--xml") == 0) _settings->_xml = true; - // Write results in xml2 format - else if (strcmp(argv[i], "--xml-version=2") == 0) + // Define the XML file version (and enable XML output) + else if (strncmp(argv[i], "--xml-version=", 14) == 0) { + std::string numberString(argv[i]); + numberString = numberString.substr(14); + + std::istringstream iss(numberString); + if (!(iss >> _settings->_xml_version)) + { + PrintMessage("cppcheck: argument to '--xml-version' is not a number"); + return false; + } + + if (_settings->_xml_version < 0 || _settings->_xml_version > 2) + { + // We only have xml versions 1 and 2 + PrintMessage("cppcheck: --xml-version can only be 1 or 2."); + return false; + } + + // Enable also XML if version is set _settings->_xml = true; - _settings->_xml_version = 2; } // Only print something when there are errors @@ -327,6 +345,44 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) AddFilesToList(12 + argv[i], _pathnames); } + // Ignored paths + else if (strncmp(argv[i], "-i", 2) == 0) + { + std::string path; + + // "-i path/" + if (strcmp(argv[i], "-i") == 0) + { + ++i; + if (i >= argc) + { + PrintMessage("cppcheck: argument to '-i' is missing"); + return false; + } + path = argv[i]; + } + + // "-ipath/" + else + { + path = 2 + argv[i]; + } + + if (!path.empty()) + { + path = Path::fromNativeSeparators(path); + + // If not "known" filename extension then assume it is path + if (!FileLister::acceptFile(path)) + { + // If path doesn't end with / or \, add it + if (path[path.length()-1] != '/') + path += '/'; + } + _ignoredPaths.push_back(path); + } + } + // Report progress else if (strcmp(argv[i], "--report-progress") == 0) { @@ -461,18 +517,18 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) TiXmlDocument doc; if (doc.LoadFile(12+argv[i])) { - TiXmlElement *root = doc.FirstChildElement(); - if (root && root->ValueStr() == "rule") + TiXmlElement *node = doc.FirstChildElement(); + for (; node && node->ValueStr() == "rule"; node = node->NextSiblingElement()) { Settings::Rule rule; - TiXmlElement *pattern = root->FirstChildElement("pattern"); + TiXmlElement *pattern = node->FirstChildElement("pattern"); if (pattern) { rule.pattern = pattern->GetText(); } - TiXmlElement *message = root->FirstChildElement("message"); + TiXmlElement *message = node->FirstChildElement("message"); if (message) { TiXmlElement *severity = message->FirstChildElement("severity"); @@ -589,6 +645,10 @@ void CmdLineParser::PrintHelp() " -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" + " -i [dir] Give path to ignore. Give several -i parameters to ignore\n" + " several paths. Give directory name or filename with path\n" + " as parameter. Directory name is matched to all parts of the\n" + " path." " --inline-suppr Enable inline suppressions. Use them by placing one or\n" " more comments, like: // cppcheck-suppress warningId\n" " on the lines before the warning to suppress.\n" @@ -608,6 +668,9 @@ void CmdLineParser::PrintHelp() " -v, --verbose More detailed error reports\n" " --version Print out version number\n" " --xml Write results in xml to error stream.\n" + " --xml-version=[version]\n" + " Select the XML file version. Currently versions 1 and 2\n" + " are available. The default version is 1." "\n" "Example usage:\n" " # Recursively check the current folder. Print the progress on the screen and\n" diff --git a/cli/cmdlineparser.h b/cli/cmdlineparser.h index 7a60e24a6..bfc047cb9 100644 --- a/cli/cmdlineparser.h +++ b/cli/cmdlineparser.h @@ -92,6 +92,14 @@ public: return _exitAfterPrint; } + /** + * Return a list of paths user wants to ignore. + */ + std::vector GetIgnoredPaths() const + { + return _ignoredPaths; + } + protected: /** @@ -111,6 +119,7 @@ private: bool _showErrorMessages; bool _exitAfterPrint; std::vector _pathnames; + std::vector _ignoredPaths; }; /// @} diff --git a/cli/cppcheck.vcproj b/cli/cppcheck.vcproj index 541363475..37ce7c22a 100755 --- a/cli/cppcheck.vcproj +++ b/cli/cppcheck.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="9,00" Name="cppcheck" - ProjectGUID="{7E69D6C6-32B2-32E1-BF56-A5BFBAF5E61F}" + ProjectGUID="{56B0F403-02CE-3F89-9A1B-E03F21240A63}" Keyword="Qt4VSv1.0"> + + - {42BC0E8E-9175-3B2D-B8B3-9EC5C36EF49A} + {A6DACC3F-847F-3498-9415-164FBC746D6B} cppcheck Qt4VSv1.0 @@ -140,6 +140,7 @@ + @@ -176,6 +177,7 @@ + diff --git a/cli/cppcheck.vcxproj.filters b/cli/cppcheck.vcxproj.filters index 4e6b80eca..de87f16e1 100644 --- a/cli/cppcheck.vcxproj.filters +++ b/cli/cppcheck.vcxproj.filters @@ -84,6 +84,9 @@ Source Files + + Source Files + Source Files @@ -188,6 +191,9 @@ Header Files + + Header Files + Header Files diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index fdb886471..c101b6592 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -25,6 +25,7 @@ #include "cmdlineparser.h" #include "filelister.h" #include "path.h" +#include "pathmatch.h" CppCheckExecutor::CppCheckExecutor() { @@ -55,7 +56,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c errorlist = true; std::cout << ErrorLogger::ErrorMessage::getXMLHeader(_settings._xml_version); cppcheck->getErrorMessages(); - std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl; + std::cout << ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version) << std::endl; } if (parser.ExitAfterPrinting()) @@ -87,19 +88,36 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c std::vector::const_iterator iter; for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) getFileLister()->recursiveAddFiles(filenames, Path::toNativeSeparators(iter->c_str())); - - for (iter = filenames.begin(); iter != filenames.end(); ++iter) - cppcheck->addFile(*iter); } - if (filenames.empty()) + if (!filenames.empty()) + { + PathMatch matcher(parser.GetIgnoredPaths()); + std::vector::iterator iterBegin = filenames.begin(); + for (int i = (int)filenames.size() - 1; i >= 0; i--) + { + if (matcher.Match(filenames[i])) + filenames.erase(iterBegin + i); + } + } + else { std::cout << "cppcheck: error: could not find or open any of the paths given." << std::endl; return false; } + + if (!filenames.empty()) + { + std::vector::iterator iter; + for (iter = filenames.begin(); iter != filenames.end(); ++iter) + cppcheck->addFile(*iter); + + return true; + } else { - return true; + std::cout << "cppcheck: error: no files to check - all paths ignored." << std::endl; + return false; } } @@ -141,7 +159,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) if (_settings._xml) { - reportErr(ErrorLogger::ErrorMessage::getXMLFooter()); + reportErr(ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version)); } if (returnValue) diff --git a/cli/filelister.h b/cli/filelister.h index aa292b701..4c6cd7d03 100644 --- a/cli/filelister.h +++ b/cli/filelister.h @@ -55,7 +55,7 @@ public: * @param filename filename to check * @return returns true if the file extension indicates it should be checked */ - virtual bool acceptFile(const std::string &filename); + static bool acceptFile(const std::string &filename); /** * @brief Is given path a directory? diff --git a/cli/filelister_unix.cpp b/cli/filelister_unix.cpp index ed6d12f4b..f9263eb78 100644 --- a/cli/filelister_unix.cpp +++ b/cli/filelister_unix.cpp @@ -72,7 +72,7 @@ void FileListerUnix::recursiveAddFiles2(std::vector &relative, continue; } - if (Path::sameFileName(path,filename) || FileListerUnix::acceptFile(filename)) + if (Path::sameFileName(path,filename) || FileLister::acceptFile(filename)) { relative.push_back(filename); absolute.push_back(fname); diff --git a/cli/pathmatch.cpp b/cli/pathmatch.cpp new file mode 100644 index 000000000..db36d99c9 --- /dev/null +++ b/cli/pathmatch.cpp @@ -0,0 +1,73 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 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 "pathmatch.h" + +PathMatch::PathMatch(const std::vector &masks) + : _masks(masks) +{ +} + +bool PathMatch::Match(const std::string &path) +{ + if (path.empty()) + return false; + + std::vector::const_iterator iterMask; + for (iterMask = _masks.begin(); iterMask != _masks.end(); ++iterMask) + { + // Filtering directory name + if ((*iterMask)[(*iterMask).length() - 1] == '/') + { + std::string findpath(path); + if (findpath[findpath.length() - 1] != '/') + findpath = RemoveFilename(findpath); + + if ((*iterMask).length() > findpath.length()) + continue; + // Match relative paths starting with mask + // -isrc matches src/foo.cpp + if (findpath.compare(0, (*iterMask).size(), *iterMask) == 0) + return true; + // Match only full directory name in middle or end of the path + // -isrc matches myproject/src/ but does not match + // myproject/srcfiles/ or myproject/mysrc/ + if (findpath.find("/" + *iterMask) != std::string::npos) + return true; + } + // Filtering filename + else + { + if ((*iterMask).length() > path.length()) + continue; + // Check if path ends with mask + // -ifoo.cpp matches (./)foo.c, src/foo.cpp and proj/src/foo.cpp + // -isrc/file.cpp matches src/foo.cpp and proj/src/foo.cpp + if (path.compare(path.size() - (*iterMask).size(), path.size(), *iterMask) == 0) + return true; + + } + } + return false; +} + +std::string PathMatch::RemoveFilename(const std::string &path) +{ + const size_t ind = path.find_last_of('/'); + return path.substr(0, ind + 1); +} diff --git a/cli/pathmatch.h b/cli/pathmatch.h new file mode 100644 index 000000000..5e1a0566c --- /dev/null +++ b/cli/pathmatch.h @@ -0,0 +1,63 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 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 PATHMATCH_H +#define PATHMATCH_H + +#include +#include + +/// @addtogroup CLI +/// @{ + +/** + * @brief Simple path matching for ignoring paths in CLI. + */ +class PathMatch +{ +public: + + /** + * The constructor. + * @param masks List of masks. + */ + PathMatch(const std::vector &masks); + + /** + * @brief Match path against list of masks. + * @param path Path to match. + * @return true if any of the masks match the path, false otherwise. + */ + bool Match(const std::string &path); + +protected: + + /** + * @brief Remove filename part from the path. + * @param path Path to edit. + * @return path without filename part. + */ + std::string RemoveFilename(const std::string &path); + +private: + std::vector _masks; +}; + +/// @} + +#endif // PATHMATCH_H diff --git a/lib/check.h b/lib/check.h index c11eb8f5d..c6e2bfa25 100644 --- a/lib/check.h +++ b/lib/check.h @@ -39,16 +39,11 @@ class Check { public: /** This constructor is used when registering the CheckClass */ - Check() - : _tokenizer(0), _settings(0), _errorLogger(0) - { - instances().push_back(this); - instances().sort(); - } + Check(const std::string &aname); /** This constructor is used when running checks. */ - Check(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) + Check(const std::string &aname, const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + : _name(aname), _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) { } virtual ~Check() @@ -98,7 +93,10 @@ public: virtual void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) = 0; /** class name, used to generate documentation */ - virtual std::string name() const = 0; + std::string name() const + { + return _name; + } /** get information about this class, used to generate documentation */ virtual std::string classInfo() const = 0; @@ -114,6 +112,7 @@ public: } protected: + const std::string _name; const Tokenizer * const _tokenizer; const Settings * const _settings; ErrorLogger * const _errorLogger; @@ -155,17 +154,28 @@ protected: private: - /** compare the names of Check classes, used when sorting the Check descendants */ - bool operator<(const Check *other) const - { - return (name() < other->name()); - } - /** disabled assignment operator */ void operator=(const Check &); }; +namespace std { + /** compare the names of Check classes, used when sorting the Check descendants */ + template <> struct less { + bool operator()(const Check *p1, const Check *p2) const + { + return (p1->name() < p2->name()); + } + }; +} + +inline Check::Check(const std::string &aname) + : _name(aname), _tokenizer(0), _settings(0), _errorLogger(0) +{ + instances().push_back(this); + instances().sort(std::less()); +} + /// @} #endif diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 414ae527e..f33a9a8ae 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -448,7 +448,7 @@ void CheckAutoVariables::returncstr() } // have we reached a function that returns a reference? - if (Token::Match(tok, "const char *")) + if (Token::simpleMatch(tok, "const char *")) { // go to the '(' const Token *tok2 = tok->tokAt(3); diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index 97df17ccf..a1faf1450 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -34,12 +34,12 @@ class CheckAutoVariables : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckAutoVariables() : Check() + CheckAutoVariables() : Check(myName()) { } /** This constructor is used when running checks. */ CheckAutoVariables(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -98,7 +98,7 @@ private: c.errorReturnTempPointer(0); } - std::string name() const + std::string myName() const { return "Auto Variables"; } diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 5f7e42619..c0afdce94 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -302,7 +302,7 @@ static bool for_condition(const Token * const tok2, unsigned int varid, std::str maxMinFlipped = false; max_value = tok2->strAt(2); } - else if (Token::Match(tok2, " %num% < %varid% ;", varid) || + else if (Token::Match(tok2, "%num% < %varid% ;", varid) || Token::Match(tok2, "%num% != %varid% ; ++ %varid%", varid) || Token::Match(tok2, "%num% != %varid% ; %varid% ++", varid)) { @@ -766,7 +766,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector(varname.empty() ? 0U : (varname.size() - 1) * 2U)); - if (Token::Match(tok, "return")) + if (Token::simpleMatch(tok, "return")) { tok = tok->next(); if (!tok) @@ -828,7 +828,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vectorstrAt(3)); if (index < 0 || index >= size) { - if (index > size || !Token::Match(tok->previous(), "& (")) + if (index > size || !Token::simpleMatch(tok->previous(), "& (")) { arrayIndexOutOfBounds(tok->next(), size, index); } diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index c2e77a20b..fe8ca2645 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -50,12 +50,12 @@ class CheckBufferOverrun : public Check public: /** This constructor is used when registering the CheckClass */ - CheckBufferOverrun() : Check() + CheckBufferOverrun() : Check(myName()) { } /** This constructor is used when running checks. */ CheckBufferOverrun(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -209,7 +209,7 @@ public: c.pointerOutOfBounds(0, "array"); } - std::string name() const + std::string myName() const { return "Bounds checking"; } diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index fc96af0cc..53dd353a2 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -42,7 +42,7 @@ CheckClass instance; //--------------------------------------------------------------------------- CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger), + : Check(myName(), tokenizer, settings, errorLogger), symbolDatabase(NULL) { @@ -310,7 +310,7 @@ void CheckClass::initializeVarList(const Function &func, std::list ftok = ftok->next(); // Using the operator= function to initialize all variables.. - if (Token::simpleMatch(ftok->next(), "* this = ")) + if (Token::simpleMatch(ftok->next(), "* this =")) { assignAllVar(usage); break; @@ -799,7 +799,7 @@ void CheckClass::noMemset() if (Token::Match(tstruct->next(), "std :: %type% %var% ;")) memsetStructError(tok, tok->str(), tstruct->strAt(3)); - else if (Token::Match(tstruct->next(), "std :: %type% < ")) + else if (Token::Match(tstruct->next(), "std :: %type% <")) { // backup the type const std::string typestr(tstruct->strAt(3)); @@ -931,7 +931,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co // check of *this is returned else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") || Token::Match(tok->tokAt(1), "(| * this +=") || - Token::Match(tok->tokAt(1), "operator= ("))) + Token::simpleMatch(tok->tokAt(1), "operator= ("))) operatorEqRetRefThisError(func->token); } } @@ -1132,7 +1132,7 @@ bool CheckClass::hasAssignSelf(const Token *first, const Token *last, const Toke { for (const Token *tok = first; tok && tok != last; tok = tok->next()) { - if (Token::Match(tok, "if (")) + if (Token::simpleMatch(tok, "if (")) { const Token *tok1 = tok->tokAt(2); const Token *tok2 = tok->tokAt(1)->link(); @@ -1412,7 +1412,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?")) { - if (Token::Match(tok->previous(), "* this")) + if (Token::simpleMatch(tok->previous(), "* this")) return true; tok = tok->previous(); diff --git a/lib/checkclass.h b/lib/checkclass.h index dd5f15883..cc550c36b 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -36,7 +36,7 @@ class CheckClass : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckClass() : Check(), symbolDatabase(NULL) + CheckClass() : Check(myName()), symbolDatabase(NULL) { } /** @brief This constructor is used when running checks. */ @@ -144,7 +144,7 @@ private: c.checkConstError(0, "class", "function"); } - std::string name() const + std::string myName() const { return "Class"; } diff --git a/lib/checkexceptionsafety.h b/lib/checkexceptionsafety.h index 584cf78d6..af92597f5 100644 --- a/lib/checkexceptionsafety.h +++ b/lib/checkexceptionsafety.h @@ -43,12 +43,12 @@ class CheckExceptionSafety : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckExceptionSafety() : Check() + CheckExceptionSafety() : Check(myName()) { } /** This constructor is used when running checks. */ CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } /** Checks that uses the simplified token list */ @@ -86,7 +86,7 @@ private: } /** Short description of class (for --doc) */ - std::string name() const + std::string myName() const { return "Exception Safety"; } diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 0ffab12c7..97a8ea249 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -223,7 +223,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok return gMalloc; if (Token::Match(tok, "fclose ( %varid% )", varid) || - Token::Match(tok, "fcloseall ( )")) + Token::simpleMatch(tok, "fcloseall ( )")) return File; if (Token::Match(tok, "close ( %varid% )", varid)) @@ -1445,7 +1445,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::liststr(";"); Token::eraseTokens(tok2, tok2->tokAt(4)); @@ -1820,7 +1820,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok) } // Reduce "if continue ; if continue ;" => "if continue ;" - else if (Token::Match(tok2->next(), "if continue ; if continue ;")) + else if (Token::simpleMatch(tok2->next(), "if continue ; if continue ;")) { Token::eraseTokens(tok2, tok2->tokAt(4)); done = false; diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index d535ea4cb..7ba6a53b4 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -172,12 +172,12 @@ class CheckMemoryLeakInFunction : private Check, public CheckMemoryLeak { public: /** @brief This constructor is used when registering this class */ - CheckMemoryLeakInFunction() : Check(), CheckMemoryLeak(0, 0), symbolDatabase(NULL) + CheckMemoryLeakInFunction() : Check(myName()), CheckMemoryLeak(0, 0), symbolDatabase(NULL) { } /** @brief This constructor is used when running checks */ CheckMemoryLeakInFunction(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) - : Check(tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) + : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) { // get the symbol database if (tokenizr) @@ -329,7 +329,7 @@ public: * Get name of class (--doc) * @return name of class */ - std::string name() const + std::string myName() const { return "Memory leaks (function variables)"; } @@ -364,11 +364,11 @@ public: class CheckMemoryLeakInClass : private Check, private CheckMemoryLeak { public: - CheckMemoryLeakInClass() : Check(), CheckMemoryLeak(0, 0) + CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(0, 0) { } CheckMemoryLeakInClass(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) - : Check(tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) + : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) { } void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) @@ -396,7 +396,7 @@ private: void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) { } - std::string name() const + std::string myName() const { return "Memory leaks (class variables)"; } @@ -414,11 +414,11 @@ private: class CheckMemoryLeakStructMember : private Check, private CheckMemoryLeak { public: - CheckMemoryLeakStructMember() : Check(), CheckMemoryLeak(0, 0) + CheckMemoryLeakStructMember() : Check(myName()), CheckMemoryLeak(0, 0) { } CheckMemoryLeakStructMember(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) - : Check(tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) + : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) { } void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) @@ -434,7 +434,7 @@ private: void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) { } - std::string name() const + std::string myName() const { return "Memory leaks (struct members)"; } @@ -452,11 +452,11 @@ private: class CheckMemoryLeakNoVar : private Check, private CheckMemoryLeak { public: - CheckMemoryLeakNoVar() : Check(), CheckMemoryLeak(0, 0) + CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(0, 0) { } CheckMemoryLeakNoVar(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) - : Check(tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) + : Check(myName(), tokenizr, settings, errLog), CheckMemoryLeak(tokenizr, errLog) { } void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) @@ -474,7 +474,7 @@ private: void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) { } - std::string name() const + std::string myName() const { return "Memory leaks (address not taken)"; } diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index bd36a4e37..ff951f5ba 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -544,7 +544,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() if (Token::Match(tok, "* %var% [;,)=]")) pointerVariables.insert(tok->next()->varId()); - else if (Token::Match(tok, "if (")) + else if (Token::simpleMatch(tok, "if (")) { // TODO: investigate false negatives: // - handle "while"? @@ -617,7 +617,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() if (null && indentlevel == 0) { // skip all "else" blocks because they are not executed in this execution path - while (Token::Match(tok2, "} else {")) + while (Token::simpleMatch(tok2, "} else {")) tok2 = tok2->tokAt(2)->link(); null = false; } diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index c1b134e91..1f23bcf87 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -37,12 +37,12 @@ class CheckNullPointer : public Check { public: /** @brief This constructor is used when registering the CheckNullPointer */ - CheckNullPointer() : Check() + CheckNullPointer() : Check(myName()) { } /** @brief This constructor is used when running checks. */ CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } /** @brief Run checks against the normal token list */ @@ -112,7 +112,7 @@ public: } /** Name of check */ - std::string name() const + std::string myName() const { return "Null pointer"; } diff --git a/lib/checkobsoletefunctions.h b/lib/checkobsoletefunctions.h index 3ee4f88f3..706803aa8 100644 --- a/lib/checkobsoletefunctions.h +++ b/lib/checkobsoletefunctions.h @@ -38,14 +38,14 @@ class CheckObsoleteFunctions : public Check { public: /** This constructor is used when registering the CheckObsoleteFunctions */ - CheckObsoleteFunctions() : Check() + CheckObsoleteFunctions() : Check(myName()) { initObsoleteFunctions(); } /** This constructor is used when running checks. */ CheckObsoleteFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { initObsoleteFunctions(); } @@ -125,7 +125,7 @@ private: } } - std::string name() const + std::string myName() const { return "Obsolete functions"; } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 6e74c7cc6..4e5ff04cd 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -137,7 +137,7 @@ void CheckOther::checkSizeofForArrayParameter() { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "sizeof ( %var% )") || Token::Match(tok, "sizeof %var% ")) + if (Token::Match(tok, "sizeof ( %var% )") || Token::Match(tok, "sizeof %var%")) { int tokIdx = 1; if (tok->tokAt(tokIdx)->str() == "(") @@ -1491,7 +1491,7 @@ void CheckOther::functionVariableUsage() variables.read(nametok->tokAt(2)->varId()); // look at initializers - if (Token::Match(nametok->tokAt(4), "= {")) + if (Token::simpleMatch(nametok->tokAt(4), "= {")) { tok = nametok->tokAt(6); while (tok->str() != "}") @@ -1911,6 +1911,8 @@ void CheckOther::functionVariableUsage() variables.use(tok->next()->varId()); // use = read + write else if (Token::Match(tok, "[;{}] %var% >>")) variables.use(tok->next()->varId()); // use = read + write + else if (Token::Match(tok, "[{,] %var% [,}]")) + variables.read(tok->next()->varId()); // function parameter else if (Token::Match(tok, "[(,] %var% [")) @@ -1922,14 +1924,14 @@ void CheckOther::functionVariableUsage() variables.use(tok->next()->link()->next()->varId()); // use = read + write // function - else if (Token::Match(tok, " %var% (")) + else if (Token::Match(tok, "%var% (")) { variables.read(tok->varId()); if (Token::Match(tok->tokAt(2), "%var% =")) variables.read(tok->tokAt(2)->varId()); } - else if (Token::Match(tok, " %var% .")) + else if (Token::Match(tok, "%var% .")) variables.use(tok->varId()); // use = read + write else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) && @@ -2703,7 +2705,7 @@ void CheckOther::checkMisusedScopedObject() } if (Token::Match(tok, "[;{}] %var% (") - && Token::Match(tok->tokAt(2)->link(), ") ;") + && Token::simpleMatch(tok->tokAt(2)->link(), ") ;") && symbolDatabase->isClassOrStruct(tok->next()->str()) ) { @@ -2832,8 +2834,11 @@ void CheckOther::sizeofsizeof() return; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "sizeof sizeof")) + if (Token::Match(tok, "sizeof (| sizeof")) + { sizeofsizeofError(tok); + tok = tok->next(); + } } } diff --git a/lib/checkother.h b/lib/checkother.h index bace5a82e..bc5b1db35 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -37,12 +37,12 @@ class CheckOther : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckOther() : Check() + CheckOther() : Check(myName()) { } /** @brief This constructor is used when running checks. */ CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } /** @brief Run checks against the normal token list */ @@ -245,7 +245,7 @@ public: c.clarifyCalculationError(0); } - std::string name() const + std::string myName() const { return "Other"; } diff --git a/lib/checkpostfixoperator.h b/lib/checkpostfixoperator.h index 2840df19e..e7e4651fb 100644 --- a/lib/checkpostfixoperator.h +++ b/lib/checkpostfixoperator.h @@ -35,12 +35,12 @@ class CheckPostfixOperator : public Check { public: /** This constructor is used when registering the CheckPostfixOperator */ - CheckPostfixOperator() : Check() + CheckPostfixOperator() : Check(myName()) { } /** This constructor is used when running checks. */ CheckPostfixOperator(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -62,7 +62,7 @@ private: c.postfixOperatorError(0); } - std::string name() const + std::string myName() const { return "Using postfix operators"; } diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index fc90339bb..a2c871db3 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -445,7 +445,7 @@ void CheckStl::erase() break; } - if (Token::Match(tok2, "%var% = %var% . begin ( ) ; %var% != %var% . end ( ) ") && + if (Token::Match(tok2, "%var% = %var% . begin ( ) ; %var% != %var% . end ( )") && tok2->str() == tok2->tokAt(8)->str() && tok2->tokAt(2)->str() == tok2->tokAt(10)->str()) { @@ -572,7 +572,7 @@ void CheckStl::pushback() } // Using push_back or push_front inside a loop.. - if (Token::Match(tok2, "for (")) + if (Token::simpleMatch(tok2, "for (")) { tok2 = tok2->tokAt(2); } @@ -1038,7 +1038,7 @@ void CheckStl::string_c_str() string_c_strError(tok); } else if (Token::Match(tok, "[;{}] %var% = %var% (") && - Token::Match(tok->tokAt(4)->link(), ") . c_str ( ) ;") && + Token::simpleMatch(tok->tokAt(4)->link(), ") . c_str ( ) ;") && tok->next()->varId() > 0 && pointers.find(tok->next()->varId()) != pointers.end() && Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) diff --git a/lib/checkstl.h b/lib/checkstl.h index e232eedcd..ebd6938b1 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -35,12 +35,12 @@ class CheckStl : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckStl() : Check() + CheckStl() : Check(myName()) { } /** This constructor is used when running checks. */ CheckStl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } /** Simplified checks. The token list is simplified. */ @@ -173,7 +173,7 @@ private: c.redundantIfRemoveError(0); } - std::string name() const + std::string myName() const { return "STL usage"; } diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index 78465d821..8ab4844ed 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -37,12 +37,12 @@ class CheckUninitVar : public Check { public: /** @brief This constructor is used when registering the CheckUninitVar */ - CheckUninitVar() : Check() + CheckUninitVar() : Check(myName()) { } /** @brief This constructor is used when running checks. */ CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } /** @brief Run checks against the normal token list */ @@ -87,7 +87,7 @@ public: c.uninitvarError(0, "varname"); } - std::string name() const + std::string myName() const { return "Uninitialized variables"; } diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 066faafd6..6d408bcdb 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -33,12 +33,12 @@ class CheckUnusedFunctions: public Check { public: /** @brief This constructor is used when registering the CheckUnusedFunctions */ - CheckUnusedFunctions() : Check() + CheckUnusedFunctions() : Check(myName()) { } /** @brief This constructor is used when running checks. */ CheckUnusedFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(tokenizer, settings, errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { } // Parse current tokens and determine.. @@ -69,7 +69,7 @@ private: } - std::string name() const + std::string myName() const { return "Unused functions"; } diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index db0a15105..8364e379e 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -335,48 +335,51 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) reportErr(errmsg); } - if (re) + if (!re) + continue; + + int pos = 0; + int ovector[30]; + while (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) { - int pos = 0; - int ovector[30]; - if (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) + unsigned int pos1 = (unsigned int)ovector[0]; + unsigned int pos2 = (unsigned int)ovector[1]; + + // jump to the end of the match for the next pcre_exec + pos = pos2; + + // determine location.. + ErrorLogger::ErrorMessage::FileLocation loc; + loc.setfile(_tokenizer.getFiles()->front()); + loc.line = 0; + + unsigned int len = 0; + for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next()) { - unsigned int pos1 = (unsigned int)ovector[0]; - unsigned int pos2 = (unsigned int)ovector[1]; - - // determine location.. - ErrorLogger::ErrorMessage::FileLocation loc; - loc.setfile(_tokenizer.getFiles()->front()); - loc.line = 0; - - unsigned int len = 0; - for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next()) + len = len + 1 + tok->str().size(); + if (len > pos1) { - len = len + 1 + tok->str().size(); - if (len > pos1) - { - loc.setfile(_tokenizer.getFiles()->at(tok->fileIndex())); - loc.line = tok->linenr(); - break; - } + loc.setfile(_tokenizer.getFiles()->at(tok->fileIndex())); + loc.line = tok->linenr(); + break; } - - const std::list callStack(1, loc); - - // Create error message - std::string summary; - if (rule.summary.empty()) - summary = "found '" + str.substr(pos1, pos2 - pos1) + "'"; - else - summary = rule.summary; - ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id); - - // Report error - reportErr(errmsg); } - pcre_free(re); + const std::list callStack(1, loc); + + // Create error message + std::string summary; + if (rule.summary.empty()) + summary = "found '" + str.substr(pos1, pos2 - pos1) + "'"; + else + summary = rule.summary; + ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id); + + // Report error + reportErr(errmsg); } + + pcre_free(re); } } #endif diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 6f4baa90f..0bb9cbc98 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -162,15 +162,16 @@ std::string ErrorLogger::ErrorMessage::getXMLHeader(int xml_version) else { ostr << "\n"; - ostr << " "; + ostr << " \n"; + ostr << " "; } return ostr.str(); } -std::string ErrorLogger::ErrorMessage::getXMLFooter() +std::string ErrorLogger::ErrorMessage::getXMLFooter(int xml_version) { - return ""; + return (xml_version<=1) ? "" : " \n"; } static std::string stringToXml(std::string s) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index da68ba499..da5b7835f 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -137,7 +137,7 @@ public: std::string toXML(bool verbose, int ver) const; static std::string getXMLHeader(int xml_version); - static std::string getXMLFooter(); + static std::string getXMLFooter(int xml_version); /** * Format the error message into a string. diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp index fad18cc58..7e8b6c4c7 100644 --- a/lib/executionpath.cpp +++ b/lib/executionpath.cpp @@ -348,7 +348,7 @@ void ExecutionPath::checkScope(const Token *tok, std::list &che } } - if (Token::Match(tok, "= {")) + if (Token::simpleMatch(tok, "= {")) { // GCC struct initialization.. bail out if (Token::Match(tok->tokAt(2), ". %var% =")) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 4cdd5f729..5aa45a0ee 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -2142,7 +2142,7 @@ public: if (Token::Match(tok, "%var% %var%") || Token::Match(tok, "%var% %num%") || Token::Match(tok, "%num% %var%") || - Token::Match(tok, "> >")) + Token::simpleMatch(tok, "> >")) macrocode += " "; } } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 51032d44d..a9634b2d1 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -254,9 +254,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti } } - // nested class function? + // nested class or friend function? else if (tok->previous()->str() == "::" && isFunction(tok, &funcStart, &argStart)) - addFunction(&scope, &tok, argStart); + { + /** @todo check entire qualification for match */ + Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2)); + + if (nested) + addFunction(&scope, &tok, argStart); + else + { + /** @todo handle friend functions */ + } + } // friend class declaration? else if (Token::Match(tok, "friend class| %any% ;")) @@ -1213,7 +1223,7 @@ const Token* skipScopeIdentifiers(const Token* tok) { ret = ret->next(); } - while (Token::Match(ret, "%type% :: ")) + while (Token::Match(ret, "%type% ::")) { ret = ret->tokAt(2); } @@ -1238,7 +1248,7 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const const Token* localTypeTok = skipScopeIdentifiers(tok); const Token* localVarTok = NULL; - if (Token::Match(localTypeTok, "%type% < ")) + if (Token::Match(localTypeTok, "%type% <")) { const Token* closeTok = NULL; bool found = findClosingBracket(localTypeTok->next(), closeTok); @@ -1398,6 +1408,26 @@ Scope * Scope::findInNestedList(const std::string & name) //--------------------------------------------------------------------------- +Scope * Scope::findInNestedListRecursive(const std::string & name) +{ + std::list::iterator it; + + for (it = nestedList.begin(); it != nestedList.end(); ++it) + { + if ((*it)->className == name) + return (*it); + } + + for (it = nestedList.begin(); it != nestedList.end(); ++it) + { + Scope *child = (*it)->findInNestedListRecursive(name); + return child; + } + return 0; +} + +//--------------------------------------------------------------------------- + const Function *Scope::getDestructor() const { std::list::const_iterator it; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index e8c858c3d..4e04f4d5a 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -311,6 +311,12 @@ public: */ Scope * findInNestedList(const std::string & name); + /** + * @brief find if name is in nested list + * @param name name of nested scope + */ + Scope * findInNestedListRecursive(const std::string & name); + void addVariable(const Token *token_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_) { varlist.push_back(Variable(token_, varlist.size(), access_, mutable_, static_, const_, class_, type_)); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 75ff66b60..5c7cfaf2d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -552,7 +552,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name) if (end) { - if (Token::Match(end, ") {")) // function parameter ? + if (Token::simpleMatch(end, ") {")) // function parameter ? { // look backwards if (Token::Match(tok->previous(), "%type%") && @@ -588,7 +588,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name) (tok->previous()->str() == "*" && tok->next()->str() != "(") || (Token::Match(tok->previous(), "%type%") && (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") && - !Token::Match(tok->tokAt(-2), "friend class")))) + !Token::simpleMatch(tok->tokAt(-2), "friend class")))) { // scan backwards for the end of the previous statement int level = (tok->previous()->str() == "}") ? 1 : 0; @@ -824,7 +824,8 @@ void Tokenizer::simplifyTypedef() if (_errorLogger && !_files.empty()) _errorLogger->reportProgress(_files[0], "Tokenize (typedef)", tok->progressValue()); - if (Token::Match(tok, "class|struct|namespace %any%")) + if (Token::Match(tok, "class|struct|namespace %any%") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) { isNamespace = (tok->str() == "namespace"); hasClass = true; @@ -926,7 +927,7 @@ void Tokenizer::simplifyTypedef() Token *namespaceStart = 0; Token *namespaceEnd = 0; - if (Token::Match(tok->next(), "::") || + if (Token::simpleMatch(tok->next(), "::") || Token::Match(tok->next(), "%type%")) { typeStart = tok->next(); @@ -940,13 +941,13 @@ void Tokenizer::simplifyTypedef() bool atEnd = false; while (!atEnd) { - if (Token::Match(tok->tokAt(offset), "::")) + if (Token::simpleMatch(tok->tokAt(offset), "::")) typeEnd = tok->tokAt(offset++); if (Token::Match(tok->tokAt(offset), "%type%") && tok->tokAt(offset + 1) && !Token::Match(tok->tokAt(offset + 1), "[|;|,|(")) typeEnd = tok->tokAt(offset++); - else if (Token::Match(tok->tokAt(offset), "const (")) + else if (Token::simpleMatch(tok->tokAt(offset), "const (")) { typeEnd = tok->tokAt(offset++); atEnd = true; @@ -1040,7 +1041,7 @@ void Tokenizer::simplifyTypedef() tok = tok->tokAt(offset); // or a function typedef - else if (Token::Match(tok->tokAt(offset), "(")) + else if (Token::simpleMatch(tok->tokAt(offset), "(")) { // unhandled typedef, skip it and continue if (typeName->str() == "void") @@ -1143,7 +1144,7 @@ void Tokenizer::simplifyTypedef() // function returning pointer to function else if (Token::Match(tok->tokAt(offset), "( * %type% (") && - Token::Match(tok->tokAt(offset + 3)->link(), ") ) (")) + Token::simpleMatch(tok->tokAt(offset + 3)->link(), ") ) (")) { functionRetFuncPtr = true; @@ -1397,8 +1398,8 @@ void Tokenizer::simplifyTypedef() inTemplate = true; // check for operator - if (Token::Match(tok2->previous(), "operator") || - Token::Match(tok2->tokAt(-2), "operator const")) + if (Token::simpleMatch(tok2->previous(), "operator") || + Token::simpleMatch(tok2->tokAt(-2), "operator const")) inOperator = true; // skip over class or struct in derived class declaration @@ -2382,6 +2383,9 @@ bool Tokenizer::tokenize(std::istream &code, // remove __attribute__((?)) simplifyAttribute(); + // remove unnecessary member qualification.. + removeUnnecessaryQualification(); + // remove Microsoft MFC.. simplifyMicrosoftMFC(); @@ -2555,11 +2559,13 @@ void Tokenizer::arraySize() const Token *tok2 = tok->tokAt(5); while (Token::Match(tok2, "%any% ,")) { + if (tok2->isName()) + break; sz++; tok2 = tok2->tokAt(2); } - if (Token::Match(tok2, "%any% } ;")) + if (!tok2->isName() && Token::Match(tok2, "%any% } ;")) tok->next()->insertToken(MathLib::toString(sz)); } @@ -2712,7 +2718,7 @@ void Tokenizer::simplifyTemplates() ostr << " "; ostr << tok3->str(); } - if (!Token::Match(tok3, "> (")) + if (!Token::simpleMatch(tok3, "> (")) continue; s = ostr.str(); } @@ -3994,7 +4000,7 @@ void Tokenizer::simplifySizeof() tok->next()->deleteNext(); } - if (Token::Match(tok->next(), "( * )")) + if (Token::simpleMatch(tok->next(), "( * )")) { tok->str(MathLib::toString(sizeOfType(tok->tokAt(2)))); Token::eraseTokens(tok, tok->tokAt(4)); @@ -4431,7 +4437,8 @@ void Tokenizer::removeRedundantAssignment() } else if (tok2->varId() && !Token::Match(tok2->previous(), "[;{}] %var% = %var% ;") && - !Token::Match(tok2->previous(), "[;{}] %var% = %num% ;")) + !Token::Match(tok2->previous(), "[;{}] %var% = %num% ;") && + !(Token::Match(tok2->previous(), "[;{}] %var% = %any% ;") && tok2->strAt(2)[0] == '\'')) { localvars.erase(tok2->varId()); } @@ -4705,9 +4712,9 @@ void Tokenizer::simplifyIfAddBraces() if (!innerIf) break; - if (Token::Match(tempToken, "; else if")) + if (Token::simpleMatch(tempToken, "; else if")) ; - else if (Token::Match(tempToken, "; else")) + else if (Token::simpleMatch(tempToken, "; else")) innerIf = false; else break; @@ -4748,7 +4755,7 @@ bool Tokenizer::simplifyDoWhileAddBracesHelper(Token *tok) tok2 = tok3; break; } - else if (Token::Match(tok3, "do {")) + else if (Token::simpleMatch(tok3, "do {")) { // Skip do{}while inside the current "do" tok3 = tok3->next()->link(); @@ -5752,37 +5759,37 @@ void Tokenizer::simplifyStdType() tok->isSigned(!isUnsigned); } - if (Token::Match(tok, "__int8")) + if (Token::simpleMatch(tok, "__int8")) tok->str("char"); - else if (Token::Match(tok, "__int16")) + else if (Token::simpleMatch(tok, "__int16")) tok->str("short"); - else if (Token::Match(tok, "__int32")) + else if (Token::simpleMatch(tok, "__int32")) tok->str("int"); - else if (Token::Match(tok, "__int64")) + else if (Token::simpleMatch(tok, "__int64")) { tok->str("long"); tok->isLong(true); } - else if (Token::Match(tok, "long")) + else if (Token::simpleMatch(tok, "long")) { - if (Token::Match(tok->next(), "long")) + if (Token::simpleMatch(tok->next(), "long")) { tok->isLong(true); tok->deleteNext(); } - if (Token::Match(tok->next(), "int")) + if (Token::simpleMatch(tok->next(), "int")) tok->deleteNext(); - else if (Token::Match(tok->next(), "double")) + else if (Token::simpleMatch(tok->next(), "double")) { tok->str("double"); tok->isLong(true); tok->deleteNext(); } } - else if (Token::Match(tok, "short")) + else if (Token::simpleMatch(tok, "short")) { - if (Token::Match(tok->next(), "int")) + if (Token::simpleMatch(tok->next(), "int")) tok->deleteNext(); } } @@ -6318,6 +6325,7 @@ bool Tokenizer::simplifyKnownVariables() else if (tok2->previous()->str() != "*" && (Token::Match(tok2, "%var% = %num% ;") || Token::Match(tok2, "%var% = %str% ;") || + (Token::Match(tok2, "%var% = %any% ;") && tok2->strAt(2)[0] == '\'') || Token::Match(tok2, "%var% [ ] = %str% ;") || Token::Match(tok2, "%var% [ %num% ] = %str% ;") || Token::Match(tok2, "%var% = %bool% ;") || @@ -6706,6 +6714,28 @@ bool Tokenizer::simplifyKnownVariables() ret = true; } + if (Token::simpleMatch(tok3, "= {")) + { + unsigned int indentlevel4 = 0; + for (const Token *tok4 = tok3; tok4; tok4 = tok4->next()) + { + if (tok4->str() == "{") + ++indentlevel4; + else if (tok4->str() == "}") + { + if (indentlevel4 <= 1) + break; + --indentlevel4; + } + if (Token::Match(tok4, "{|, %varid% ,|}", varid)) + { + tok4->next()->str(value); + tok4->next()->varId(valueVarId); + ret = true; + } + } + } + // Using the variable in for-condition.. if (Token::simpleMatch(tok3, "for (")) { @@ -7463,7 +7493,7 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) if (end) { - if (Token::Match(end, ") {")) // function parameter ? + if (Token::simpleMatch(end, ") {")) // function parameter ? { // look backwards if (tok->previous()->str() == "enum" || @@ -7520,7 +7550,8 @@ void Tokenizer::simplifyEnum() int classLevel = 0; for (Token *tok = _tokens; tok; tok = tok->next()) { - if (Token::Match(tok, "class|struct|namespace %any%")) + if (Token::Match(tok, "class|struct|namespace %any%") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) { className = tok->next()->str(); classLevel = 0; @@ -7540,7 +7571,7 @@ void Tokenizer::simplifyEnum() continue; } else if (Token::Match(tok, "enum class|struct| {|:") || - Token::Match(tok, "enum class|struct| %type% {|:")) + Token::Match(tok, "enum class|struct| %type% {|:|;")) { Token *tok1; Token *start = tok; @@ -7561,12 +7592,19 @@ void Tokenizer::simplifyEnum() offset = 3; // check for forward declaration - /** @todo start substitution check at forward declaration */ const Token *temp = tok->tokAt(offset); while (!Token::Match(temp, "{|;")) temp = temp->next(); if (temp->str() == ";") + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); + tok->deleteThis(); continue; + } typeTokenStart = tok->tokAt(offset); typeTokenEnd = typeTokenStart; @@ -7580,6 +7618,16 @@ void Tokenizer::simplifyEnum() } } + // check for forward declaration + else if (Token::Match(tok->next(), "%type% ;")) + { + /** @todo start substitution check at forward declaration */ + // delete forward declaration + tok->deleteThis(); + tok->deleteThis(); + continue; + } + if (tok->tokAt(1)->str() == "{") tok1 = tok->tokAt(2); else if (tok->tokAt(1)->str() == ":") @@ -7673,7 +7721,7 @@ void Tokenizer::simplifyEnum() lastEnumValueStart = 0; lastEnumValueEnd = 0; } - else if (Token::Match(tok1->previous(), ",|{ %type% = ")) + else if (Token::Match(tok1->previous(), ",|{ %type% =")) { // value is specified expression enumName = tok1; @@ -7879,7 +7927,7 @@ void Tokenizer::simplifyEnum() } else if (tok2->str() == "{") ++level; - else if (!pattern.empty() && ((Token::Match(tok2, "enum") && Token::Match(tok2->next(), pattern.c_str())) || Token::Match(tok2, pattern.c_str()))) + else if (!pattern.empty() && ((Token::simpleMatch(tok2, "enum") && Token::Match(tok2->next(), pattern.c_str())) || Token::Match(tok2, pattern.c_str()))) { simplify = true; hasClass = true; @@ -8214,7 +8262,7 @@ void Tokenizer::simplifyComma() // We must not accept just any keyword, e.g. accepting int // would cause function parameters to corrupt. - if (Token::Match(tok->next(), "delete")) + if (Token::simpleMatch(tok->next(), "delete")) { // Handle "delete a, delete b;" tok->str(";"); @@ -8222,7 +8270,7 @@ void Tokenizer::simplifyComma() if (tok->previous() && tok->previous()->previous()) { - if (Token::Match(tok->previous()->previous(), "delete") && + if (Token::simpleMatch(tok->previous()->previous(), "delete") && tok->next()->varId() != 0) { // Handle "delete a, b;" @@ -8537,7 +8585,7 @@ void Tokenizer::simplifyStructInit() if (Token::simpleMatch(tok2, ", .")) tok2 = tok2->next(); } - if (!Token::Match(tok2, "} ;")) + if (!Token::simpleMatch(tok2, "} ;")) continue; // Known expression format => Perform simplification @@ -9225,6 +9273,12 @@ void Tokenizer::simplifyQtSignalsSlots() Token *tok = _tokens; while ((tok = const_cast(Token::findmatch(tok, "class %var% :")))) { + if (tok->previous() && tok->previous()->str() == "enum") + { + tok = tok->tokAt(2); + continue; + } + // count { and } for tok2 unsigned int indentlevel = 0; for (Token *tok2 = tok; tok2; tok2 = tok2->next()) @@ -9299,3 +9353,61 @@ void Tokenizer::simplifyOperatorName() } } } + +// remove unnecessary member qualification.. +struct ClassInfo +{ + std::string className; + Token *end; +}; + +void Tokenizer::removeUnnecessaryQualification() +{ + std::stack classInfo; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class|struct %type% :|{") && + (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) + { + tok = tok->next(); + ClassInfo info; + info.className = tok->str(); + tok = tok->next(); + while (tok && tok->str() != "{") + tok = tok->next(); + if (!tok) + return; + info.end = tok->link(); + classInfo.push(info); + } + else if (!classInfo.empty()) + { + if (tok == classInfo.top().end) + classInfo.pop(); + else if (tok->str() == classInfo.top().className && + Token::Match(tok, "%type% :: %type% (") && + Token::Match(tok->tokAt(3)->link(), ") const| {|;")) + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::portability, + "Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.", + "portability"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + + tok->deleteThis(); + tok->deleteThis(); + } + } + } +} + diff --git a/lib/tokenize.h b/lib/tokenize.h index 5662d7843..e9a280698 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -519,6 +519,11 @@ public: */ void simplifyBuiltinExpect(); + /** + * Remove unnecessary member qualification + */ + void removeUnnecessaryQualification(); + /** * Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' */ diff --git a/readme.txt b/readme.txt index 8f746cd4e..5487fa574 100644 --- a/readme.txt +++ b/readme.txt @@ -56,5 +56,5 @@ Cross compiling Win32 (CLI) version of Cppcheck in Linux Webpage - http://www.sf.net/projects/cppcheck + http://cppcheck.sourceforge.net/ diff --git a/rules/error-reporting.xml b/rules/error-reporting.xml new file mode 100644 index 000000000..2813c9bba --- /dev/null +++ b/rules/error-reporting.xml @@ -0,0 +1,10 @@ + + + Severity :: fromString \( "\w+" \) + + ConstantSeverityFromString + style + Constant severity lookups should be done via +Severity::constant. + + diff --git a/rules/stl.xml b/rules/stl.xml new file mode 100644 index 000000000..e98d55831 --- /dev/null +++ b/rules/stl.xml @@ -0,0 +1,11 @@ + + + + \. find \( "[^"]+?" \) == \d+ + + UselessSTDStringFind + performance + When looking for a string at a fixed position compare +is faster. + + diff --git a/rules/token-matching.xml b/rules/token-matching.xml new file mode 100644 index 000000000..3371f3496 --- /dev/null +++ b/rules/token-matching.xml @@ -0,0 +1,34 @@ + + + Token :: (?:findm|(?:simple|)M)atch \([^,]+,\s+"(?:\s+|[^"]+?\s+") + + TokenMatchSpacing + style + Useless extra spacing for Token::*Match. + + + + (?U)Token :: Match \([^,]+,\s+"[^%|!\[\]]+" + + UseTokensimpleMatch + error + Token::simpleMatch should be used to match tokens +without special pattern requirements. + + + + \b[\w_]+ \. tokAt \( 0 \) + + TokentokAt0 + error + tok->tokAt(0) is a slow way to say tok. + + + + \b[\w_]+ \. strAt \( 0 \) + + TokenstrAt0 + error + tok->strAt(0) is a slow way to say tok->str() + + diff --git a/test/test.pro b/test/test.pro index 0196222ed..f7237777c 100644 --- a/test/test.pro +++ b/test/test.pro @@ -1,73 +1,85 @@ - -TEMPLATE = app -TARGET = test -DEPENDPATH += . -INCLUDEPATH += . ../cli ../lib -OBJECTS_DIR = temp -CONFIG += warn_on console -CONFIG -= qt app_bundle -win32 { - LIBS += -lshlwapi -} - -BASEPATH = ../externals/tinyxml/ -include(../externals/tinyxml/tinyxml.pri) -BASEPATH = ../lib/ -include(../lib/lib.pri) - -# cli/* -SOURCES += ../cli/cmdlineparser.cpp \ - ../cli/cppcheckexecutor.cpp \ - ../cli/filelister.cpp \ - ../cli/filelister_unix.cpp \ - ../cli/filelister_win32.cpp \ - ../cli/threadexecutor.cpp -HEADERS += ../cli/cmdlineparser.h \ - ../cli/cppcheckexecutor.h \ - ../cli/filelister.h \ - ../cli/filelister_unix.h \ - ../cli/filelister_win32.h \ - ../cli/threadexecutor.h - -# test/* -HEADERS += options.h redirect.h testsuite.h -SOURCES += options.cpp \ - testautovariables.cpp \ - testbufferoverrun.cpp \ - testcharvar.cpp \ - testclass.cpp \ - testcmdlineparser.cpp \ - testconstructors.cpp \ - testcppcheck.cpp \ - testdivision.cpp \ - testerrorlogger.cpp \ - testexceptionsafety.cpp \ - testincompletestatement.cpp \ - testmathlib.cpp \ - testmemleak.cpp \ - testnullpointer.cpp \ - testobsoletefunctions.cpp \ - testoptions.cpp \ - testother.cpp \ - testpath.cpp \ - testpostfixoperator.cpp \ - testpreprocessor.cpp \ - testrunner.cpp \ - testsettings.cpp \ - testsimplifytokens.cpp \ - teststl.cpp \ - testsuite.cpp \ - testthreadexecutor.cpp \ - testtoken.cpp \ - testtokenize.cpp \ - testuninitvar.cpp \ - testunusedfunctions.cpp \ - testunusedprivfunc.cpp \ - testunusedvar.cpp - -# Change Visual Studio compiler (CL) warning level to W4 -contains(QMAKE_CXX, cl) { - QMAKE_CXXFLAGS_WARN_ON -= -W3 - QMAKE_CXXFLAGS_WARN_ON += -W4 - DEFINES += _CRT_SECURE_NO_WARNINGS -} + +TEMPLATE = app +TARGET = test +DEPENDPATH += . +INCLUDEPATH += . ../cli ../lib +OBJECTS_DIR = temp +CONFIG += warn_on console +CONFIG -= qt app_bundle +win32 { + LIBS += -lshlwapi +} + +BASEPATH = ../externals/tinyxml/ +include(../externals/tinyxml/tinyxml.pri) +BASEPATH = ../lib/ +include(../lib/lib.pri) + +# cli/* +SOURCES += ../cli/cmdlineparser.cpp \ + ../cli/cppcheckexecutor.cpp \ + ../cli/filelister.cpp \ + ../cli/filelister_unix.cpp \ + ../cli/filelister_win32.cpp \ + ../cli/pathmatch.cpp \ + ../cli/threadexecutor.cpp \ + testpathmatch.cpp +HEADERS += ../cli/cmdlineparser.h \ + ../cli/cppcheckexecutor.h \ + ../cli/filelister.h \ + ../cli/filelister_unix.h \ + ../cli/filelister_win32.h \ + ../cli/pathmatch.h \ + ../cli/threadexecutor.h + +# test/* + +# Note: +# testfilelister_unix.cpp omitted since there is test fail when run in QtCreator +# Test assumes the test (executable) is built from the test directory (or +# directory containing source files). But QtCreator builds to separate build +# directory. Hence the test does not find the source files. + +HEADERS += options.h redirect.h testsuite.h +SOURCES += options.cpp \ + testautovariables.cpp \ + testbufferoverrun.cpp \ + testcharvar.cpp \ + testclass.cpp \ + testcmdlineparser.cpp \ + testconstructors.cpp \ + testcppcheck.cpp \ + testdivision.cpp \ + testerrorlogger.cpp \ + testexceptionsafety.cpp \ + testincompletestatement.cpp \ + testmathlib.cpp \ + testmemleak.cpp \ + testnullpointer.cpp \ + testobsoletefunctions.cpp \ + testoptions.cpp \ + testother.cpp \ + testpath.cpp \ + testpathmatch.cpp \ + testpostfixoperator.cpp \ + testpreprocessor.cpp \ + testrunner.cpp \ + testsettings.cpp \ + testsimplifytokens.cpp \ + teststl.cpp \ + testsuite.cpp \ + testsymboldatabase.cpp \ + testthreadexecutor.cpp \ + testtoken.cpp \ + testtokenize.cpp \ + testuninitvar.cpp \ + testunusedfunctions.cpp \ + testunusedprivfunc.cpp \ + testunusedvar.cpp + +# Change Visual Studio compiler (CL) warning level to W4 +contains(QMAKE_CXX, cl) { + QMAKE_CXXFLAGS_WARN_ON -= -W3 + QMAKE_CXXFLAGS_WARN_ON += -W4 + DEFINES += _CRT_SECURE_NO_WARNINGS +} diff --git a/test/test.vcproj b/test/test.vcproj index 45d3f2948..bc314d136 100755 --- a/test/test.vcproj +++ b/test/test.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="9,00" Name="test" - ProjectGUID="{48110A35-C2BB-3F1C-A741-C15295041A2D}" + ProjectGUID="{5B7869EA-A1CB-3E73-8569-5B385608779E}" Keyword="Qt4VSv1.0"> + + + + - {081168BA-E630-3D82-8EDB-A19028999479} + {D0001948-3B19-3314-8BEE-3B92350BC5B5} test Qt4VSv1.0 @@ -140,6 +140,7 @@ + @@ -161,6 +162,7 @@ + @@ -168,6 +170,7 @@ + @@ -209,6 +212,7 @@ + diff --git a/test/test.vcxproj.filters b/test/test.vcxproj.filters index 84b2d7672..deb632b52 100644 --- a/test/test.vcxproj.filters +++ b/test/test.vcxproj.filters @@ -80,6 +80,9 @@ Source Files + + Source Files + Source Files @@ -143,6 +146,9 @@ Source Files + + Source Files + Source Files @@ -164,6 +170,9 @@ Source Files + + Source Files + Source Files @@ -283,6 +292,9 @@ Header Files + + Header Files + Header Files diff --git a/test/testclass.cpp b/test/testclass.cpp index 03080cfb8..ffeac3df6 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -188,6 +188,7 @@ private: TEST_CASE(symboldatabase7); // ticket #2230 TEST_CASE(symboldatabase8); // ticket #2252 TEST_CASE(symboldatabase9); // ticket #2525 + TEST_CASE(symboldatabase10); // ticket #2537 } // Check the operator Equal @@ -5490,6 +5491,20 @@ private: ASSERT_EQUALS("", errout.str()); } + void symboldatabase10() + { + // ticket #2537 - segmentation fault + checkConst("class A {\n" + "private:\n" + " void f();\n" + "};\n" + "class B {\n" + " friend void A::f();\n" + "};\n"); + + ASSERT_EQUALS("", errout.str()); + } + }; REGISTER_TEST(TestClass) diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 009be82f0..bdbd1e4d7 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -81,12 +81,22 @@ private: TEST_CASE(templatesGcc); TEST_CASE(templatesVs); TEST_CASE(xml); + TEST_CASE(xmlver1); TEST_CASE(xmlver2); TEST_CASE(xmlver2both); TEST_CASE(xmlver2both2); + TEST_CASE(xmlverunknown); + TEST_CASE(xmlverinvalid); TEST_CASE(errorlist1); TEST_CASE(errorlistverbose1) TEST_CASE(errorlistverbose2) + TEST_CASE(ignorepathsnopath) + TEST_CASE(ignorepaths1) + TEST_CASE(ignorepaths2) + TEST_CASE(ignorepaths3) + TEST_CASE(ignorepaths4) + TEST_CASE(ignorefilepaths1) + TEST_CASE(ignorefilepaths2) TEST_CASE(unknownParam); } @@ -585,6 +595,17 @@ private: ASSERT_EQUALS(1, settings._xml_version); } + void xmlver1() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml-version=1", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT(settings._xml); + ASSERT_EQUALS(1, settings._xml_version); + } + void xmlver2() { REDIRECT; @@ -618,6 +639,24 @@ private: ASSERT_EQUALS(2, settings._xml_version); } + void xmlverunknown() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml", "--xml-version=3", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(!parser.ParseFromArgs(4, argv)); + } + + void xmlverinvalid() + { + REDIRECT; + const char *argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(!parser.ParseFromArgs(4, argv)); + } + void errorlist1() { REDIRECT; @@ -647,6 +686,84 @@ private: ASSERT(settings._verbose); } + void ignorepathsnopath() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-i"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(!parser.ParseFromArgs(2, argv)); + ASSERT_EQUALS(0, parser.GetIgnoredPaths().size()); + } + + void ignorepaths1() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-isrc", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]); + } + + void ignorepaths2() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-i", "src", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(4, argv)); + ASSERT_EQUALS(1, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]); + } + + void ignorepaths3() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-isrc", "-imodule", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(4, argv)); + ASSERT_EQUALS(2, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]); + ASSERT_EQUALS("module/", parser.GetIgnoredPaths()[1]); + } + + void ignorepaths4() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-i", "src", "-i", "module", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(6, argv)); + ASSERT_EQUALS(2, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]); + ASSERT_EQUALS("module/", parser.GetIgnoredPaths()[1]); + } + + void ignorefilepaths1() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("foo.cpp", parser.GetIgnoredPaths()[0]); + } + + void ignorefilepaths2() + { + REDIRECT; + const char *argv[] = {"cppcheck", "-isrc/foo.cpp", "file.cpp"}; + Settings settings; + CmdLineParser parser(&settings); + ASSERT(parser.ParseFromArgs(3, argv)); + ASSERT_EQUALS(1, parser.GetIgnoredPaths().size()); + ASSERT_EQUALS("src/foo.cpp", parser.GetIgnoredPaths()[0]); + } + void unknownParam() { REDIRECT; diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index af6e33883..3aaff3c35 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -66,9 +66,21 @@ private: void run() { + TEST_CASE(instancesSorted); TEST_CASE(getErrorMessages); } + void instancesSorted() + { + for (std::list::iterator i = Check::instances().begin(); i != Check::instances().end(); ++i) { + std::list::iterator j = i; + ++j; + if (j != Check::instances().end()) { + ASSERT_EQUALS(true, (*i)->name() < (*j)->name()); + } + } + } + void getErrorMessages() { ErrorLogger2 errorLogger; diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index e1064464b..e716602a5 100644 --- a/test/testerrorlogger.cpp +++ b/test/testerrorlogger.cpp @@ -17,6 +17,7 @@ */ #include +#include "cppcheck.h" #include "testsuite.h" #include "errorlogger.h" @@ -38,6 +39,7 @@ private: TEST_CASE(CustomFormat2); TEST_CASE(ToXml); TEST_CASE(ToVerboseXml); + TEST_CASE(ToXmlV2); } void FileLocationDefaults() @@ -124,7 +126,7 @@ private: locs.push_back(loc); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId"); ASSERT_EQUALS("\n", ErrorLogger::ErrorMessage::getXMLHeader(1)); - ASSERT_EQUALS("", ErrorLogger::ErrorMessage::getXMLFooter()); + ASSERT_EQUALS("", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("", msg.toXML(false,1)); } @@ -137,8 +139,28 @@ private: locs.push_back(loc); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId"); ASSERT_EQUALS("\n", ErrorLogger::ErrorMessage::getXMLHeader(1)); - ASSERT_EQUALS("", ErrorLogger::ErrorMessage::getXMLFooter()); + ASSERT_EQUALS("", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("", msg.toXML(true,1)); } + + void ToXmlV2() + { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.setfile("foo.cpp"); + loc.line = 5; + std::list locs; + locs.push_back(loc); + ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId"); + std::string header("\n\n"); + header += " \n "; + ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2)); + ASSERT_EQUALS(" \n", ErrorLogger::ErrorMessage::getXMLFooter(2)); + std::string message(" \n"; + message += " \n "; + ASSERT_EQUALS(message, msg.toXML(false,2)); + } }; REGISTER_TEST(TestErrorLogger) diff --git a/test/testother.cpp b/test/testother.cpp index af08d80c4..dced35a69 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -961,6 +961,18 @@ private: " int i = sizeof sizeof char;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str()); + + check("void foo()\n" + "{\n" + " int i = sizeof (sizeof long);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str()); + + check("void foo(long *p)\n" + "{\n" + " int i = sizeof (sizeof (p));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str()); } void sizeofCalculation() diff --git a/test/testpathmatch.cpp b/test/testpathmatch.cpp new file mode 100644 index 000000000..1f552e0f8 --- /dev/null +++ b/test/testpathmatch.cpp @@ -0,0 +1,258 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 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 +#include +#include "testsuite.h" +#include "pathmatch.h" + +class TestPathMatch : public TestFixture +{ +public: + TestPathMatch() : TestFixture("TestPathMatch") + { } + +private: + + void run() + { + TEST_CASE(emptymaskemptyfile); + TEST_CASE(emptymaskpath1); + TEST_CASE(emptymaskpath2); + TEST_CASE(emptymaskpath3); + TEST_CASE(onemaskemptypath); + TEST_CASE(onemasksamepath); + TEST_CASE(onemasksamepathwithfile); + TEST_CASE(onemaskdifferentdir1); + TEST_CASE(onemaskdifferentdir2); + TEST_CASE(onemaskdifferentdir3); + TEST_CASE(onemaskdifferentdir4); + TEST_CASE(onemasklongerpath1); + TEST_CASE(onemasklongerpath2); + TEST_CASE(onemasklongerpath3); + TEST_CASE(filemask1); + TEST_CASE(filemask2); + TEST_CASE(filemask3); + TEST_CASE(filemaskpath1); + TEST_CASE(filemaskpath2); + TEST_CASE(filemaskpath3); + TEST_CASE(filemaskpath4); + } + + void emptymaskemptyfile() + { + std::vector masks; + PathMatch match(masks); + ASSERT(!match.Match("")); + } + + void emptymaskpath1() + { + std::vector masks; + PathMatch match(masks); + ASSERT(!match.Match("src/")); + } + + void emptymaskpath2() + { + std::vector masks; + PathMatch match(masks); + ASSERT(!match.Match("../src/")); + } + + void emptymaskpath3() + { + std::vector masks; + PathMatch match(masks); + ASSERT(!match.Match("/home/user/code/src/")); + } + + void onemaskemptypath() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(!match.Match("")); + } + + void onemasksamepath() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(match.Match("src/")); + } + + void onemasksamepathwithfile() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(match.Match("src/file.txt")); + } + + void onemaskdifferentdir1() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(!match.Match("srcfiles/file.txt")); + } + + void onemaskdifferentdir2() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(!match.Match("proj/srcfiles/file.txt")); + } + + void onemaskdifferentdir3() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(!match.Match("proj/mysrc/file.txt")); + } + + void onemaskdifferentdir4() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(!match.Match("proj/mysrcfiles/file.txt")); + } + + void onemasklongerpath1() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(match.Match("/tmp/src/")); + } + + void onemasklongerpath2() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(match.Match("src/module/")); + } + + void onemasklongerpath3() + { + std::vector masks; + masks.push_back("src/"); + PathMatch match(masks); + ASSERT(match.Match("project/src/module/")); + } + + void twomasklongerpath1() + { + std::vector masks; + masks.push_back("src/"); + masks.push_back("module/"); + PathMatch match(masks); + ASSERT(!match.Match("project/")); + } + + void twomasklongerpath2() + { + std::vector masks; + masks.push_back("src/"); + masks.push_back("module/"); + PathMatch match(masks); + ASSERT(match.Match("project/src/")); + } + + void twomasklongerpath3() + { + std::vector masks; + masks.push_back("src/"); + masks.push_back("module/"); + PathMatch match(masks); + ASSERT(match.Match("project/module/")); + } + + void twomasklongerpath4() + { + std::vector masks; + masks.push_back("src/"); + masks.push_back("module/"); + PathMatch match(masks); + ASSERT(match.Match("project/src/module/")); + } + + void filemask1() + { + std::vector masks; + masks.push_back("foo.cpp"); + PathMatch match(masks); + ASSERT(match.Match("foo.cpp")); + } + + void filemask2() + { + std::vector masks; + masks.push_back("foo.cpp"); + PathMatch match(masks); + ASSERT(match.Match("../foo.cpp")); + } + + void filemask3() + { + std::vector masks; + masks.push_back("foo.cpp"); + PathMatch match(masks); + ASSERT(match.Match("src/foo.cpp")); + } + + void filemaskpath1() + { + std::vector masks; + masks.push_back("src/foo.cpp"); + PathMatch match(masks); + ASSERT(match.Match("src/foo.cpp")); + } + + void filemaskpath2() + { + std::vector masks; + masks.push_back("src/foo.cpp"); + PathMatch match(masks); + ASSERT(match.Match("proj/src/foo.cpp")); + } + + void filemaskpath3() + { + std::vector masks; + masks.push_back("src/foo.cpp"); + PathMatch match(masks); + ASSERT(!match.Match("foo.cpp")); + } + + void filemaskpath4() + { + std::vector masks; + masks.push_back("src/foo.cpp"); + PathMatch match(masks); + ASSERT(!match.Match("bar/foo.cpp")); + } +}; + +REGISTER_TEST(TestPathMatch) diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index e298bcfd0..0de4ff250 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -278,6 +278,7 @@ private: TEST_CASE(enum16); // ticket #1988 TEST_CASE(enum17); // ticket #2381 (duplicate enums) TEST_CASE(enum18); // #2466 (array with same name as enum constant) + TEST_CASE(enum19); // ticket #2536 // remove "std::" on some standard functions TEST_CASE(removestd); @@ -315,6 +316,8 @@ private: TEST_CASE(redundant_semicolon); TEST_CASE(simplifyFunctionReturn); + + TEST_CASE(removeUnnecessaryQualification); } std::string tok(const char code[], bool simplify = true) @@ -6097,6 +6100,13 @@ private: ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false)); } + void enum19() // ticket #2536 + { + const char code[] = "enum class E1;\n" + "enum class E2 : int;\n"; + ASSERT_EQUALS(";", tok(code, false)); + } + void removestd() { ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); @@ -6408,6 +6418,14 @@ private: "} ;"; ASSERT_EQUALS(expected, tok(code, false)); } + + void removeUnnecessaryQualification() + { + const char code[] = "class Fred { Fred::Fred() {} };"; + const char expected[] = "class Fred { Fred ( ) { } } ;"; + ASSERT_EQUALS(expected, tok(code, false)); + ASSERT_EQUALS("[test.cpp:1]: (portability) Extra qualification 'Fred::' unnecessary and considered an error by many compilers.\n", errout.str()); + } }; REGISTER_TEST(TestSimplifyTokens) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 5f71f753f..77f464776 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -126,6 +126,7 @@ private: TEST_CASE(simplifyKnownVariables37); // ticket #2398 - false positive caused by no simplification in for loop TEST_CASE(simplifyKnownVariables38); // ticket #2399 - simplify conditions TEST_CASE(simplifyKnownVariables39); + TEST_CASE(simplifyKnownVariables40); TEST_CASE(simplifyKnownVariablesBailOutAssign); TEST_CASE(simplifyKnownVariablesBailOutFor1); TEST_CASE(simplifyKnownVariablesBailOutFor2); @@ -2046,6 +2047,16 @@ private: } } + + void simplifyKnownVariables40() + { + const char code[] = "void f() {\n" + " char c1 = 'a';\n" + " char c2 = { c1 };\n" + "}"; + ASSERT_EQUALS("void f ( ) {\n;\nchar c2 ; c2 = { 'a' } ;\n}", tokenizeAndStringify(code, true)); + } + void simplifyKnownVariablesBailOutAssign() { const char code[] = "int foo() {\n" @@ -4669,6 +4680,7 @@ private: void arraySize() { ASSERT_EQUALS("; int a[3]={1,2,3};", arraySize_(";int a[]={1,2,3};")); + ASSERT_EQUALS("; int a[]={ ABC,2,3};", arraySize_(";int a[]={ABC,2,3};")); } std::string labels_(const std::string &code) diff --git a/tools/dmake.cpp b/tools/dmake.cpp index 434a4128c..7e688f33c 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -230,8 +230,8 @@ int main(int argc, char **argv) fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n"; fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o cppcheck $(CLIOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre $(LDFLAGS)\n\n"; fout << "all:\tcppcheck testrunner\n\n"; - fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o\n"; - fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o $(LDFLAGS)\n\n"; + fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o\n"; + fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o $(LDFLAGS)\n\n"; fout << "test:\tall\n"; fout << "\t./testrunner\n\n"; fout << "check:\tall\n";