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_win32.o \
cli/main.o \
cli/pathmatch.o \
cli/threadexecutor.o
TESTOBJ = test/options.o \
@ -74,6 +75,7 @@ TESTOBJ = test/options.o \
test/testoptions.o \
test/testother.o \
test/testpath.o \
test/testpathmatch.o \
test/testpostfixoperator.o \
test/testpreprocessor.o \
test/testrunner.o \
@ -103,8 +105,8 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)
all: cppcheck testrunner
testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o $(LDFLAGS)
testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o $(LDFLAGS)
test: all
./testrunner
@ -206,7 +208,7 @@ lib/tokenize.o: lib/tokenize.cpp lib/tokenize.h lib/token.h lib/mathlib.h lib/se
cli/cmdlineparser.o: cli/cmdlineparser.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h lib/timer.h cli/cmdlineparser.h lib/path.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h cli/threadexecutor.h cli/cmdlineparser.h cli/filelister.h lib/path.h
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h cli/threadexecutor.h cli/cmdlineparser.h cli/filelister.h lib/path.h cli/pathmatch.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp
cli/filelister.o: cli/filelister.cpp cli/filelister.h cli/filelister_win32.h cli/filelister_unix.h
@ -221,6 +223,9 @@ cli/filelister_win32.o: cli/filelister_win32.cpp cli/filelister.h cli/filelister
cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/errorlogger.h lib/settings.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/main.o cli/main.cpp
cli/pathmatch.o: cli/pathmatch.cpp cli/pathmatch.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/pathmatch.o cli/pathmatch.cpp
cli/threadexecutor.o: cli/threadexecutor.cpp cli/threadexecutor.h lib/settings.h lib/errorlogger.h lib/cppcheck.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Iexternals -c -o cli/threadexecutor.o cli/threadexecutor.cpp
@ -284,6 +289,9 @@ test/testother.o: test/testother.cpp lib/tokenize.h lib/checkother.h lib/check.h
test/testpath.o: test/testpath.cpp test/testsuite.h lib/errorlogger.h test/redirect.h lib/path.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpath.o test/testpath.cpp
test/testpathmatch.o: test/testpathmatch.cpp test/testsuite.h lib/errorlogger.h test/redirect.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpathmatch.o test/testpathmatch.cpp
test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/tokenize.h lib/checkpostfixoperator.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Ilib -Icli -Iexternals -c -o test/testpostfixoperator.o test/testpostfixoperator.cpp

View File

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

View File

