This commit is contained in:
Sébastien Debrard 2011-02-04 00:56:37 +01:00
commit 78498d4888
59 changed files with 1233 additions and 263 deletions

View File

@ -52,6 +52,7 @@ CLIOBJ = cli/cmdlineparser.o \
cli/filelister_unix.o \ cli/filelister_unix.o \
cli/filelister_win32.o \ cli/filelister_win32.o \
cli/main.o \ cli/main.o \
cli/pathmatch.o \
cli/threadexecutor.o cli/threadexecutor.o
TESTOBJ = test/options.o \ TESTOBJ = test/options.o \
@ -74,6 +75,7 @@ TESTOBJ = test/options.o \
test/testoptions.o \ test/testoptions.o \
test/testother.o \ test/testother.o \
test/testpath.o \ test/testpath.o \
test/testpathmatch.o \
test/testpostfixoperator.o \ test/testpostfixoperator.o \
test/testpreprocessor.o \ test/testpreprocessor.o \
test/testrunner.o \ test/testrunner.o \
@ -103,8 +105,8 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)
all: cppcheck testrunner all: cppcheck testrunner
testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o 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 $(LDFLAGS) $(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 test: all
./testrunner ./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 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 $(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 $(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 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 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 $(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 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 $(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 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 $(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 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 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpostfixoperator.o test/testpostfixoperator.cpp

View File

@ -17,12 +17,15 @@ SOURCES += main.cpp \
filelister.cpp \ filelister.cpp \
filelister_unix.cpp \ filelister_unix.cpp \
filelister_win32.cpp \ filelister_win32.cpp \
pathmatch.cpp \
threadexecutor.cpp threadexecutor.cpp
HEADERS += cppcheckexecutor.h \ HEADERS += cppcheckexecutor.h \
cmdlineparser.h \ cmdlineparser.h \
filelister.h \ filelister.h \
filelister_unix.h \ filelister_unix.h \
filelister_win32.h \ filelister_win32.h \
pathmatch.h \
threadexecutor.h threadexecutor.h
CONFIG(release, debug|release) { CONFIG(release, debug|release) {

View File

@ -26,6 +26,7 @@
#include "settings.h" #include "settings.h"
#include "cmdlineparser.h" #include "cmdlineparser.h"
#include "path.h" #include "path.h"
#include "filelister.h"
// xml is used in rules // xml is used in rules
#include "tinyxml/tinyxml.h" #include "tinyxml/tinyxml.h"
@ -210,11 +211,28 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
else if (strcmp(argv[i], "--xml") == 0) else if (strcmp(argv[i], "--xml") == 0)
_settings->_xml = true; _settings->_xml = true;
// Write results in xml2 format // Define the XML file version (and enable XML output)
else if (strcmp(argv[i], "--xml-version=2") == 0) 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 = true;
_settings->_xml_version = 2;
} }
// Only print something when there are errors // 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); 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 // Report progress
else if (strcmp(argv[i], "--report-progress") == 0) else if (strcmp(argv[i], "--report-progress") == 0)
{ {
@ -461,18 +517,18 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
TiXmlDocument doc; TiXmlDocument doc;
if (doc.LoadFile(12+argv[i])) if (doc.LoadFile(12+argv[i]))
{ {
TiXmlElement *root = doc.FirstChildElement(); TiXmlElement *node = doc.FirstChildElement();
if (root && root->ValueStr() == "rule") for (; node && node->ValueStr() == "rule"; node = node->NextSiblingElement())
{ {
Settings::Rule rule; Settings::Rule rule;
TiXmlElement *pattern = root->FirstChildElement("pattern"); TiXmlElement *pattern = node->FirstChildElement("pattern");
if (pattern) if (pattern)
{ {
rule.pattern = pattern->GetText(); rule.pattern = pattern->GetText();
} }
TiXmlElement *message = root->FirstChildElement("message"); TiXmlElement *message = node->FirstChildElement("message");
if (message) if (message)
{ {
TiXmlElement *severity = message->FirstChildElement("severity"); TiXmlElement *severity = message->FirstChildElement("severity");
@ -589,6 +645,10 @@ void CmdLineParser::PrintHelp()
" -I [dir] Give include path. Give several -I parameters to give\n" " -I [dir] Give include path. Give several -I parameters to give\n"
" several paths. First given path is checked first. If\n" " several paths. First given path is checked first. If\n"
" paths are relative to source files, this is not needed\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" " --inline-suppr Enable inline suppressions. Use them by placing one or\n"
" more comments, like: // cppcheck-suppress warningId\n" " more comments, like: // cppcheck-suppress warningId\n"
" on the lines before the warning to suppress.\n" " on the lines before the warning to suppress.\n"
@ -608,6 +668,9 @@ void CmdLineParser::PrintHelp()
" -v, --verbose More detailed error reports\n" " -v, --verbose More detailed error reports\n"
" --version Print out version number\n" " --version Print out version number\n"
" --xml Write results in xml to error stream.\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" "\n"
"Example usage:\n" "Example usage:\n"
" # Recursively check the current folder. Print the progress on the screen and\n" " # Recursively check the current folder. Print the progress on the screen and\n"

View File

@ -92,6 +92,14 @@ public:
return _exitAfterPrint; return _exitAfterPrint;
} }
/**
* Return a list of paths user wants to ignore.
*/
std::vector<std::string> GetIgnoredPaths() const
{
return _ignoredPaths;
}
protected: protected:
/** /**
@ -111,6 +119,7 @@ private:
bool _showErrorMessages; bool _showErrorMessages;
bool _exitAfterPrint; bool _exitAfterPrint;
std::vector<std::string> _pathnames; std::vector<std::string> _pathnames;
std::vector<std::string> _ignoredPaths;
}; };
/// @} /// @}

View File

@ -3,7 +3,7 @@
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9,00" Version="9,00"
Name="cppcheck" Name="cppcheck"
ProjectGUID="{7E69D6C6-32B2-32E1-BF56-A5BFBAF5E61F}" ProjectGUID="{56B0F403-02CE-3F89-9A1B-E03F21240A63}"
Keyword="Qt4VSv1.0"> Keyword="Qt4VSv1.0">
<Platforms> <Platforms>
<Platform <Platform
@ -169,6 +169,8 @@
RelativePath="..\lib\mathlib.cpp" /> RelativePath="..\lib\mathlib.cpp" />
<File <File
RelativePath="..\lib\path.cpp" /> RelativePath="..\lib\path.cpp" />
<File
RelativePath="pathmatch.cpp" />
<File <File
RelativePath="..\lib\preprocessor.cpp" /> RelativePath="..\lib\preprocessor.cpp" />
<File <File
@ -242,6 +244,8 @@
RelativePath="..\lib\mathlib.h" /> RelativePath="..\lib\mathlib.h" />
<File <File
RelativePath="..\lib\path.h" /> RelativePath="..\lib\path.h" />
<File
RelativePath="pathmatch.h" />
<File <File
RelativePath="..\lib\preprocessor.h" /> RelativePath="..\lib\preprocessor.h" />
<File <File

View File

@ -11,7 +11,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{42BC0E8E-9175-3B2D-B8B3-9EC5C36EF49A}</ProjectGuid> <ProjectGuid>{A6DACC3F-847F-3498-9415-164FBC746D6B}</ProjectGuid>
<RootNamespace>cppcheck</RootNamespace> <RootNamespace>cppcheck</RootNamespace>
<Keyword>Qt4VSv1.0</Keyword> <Keyword>Qt4VSv1.0</Keyword>
</PropertyGroup> </PropertyGroup>
@ -140,6 +140,7 @@
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="..\lib\mathlib.cpp" /> <ClCompile Include="..\lib\mathlib.cpp" />
<ClCompile Include="..\lib\path.cpp" /> <ClCompile Include="..\lib\path.cpp" />
<ClCompile Include="pathmatch.cpp" />
<ClCompile Include="..\lib\preprocessor.cpp" /> <ClCompile Include="..\lib\preprocessor.cpp" />
<ClCompile Include="..\lib\settings.cpp" /> <ClCompile Include="..\lib\settings.cpp" />
<ClCompile Include="..\lib\symboldatabase.cpp" /> <ClCompile Include="..\lib\symboldatabase.cpp" />
@ -176,6 +177,7 @@
<ClInclude Include="filelister_win32.h" /> <ClInclude Include="filelister_win32.h" />
<ClInclude Include="..\lib\mathlib.h" /> <ClInclude Include="..\lib\mathlib.h" />
<ClInclude Include="..\lib\path.h" /> <ClInclude Include="..\lib\path.h" />
<ClInclude Include="pathmatch.h" />
<ClInclude Include="..\lib\preprocessor.h" /> <ClInclude Include="..\lib\preprocessor.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="..\lib\settings.h" /> <ClInclude Include="..\lib\settings.h" />

View File

@ -84,6 +84,9 @@
<ClCompile Include="..\lib\path.cpp"> <ClCompile Include="..\lib\path.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="pathmatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\lib\preprocessor.cpp"> <ClCompile Include="..\lib\preprocessor.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -188,6 +191,9 @@
<ClInclude Include="..\lib\path.h"> <ClInclude Include="..\lib\path.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="pathmatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\lib\preprocessor.h"> <ClInclude Include="..\lib\preprocessor.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>

View File

@ -25,6 +25,7 @@
#include "cmdlineparser.h" #include "cmdlineparser.h"
#include "filelister.h" #include "filelister.h"
#include "path.h" #include "path.h"
#include "pathmatch.h"
CppCheckExecutor::CppCheckExecutor() CppCheckExecutor::CppCheckExecutor()
{ {
@ -55,7 +56,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
errorlist = true; errorlist = true;
std::cout << ErrorLogger::ErrorMessage::getXMLHeader(_settings._xml_version); std::cout << ErrorLogger::ErrorMessage::getXMLHeader(_settings._xml_version);
cppcheck->getErrorMessages(); cppcheck->getErrorMessages();
std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl; std::cout << ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version) << std::endl;
} }
if (parser.ExitAfterPrinting()) if (parser.ExitAfterPrinting())
@ -87,19 +88,36 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
std::vector<std::string>::const_iterator iter; std::vector<std::string>::const_iterator iter;
for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) for (iter = pathnames.begin(); iter != pathnames.end(); ++iter)
getFileLister()->recursiveAddFiles(filenames, Path::toNativeSeparators(iter->c_str())); 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<std::string>::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; std::cout << "cppcheck: error: could not find or open any of the paths given." << std::endl;
return false; return false;
} }
if (!filenames.empty())
{
std::vector<std::string>::iterator iter;
for (iter = filenames.begin(); iter != filenames.end(); ++iter)
cppcheck->addFile(*iter);
return true;
}
else 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) if (_settings._xml)
{ {
reportErr(ErrorLogger::ErrorMessage::getXMLFooter()); reportErr(ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version));
} }
if (returnValue) if (returnValue)

View File

@ -55,7 +55,7 @@ public:
* @param filename filename to check * @param filename filename to check
* @return returns true if the file extension indicates it should be checked * @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? * @brief Is given path a directory?

View File

@ -72,7 +72,7 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
continue; continue;
} }
if (Path::sameFileName(path,filename) || FileListerUnix::acceptFile(filename)) if (Path::sameFileName(path,filename) || FileLister::acceptFile(filename))
{ {
relative.push_back(filename); relative.push_back(filename);
absolute.push_back(fname); absolute.push_back(fname);

73
cli/pathmatch.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "pathmatch.h"
PathMatch::PathMatch(const std::vector<std::string> &masks)
: _masks(masks)
{
}
bool PathMatch::Match(const std::string &path)
{
if (path.empty())
return false;
std::vector<std::string>::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);
}

63
cli/pathmatch.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef PATHMATCH_H
#define PATHMATCH_H
#include <string>
#include <vector>
/// @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<std::string> &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<std::string> _masks;
};
/// @}
#endif // PATHMATCH_H

View File

@ -7,6 +7,8 @@
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /> <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="alternate" type="application/atom+xml" title="Recent Commits to cppcheck:master" <link rel="alternate" type="application/atom+xml" title="Recent Commits to cppcheck:master"
href="https://github.com/danmar/cppcheck/commits/master.atom" /> href="https://github.com/danmar/cppcheck/commits/master.atom" />
<link rel="alternate" type="application/atom+xml" title="Trac Timeline"
href="http://sourceforge.net/apps/trac/cppcheck/timeline?changeset=on&amp;ticket=on&amp;milestone=on&amp;wiki=on&amp;max=50&amp;daysback=90&amp;format=rss" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
<script src="/site/js/github.js" type="text/javascript"></script> <script src="/site/js/github.js" type="text/javascript"></script>
<script type="text/javascript"> <script type="text/javascript">
@ -44,6 +46,23 @@ cppcheck git repository</a>. To download it, run the following command:</p>
the latest sources in a zip or tgz archive</a> from the github website.</p> the latest sources in a zip or tgz archive</a> from the github website.</p>
<h3>Recent Commits</h3> <h3>Recent Commits</h3>
<div id="github-commits"><a href="https://github.com/danmar/cppcheck/commits/master">View recent commits&hellip;</a></div> <div id="github-commits"><a href="https://github.com/danmar/cppcheck/commits/master">View recent commits&hellip;</a></div>
<p><a href="https://github.com/danmar/cppcheck/commits/master">View all commits&hellip;</a></p>
<h2>Trac Timeline</h2>
<?php
require '../site/simplepie/simplepie.inc';
$feed = new SimplePie();
$feed->set_feed_url('http://sourceforge.net/apps/trac/cppcheck/timeline?changeset=on&ticket=on&milestone=on&wiki=on&max=10&daysback=90&format=rss');
$feed->set_cache_location('./site/simplepie/cache');
$feed->init();
print("<ul class=\"rssfeeditems\">\n");
foreach ($feed->get_items() as $item) { //for the last timeline items...
$author = $item->get_author();
print(" <li><a href=\"".$item->get_link()."\">".$item->get_title()."</a> by <strong>".$author->get_name()."</strong><em>".$item->get_date('Y-m-d')."</em></li>\n");
}
print("</ul>\n");
?>
<p><a href="http://sourceforge.net/apps/trac/cppcheck/timeline">View complete Trac timeline&hellip;</a></p>
<h2>Doxygen</h2> <h2>Doxygen</h2>
<ul> <ul>
<li><a href="/doxyoutput/">Output</a></li> <li><a href="/doxyoutput/">Output</a></li>

View File

@ -81,6 +81,10 @@ Cppcheck as an external tool.</p>
?> ?>
<p><a href="http://sourceforge.net/news/?group_id=195752">View all news&hellip;</a></p> <p><a href="http://sourceforge.net/news/?group_id=195752">View all news&hellip;</a></p>
<h2>Documentation</h2>
<p>You can read the <a href="manual.pdf">manual</a> or download some
<a href="http://sourceforge.net/projects/cppcheck/files/Articles/">articles</a>.</p>
<h2>Support</h2> <h2>Support</h2>
<ul> <ul>
<li>Use <a href="http://sourceforge.net/apps/trac/cppcheck/">Trac</a> to report <li>Use <a href="http://sourceforge.net/apps/trac/cppcheck/">Trac</a> to report

View File

@ -39,16 +39,11 @@ class Check
{ {
public: public:
/** This constructor is used when registering the CheckClass */ /** This constructor is used when registering the CheckClass */
Check() Check(const std::string &aname);
: _tokenizer(0), _settings(0), _errorLogger(0)
{
instances().push_back(this);
instances().sort();
}
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
Check(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) Check(const std::string &aname, const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) : _name(aname), _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger)
{ } { }
virtual ~Check() virtual ~Check()
@ -98,7 +93,10 @@ public:
virtual void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) = 0; virtual void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) = 0;
/** class name, used to generate documentation */ /** 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 */ /** get information about this class, used to generate documentation */
virtual std::string classInfo() const = 0; virtual std::string classInfo() const = 0;
@ -114,6 +112,7 @@ public:
} }
protected: protected:
const std::string _name;
const Tokenizer * const _tokenizer; const Tokenizer * const _tokenizer;
const Settings * const _settings; const Settings * const _settings;
ErrorLogger * const _errorLogger; ErrorLogger * const _errorLogger;
@ -155,17 +154,30 @@ protected:
private: 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 */ /** disabled assignment operator */
void operator=(const Check &); void operator=(const Check &);
}; };
namespace std
{
/** compare the names of Check classes, used when sorting the Check descendants */
template <> struct less<Check *>
{
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<Check *>());
}
/// @} /// @}
#endif #endif

View File

@ -448,7 +448,7 @@ void CheckAutoVariables::returncstr()
} }
// have we reached a function that returns a reference? // have we reached a function that returns a reference?
if (Token::Match(tok, "const char *")) if (Token::simpleMatch(tok, "const char *"))
{ {
// go to the '(' // go to the '('
const Token *tok2 = tok->tokAt(3); const Token *tok2 = tok->tokAt(3);

View File

@ -34,12 +34,12 @@ class CheckAutoVariables : public Check
{ {
public: public:
/** This constructor is used when registering the CheckClass */ /** This constructor is used when registering the CheckClass */
CheckAutoVariables() : Check() CheckAutoVariables() : Check(myName())
{ } { }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckAutoVariables(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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) void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
@ -98,7 +98,7 @@ private:
c.errorReturnTempPointer(0); c.errorReturnTempPointer(0);
} }
std::string name() const std::string myName() const
{ {
return "Auto Variables"; return "Auto Variables";
} }

View File

@ -766,7 +766,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
const unsigned char varc(static_cast<unsigned char>(varname.empty() ? 0U : (varname.size() - 1) * 2U)); const unsigned char varc(static_cast<unsigned char>(varname.empty() ? 0U : (varname.size() - 1) * 2U));
if (Token::Match(tok, "return")) if (Token::simpleMatch(tok, "return"))
{ {
tok = tok->next(); tok = tok->next();
if (!tok) if (!tok)
@ -828,7 +828,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(3)); const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(3));
if (index < 0 || index >= size) if (index < 0 || index >= size)
{ {
if (index > size || !Token::Match(tok->previous(), "& (")) if (index > size || !Token::simpleMatch(tok->previous(), "& ("))
{ {
arrayIndexOutOfBounds(tok->next(), size, index); arrayIndexOutOfBounds(tok->next(), size, index);
} }

View File

@ -50,12 +50,12 @@ class CheckBufferOverrun : public Check
public: public:
/** This constructor is used when registering the CheckClass */ /** This constructor is used when registering the CheckClass */
CheckBufferOverrun() : Check() CheckBufferOverrun() : Check(myName())
{ } { }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckBufferOverrun(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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) void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
@ -209,7 +209,7 @@ public:
c.pointerOutOfBounds(0, "array"); c.pointerOutOfBounds(0, "array");
} }
std::string name() const std::string myName() const
{ {
return "Bounds checking"; return "Bounds checking";
} }

View File

@ -42,7 +42,7 @@ CheckClass instance;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(tokenizer, settings, errorLogger), : Check(myName(), tokenizer, settings, errorLogger),
symbolDatabase(NULL) symbolDatabase(NULL)
{ {
@ -931,7 +931,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co
// check of *this is returned // check of *this is returned
else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") || else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") ||
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); 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()) 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 *tok1 = tok->tokAt(2);
const Token *tok2 = tok->tokAt(1)->link(); 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|:|?")) 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; return true;
tok = tok->previous(); tok = tok->previous();

View File

@ -36,7 +36,7 @@ class CheckClass : public Check
{ {
public: public:
/** @brief This constructor is used when registering the CheckClass */ /** @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. */ /** @brief This constructor is used when running checks. */
@ -144,7 +144,7 @@ private:
c.checkConstError(0, "class", "function"); c.checkConstError(0, "class", "function");
} }
std::string name() const std::string myName() const
{ {
return "Class"; return "Class";
} }

View File

@ -43,12 +43,12 @@ class CheckExceptionSafety : public Check
{ {
public: public:
/** This constructor is used when registering the CheckClass */ /** This constructor is used when registering the CheckClass */
CheckExceptionSafety() : Check() CheckExceptionSafety() : Check(myName())
{ } { }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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 */ /** Checks that uses the simplified token list */
@ -86,7 +86,7 @@ private:
} }
/** Short description of class (for --doc) */ /** Short description of class (for --doc) */
std::string name() const std::string myName() const
{ {
return "Exception Safety"; return "Exception Safety";
} }

View File

@ -223,7 +223,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
return gMalloc; return gMalloc;
if (Token::Match(tok, "fclose ( %varid% )", varid) || if (Token::Match(tok, "fclose ( %varid% )", varid) ||
Token::Match(tok, "fcloseall ( )")) Token::simpleMatch(tok, "fcloseall ( )"))
return File; return File;
if (Token::Match(tok, "close ( %varid% )", varid)) if (Token::Match(tok, "close ( %varid% )", varid))
@ -1445,7 +1445,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
// Assignment.. // Assignment..
if (varid) if (varid)
{ {
if (Token::Match(tok, "= {")) if (Token::simpleMatch(tok, "= {"))
{ {
unsigned int indentlevel2 = 0; unsigned int indentlevel2 = 0;
bool use = false; bool use = false;
@ -1754,7 +1754,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
} }
} }
if (Token::Match(tok2, "while1 { if { dealloc ; return ; } }")) if (Token::simpleMatch(tok2, "while1 { if { dealloc ; return ; } }"))
{ {
tok2->str(";"); tok2->str(";");
Token::eraseTokens(tok2, tok2->tokAt(4)); Token::eraseTokens(tok2, tok2->tokAt(4));
@ -1820,7 +1820,7 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok)
} }
// Reduce "if continue ; if continue ;" => "if continue ;" // 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)); Token::eraseTokens(tok2, tok2->tokAt(4));
done = false; done = false;

View File

@ -172,12 +172,12 @@ class CheckMemoryLeakInFunction : private Check, public CheckMemoryLeak
{ {
public: public:
/** @brief This constructor is used when registering this class */ /** @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 */ /** @brief This constructor is used when running checks */
CheckMemoryLeakInFunction(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) 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 // get the symbol database
if (tokenizr) if (tokenizr)
@ -329,7 +329,7 @@ public:
* Get name of class (--doc) * Get name of class (--doc)
* @return name of class * @return name of class
*/ */
std::string name() const std::string myName() const
{ {
return "Memory leaks (function variables)"; return "Memory leaks (function variables)";
} }
@ -364,11 +364,11 @@ public:
class CheckMemoryLeakInClass : private Check, private CheckMemoryLeak class CheckMemoryLeakInClass : private Check, private CheckMemoryLeak
{ {
public: public:
CheckMemoryLeakInClass() : Check(), CheckMemoryLeak(0, 0) CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(0, 0)
{ } { }
CheckMemoryLeakInClass(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) 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) void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
@ -396,7 +396,7 @@ private:
void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/)
{ } { }
std::string name() const std::string myName() const
{ {
return "Memory leaks (class variables)"; return "Memory leaks (class variables)";
} }
@ -414,11 +414,11 @@ private:
class CheckMemoryLeakStructMember : private Check, private CheckMemoryLeak class CheckMemoryLeakStructMember : private Check, private CheckMemoryLeak
{ {
public: public:
CheckMemoryLeakStructMember() : Check(), CheckMemoryLeak(0, 0) CheckMemoryLeakStructMember() : Check(myName()), CheckMemoryLeak(0, 0)
{ } { }
CheckMemoryLeakStructMember(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) 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) void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
@ -434,7 +434,7 @@ private:
void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/)
{ } { }
std::string name() const std::string myName() const
{ {
return "Memory leaks (struct members)"; return "Memory leaks (struct members)";
} }
@ -452,11 +452,11 @@ private:
class CheckMemoryLeakNoVar : private Check, private CheckMemoryLeak class CheckMemoryLeakNoVar : private Check, private CheckMemoryLeak
{ {
public: public:
CheckMemoryLeakNoVar() : Check(), CheckMemoryLeak(0, 0) CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(0, 0)
{ } { }
CheckMemoryLeakNoVar(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) 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) void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
@ -474,7 +474,7 @@ private:
void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/)
{ } { }
std::string name() const std::string myName() const
{ {
return "Memory leaks (address not taken)"; return "Memory leaks (address not taken)";
} }

View File

@ -71,7 +71,6 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
functionNames1.insert("strstr"); functionNames1.insert("strstr");
functionNames1.insert("fclose"); functionNames1.insert("fclose");
functionNames1.insert("feof"); functionNames1.insert("feof");
functionNames1.insert("fread");
functionNames1.insert("fwrite"); functionNames1.insert("fwrite");
functionNames1.insert("fseek"); functionNames1.insert("fseek");
functionNames1.insert("ftell"); functionNames1.insert("ftell");
@ -544,7 +543,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
if (Token::Match(tok, "* %var% [;,)=]")) if (Token::Match(tok, "* %var% [;,)=]"))
pointerVariables.insert(tok->next()->varId()); pointerVariables.insert(tok->next()->varId());
else if (Token::Match(tok, "if (")) else if (Token::simpleMatch(tok, "if ("))
{ {
// TODO: investigate false negatives: // TODO: investigate false negatives:
// - handle "while"? // - handle "while"?
@ -617,7 +616,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
if (null && indentlevel == 0) if (null && indentlevel == 0)
{ {
// skip all "else" blocks because they are not executed in this execution path // 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(); tok2 = tok2->tokAt(2)->link();
null = false; null = false;
} }

View File

@ -37,12 +37,12 @@ class CheckNullPointer : public Check
{ {
public: public:
/** @brief This constructor is used when registering the CheckNullPointer */ /** @brief This constructor is used when registering the CheckNullPointer */
CheckNullPointer() : Check() CheckNullPointer() : Check(myName())
{ } { }
/** @brief This constructor is used when running checks. */ /** @brief This constructor is used when running checks. */
CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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 */ /** @brief Run checks against the normal token list */
@ -112,7 +112,7 @@ public:
} }
/** Name of check */ /** Name of check */
std::string name() const std::string myName() const
{ {
return "Null pointer"; return "Null pointer";
} }

View File

@ -38,14 +38,14 @@ class CheckObsoleteFunctions : public Check
{ {
public: public:
/** This constructor is used when registering the CheckObsoleteFunctions */ /** This constructor is used when registering the CheckObsoleteFunctions */
CheckObsoleteFunctions() : Check() CheckObsoleteFunctions() : Check(myName())
{ {
initObsoleteFunctions(); initObsoleteFunctions();
} }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckObsoleteFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) CheckObsoleteFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(tokenizer, settings, errorLogger) : Check(myName(), tokenizer, settings, errorLogger)
{ {
initObsoleteFunctions(); initObsoleteFunctions();
} }
@ -125,7 +125,7 @@ private:
} }
} }
std::string name() const std::string myName() const
{ {
return "Obsolete functions"; return "Obsolete functions";
} }

View File

@ -1491,7 +1491,7 @@ void CheckOther::functionVariableUsage()
variables.read(nametok->tokAt(2)->varId()); variables.read(nametok->tokAt(2)->varId());
// look at initializers // look at initializers
if (Token::Match(nametok->tokAt(4), "= {")) if (Token::simpleMatch(nametok->tokAt(4), "= {"))
{ {
tok = nametok->tokAt(6); tok = nametok->tokAt(6);
while (tok->str() != "}") while (tok->str() != "}")
@ -2705,7 +2705,7 @@ void CheckOther::checkMisusedScopedObject()
} }
if (Token::Match(tok, "[;{}] %var% (") if (Token::Match(tok, "[;{}] %var% (")
&& Token::Match(tok->tokAt(2)->link(), ") ;") && Token::simpleMatch(tok->tokAt(2)->link(), ") ;")
&& symbolDatabase->isClassOrStruct(tok->next()->str()) && symbolDatabase->isClassOrStruct(tok->next()->str())
) )
{ {
@ -2834,8 +2834,11 @@ void CheckOther::sizeofsizeof()
return; return;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{ {
if (Token::simpleMatch(tok, "sizeof sizeof")) if (Token::Match(tok, "sizeof (| sizeof"))
{
sizeofsizeofError(tok); sizeofsizeofError(tok);
tok = tok->next();
}
} }
} }

View File

@ -37,12 +37,12 @@ class CheckOther : public Check
{ {
public: public:
/** @brief This constructor is used when registering the CheckClass */ /** @brief This constructor is used when registering the CheckClass */
CheckOther() : Check() CheckOther() : Check(myName())
{ } { }
/** @brief This constructor is used when running checks. */ /** @brief This constructor is used when running checks. */
CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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 */ /** @brief Run checks against the normal token list */
@ -245,7 +245,7 @@ public:
c.clarifyCalculationError(0); c.clarifyCalculationError(0);
} }
std::string name() const std::string myName() const
{ {
return "Other"; return "Other";
} }

View File

@ -35,12 +35,12 @@ class CheckPostfixOperator : public Check
{ {
public: public:
/** This constructor is used when registering the CheckPostfixOperator */ /** This constructor is used when registering the CheckPostfixOperator */
CheckPostfixOperator() : Check() CheckPostfixOperator() : Check(myName())
{ } { }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckPostfixOperator(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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) void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
@ -62,7 +62,7 @@ private:
c.postfixOperatorError(0); c.postfixOperatorError(0);
} }
std::string name() const std::string myName() const
{ {
return "Using postfix operators"; return "Using postfix operators";
} }

View File

@ -572,7 +572,7 @@ void CheckStl::pushback()
} }
// Using push_back or push_front inside a loop.. // Using push_back or push_front inside a loop..
if (Token::Match(tok2, "for (")) if (Token::simpleMatch(tok2, "for ("))
{ {
tok2 = tok2->tokAt(2); tok2 = tok2->tokAt(2);
} }
@ -1038,7 +1038,7 @@ void CheckStl::string_c_str()
string_c_strError(tok); string_c_strError(tok);
} }
else if (Token::Match(tok, "[;{}] %var% = %var% (") && 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 && tok->next()->varId() > 0 &&
pointers.find(tok->next()->varId()) != pointers.end() && pointers.find(tok->next()->varId()) != pointers.end() &&
Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str()))

