This commit is contained in:
Sébastien Debrard 2011-02-13 21:57:42 +01:00
commit de50e21ada
20 changed files with 872 additions and 503 deletions

View File

@ -60,8 +60,13 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
if (filename[filename.length()-1] != '/')
{
// File
#ifdef PATH_MAX
char fname[PATH_MAX];
if (realpath(filename.c_str(), fname) == NULL)
#else
char *fname;
if ((fname = realpath(filename.c_str(), NULL)) == NULL)
#endif
{
continue;
}
@ -69,6 +74,9 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
// Does absolute path exist? then bail out
if (std::find(absolute.begin(), absolute.end(), std::string(fname)) != absolute.end())
{
#ifndef PATH_MAX
free(fname);
#endif
continue;
}
@ -77,6 +85,10 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
relative.push_back(filename);
absolute.push_back(fname);
}
#ifndef PATH_MAX
free(fname);
#endif
}
else
{

View File

@ -42,12 +42,18 @@ public:
: Check(myName(), tokenizer, settings, errorLogger)
{ }
/** @brief Run checks against the normal token list */
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
{
CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger);
checkAutoVariables.returnReference();
}
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
{
CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger);
checkAutoVariables.autoVariables();
checkAutoVariables.returnPointerToLocalArray();
checkAutoVariables.returnReference();
checkAutoVariables.returncstr();
}

View File

@ -791,7 +791,7 @@ void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &ar
return;
// Get index variable and stopsize.
bool condition_out_of_bounds = true;
bool condition_out_of_bounds = bool(size > 0);
if (MathLib::toLongNumber(max_counter_value) < size)
condition_out_of_bounds = false;

View File

@ -317,12 +317,21 @@ void CheckOther::checkSelfAssignment()
if (!_settings->_checkCodingStyle)
return;
// POD variables..
std::set<unsigned int> pod;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
if (tok->isStandardType() && tok->next()->varId() && Token::Match(tok->tokAt(2), "[,);]"))
pod.insert(tok->next()->varId());
}
const char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
while (tok)
{
if (Token::Match(tok->previous(), "[;{}]") &&
tok->varId() && tok->varId() == tok->tokAt(2)->varId())
tok->varId() && tok->varId() == tok->tokAt(2)->varId() &&
pod.find(tok->varId()) != pod.end())
{
selfAssignmentError(tok, tok->str());
}

View File