@ -26,6 +26,7 @@
#include "settings.h"
#include "cmdlineparser.h"
#include "path.h"
#include "filelister.h"
// xml is used in rules
#include "tinyxml/tinyxml.h"
@ -210,11 +211,28 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
else if (strcmp(argv[i], "--xml") == 0)
_settings->_xml = true;
// Write results in xml2 format
else if (strcmp(argv[i], "--xml-version=2") == 0)
// Define the XML file version (and enable XML output)
else if (strncmp(argv[i], "--xml-version=", 14) == 0)
{
std::string numberString(argv[i]);
numberString = numberString.substr(14);
std::istringstream iss(numberString);
if (!(iss >> _settings->_xml_version))
{
PrintMessage("cppcheck: argument to '--xml-version' is not a number");
return false;
}
if (_settings->_xml_version < 0 || _settings->_xml_version > 2)
{
// We only have xml versions 1 and 2
PrintMessage("cppcheck: --xml-version can only be 1 or 2.");
return false;
}
// Enable also XML if version is set
_settings->_xml = true;
_settings->_xml_version = 2;
}
// Only print something when there are errors
@ -327,6 +345,44 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
AddFilesToList(12 + argv[i], _pathnames);
}
// Ignored paths
else if (strncmp(argv[i], "-i", 2) == 0)
{
std::string path;
// "-i path/"
if (strcmp(argv[i], "-i") == 0)
{
++i;
if (i >= argc)
{
PrintMessage("cppcheck: argument to '-i' is missing");
return false;
}
path = argv[i];
}
// "-ipath/"
else
{
path = 2 + argv[i];
}
if (!path.empty())
{
path = Path::fromNativeSeparators(path);
// If not "known" filename extension then assume it is path
if (!FileLister::acceptFile(path))
{
// If path doesn't end with / or \, add it
if (path[path.length()-1] != '/')
path += '/';
}
_ignoredPaths.push_back(path);
}
}
// Report progress
else if (strcmp(argv[i], "--report-progress") == 0)
{
@ -461,18 +517,18 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
TiXmlDocument doc;
if (doc.LoadFile(12+argv[i]))
{
TiXmlElement *root = doc.FirstChildElement();
if (root && root->ValueStr() == "rule")
TiXmlElement *node = doc.FirstChildElement();
for (; node && node->ValueStr() == "rule"; node = node->NextSiblingElement())
{
Settings::Rule rule;
TiXmlElement *pattern = root->FirstChildElement("pattern");
TiXmlElement *pattern = node->FirstChildElement("pattern");
if (pattern)
{
rule.pattern = pattern->GetText();
}
TiXmlElement *message = root->FirstChildElement("message");
TiXmlElement *message = node->FirstChildElement("message");
if (message)
{
TiXmlElement *severity = message->FirstChildElement("severity");
@ -589,6 +645,10 @@ void CmdLineParser::PrintHelp()
" -I [dir] Give include path. Give several -I parameters to give\n"
" several paths. First given path is checked first. If\n"
" paths are relative to source files, this is not needed\n"
" -i [dir] Give path to ignore. Give several -i parameters to ignore\n"
" several paths. Give directory name or filename with path\n"
" as parameter. Directory name is matched to all parts of the\n"
" path."
" --inline-suppr Enable inline suppressions. Use them by placing one or\n"
" more comments, like: // cppcheck-suppress warningId\n"
" on the lines before the warning to suppress.\n"
@ -608,6 +668,9 @@ void CmdLineParser::PrintHelp()
" -v, --verbose More detailed error reports\n"
" --version Print out version number\n"
" --xml Write results in xml to error stream.\n"
" --xml-version=[version]\n"
" Select the XML file version. Currently versions 1 and 2\n"
" are available. The default version is 1."
"\n"
"Example usage:\n"
" # Recursively check the current folder. Print the progress on the screen and\n"

View File

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

View File

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

View File

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

View File

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

View File

@ -25,6 +25,7 @@
#include "cmdlineparser.h"
#include "filelister.h"
#include "path.h"
#include "pathmatch.h"
CppCheckExecutor::CppCheckExecutor()
{
@ -55,7 +56,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
errorlist = true;
std::cout << ErrorLogger::ErrorMessage::getXMLHeader(_settings._xml_version);
cppcheck->getErrorMessages();
std::cout << ErrorLogger::ErrorMessage::getXMLFooter() << std::endl;
std::cout << ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version) << std::endl;
}
if (parser.ExitAfterPrinting())
@ -87,19 +88,36 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
std::vector<std::string>::const_iterator iter;
for (iter = pathnames.begin(); iter != pathnames.end(); ++iter)
getFileLister()->recursiveAddFiles(filenames, Path::toNativeSeparators(iter->c_str()));
for (iter = filenames.begin(); iter != filenames.end(); ++iter)
cppcheck->addFile(*iter);
}
if (filenames.empty())
if (!filenames.empty())
{
PathMatch matcher(parser.GetIgnoredPaths());
std::vector<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;
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
{
return true;
std::cout << "cppcheck: error: no files to check - all paths ignored." << std::endl;
return false;
}
}
@ -141,7 +159,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
if (_settings._xml)
{
reportErr(ErrorLogger::ErrorMessage::getXMLFooter());
reportErr(ErrorLogger::ErrorMessage::getXMLFooter(_settings._xml_version));
}
if (returnValue)

View File

@ -55,7 +55,7 @@ public:
* @param filename filename to check
* @return returns true if the file extension indicates it should be checked
*/
virtual bool acceptFile(const std::string &filename);
static bool acceptFile(const std::string &filename);
/**
* @brief Is given path a directory?

View File

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

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="alternate" type="application/atom+xml" title="Recent Commits to cppcheck:master"
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="/site/js/github.js" type="text/javascript"></script>
<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>
<h3>Recent Commits</h3>
<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>
<ul>
<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>
<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>
<ul>
<li>Use <a href="http://sourceforge.net/apps/trac/cppcheck/">Trac</a> to report

View File

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

View File

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

View File

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

View File

@ -302,7 +302,7 @@ static bool for_condition(const Token * const tok2, unsigned int varid, std::str
maxMinFlipped = false;
max_value = tok2->strAt(2);
}
else if (Token::Match(tok2, " %num% < %varid% ;", varid) ||
else if (Token::Match(tok2, "%num% < %varid% ;", varid) ||
Token::Match(tok2, "%num% != %varid% ; ++ %varid%", varid) ||
Token::Match(tok2, "%num% != %varid% ; %varid% ++", varid))
{
@ -766,7 +766,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
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();
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));
if (index < 0 || index >= size)
{
if (index > size || !Token::Match(tok->previous(), "& ("))
if (index > size || !Token::simpleMatch(tok->previous(), "& ("))
{
arrayIndexOutOfBounds(tok->next(), size, index);
}

View File

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

View File

@ -42,7 +42,7 @@ CheckClass instance;
//---------------------------------------------------------------------------
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(tokenizer, settings, errorLogger),
: Check(myName(), tokenizer, settings, errorLogger),
symbolDatabase(NULL)
{
@ -310,7 +310,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<std::string>
ftok = ftok->next();
// Using the operator= function to initialize all variables..
if (Token::simpleMatch(ftok->next(), "* this = "))
if (Token::simpleMatch(ftok->next(), "* this ="))
{
assignAllVar(usage);
break;
@ -799,7 +799,7 @@ void CheckClass::noMemset()
if (Token::Match(tstruct->next(), "std :: %type% %var% ;"))
memsetStructError(tok, tok->str(), tstruct->strAt(3));
else if (Token::Match(tstruct->next(), "std :: %type% < "))
else if (Token::Match(tstruct->next(), "std :: %type% <"))
{
// backup the type
const std::string typestr(tstruct->strAt(3));
@ -931,7 +931,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co
// check of *this is returned
else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") ||
Token::Match(tok->tokAt(1), "(| * this +=") ||
Token::Match(tok->tokAt(1), "operator= (")))
Token::simpleMatch(tok->tokAt(1), "operator= (")))
operatorEqRetRefThisError(func->token);
}
}
@ -1132,7 +1132,7 @@ bool CheckClass::hasAssignSelf(const Token *first, const Token *last, const Toke
{
for (const Token *tok = first; tok && tok != last; tok = tok->next())
{
if (Token::Match(tok, "if ("))
if (Token::simpleMatch(tok, "if ("))
{
const Token *tok1 = tok->tokAt(2);
const Token *tok2 = tok->tokAt(1)->link();
@ -1412,7 +1412,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok)
while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?"))
{
if (Token::Match(tok->previous(), "* this"))
if (Token::simpleMatch(tok->previous(), "* this"))
return true;
tok = tok->previous();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -335,48 +335,51 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
reportErr(errmsg);
}
if (re)
if (!re)
continue;
int pos = 0;
int ovector[30];
while (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30))
{
int pos = 0;
int ovector[30];
if (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30))
unsigned int pos1 = (unsigned int)ovector[0];
unsigned int pos2 = (unsigned int)ovector[1];
// jump to the end of the match for the next pcre_exec
pos = pos2;
// determine location..
ErrorLogger::ErrorMessage::FileLocation loc;
loc.setfile(_tokenizer.getFiles()->front());
loc.line = 0;
unsigned int len = 0;
for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next())
{
unsigned int pos1 = (unsigned int)ovector[0];
unsigned int pos2 = (unsigned int)ovector[1];
// determine location..
ErrorLogger::ErrorMessage::FileLocation loc;
loc.setfile(_tokenizer.getFiles()->front());
loc.line = 0;
unsigned int len = 0;
for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next())
len = len + 1 + tok->str().size();
if (len > pos1)
{
len = len + 1 + tok->str().size();
if (len > pos1)
{
loc.setfile(_tokenizer.getFiles()->at(tok->fileIndex()));
loc.line = tok->linenr();
break;
}
loc.setfile(_tokenizer.getFiles()->at(tok->fileIndex()));
loc.line = tok->linenr();
break;
}
const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);
// Create error message
std::string summary;
if (rule.summary.empty())
summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
else
summary = rule.summary;
ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id);
// Report error
reportErr(errmsg);
}
pcre_free(re);
const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);
// Create error message
std::string summary;
if (rule.summary.empty())
summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
else
summary = rule.summary;
ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id);
// Report error
reportErr(errmsg);
}
pcre_free(re);
}
}
#endif

View File

@ -162,15 +162,16 @@ std::string ErrorLogger::ErrorMessage::getXMLHeader(int xml_version)
else
{
ostr << "<results version=\"" << xml_version << "\">\n";
ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>";
ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>\n";
ostr << " <errors>";
}
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)

View File

@ -137,7 +137,7 @@ public:
std::string toXML(bool verbose, int ver) const;
static std::string getXMLHeader(int xml_version);
static std::string getXMLFooter();
static std::string getXMLFooter(int xml_version);
/**
* Format the error message into a string.

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
if (Token::Match(tok->tokAt(2), ". %var% ="))

View File

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

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))
addFunction(&scope, &tok, argStart);
{
/** @todo check entire qualification for match */
Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2));
if (nested)
addFunction(&scope, &tok, argStart);
else
{
/** @todo handle friend functions */
}
}
// friend class declaration?
else if (Token::Match(tok, "friend class| %any% ;"))
@ -1213,7 +1223,7 @@ const Token* skipScopeIdentifiers(const Token* tok)
{
ret = ret->next();
}
while (Token::Match(ret, "%type% :: "))
while (Token::Match(ret, "%type% ::"))
{
ret = ret->tokAt(2);
}
@ -1238,7 +1248,7 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
const Token* localTypeTok = skipScopeIdentifiers(tok);
const Token* localVarTok = NULL;
if (Token::Match(localTypeTok, "%type% < "))
if (Token::Match(localTypeTok, "%type% <"))
{
const Token* closeTok = NULL;
bool found = findClosingBracket(localTypeTok->next(), closeTok);
@ -1398,6 +1408,26 @@ Scope * Scope::findInNestedList(const std::string & name)
//---------------------------------------------------------------------------
Scope * Scope::findInNestedListRecursive(const std::string & name)
{
std::list<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
{
std::list<Function>::const_iterator it;

View File

@ -311,6 +311,12 @@ public:
*/
Scope * findInNestedList(const std::string & name);
/**
* @brief find if name is in nested list
* @param name name of nested scope
*/
Scope * findInNestedListRecursive(const std::string & name);
void addVariable(const Token *token_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_)
{
varlist.push_back(Variable(token_, varlist.size(), access_, mutable_, static_, const_, class_, type_));

View File

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

@ -1,73 +1,85 @@
TEMPLATE = app
TARGET = test
DEPENDPATH += .
INCLUDEPATH += . ../cli ../lib
OBJECTS_DIR = temp
CONFIG += warn_on console
CONFIG -= qt app_bundle
win32 {
LIBS += -lshlwapi
}
BASEPATH = ../externals/tinyxml/
include(../externals/tinyxml/tinyxml.pri)
BASEPATH = ../lib/
include(../lib/lib.pri)
# cli/*
SOURCES += ../cli/cmdlineparser.cpp \
../cli/cppcheckexecutor.cpp \
../cli/filelister.cpp \
../cli/filelister_unix.cpp \
../cli/filelister_win32.cpp \
../cli/threadexecutor.cpp
HEADERS += ../cli/cmdlineparser.h \
../cli/cppcheckexecutor.h \
../cli/filelister.h \
../cli/filelister_unix.h \
../cli/filelister_win32.h \
../cli/threadexecutor.h
# test/*
HEADERS += options.h redirect.h testsuite.h
SOURCES += options.cpp \
testautovariables.cpp \
testbufferoverrun.cpp \
testcharvar.cpp \
testclass.cpp \
testcmdlineparser.cpp \
testconstructors.cpp \
testcppcheck.cpp \
testdivision.cpp \
testerrorlogger.cpp \
testexceptionsafety.cpp \
testincompletestatement.cpp \
testmathlib.cpp \
testmemleak.cpp \
testnullpointer.cpp \
testobsoletefunctions.cpp \
testoptions.cpp \
testother.cpp \
testpath.cpp \
testpostfixoperator.cpp \
testpreprocessor.cpp \
testrunner.cpp \
testsettings.cpp \
testsimplifytokens.cpp \
teststl.cpp \
testsuite.cpp \
testthreadexecutor.cpp \
testtoken.cpp \
testtokenize.cpp \
testuninitvar.cpp \
testunusedfunctions.cpp \
testunusedprivfunc.cpp \
testunusedvar.cpp
# Change Visual Studio compiler (CL) warning level to W4
contains(QMAKE_CXX, cl) {
QMAKE_CXXFLAGS_WARN_ON -= -W3
QMAKE_CXXFLAGS_WARN_ON += -W4
DEFINES += _CRT_SECURE_NO_WARNINGS
}
TEMPLATE = app
TARGET = test
DEPENDPATH += .
INCLUDEPATH += . ../cli ../lib
OBJECTS_DIR = temp
CONFIG += warn_on console
CONFIG -= qt app_bundle
win32 {
LIBS += -lshlwapi
}
BASEPATH = ../externals/tinyxml/
include(../externals/tinyxml/tinyxml.pri)
BASEPATH = ../lib/
include(../lib/lib.pri)
# cli/*
SOURCES += ../cli/cmdlineparser.cpp \
../cli/cppcheckexecutor.cpp \
../cli/filelister.cpp \
../cli/filelister_unix.cpp \
../cli/filelister_win32.cpp \
../cli/pathmatch.cpp \
../cli/threadexecutor.cpp \
testpathmatch.cpp
HEADERS += ../cli/cmdlineparser.h \
../cli/cppcheckexecutor.h \
../cli/filelister.h \
../cli/filelister_unix.h \
../cli/filelister_win32.h \
../cli/pathmatch.h \
../cli/threadexecutor.h
# test/*
# Note:
# testfilelister_unix.cpp omitted since there is test fail when run in QtCreator
# Test assumes the test (executable) is built from the test directory (or
# directory containing source files). But QtCreator builds to separate build
# directory. Hence the test does not find the source files.
HEADERS += options.h redirect.h testsuite.h
SOURCES += options.cpp \
testautovariables.cpp \
testbufferoverrun.cpp \
testcharvar.cpp \
testclass.cpp \
testcmdlineparser.cpp \
testconstructors.cpp \
testcppcheck.cpp \
testdivision.cpp \
testerrorlogger.cpp \
testexceptionsafety.cpp \
testincompletestatement.cpp \
testmathlib.cpp \
testmemleak.cpp \
testnullpointer.cpp \
testobsoletefunctions.cpp \
testoptions.cpp \
testother.cpp \
testpath.cpp \
testpathmatch.cpp \
testpostfixoperator.cpp \
testpreprocessor.cpp \
testrunner.cpp \
testsettings.cpp \
testsimplifytokens.cpp \
teststl.cpp \
testsuite.cpp \
testsymboldatabase.cpp \
testthreadexecutor.cpp \
testtoken.cpp \
testtokenize.cpp \
testuninitvar.cpp \
testunusedfunctions.cpp \
testunusedprivfunc.cpp \
testunusedvar.cpp
# Change Visual Studio compiler (CL) warning level to W4
contains(QMAKE_CXX, cl) {
QMAKE_CXXFLAGS_WARN_ON -= -W3
QMAKE_CXXFLAGS_WARN_ON += -W4
DEFINES += _CRT_SECURE_NO_WARNINGS
}

View File

@ -3,7 +3,7 @@
ProjectType="Visual C++"
Version="9,00"
Name="test"
ProjectGUID="{48110A35-C2BB-3F1C-A741-C15295041A2D}"
ProjectGUID="{5B7869EA-A1CB-3E73-8569-5B385608779E}"
Keyword="Qt4VSv1.0">
<Platforms>
<Platform
@ -72,7 +72,7 @@
UseOfMfc="0">
<Tool
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"
AssemblerListingLocation="temp\"
BufferSecurityCheck="false"
@ -169,6 +169,8 @@
RelativePath="options.cpp" />
<File
RelativePath="..\lib\path.cpp" />
<File
RelativePath="..\cli\pathmatch.cpp" />
<File
RelativePath="..\lib\preprocessor.cpp" />
<File
@ -211,6 +213,8 @@
RelativePath="testother.cpp" />
<File
RelativePath="testpath.cpp" />
<File
RelativePath="testpathmatch.cpp" />
<File
RelativePath="testpostfixoperator.cpp" />
<File
@ -225,6 +229,8 @@
RelativePath="teststl.cpp" />
<File
RelativePath="testsuite.cpp" />
<File
RelativePath="testsymboldatabase.cpp" />
<File
RelativePath="testthreadexecutor.cpp" />
<File
@ -308,6 +314,8 @@
RelativePath="options.h" />
<File
RelativePath="..\lib\path.h" />
<File
RelativePath="..\cli\pathmatch.h" />
<File
RelativePath="..\lib\preprocessor.h" />
<File

View File

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

View File

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

View File

@ -188,6 +188,7 @@ private:
TEST_CASE(symboldatabase7); // ticket #2230
TEST_CASE(symboldatabase8); // ticket #2252
TEST_CASE(symboldatabase9); // ticket #2525
TEST_CASE(symboldatabase10); // ticket #2537
}
// Check the operator Equal
@ -5490,6 +5491,20 @@ private:
ASSERT_EQUALS("", errout.str());
}
void symboldatabase10()
{
// ticket #2537 - segmentation fault
checkConst("class A {\n"
"private:\n"
" void f();\n"
"};\n"
"class B {\n"
" friend void A::f();\n"
"};\n");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestClass)

View File

@ -81,12 +81,22 @@ private:
TEST_CASE(templatesGcc);
TEST_CASE(templatesVs);
TEST_CASE(xml);
TEST_CASE(xmlver1);
TEST_CASE(xmlver2);
TEST_CASE(xmlver2both);
TEST_CASE(xmlver2both2);
TEST_CASE(xmlverunknown);
TEST_CASE(xmlverinvalid);
TEST_CASE(errorlist1);
TEST_CASE(errorlistverbose1)
TEST_CASE(errorlistverbose2)
TEST_CASE(ignorepathsnopath)
TEST_CASE(ignorepaths1)
TEST_CASE(ignorepaths2)
TEST_CASE(ignorepaths3)
TEST_CASE(ignorepaths4)
TEST_CASE(ignorefilepaths1)
TEST_CASE(ignorefilepaths2)
TEST_CASE(unknownParam);
}
@ -585,6 +595,17 @@ private:
ASSERT_EQUALS(1, settings._xml_version);
}
void xmlver1()
{
REDIRECT;
const char *argv[] = {"cppcheck", "--xml-version=1", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(3, argv));
ASSERT(settings._xml);
ASSERT_EQUALS(1, settings._xml_version);
}
void xmlver2()
{
REDIRECT;
@ -618,6 +639,24 @@ private:
ASSERT_EQUALS(2, settings._xml_version);
}
void xmlverunknown()
{
REDIRECT;
const char *argv[] = {"cppcheck", "--xml", "--xml-version=3", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(4, argv));
}
void xmlverinvalid()
{
REDIRECT;
const char *argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(4, argv));
}
void errorlist1()
{
REDIRECT;
@ -647,6 +686,84 @@ private:
ASSERT(settings._verbose);
}
void ignorepathsnopath()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-i"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(!parser.ParseFromArgs(2, argv));
ASSERT_EQUALS(0, parser.GetIgnoredPaths().size());
}
void ignorepaths1()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-isrc", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(3, argv));
ASSERT_EQUALS(1, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]);
}
void ignorepaths2()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-i", "src", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(4, argv));
ASSERT_EQUALS(1, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]);
}
void ignorepaths3()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-isrc", "-imodule", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(4, argv));
ASSERT_EQUALS(2, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]);
ASSERT_EQUALS("module/", parser.GetIgnoredPaths()[1]);
}
void ignorepaths4()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-i", "src", "-i", "module", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(6, argv));
ASSERT_EQUALS(2, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("src/", parser.GetIgnoredPaths()[0]);
ASSERT_EQUALS("module/", parser.GetIgnoredPaths()[1]);
}
void ignorefilepaths1()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(3, argv));
ASSERT_EQUALS(1, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("foo.cpp", parser.GetIgnoredPaths()[0]);
}
void ignorefilepaths2()
{
REDIRECT;
const char *argv[] = {"cppcheck", "-isrc/foo.cpp", "file.cpp"};
Settings settings;
CmdLineParser parser(&settings);
ASSERT(parser.ParseFromArgs(3, argv));
ASSERT_EQUALS(1, parser.GetIgnoredPaths().size());
ASSERT_EQUALS("src/foo.cpp", parser.GetIgnoredPaths()[0]);
}
void unknownParam()
{
REDIRECT;

View File

@ -66,9 +66,23 @@ private:
void run()
{
TEST_CASE(instancesSorted);
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()
{
ErrorLogger2 errorLogger;

View File

@ -17,6 +17,7 @@
*/
#include <list>
#include "cppcheck.h"
#include "testsuite.h"
#include "errorlogger.h"
@ -38,6 +39,7 @@ private:
TEST_CASE(CustomFormat2);
TEST_CASE(ToXml);
TEST_CASE(ToVerboseXml);
TEST_CASE(ToXmlV2);
}
void FileLocationDefaults()
@ -124,7 +126,7 @@ private:
locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId");
ASSERT_EQUALS("<?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));
}
@ -137,8 +139,28 @@ private:
locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId");
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));
}
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)