View File

@ -35,12 +35,12 @@ class CheckStl : public Check
{ {
public: public:
/** This constructor is used when registering the CheckClass */ /** This constructor is used when registering the CheckClass */
CheckStl() : Check() CheckStl() : Check(myName())
{ } { }
/** This constructor is used when running checks. */ /** This constructor is used when running checks. */
CheckStl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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. */ /** Simplified checks. The token list is simplified. */
@ -173,7 +173,7 @@ private:
c.redundantIfRemoveError(0); c.redundantIfRemoveError(0);
} }
std::string name() const std::string myName() const
{ {
return "STL usage"; return "STL usage";
} }

View File

@ -37,12 +37,12 @@ class CheckUninitVar : public Check
{ {
public: public:
/** @brief This constructor is used when registering the CheckUninitVar */ /** @brief This constructor is used when registering the CheckUninitVar */
CheckUninitVar() : Check() CheckUninitVar() : Check(myName())
{ } { }
/** @brief This constructor is used when running checks. */ /** @brief This constructor is used when running checks. */
CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 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 */ /** @brief Run checks against the normal token list */
@ -87,7 +87,7 @@ public:
c.uninitvarError(0, "varname"); c.uninitvarError(0, "varname");
} }
std::string name() const std::string myName() const
{ {
return "Uninitialized variables"; return "Uninitialized variables";
} }