@ -25,6 +25,7 @@
#include <iostream>
#include <cctype> // std::isdigit, std::isalnum, etc
#include <set>
#include <stack>
Settings::Settings()
{
@ -116,6 +117,137 @@ std::string Settings::Suppressions::parseFile(std::istream &istr)
return "";
}
bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, const std::string &name)
{
const char *p = pattern.c_str();
const char *n = name.c_str();
std::stack<std::pair<const char *, const char *> > backtrack;
for (;;)
{
bool matching = true;
while (*p != '\0' && matching)
{
switch (*p)
{
case '*':
// Step forward until we match the next character after *
while (*n != '\0' && *n != p[1])
{
n++;
}
if (*n != '\0')
{
// If this isn't the last possibility, save it for later
backtrack.push(std::make_pair(p, n));
}
break;
case '?':
// Any character matches unless we're at the end of the name
if (*n != '\0')
{
n++;
}
else
{
matching = false;
}
break;
default:
// Non-wildcard characters match literally
if (*n == *p)
{
n++;
}
else
{
matching = false;
}
break;
}
p++;
}
// If we haven't failed matching and we've reached the end of the name, then success
if (matching && *n == '\0')
{
return true;
}
// If there are no other paths to tray, then fail
if (backtrack.empty())
{
return false;
}
// Restore pointers from backtrack stack
p = backtrack.top().first;
n = backtrack.top().second;
backtrack.pop();
// Advance name pointer by one because the current position didn't work
n++;
}
}
std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name, unsigned int line)
{
if (name.find_first_of("*?") != std::string::npos)
{
for (std::string::const_iterator i = name.begin(); i != name.end(); ++i)
{
if (*i == '*')
{
std::string::const_iterator j = i + 1;
if (j != name.end() && (*j == '*' || *j == '?'))
{
return "Failed to add suppression. Syntax error in glob.";
}
}
}
_globs[name].insert(line);
}
else
{
_files[name].insert(line);
}
return "";
}
bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, unsigned int line)
{
// Check are all errors of this type filtered out
if (_files.find("") != _files.end())
return true;
std::set<unsigned int> lineset;
std::map<std::string, std::set<unsigned int> >::const_iterator f = _files.find(file);
if (f != _files.end())
{
lineset.insert(f->second.begin(), f->second.end());
}
for (std::map<std::string, std::set<unsigned int> >::iterator g = _globs.begin(); g != _globs.end(); ++g)
{
if (match(g->first, file))
{
lineset.insert(g->second.begin(), g->second.end());
}
}
if (lineset.empty())
return false;
// Check should all errors in this file be filtered out
if (lineset.find(0U) != lineset.end())
return true;
if (lineset.find(line) == lineset.end())
return false;
return true;
}
std::string Settings::Suppressions::addSuppression(const std::string &errorId, const std::string &file, unsigned int line)
{
// Check that errorId is valid..
@ -135,10 +267,7 @@ std::string Settings::Suppressions::addSuppression(const std::string &errorId, c
}
}
_suppressions[errorId][file].push_back(line);
_suppressions[errorId][file].sort();
return "";
return _suppressions[errorId].addFile(file, line);
}
bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std::string &file, unsigned int line)
@ -146,21 +275,7 @@ bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std:
if (_suppressions.find(errorId) == _suppressions.end())
return false;
// Check are all errors of this type filtered out
if (_suppressions[errorId].find("") != _suppressions[errorId].end())
return true;
if (_suppressions[errorId].find(file) == _suppressions[errorId].end())
return false;
// Check should all errors in this file be filtered out
if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), 0) != _suppressions[errorId][file].end())
return true;
if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), line) == _suppressions[errorId][file].end())
return false;
return true;
return _suppressions[errorId].isSuppressed(file, line);
}
std::string Settings::addEnabled(const std::string &str)

View File