View File

@ -961,6 +961,18 @@ private:
" int i = sizeof sizeof char;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str());
check("void foo()\n"
"{\n"
" int i = sizeof (sizeof long);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str());
check("void foo(long *p)\n"
"{\n"
" int i = sizeof (sizeof (p));\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Calling sizeof for 'sizeof'.\n", errout.str());
}
void sizeofCalculation()

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(enum17); // ticket #2381 (duplicate enums)
TEST_CASE(enum18); // #2466 (array with same name as enum constant)
TEST_CASE(enum19); // ticket #2536
// remove "std::" on some standard functions
TEST_CASE(removestd);
@ -315,6 +316,8 @@ private:
TEST_CASE(redundant_semicolon);
TEST_CASE(simplifyFunctionReturn);
TEST_CASE(removeUnnecessaryQualification);
}
std::string tok(const char code[], bool simplify = true)
@ -6097,6 +6100,13 @@ private:
ASSERT_EQUALS("; void f ( ) { a [ 0 ] ; }", tok(code, false));
}
void enum19() // ticket #2536
{
const char code[] = "enum class E1;\n"
"enum class E2 : int;\n";
ASSERT_EQUALS(";", tok(code, false));
}
void removestd()
{
ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);"));
@ -6408,6 +6418,14 @@ private:
"} ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void removeUnnecessaryQualification()
{
const char code[] = "class Fred { Fred::Fred() {} };";
const char expected[] = "class Fred { Fred ( ) { } } ;";
ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS("[test.cpp:1]: (portability) Extra qualification 'Fred::' unnecessary and considered an error by many compilers.\n", errout.str());
}
};
REGISTER_TEST(TestSimplifyTokens)

View File

@ -1412,6 +1412,12 @@ private:
" return cmd[0];\n"
"}\n");
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()

View File

@ -230,8 +230,8 @@ int main(int argc, char **argv)
fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n";
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o cppcheck $(CLIOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre $(LDFLAGS)\n\n";
fout << "all:\tcppcheck testrunner\n\n";
fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o\n";
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o $(LDFLAGS)\n\n";
fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o\n";
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o testrunner $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) -lpcre cli/threadexecutor.o cli/cmdlineparser.o cli/filelister.o cli/filelister_unix.o cli/pathmatch.o $(LDFLAGS)\n\n";
fout << "test:\tall\n";
fout << "\t./testrunner\n\n";
fout << "check:\tall\n";