View File

@ -33,12 +33,12 @@ class CheckUnusedFunctions: public Check
{ {
public: public:
/** @brief This constructor is used when registering the CheckUnusedFunctions */ /** @brief This constructor is used when registering the CheckUnusedFunctions */
CheckUnusedFunctions() : Check() CheckUnusedFunctions() : Check(myName())
{ } { }
/** @brief This constructor is used when running checks. */ /** @brief This constructor is used when running checks. */
CheckUnusedFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) CheckUnusedFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(tokenizer, settings, errorLogger) : Check(myName(), tokenizer, settings, errorLogger)
{ } { }
// Parse current tokens and determine.. // Parse current tokens and determine..
@ -69,7 +69,7 @@ private:
} }
std::string name() const std::string myName() const
{ {
return "Unused functions"; return "Unused functions";
} }

View File

@ -335,15 +335,19 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
reportErr(errmsg); reportErr(errmsg);
} }
if (re) if (!re)
{ continue;
int pos = 0; int pos = 0;
int ovector[30]; int ovector[30];
if (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) while (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30))
{ {
unsigned int pos1 = (unsigned int)ovector[0]; unsigned int pos1 = (unsigned int)ovector[0];
unsigned int pos2 = (unsigned int)ovector[1]; unsigned int pos2 = (unsigned int)ovector[1];
// jump to the end of the match for the next pcre_exec
pos = pos2;
// determine location.. // determine location..
ErrorLogger::ErrorMessage::FileLocation loc; ErrorLogger::ErrorMessage::FileLocation loc;
loc.setfile(_tokenizer.getFiles()->front()); loc.setfile(_tokenizer.getFiles()->front());
@ -378,7 +382,6 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
pcre_free(re); pcre_free(re);
} }
} }
}
#endif #endif
} }