@ -23,6 +23,7 @@
#include <string>
#include <istream>
#include <map>
#include <set>
/// @addtogroup Core
/// @{
@ -135,8 +136,42 @@ public:
class Suppressions
{
private:
class FileMatcher
{
private:
/** @brief List of filenames suppressed. */
std::map<std::string, std::set<unsigned int> > _files;
/** @brief List of globs suppressed. */
std::map<std::string, std::set<unsigned int> > _globs;
/**
* @brief Match a name against a glob pattern.
* @param pattern The glob pattern to match.
* @param name The filename to match against the glob pattern.
* @return match success
*/
static bool match(const std::string &pattern, const std::string &name);
public:
/**
* @brief Add a file or glob (and line number).
* @param name File name or glob pattern
* @param line Line number
* @return error message. empty upon success
*/
std::string addFile(const std::string &name, unsigned int line);
/**
* @brief Returns true if the file name matches a previously added file or glob pattern.
* @param name File name to check
* @param line Line number
* @return true if this filename/line matches
*/
bool isSuppressed(const std::string &file, unsigned int line);
};
/** @brief List of error which the user doesn't want to see. */
std::map<std::string, std::map<std::string, std::list<unsigned int> > > _suppressions;
std::map<std::string, FileMatcher> _suppressions;
public:
/**
* @brief Don't show errors listed in the file.

View File

@ -227,7 +227,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// out of line function
if (Token::Match(end, ") const| ;") ||
Token::Match(end, ") const| = %any% ;"))
Token::Match(end, ") const| = %any%"))
{
// find the function implementation later
tok = end->next();

View File

@ -854,6 +854,65 @@ static Token *splitDefinitionFromTypedef(Token *tok)
return tok;
}
/* This function is called when processing function related typedefs.
* If simplifyTypedef generates an "Internal Error" message and the
* code that generated it deals in some way with functions, then this
* fucntion will probably need to be extended to handle a new function
* related pattern */
static Token *processFunc(Token *tok2, bool inOperator)
{
if (tok2->next() && tok2->next()->str() != ")" &&
tok2->next()->str() != ",")
{
// skip over tokens for some types of canonicalization
if (Token::Match(tok2->next(), "( * %type% ) ("))
tok2 = tok2->tokAt(5)->link();
else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
tok2 = tok2->tokAt(6)->link();
else if (Token::Match(tok2->next(), "* ( %type% [") &&
Token::Match(tok2->tokAt(4)->link(), "] ) ;|="))
tok2 = tok2->tokAt(4)->link()->next();
else if (Token::Match(tok2->next(), "* ( * %type% ("))
tok2 = tok2->tokAt(5)->link()->next();
else
{
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
else if (!inOperator && !Token::Match(tok2->next(), "[|>|;"))
{
tok2 = tok2->next();
while (Token::Match(tok2, "*|&") &&
!Token::Match(tok2->next(), ")|>"))
tok2 = tok2->next();
// skip over namespace
while (Token::Match(tok2, "%var% ::"))
tok2 = tok2->tokAt(2);
if (tok2->str() == "(" &&
tok2->link()->next()->str() == "(")
{
tok2 = tok2->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
// skip over typedef parameter
if (tok2->next()->str() == "(")
{
tok2 = tok2->next()->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
}
}
}
return tok2;
}
void Tokenizer::simplifyTypedef()
{
std::vector<Space> spaceInfo;
@ -1473,49 +1532,7 @@ void Tokenizer::simplifyTypedef()
tok2 = copyTokens(tok2, funcStart, funcEnd);
if (!inCast)
{
if (tok2->next() && tok2->next()->str() != ")" &&
tok2->next()->str() != ",")
{
if (Token::Match(tok2->next(), "( * %type% ) ("))
tok2 = tok2->tokAt(5)->link();
else
{
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
else if (!inOperator && !Token::Match(tok2->next(), "[|>|;"))
{
tok2 = tok2->next();
while (Token::Match(tok2, "*|&") &&
!Token::Match(tok2->next(), ")|>"))
tok2 = tok2->next();
// skip over namespace
while (Token::Match(tok2, "%var% ::"))
tok2 = tok2->tokAt(2);
if (tok2->str() == "(" &&
tok2->link()->next()->str() == "(")
{
tok2 = tok2->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
// skip over typedef parameter
else if (tok2->next()->str() == "(")
{
tok2 = tok2->next()->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
}
}
}
}
tok2 = processFunc(tok2, inOperator);
tok2->insertToken(")");
tok2 = tok2->next();
@ -1586,45 +1603,7 @@ void Tokenizer::simplifyTypedef()
}
if (!inCast)
{
if (tok2->next() && tok2->next()->str() != ")" &&
tok2->next()->str() != ",")
{
if (Token::Match(tok2->next(), "( * %type% ) ("))
tok2 = tok2->tokAt(5)->link();
else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
tok2 = tok2->tokAt(6)->link();
else if (Token::Match(tok2->next(), "* ( %type% [") &&
Token::Match(tok2->tokAt(4)->link(), "] ) ;|="))
tok2 = tok2->tokAt(4)->link()->next();
else
{
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
else if (!inOperator && !Token::Match(tok2->next(), "[|>|;"))
{
tok2 = tok2->next();
while (Token::Match(tok2, "*|&") &&
!Token::Match(tok2->next(), ")|>"))
tok2 = tok2->next();
// skip over namespace
while (Token::Match(tok2, "%var% ::"))
tok2 = tok2->tokAt(2);
// skip over typedef parameter
if (tok2->next()->str() == "(")
{
tok2 = tok2->next()->link();
if (tok2->next()->str() == "(")
tok2 = tok2->next()->link();
}
}
}
}
}
tok2 = processFunc(tok2, inOperator);
if (needParen)
{
@ -2290,14 +2269,10 @@ bool Tokenizer::tokenize(std::istream &code,
// typedef..
simplifyTypedef();
// Fix internal error by updating links (#2376)
// TODO: Remove this "createLinks". Make sure that the testcase
// TestSimplifyTokens::simplifyTypedefFunction8
// doesn't fail.
if (!createLinks())
// catch bad typedef canonicalization
if (!validate())
{
// Source has syntax errors, can't proceed
cppcheckError(0);
return false;
}
@ -2548,7 +2523,7 @@ static void removeTemplates(Token *tok)
}
}
void Tokenizer::simplifyTemplates()
std::set<std::string> Tokenizer::simplifyTemplatesExpandSpecialized()
{
std::set<std::string> expandedtemplates;
@ -2614,7 +2589,11 @@ void Tokenizer::simplifyTemplates()
}
}
// Locate templates..
return expandedtemplates;
}
std::list<Token *> Tokenizer::simplifyTemplatesGetTemplateDeclarations()
{
std::list<Token *> templates;
for (Token *tok = _tokens; tok; tok = tok->next())
{
@ -2639,30 +2618,13 @@ void Tokenizer::simplifyTemplates()
}
}
}
if (templates.empty())
{
removeTemplates(_tokens);
return;
return templates;
}
// There are templates..
// Remove "typename" unless used in template arguments..
for (Token *tok = _tokens; tok; tok = tok->next())
std::list<Token *> Tokenizer::simplifyTemplatesGetTemplateInstantiations()
{
if (tok->str() == "typename")
tok->deleteThis();
if (Token::simpleMatch(tok, "template <"))
{
while (tok && tok->str() != ">")
tok = tok->next();
if (!tok)
break;
}
}
// Locate possible instantiations of templates..
std::list<Token *> used;
for (Token *tok = _tokens; tok; tok = tok->next())
{
// template definition.. skip it
@ -2703,18 +2665,14 @@ void Tokenizer::simplifyTemplates()
}
}
// No template instantiations? Then remove all templates.
if (used.empty())
{
removeTemplates(_tokens);
return;
return used;
}
// Template arguments with default values
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list<Token *> &templates,
const std::list<Token *> &instantiations)
{
for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
{
// template parameters with default value has syntax such as:
// x = y
@ -2750,7 +2708,7 @@ void Tokenizer::simplifyTemplates()
continue;
// iterate through all template instantiations
for (std::list<Token *>::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
for (std::list<Token *>::const_iterator iter2 = instantiations.begin(); iter2 != instantiations.end(); ++iter2)
{
Token *tok = *iter2;
@ -2780,8 +2738,21 @@ void Tokenizer::simplifyTemplates()
{
tok->insertToken(",");
tok = tok->next();
tok->insertToken((*it)->strAt(1));
const Token *from = (*it)->next();
std::stack<Token *> links;
while (from && (!links.empty() || (from->str() != "," && from->str() != ">")))
{
tok->insertToken(from->str());
tok = tok->next();
if (Token::Match(tok, "(|["))
links.push(tok);
else if (!links.empty() && Token::Match(tok, ")|]"))
{
Token::createMutualLinks(links.top(), tok);
links.pop();
}
from = from->next();
}
++it;
}
}
@ -2793,16 +2764,16 @@ void Tokenizer::simplifyTemplates()
(*it)->deleteThis();
}
}
}
// expand templates
void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
std::list<Token *> &used,
std::set<std::string> &expandedtemplates)
{
// this variable is not used at the moment. the intention was to
// allow continous instantiations until all templates has been expanded
bool done = false;
//while (!done)
{
done = true;
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
{
Token *tok = *iter1;
std::vector<const Token *> type;
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next())
{
@ -2811,7 +2782,7 @@ void Tokenizer::simplifyTemplates()
}
// bail out if the end of the file was reached
if (!tok)
break;
return;
// get the position of the template name
unsigned char namepos = 0;
@ -2842,7 +2813,7 @@ void Tokenizer::simplifyTemplates()
else
Check::reportError(errmsg);
}
continue;
return;
}
if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&"))
++namepos;
@ -2866,7 +2837,7 @@ void Tokenizer::simplifyTemplates()
std::string::size_type sz1 = used.size();
unsigned int recursiveCount = 0;
for (std::list<Token *>::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
for (std::list<Token *>::const_iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
{
// If the size of "used" has changed, simplify calculations
if (sz1 != used.size())
@ -3113,6 +3084,58 @@ void Tokenizer::simplifyTemplates()
}
}
}
void Tokenizer::simplifyTemplates()
{
std::set<std::string> expandedtemplates(simplifyTemplatesExpandSpecialized());
// Locate templates..
std::list<Token *> templates(simplifyTemplatesGetTemplateDeclarations());
if (templates.empty())
{
removeTemplates(_tokens);
return;
}
// There are templates..
// Remove "typename" unless used in template arguments..
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (tok->str() == "typename")
tok->deleteThis();
if (Token::simpleMatch(tok, "template <"))
{
while (tok && tok->str() != ">")
tok = tok->next();
if (!tok)
break;
}
}
// Locate possible instantiations of templates..
std::list<Token *> used(simplifyTemplatesGetTemplateInstantiations());
// No template instantiations? Then remove all templates.
if (used.empty())
{
removeTemplates(_tokens);
return;
}
// Template arguments with default values
simplifyTemplatesUseDefaultArgumentValues(templates, used);
// expand templates
bool done = false;
//while (!done)
{
done = true;
for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
{
simplifyTemplatesInstantiate(*iter1, used, expandedtemplates);
}
}
removeTemplates(_tokens);
@ -8725,7 +8748,7 @@ void Tokenizer::simplifyStructDecl()
}
// unnamed anonymous struct/union so remove it
else if (tok->next()->str() == ";")
else if (tok->next() && tok->next()->str() == ";")
{
if (tok1->str() == "union")
{

View File

@ -24,7 +24,9 @@
#include <string>
#include <map>
#include <list>
#include <vector>
#include <set>
class Token;
class ErrorLogger;
@ -395,6 +397,43 @@ public:
*/
void simplifyTemplates();
/**
* Expand specialized templates : "template<>.."
* @return names of expanded templates
*/
std::set<std::string> simplifyTemplatesExpandSpecialized();
/**
* Get template declarations
* @return list of template declarations
*/
std::list<Token *> simplifyTemplatesGetTemplateDeclarations();
/**
* Get template instantiations
* @return list of template instantiations
*/
std::list<Token *> simplifyTemplatesGetTemplateInstantiations();
/**
* simplify template instantiations (use default argument values)
* @param templates list of template declarations
* @param instantiations list of template instantiations
*/
void simplifyTemplatesUseDefaultArgumentValues(const std::list<Token *> &templates,
const std::list<Token *> &instantiations);
/**
* Simplify templates : expand all instantiatiations for a template
* @todo It seems that inner templates should be instantiated recursively
* @param tok token where the template declaration begins
* @param used a list of template usages (not necessarily just for this template)
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
*/
void simplifyTemplatesInstantiate(const Token *tok,
std::list<Token *> &used,
std::set<std::string> &expandedtemplates);
/**
* Used after simplifyTemplates to perform a little cleanup.
* Sometimes the simplifyTemplates isn't fully successful and then

View File

@ -307,7 +307,8 @@ Directory name is matched to all parts of the path.</para>
<term><option>--suppressions-list=&lt;file&gt;</option></term>
<listitem>
<para>Suppress warnings listed in the file. Filename and line are optional. The format of the single line in file is: [error id]:[filename]:[line].
You can use --template or --xml to see the error id.</para>
You can use --template or --xml to see the error id.
The filename may contain the wildcard characters * or ?.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -385,6 +385,10 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
line flag. Copy and paste the <literal>id</literal> string from the XML
output.</para>
<para>The <literal>filename</literal> may include the wildcard characters
* or ?, which match any sequence of characters or any single character
respectively.</para>
<para>Here is an example:</para>
<programlisting>memleak:file1.cpp

View File

@ -47,6 +47,10 @@ private:
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this);
checkAutoVariables.runChecks(&tokenizer, &settings, this);
tokenizer.simplifyTokenList();
// Assign variable ids
@ -56,10 +60,8 @@ private:
tokenizer.fillFunctionList();
// Check auto variables
CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this);
checkAutoVariables.autoVariables();
checkAutoVariables.returnPointerToLocalArray();
checkAutoVariables.returnReference();
checkAutoVariables.returncstr();
}
@ -81,6 +83,7 @@ private:
// return reference..
TEST_CASE(returnReference1);
TEST_CASE(returnReference2);
TEST_CASE(returnReference3);
// return c_str()..
TEST_CASE(returncstr1);
@ -351,6 +354,16 @@ private:
ASSERT_EQUALS("[test.cpp:11]: (error) Returning reference to temporary\n", errout.str());
}
void returnReference3()
{
check("double & f(double & rd) {\n"
" double ret = getValue();\n"
" rd = ret;\n"
" return rd;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void returncstr1()
{
check("const char *foo()\n"

View File

@ -84,7 +84,6 @@ private:
TEST_CASE(array_index_7);
TEST_CASE(array_index_8);
TEST_CASE(array_index_9);
TEST_CASE(array_index_10);
TEST_CASE(array_index_11);
TEST_CASE(array_index_12);
TEST_CASE(array_index_13);
@ -135,6 +134,7 @@ private:
TEST_CASE(buffer_overrun_15); // ticket #1787
TEST_CASE(buffer_overrun_16);
TEST_CASE(buffer_overrun_17); // ticket #2548
TEST_CASE(buffer_overrun_18); // ticket #2576 - for, calculation with loop variable
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
// It is undefined behaviour to point out of bounds of an array
@ -597,27 +597,6 @@ private:
}
void array_index_10()
{
check("struct ABC\n"
"{\n"
" char str[10];\n"
"};\n"
"\n"
"static void memclr( char *data )\n"
"{\n"
" data[10] = 0;\n"
"}\n"
"\n"
"static void f(struct ABC *abc)\n"
"{\n"
" memclr(abc->str);\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:13] -> [test.cpp:8]: (possible error) Array index out of bounds\n",
"", errout.str());
}
void array_index_11()
{
check("class ABC\n"
@ -1883,6 +1862,21 @@ private:
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer access out-of-bounds\n", errout.str());
}
void buffer_overrun_18() // ticket #2576
{
check("class A {\n"
" void foo();\n"
" bool b[7];\n"
"};\n"
"\n"
"void A::foo() {\n"
" for (int i=0; i<6; i++) {\n"
" b[i] = b[i+1];\n"
" }\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void buffer_overrun_bailoutIfSwitch()
{
// No false positive

View File

@ -191,6 +191,7 @@ private:
TEST_CASE(symboldatabase10); // ticket #2537
TEST_CASE(symboldatabase11); // ticket #2539
TEST_CASE(symboldatabase12); // ticket #2547
TEST_CASE(symboldatabase13); // ticket #2577
}
// Check the operator Equal
@ -5528,6 +5529,16 @@ private:
ASSERT_EQUALS("", errout.str());
}
void symboldatabase13()
{
// ticket #2577 - segmentation fault
checkConst("class foo {\n"
" void bar2 () = A::f;\n"
"};\n");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestClass)

View File

@ -1157,14 +1157,12 @@ private:
check("void foo()\n"
"{\n"
" int x = x;\n"
" return 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"x\" to itself\n", errout.str());
check("void foo()\n"
"{\n"
" std::string var = var = \"test\";\n"
" return 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"var\" to itself\n", "", errout.str());
@ -1182,6 +1180,13 @@ private:
" *x = x;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// non-primitive type -> there might be some side effects
check("void foo()\n"
"{\n"
" Fred fred; fred = fred;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void testScanf1()

View File

@ -1232,6 +1232,7 @@ private:
}
void if_cond7()
{
{
const char filedata[] = "#define A 1\n"
"#if A==1\n"
@ -1250,6 +1251,27 @@ private:
ASSERT_EQUALS("\n\na1;\n\n", actual[""]);
}
{
const char filedata[] = "#define A 0\n"
"#if A\n"
"foo();\n"
"#endif\n";
// Preprocess => actual result..
std::istringstream istr(filedata);
std::map<std::string, std::string> actual;
Settings settings;
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
// Compare results..
TODO_ASSERT_EQUALS(2,
1, static_cast<unsigned int>(actual.size()));
TODO_ASSERT_EQUALS("\n\n\n\n",
"\n\nfoo();\n\n", actual[""]);
}
}
void if_cond8()
{

View File

@ -36,6 +36,7 @@ private:
TEST_CASE(suppressionsBadId1);
TEST_CASE(suppressionsDosFormat); // Ticket #1836
TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon
TEST_CASE(suppressionsGlob);
}
void suppressionsBadId1()
@ -63,6 +64,41 @@ private:
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 10));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 12));
}
void suppressionsGlob()
{
// Check for syntax errors in glob
{
Settings::Suppressions suppressions;
std::istringstream s("errorid:**.cpp\n");
ASSERT_EQUALS("Failed to add suppression. Syntax error in glob.", suppressions.parseFile(s));
}
// Check that globbing works
{
Settings::Suppressions suppressions;
std::istringstream s("errorid:x*.cpp\nerrorid:y?.cpp\nerrorid:test.c*");
ASSERT_EQUALS("", suppressions.parseFile(s));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp.cpp", 1));
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "ya.cpp", 1));
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "y.cpp", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.c", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.cpp", 1));
}
// Check that both a filename match and a glob match apply
{
Settings::Suppressions suppressions;
std::istringstream s("errorid:x*.cpp\nerrorid:xyz.cpp:1\nerrorid:a*.cpp:1\nerrorid:abc.cpp:2");
ASSERT_EQUALS("", suppressions.parseFile(s));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 2));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 1));
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 2));
}
}
};
REGISTER_TEST(TestSettings)

View File

@ -304,7 +304,8 @@ private:
TEST_CASE(initstruct);
// struct ABC { } abc; => struct ABC { }; ABC abc;
TEST_CASE(simplifyStructDecl);
TEST_CASE(simplifyStructDecl1);
TEST_CASE(simplifyStructDecl2); // ticket #2579
// register int var; => int var;
// inline int foo() {} => int foo() {}
@ -6222,7 +6223,7 @@ private:
tok("; struct A a = { .buf = {0} };"));
}
void simplifyStructDecl()
void simplifyStructDecl1()
{
{
const char code[] = "struct ABC { } abc;";
@ -6365,6 +6366,13 @@ private:
}
}
void simplifyStructDecl2() // ticket #2479 (segmentation fault)
{
const char code[] = "struct { char c; }";
const char expected[] = "struct { char c ; }";
ASSERT_EQUALS(expected, tok(code, false));
}
void removeUnwantedKeywords()
{
ASSERT_EQUALS("int var ;", tok("register int var ;", true));

View File

@ -264,6 +264,7 @@ private:
TEST_CASE(removeattribute);
TEST_CASE(cpp0xtemplate1);
TEST_CASE(cpp0xtemplate2);
TEST_CASE(cpp0xtemplate3);
TEST_CASE(cpp0xdefault);
TEST_CASE(arraySize);
@ -4634,6 +4635,18 @@ private:
"list < list < int >> ints ;", tokenizeAndStringify(code));
}
void cpp0xtemplate3()
{
// #2549
const char *code = "template<class T, T t = (T)0>\n"
"struct S\n"
"{};\n"
"S<int> s;\n";
TODO_ASSERT_EQUALS(";\n\n\nS < int , ( int ) 0 > s ;", // wanted result
";\n\n\nS < int , ( T ) 0 > s ;", // current result
tokenizeAndStringify(code));
}
void cpp0xdefault()
{
{

View File

@ -46,6 +46,7 @@ private:
TEST_CASE(uninitvar_references); // references
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
TEST_CASE(uninitvar_func); // analyse functions
TEST_CASE(uninitvar_func2); // usage of 'void a(int *p) { *p = 0; }'
TEST_CASE(uninitvar_typeof); // typeof
}
@ -1420,6 +1421,28 @@ private:
ASSERT_EQUALS("", errout.str());
}
// valid and invalid use of 'void a(int *p) { *p = 0; }'
void uninitvar_func2()
{
const std::string funca("void a(int *p) { *p = 0; }\n");
// ok - initialized pointer
checkUninitVar((funca +
"void b() {\n"
" int buf[10];\n"
" a(buf);\n"
"}\n").c_str());
ASSERT_EQUALS("", errout.str());
// not ok - uninitialized pointer
checkUninitVar((funca +
"void b() {\n"
" int *p;\n"
" a(p);\n"
"}\n").c_str());
TODO_ASSERT_EQUALS("error", "", errout.str());
}
void uninitvar_typeof()
{
checkUninitVar("void f() {\n"