View File

@ -162,15 +162,16 @@ std::string ErrorLogger::ErrorMessage::getXMLHeader(int xml_version)
else else
{ {
ostr << "<results version=\"" << xml_version << "\">\n"; ostr << "<results version=\"" << xml_version << "\">\n";
ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>"; ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>\n";
ostr << " <errors>";
} }
return ostr.str(); return ostr.str();
} }
std::string ErrorLogger::ErrorMessage::getXMLFooter() std::string ErrorLogger::ErrorMessage::getXMLFooter(int xml_version)
{ {
return "</results>"; return (xml_version<=1) ? "</results>" : " </errors>\n</results>";
} }
static std::string stringToXml(std::string s) static std::string stringToXml(std::string s)

View File

@ -137,7 +137,7 @@ public:
std::string toXML(bool verbose, int ver) const; std::string toXML(bool verbose, int ver) const;
static std::string getXMLHeader(int xml_version); 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. * Format the error message into a string.

View File

@ -348,7 +348,7 @@ void ExecutionPath::checkScope(const Token *tok, std::list<ExecutionPath *> &che
} }
} }
if (Token::Match(tok, "= {")) if (Token::simpleMatch(tok, "= {"))
{ {
// GCC struct initialization.. bail out // GCC struct initialization.. bail out
if (Token::Match(tok->tokAt(2), ". %var% =")) if (Token::Match(tok->tokAt(2), ". %var% ="))

View File

@ -2142,7 +2142,7 @@ public:
if (Token::Match(tok, "%var% %var%") || if (Token::Match(tok, "%var% %var%") ||
Token::Match(tok, "%var% %num%") || Token::Match(tok, "%var% %num%") ||
Token::Match(tok, "%num% %var%") || Token::Match(tok, "%num% %var%") ||
Token::Match(tok, "> >")) Token::simpleMatch(tok, "> >"))
macrocode += " "; macrocode += " ";
} }
} }

View File

@ -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)) else if (tok->previous()->str() == "::" && isFunction(tok, &funcStart, &argStart))
{
/** @todo check entire qualification for match */
Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2));
if (nested)
addFunction(&scope, &tok, argStart); addFunction(&scope, &tok, argStart);
else
{
/** @todo handle friend functions */
}
}
// friend class declaration? // friend class declaration?
else if (Token::Match(tok, "friend class| %any% ;")) else if (Token::Match(tok, "friend class| %any% ;"))
@ -1398,6 +1408,26 @@ Scope * Scope::findInNestedList(const std::string & name)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
Scope * Scope::findInNestedListRecursive(const std::string & name)
{
std::list<Scope *>::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 const Function *Scope::getDestructor() const
{ {
std::list<Function>::const_iterator it; std::list<Function>::const_iterator it;

View File

@ -311,6 +311,12 @@ public:
*/ */
Scope * findInNestedList(const std::string & name); 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_) 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_)); varlist.push_back(Variable(token_, varlist.size(), access_, mutable_, static_, const_, class_, type_));

View File

@ -552,7 +552,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name)
if (end) if (end)
{ {
if (Token::Match(end, ") {")) // function parameter ? if (Token::simpleMatch(end, ") {")) // function parameter ?
{ {
// look backwards // look backwards
if (Token::Match(tok->previous(), "%type%") && if (Token::Match(tok->previous(), "%type%") &&
@ -588,7 +588,7 @@ bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name)
(tok->previous()->str() == "*" && tok->next()->str() != "(") || (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
(Token::Match(tok->previous(), "%type%") && (Token::Match(tok->previous(), "%type%") &&
(!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") && (!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 // scan backwards for the end of the previous statement
int level = (tok->previous()->str() == "}") ? 1 : 0; int level = (tok->previous()->str() == "}") ? 1 : 0;
@ -824,7 +824,8 @@ void Tokenizer::simplifyTypedef()
if (_errorLogger && !_files.empty()) if (_errorLogger && !_files.empty())
_errorLogger->reportProgress(_files[0], "Tokenize (typedef)", tok->progressValue()); _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"); isNamespace = (tok->str() == "namespace");
hasClass = true; hasClass = true;
@ -926,7 +927,7 @@ void Tokenizer::simplifyTypedef()
Token *namespaceStart = 0; Token *namespaceStart = 0;
Token *namespaceEnd = 0; Token *namespaceEnd = 0;
if (Token::Match(tok->next(), "::") || if (Token::simpleMatch(tok->next(), "::") ||
Token::Match(tok->next(), "%type%")) Token::Match(tok->next(), "%type%"))
{ {
typeStart = tok->next(); typeStart = tok->next();
@ -940,13 +941,13 @@ void Tokenizer::simplifyTypedef()
bool atEnd = false; bool atEnd = false;
while (!atEnd) while (!atEnd)
{ {
if (Token::Match(tok->tokAt(offset), "::")) if (Token::simpleMatch(tok->tokAt(offset), "::"))
typeEnd = tok->tokAt(offset++); typeEnd = tok->tokAt(offset++);
if (Token::Match(tok->tokAt(offset), "%type%") && if (Token::Match(tok->tokAt(offset), "%type%") &&
tok->tokAt(offset + 1) && !Token::Match(tok->tokAt(offset + 1), "[|;|,|(")) tok->tokAt(offset + 1) && !Token::Match(tok->tokAt(offset + 1), "[|;|,|("))
typeEnd = tok->tokAt(offset++); typeEnd = tok->tokAt(offset++);
else if (Token::Match(tok->tokAt(offset), "const (")) else if (Token::simpleMatch(tok->tokAt(offset), "const ("))
{ {
typeEnd = tok->tokAt(offset++); typeEnd = tok->tokAt(offset++);
atEnd = true; atEnd = true;
@ -1040,7 +1041,7 @@ void Tokenizer::simplifyTypedef()
tok = tok->tokAt(offset); tok = tok->tokAt(offset);
// or a function typedef // or a function typedef
else if (Token::Match(tok->tokAt(offset), "(")) else if (Token::simpleMatch(tok->tokAt(offset), "("))
{ {
// unhandled typedef, skip it and continue // unhandled typedef, skip it and continue
if (typeName->str() == "void") if (typeName->str() == "void")
@ -1143,7 +1144,7 @@ void Tokenizer::simplifyTypedef()
// function returning pointer to function // function returning pointer to function
else if (Token::Match(tok->tokAt(offset), "( * %type% (") && else if (Token::Match(tok->tokAt(offset), "( * %type% (") &&
Token::Match(tok->tokAt(offset + 3)->link(), ") ) (")) Token::simpleMatch(tok->tokAt(offset + 3)->link(), ") ) ("))
{ {
functionRetFuncPtr = true; functionRetFuncPtr = true;
@ -1397,8 +1398,8 @@ void Tokenizer::simplifyTypedef()
inTemplate = true; inTemplate = true;
// check for operator // check for operator
if (Token::Match(tok2->previous(), "operator") || if (Token::simpleMatch(tok2->previous(), "operator") ||
Token::Match(tok2->tokAt(-2), "operator const")) Token::simpleMatch(tok2->tokAt(-2), "operator const"))
inOperator = true; inOperator = true;
// skip over class or struct in derived class declaration // skip over class or struct in derived class declaration
@ -2382,6 +2383,9 @@ bool Tokenizer::tokenize(std::istream &code,
// remove __attribute__((?)) // remove __attribute__((?))
simplifyAttribute(); simplifyAttribute();
// remove unnecessary member qualification..
removeUnnecessaryQualification();
// remove Microsoft MFC.. // remove Microsoft MFC..
simplifyMicrosoftMFC(); simplifyMicrosoftMFC();
@ -2714,7 +2718,7 @@ void Tokenizer::simplifyTemplates()
ostr << " "; ostr << " ";
ostr << tok3->str(); ostr << tok3->str();
} }
if (!Token::Match(tok3, "> (")) if (!Token::simpleMatch(tok3, "> ("))
continue; continue;
s = ostr.str(); s = ostr.str();
} }
@ -3996,7 +4000,7 @@ void Tokenizer::simplifySizeof()
tok->next()->deleteNext(); tok->next()->deleteNext();
} }
if (Token::Match(tok->next(), "( * )")) if (Token::simpleMatch(tok->next(), "( * )"))
{ {
tok->str(MathLib::toString<unsigned long>(sizeOfType(tok->tokAt(2)))); tok->str(MathLib::toString<unsigned long>(sizeOfType(tok->tokAt(2))));
Token::eraseTokens(tok, tok->tokAt(4)); Token::eraseTokens(tok, tok->tokAt(4));
@ -4708,9 +4712,9 @@ void Tokenizer::simplifyIfAddBraces()
if (!innerIf) if (!innerIf)
break; 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; innerIf = false;
else else
break; break;
@ -4751,7 +4755,7 @@ bool Tokenizer::simplifyDoWhileAddBracesHelper(Token *tok)
tok2 = tok3; tok2 = tok3;
break; break;
} }
else if (Token::Match(tok3, "do {")) else if (Token::simpleMatch(tok3, "do {"))
{ {
// Skip do{}while inside the current "do" // Skip do{}while inside the current "do"
tok3 = tok3->next()->link(); tok3 = tok3->next()->link();
@ -5755,37 +5759,37 @@ void Tokenizer::simplifyStdType()
tok->isSigned(!isUnsigned); tok->isSigned(!isUnsigned);
} }
if (Token::Match(tok, "__int8")) if (Token::simpleMatch(tok, "__int8"))
tok->str("char"); tok->str("char");
else if (Token::Match(tok, "__int16")) else if (Token::simpleMatch(tok, "__int16"))
tok->str("short"); tok->str("short");
else if (Token::Match(tok, "__int32")) else if (Token::simpleMatch(tok, "__int32"))
tok->str("int"); tok->str("int");
else if (Token::Match(tok, "__int64")) else if (Token::simpleMatch(tok, "__int64"))
{ {
tok->str("long"); tok->str("long");
tok->isLong(true); 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->isLong(true);
tok->deleteNext(); tok->deleteNext();
} }
if (Token::Match(tok->next(), "int")) if (Token::simpleMatch(tok->next(), "int"))
tok->deleteNext(); tok->deleteNext();
else if (Token::Match(tok->next(), "double")) else if (Token::simpleMatch(tok->next(), "double"))
{ {
tok->str("double"); tok->str("double");
tok->isLong(true); tok->isLong(true);
tok->deleteNext(); 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(); tok->deleteNext();
} }
} }
@ -7489,7 +7493,7 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name)
if (end) if (end)
{ {
if (Token::Match(end, ") {")) // function parameter ? if (Token::simpleMatch(end, ") {")) // function parameter ?
{ {
// look backwards // look backwards
if (tok->previous()->str() == "enum" || if (tok->previous()->str() == "enum" ||
@ -7546,7 +7550,8 @@ void Tokenizer::simplifyEnum()
int classLevel = 0; int classLevel = 0;
for (Token *tok = _tokens; tok; tok = tok->next()) 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(); className = tok->next()->str();
classLevel = 0; classLevel = 0;
@ -7566,7 +7571,7 @@ void Tokenizer::simplifyEnum()
continue; continue;
} }
else if (Token::Match(tok, "enum class|struct| {|:") || 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 *tok1;
Token *start = tok; Token *start = tok;
@ -7587,12 +7592,19 @@ void Tokenizer::simplifyEnum()
offset = 3; offset = 3;
// check for forward declaration // check for forward declaration
/** @todo start substitution check at forward declaration */
const Token *temp = tok->tokAt(offset); const Token *temp = tok->tokAt(offset);
while (!Token::Match(temp, "{|;")) while (!Token::Match(temp, "{|;"))
temp = temp->next(); temp = temp->next();
if (temp->str() == ";") if (temp->str() == ";")
{
/** @todo start substitution check at forward declaration */
// delete forward declaration
tok->deleteThis();
tok->deleteThis();
tok->deleteThis();
tok->deleteThis();
continue; continue;
}
typeTokenStart = tok->tokAt(offset); typeTokenStart = tok->tokAt(offset);
typeTokenEnd = typeTokenStart; typeTokenEnd = typeTokenStart;
@ -7606,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() == "{") if (tok->tokAt(1)->str() == "{")
tok1 = tok->tokAt(2); tok1 = tok->tokAt(2);
else if (tok->tokAt(1)->str() == ":") else if (tok->tokAt(1)->str() == ":")
@ -7905,7 +7927,7 @@ void Tokenizer::simplifyEnum()
} }
else if (tok2->str() == "{") else if (tok2->str() == "{")
++level; ++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; simplify = true;
hasClass = true; hasClass = true;
@ -8240,7 +8262,7 @@ void Tokenizer::simplifyComma()
// We must not accept just any keyword, e.g. accepting int // We must not accept just any keyword, e.g. accepting int
// would cause function parameters to corrupt. // would cause function parameters to corrupt.
if (Token::Match(tok->next(), "delete")) if (Token::simpleMatch(tok->next(), "delete"))
{ {
// Handle "delete a, delete b;" // Handle "delete a, delete b;"
tok->str(";"); tok->str(";");
@ -8248,7 +8270,7 @@ void Tokenizer::simplifyComma()
if (tok->previous() && tok->previous()->previous()) if (tok->previous() && tok->previous()->previous())
{ {
if (Token::Match(tok->previous()->previous(), "delete") && if (Token::simpleMatch(tok->previous()->previous(), "delete") &&
tok->next()->varId() != 0) tok->next()->varId() != 0)
{ {
// Handle "delete a, b;" // Handle "delete a, b;"
@ -8563,7 +8585,7 @@ void Tokenizer::simplifyStructInit()
if (Token::simpleMatch(tok2, ", .")) if (Token::simpleMatch(tok2, ", ."))
tok2 = tok2->next(); tok2 = tok2->next();
} }
if (!Token::Match(tok2, "} ;")) if (!Token::simpleMatch(tok2, "} ;"))
continue; continue;
// Known expression format => Perform simplification // Known expression format => Perform simplification
@ -9251,6 +9273,12 @@ void Tokenizer::simplifyQtSignalsSlots()
Token *tok = _tokens; Token *tok = _tokens;
while ((tok = const_cast<Token *>(Token::findmatch(tok, "class %var% :")))) while ((tok = const_cast<Token *>(Token::findmatch(tok, "class %var% :"))))
{ {
if (tok->previous() && tok->previous()->str() == "enum")
{
tok = tok->tokAt(2);
continue;
}
// count { and } for tok2 // count { and } for tok2
unsigned int indentlevel = 0; unsigned int indentlevel = 0;
for (Token *tok2 = tok; tok2; tok2 = tok2->next()) for (Token *tok2 = tok; tok2; tok2 = tok2->next())
@ -9325,3 +9353,61 @@ void Tokenizer::simplifyOperatorName()
} }
} }
} }
// remove unnecessary member qualification..
struct ClassInfo
{
std::string className;
Token *end;
};
void Tokenizer::removeUnnecessaryQualification()
{
std::stack<ClassInfo> 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<ErrorLogger::ErrorMessage::FileLocation> 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();
}
}
}
}

View File

@ -519,6 +519,11 @@ public:
*/ */
void simplifyBuiltinExpect(); void simplifyBuiltinExpect();
/**
* Remove unnecessary member qualification
*/
void removeUnnecessaryQualification();
/** /**
* Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' * Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()'
*/ */

10
rules/error-reporting.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<rule version="1">
<pattern>Severity :: fromString \( "\w+" \)</pattern>
<message>
<id>ConstantSeverityFromString</id>
<severity>style</severity>
<summary>Constant severity lookups should be done via
Severity::constant.</summary>
</message>
</rule>

11
rules/stl.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<rule version="1">
<!-- This should ideally be checked by lib/checkstl.cpp -->
<pattern> \. find \( "[^"]+?" \) == \d+ </pattern>
<message>
<id>UselessSTDStringFind</id>
<severity>performance</severity>
<summary>When looking for a string at a fixed position compare
is faster.</summary>
</message>
</rule>

34
rules/token-matching.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0"?>
<rule version="1">
<pattern>Token :: (?:findm|(?:simple|)M)atch \([^,]+,\s+"(?:\s+|[^"]+?\s+")</pattern>
<message>
<id>TokenMatchSpacing</id>
<severity>style</severity>
<summary>Useless extra spacing for Token::*Match.</summary>
</message>
</rule>
<rule version="1">
<pattern>(?U)Token :: Match \([^,]+,\s+"[^%|!\[\]]+"</pattern>
<message>
<id>UseTokensimpleMatch</id>
<severity>error</severity>
<summary>Token::simpleMatch should be used to match tokens
without special pattern requirements.</summary>
</message>
</rule>
<rule version="1">
<pattern>\b[\w_]+ \. tokAt \( 0 \)</pattern>
<message>
<id>TokentokAt0</id>
<severity>error</severity>
<summary>tok->tokAt(0) is a slow way to say tok.</summary>
</message>
</rule>
<rule version="1">
<pattern>\b[\w_]+ \. strAt \( 0 \)</pattern>
<message>
<id>TokenstrAt0</id>
<severity>error</severity>
<summary>tok->strAt(0) is a slow way to say tok->str()</summary>
</message>
</rule>

View File

@ -21,15 +21,25 @@ SOURCES += ../cli/cmdlineparser.cpp \
../cli/filelister.cpp \ ../cli/filelister.cpp \
../cli/filelister_unix.cpp \ ../cli/filelister_unix.cpp \
../cli/filelister_win32.cpp \ ../cli/filelister_win32.cpp \
../cli/threadexecutor.cpp ../cli/pathmatch.cpp \
../cli/threadexecutor.cpp \
testpathmatch.cpp
HEADERS += ../cli/cmdlineparser.h \ HEADERS += ../cli/cmdlineparser.h \
../cli/cppcheckexecutor.h \ ../cli/cppcheckexecutor.h \
../cli/filelister.h \ ../cli/filelister.h \
../cli/filelister_unix.h \ ../cli/filelister_unix.h \
../cli/filelister_win32.h \ ../cli/filelister_win32.h \
../cli/pathmatch.h \
../cli/threadexecutor.h ../cli/threadexecutor.h
# test/* # 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 HEADERS += options.h redirect.h testsuite.h
SOURCES += options.cpp \ SOURCES += options.cpp \
testautovariables.cpp \ testautovariables.cpp \
@ -50,6 +60,7 @@ SOURCES += options.cpp \
testoptions.cpp \ testoptions.cpp \
testother.cpp \ testother.cpp \
testpath.cpp \ testpath.cpp \
testpathmatch.cpp \
testpostfixoperator.cpp \ testpostfixoperator.cpp \
testpreprocessor.cpp \ testpreprocessor.cpp \
testrunner.cpp \ testrunner.cpp \
@ -57,6 +68,7 @@ SOURCES += options.cpp \
testsimplifytokens.cpp \ testsimplifytokens.cpp \
teststl.cpp \ teststl.cpp \
testsuite.cpp \ testsuite.cpp \
testsymboldatabase.cpp \
testthreadexecutor.cpp \ testthreadexecutor.cpp \
testtoken.cpp \ testtoken.cpp \
testtokenize.cpp \ testtokenize.cpp \

View File

@ -3,7 +3,7 @@
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9,00" Version="9,00"
Name="test" Name="test"
ProjectGUID="{48110A35-C2BB-3F1C-A741-C15295041A2D}" ProjectGUID="{5B7869EA-A1CB-3E73-8569-5B385608779E}"
Keyword="Qt4VSv1.0"> Keyword="Qt4VSv1.0">
<Platforms> <Platforms>
<Platform <Platform
@ -72,7 +72,7 @@
UseOfMfc="0"> UseOfMfc="0">
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;.&quot;,&quot;..\cli&quot;,&quot;..\lib&quot;,&quot;..\externals&quot;,c:\Qt\VS4.7.0\mkspecs\win32-msvc2008" AdditionalIncludeDirectories="&quot;.&quot;,&quot;..\cli&quot;,&quot;..\lib&quot;,&quot;..\externals&quot;,..\..\..\..\Qt\qt-everywhere-opensource-src-4.7.1-vs2008-x86\mkspecs\win32-msvc2008"
AdditionalOptions="-Zm200 -w34100 -w34189" AdditionalOptions="-Zm200 -w34100 -w34189"
AssemblerListingLocation="temp\" AssemblerListingLocation="temp\"
BufferSecurityCheck="false" BufferSecurityCheck="false"
@ -169,6 +169,8 @@
RelativePath="options.cpp" /> RelativePath="options.cpp" />
<File <File
RelativePath="..\lib\path.cpp" /> RelativePath="..\lib\path.cpp" />
<File
RelativePath="..\cli\pathmatch.cpp" />
<File <File
RelativePath="..\lib\preprocessor.cpp" /> RelativePath="..\lib\preprocessor.cpp" />
<File <File
@ -211,6 +213,8 @@
RelativePath="testother.cpp" /> RelativePath="testother.cpp" />
<File <File
RelativePath="testpath.cpp" /> RelativePath="testpath.cpp" />
<File
RelativePath="testpathmatch.cpp" />
<File <File
RelativePath="testpostfixoperator.cpp" /> RelativePath="testpostfixoperator.cpp" />
<File <File
@ -225,6 +229,8 @@
RelativePath="teststl.cpp" /> RelativePath="teststl.cpp" />
<File <File
RelativePath="testsuite.cpp" /> RelativePath="testsuite.cpp" />
<File
RelativePath="testsymboldatabase.cpp" />
<File <File
RelativePath="testthreadexecutor.cpp" /> RelativePath="testthreadexecutor.cpp" />
<File <File
@ -308,6 +314,8 @@
RelativePath="options.h" /> RelativePath="options.h" />
<File <File
RelativePath="..\lib\path.h" /> RelativePath="..\lib\path.h" />
<File
RelativePath="..\cli\pathmatch.h" />
<File <File
RelativePath="..\lib\preprocessor.h" /> RelativePath="..\lib\preprocessor.h" />
<File <File

View File

@ -11,7 +11,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{081168BA-E630-3D82-8EDB-A19028999479}</ProjectGuid> <ProjectGuid>{D0001948-3B19-3314-8BEE-3B92350BC5B5}</ProjectGuid>
<RootNamespace>test</RootNamespace> <RootNamespace>test</RootNamespace>
<Keyword>Qt4VSv1.0</Keyword> <Keyword>Qt4VSv1.0</Keyword>
</PropertyGroup> </PropertyGroup>
@ -140,6 +140,7 @@
<ClCompile Include="..\lib\mathlib.cpp" /> <ClCompile Include="..\lib\mathlib.cpp" />
<ClCompile Include="options.cpp" /> <ClCompile Include="options.cpp" />
<ClCompile Include="..\lib\path.cpp" /> <ClCompile Include="..\lib\path.cpp" />
<ClCompile Include="..\cli\pathmatch.cpp" />
<ClCompile Include="..\lib\preprocessor.cpp" /> <ClCompile Include="..\lib\preprocessor.cpp" />
<ClCompile Include="..\lib\settings.cpp" /> <ClCompile Include="..\lib\settings.cpp" />
<ClCompile Include="..\lib\symboldatabase.cpp" /> <ClCompile Include="..\lib\symboldatabase.cpp" />
@ -161,6 +162,7 @@
<ClCompile Include="testoptions.cpp" /> <ClCompile Include="testoptions.cpp" />
<ClCompile Include="testother.cpp" /> <ClCompile Include="testother.cpp" />
<ClCompile Include="testpath.cpp" /> <ClCompile Include="testpath.cpp" />
<ClCompile Include="testpathmatch.cpp" />
<ClCompile Include="testpostfixoperator.cpp" /> <ClCompile Include="testpostfixoperator.cpp" />
<ClCompile Include="testpreprocessor.cpp" /> <ClCompile Include="testpreprocessor.cpp" />
<ClCompile Include="testrunner.cpp" /> <ClCompile Include="testrunner.cpp" />
@ -168,6 +170,7 @@
<ClCompile Include="testsimplifytokens.cpp" /> <ClCompile Include="testsimplifytokens.cpp" />
<ClCompile Include="teststl.cpp" /> <ClCompile Include="teststl.cpp" />
<ClCompile Include="testsuite.cpp" /> <ClCompile Include="testsuite.cpp" />
<ClCompile Include="testsymboldatabase.cpp" />
<ClCompile Include="testthreadexecutor.cpp" /> <ClCompile Include="testthreadexecutor.cpp" />
<ClCompile Include="testtoken.cpp" /> <ClCompile Include="testtoken.cpp" />
<ClCompile Include="testtokenize.cpp" /> <ClCompile Include="testtokenize.cpp" />
@ -209,6 +212,7 @@
<ClInclude Include="..\lib\mathlib.h" /> <ClInclude Include="..\lib\mathlib.h" />
<ClInclude Include="options.h" /> <ClInclude Include="options.h" />
<ClInclude Include="..\lib\path.h" /> <ClInclude Include="..\lib\path.h" />
<ClInclude Include="..\cli\pathmatch.h" />
<ClInclude Include="..\lib\preprocessor.h" /> <ClInclude Include="..\lib\preprocessor.h" />
<ClInclude Include="redirect.h" /> <ClInclude Include="redirect.h" />
<ClInclude Include="..\lib\settings.h" /> <ClInclude Include="..\lib\settings.h" />

View File

@ -80,6 +80,9 @@
<ClCompile Include="..\lib\path.cpp"> <ClCompile Include="..\lib\path.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\cli\pathmatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\lib\preprocessor.cpp"> <ClCompile Include="..\lib\preprocessor.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -143,6 +146,9 @@
<ClCompile Include="testpath.cpp"> <ClCompile Include="testpath.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="testpathmatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="testpostfixoperator.cpp"> <ClCompile Include="testpostfixoperator.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -164,6 +170,9 @@
<ClCompile Include="testsuite.cpp"> <ClCompile Include="testsuite.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="testsymboldatabase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="testthreadexecutor.cpp"> <ClCompile Include="testthreadexecutor.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -283,6 +292,9 @@
<ClInclude Include="..\lib\path.h"> <ClInclude Include="..\lib\path.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\cli\pathmatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\lib\preprocessor.h"> <ClInclude Include="..\lib\preprocessor.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>

View File

@ -188,6 +188,7 @@ private:
TEST_CASE(symboldatabase7); // ticket #2230 TEST_CASE(symboldatabase7); // ticket #2230
TEST_CASE(symboldatabase8); // ticket #2252 TEST_CASE(symboldatabase8); // ticket #2252
TEST_CASE(symboldatabase9); // ticket #2525 TEST_CASE(symboldatabase9); // ticket #2525
TEST_CASE(symboldatabase10); // ticket #2537
} }
// Check the operator Equal // Check the operator Equal
@ -5490,6 +5491,20 @@ private:
ASSERT_EQUALS("", errout.str()); 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) REGISTER_TEST(TestClass)

View File

@ -81,12 +81,22 @@ private:
TEST_CASE(templatesGcc); TEST_CASE(templatesGcc);
TEST_CASE(templatesVs); TEST_CASE(templatesVs);
TEST_CASE(xml); TEST_CASE(xml);
TEST_CASE(xmlver1);
TEST_CASE(xmlver2); TEST_CASE(xmlver2);
TEST_CASE(xmlver2both); TEST_CASE(xmlver2both);
TEST_CASE(xmlver2both2); TEST_CASE(xmlver2both2);
TEST_CASE(xmlverunknown);
TEST_CASE(xmlverinvalid);
TEST_CASE(errorlist1); TEST_CASE(errorlist1);
TEST_CASE(errorlistverbose1) TEST_CASE(errorlistverbose1)
TEST_CASE(errorlistverbose2) 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); TEST_CASE(unknownParam);
} }
@ -585,6 +595,17 @@ private:
ASSERT_EQUALS(1, settings._xml_version); 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() void xmlver2()
{ {
REDIRECT; REDIRECT;
@ -618,6 +639,24 @@ private:
ASSERT_EQUALS(2, settings._xml_version); 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() void errorlist1()
{ {
REDIRECT; REDIRECT;
@ -647,6 +686,84 @@ private:
ASSERT(settings._verbose); 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() void unknownParam()
{ {
REDIRECT; REDIRECT;

View File

@ -66,9 +66,23 @@ private:
void run() void run()
{ {
TEST_CASE(instancesSorted);
TEST_CASE(getErrorMessages); TEST_CASE(getErrorMessages);
} }
void instancesSorted()
{
for (std::list<Check *>::iterator i = Check::instances().begin(); i != Check::instances().end(); ++i)
{
std::list<Check *>::iterator j = i;
++j;
if (j != Check::instances().end())
{
ASSERT_EQUALS(true, (*i)->name() < (*j)->name());
}
}
}
void getErrorMessages() void getErrorMessages()
{ {
ErrorLogger2 errorLogger; ErrorLogger2 errorLogger;

View File

@ -17,6 +17,7 @@
*/ */
#include <list> #include <list>
#include "cppcheck.h"
#include "testsuite.h" #include "testsuite.h"
#include "errorlogger.h" #include "errorlogger.h"
@ -38,6 +39,7 @@ private:
TEST_CASE(CustomFormat2); TEST_CASE(CustomFormat2);
TEST_CASE(ToXml); TEST_CASE(ToXml);
TEST_CASE(ToVerboseXml); TEST_CASE(ToVerboseXml);
TEST_CASE(ToXmlV2);
} }
void FileLocationDefaults() void FileLocationDefaults()
@ -124,7 +126,7 @@ private:
locs.push_back(loc); locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId"); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId");
ASSERT_EQUALS("<?xml version=\"1.0\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter()); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1)); ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
} }
@ -137,8 +139,28 @@ private:
locs.push_back(loc); locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId"); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId");
ASSERT_EQUALS("<?xml version=\"1.0\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter()); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1)); ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
} }
void ToXmlV2()
{
ErrorLogger::ErrorMessage::FileLocation loc;
loc.setfile("foo.cpp");
loc.line = 5;
std::list<ErrorLogger::ErrorMessage::FileLocation> locs;
locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId");
std::string header("<?xml version=\"1.0\"?>\n<results version=\"2\">\n");
header += " <cppcheck version=\"";
header += CppCheck::version();
header += "\"/>\n <errors>";
ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2));
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\"");
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
ASSERT_EQUALS(message, msg.toXML(false,2));
}
}; };
REGISTER_TEST(TestErrorLogger) REGISTER_TEST(TestErrorLogger)

View File

@ -961,6 +961,18 @@ private:
" int i = sizeof sizeof char;\n" " int i = sizeof sizeof char;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str()); 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() void sizeofCalculation()

258
test/testpathmatch.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <vector>
#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<std::string> masks;
PathMatch match(masks);
ASSERT(!match.Match(""));
}
void emptymaskpath1()
{
std::vector<std::string> masks;
PathMatch match(masks);
ASSERT(!match.Match("src/"));
}
void emptymaskpath2()
{
std::vector<std::string> masks;
PathMatch match(masks);
ASSERT(!match.Match("../src/"));
}
void emptymaskpath3()
{
std::vector<std::string> masks;
PathMatch match(masks);
ASSERT(!match.Match("/home/user/code/src/"));
}
void onemaskemptypath()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(!match.Match(""));
}
void onemasksamepath()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(match.Match("src/"));
}
void onemasksamepathwithfile()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(match.Match("src/file.txt"));
}
void onemaskdifferentdir1()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(!match.Match("srcfiles/file.txt"));
}
void onemaskdifferentdir2()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(!match.Match("proj/srcfiles/file.txt"));
}
void onemaskdifferentdir3()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(!match.Match("proj/mysrc/file.txt"));
}
void onemaskdifferentdir4()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(!match.Match("proj/mysrcfiles/file.txt"));
}
void onemasklongerpath1()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(match.Match("/tmp/src/"));
}
void onemasklongerpath2()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(match.Match("src/module/"));
}
void onemasklongerpath3()
{
std::vector<std::string> masks;
masks.push_back("src/");
PathMatch match(masks);
ASSERT(match.Match("project/src/module/"));
}
void twomasklongerpath1()
{
std::vector<std::string> masks;
masks.push_back("src/");
masks.push_back("module/");
PathMatch match(masks);
ASSERT(!match.Match("project/"));
}
void twomasklongerpath2()
{
std::vector<std::string> masks;
masks.push_back("src/");
masks.push_back("module/");
PathMatch match(masks);
ASSERT(match.Match("project/src/"));
}
void twomasklongerpath3()
{
std::vector<std::string> masks;
masks.push_back("src/");
masks.push_back("module/");
PathMatch match(masks);
ASSERT(match.Match("project/module/"));
}
void twomasklongerpath4()
{
std::vector<std::string> masks;
masks.push_back("src/");
masks.push_back("module/");
PathMatch match(masks);
ASSERT(match.Match("project/src/module/"));
}
void filemask1()
{
std::vector<std::string> masks;
masks.push_back("foo.cpp");
PathMatch match(masks);
ASSERT(match.Match("foo.cpp"));
}
void filemask2()
{
std::vector<std::string> masks;
masks.push_back("foo.cpp");
PathMatch match(masks);
ASSERT(match.Match("../foo.cpp"));
}
void filemask3()
{
std::vector<std::string> masks;
masks.push_back("foo.cpp");
PathMatch match(masks);
ASSERT(match.Match("src/foo.cpp"));
}
void filemaskpath1()
{
std::vector<std::string> masks;
masks.push_back("src/foo.cpp");
PathMatch match(masks);
ASSERT(match.Match("src/foo.cpp"));
}
void filemaskpath2()
{
std::vector<std::string> masks;
masks.push_back("src/foo.cpp");
PathMatch match(masks);
ASSERT(match.Match("proj/src/foo.cpp"));
}
void filemaskpath3()
{
std::vector<std::string> masks;
masks.push_back("src/foo.cpp");
PathMatch match(masks);
ASSERT(!match.Match("foo.cpp"));
}
void filemaskpath4()
{
std::vector<std::string> masks;
masks.push_back("src/foo.cpp");
PathMatch match(masks);
ASSERT(!match.Match("bar/foo.cpp"));
}
};
REGISTER_TEST(TestPathMatch)

View File

@ -278,6 +278,7 @@ private:
TEST_CASE(enum16); // ticket #1988 TEST_CASE(enum16); // ticket #1988
TEST_CASE(enum17); // ticket #2381 (duplicate enums) TEST_CASE(enum17); // ticket #2381 (duplicate enums)
TEST_CASE(enum18); // #2466 (array with same name as enum constant) TEST_CASE(enum18); // #2466 (array with same name as enum constant)
TEST_CASE(enum19); // ticket #2536
// remove "std::" on some standard functions // remove "std::" on some standard functions
TEST_CASE(removestd); TEST_CASE(removestd);
@ -315,6 +316,8 @@ private:
TEST_CASE(redundant_semicolon); TEST_CASE(redundant_semicolon);
TEST_CASE(simplifyFunctionReturn); TEST_CASE(simplifyFunctionReturn);
TEST_CASE(removeUnnecessaryQualification);
} }
std::string tok(const char code[], bool simplify = true) std::string tok(const char code[], bool simplify = true)
@ -6097,6 +6100,13 @@ private:
ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false)); 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() void removestd()
{ {
ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);"));
@ -6408,6 +6418,14 @@ private:
"} ;"; "} ;";
ASSERT_EQUALS(expected, tok(code, false)); 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) REGISTER_TEST(TestSimplifyTokens)

View File

@ -1412,6 +1412,12 @@ private:
" return cmd[0];\n" " return cmd[0];\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
checkUninitVar("char fn(FILE *f) {\n"
" char buf[10];\n"
" fread(buf, 1, 10, f);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void uninitvar_typeof() void uninitvar_typeof()

View File

@ -230,8 +230,8 @@ int main(int argc, char **argv)
fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n"; fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n";
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o cppcheck $(CLIOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre $(LDFLAGS)\n\n"; fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o cppcheck $(CLIOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre $(LDFLAGS)\n\n";
fout << "all:\tcppcheck testrunner\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 << "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 $(LDFLAGS)\n\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 << "test:\tall\n";
fout << "\t./testrunner\n\n"; fout << "\t./testrunner\n\n";
fout << "check:\tall\n"; fout << "check:\tall\n";