Merge branch 'master' of http://github.com/danmar/cppcheck
This commit is contained in:
commit
de50e21ada
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
153
lib/settings.cpp
153
lib/settings.cpp
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
295
lib/tokenize.cpp
295
lib/tokenize.cpp
|
@ -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())
|
||||
{
|
||||
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 *> Tokenizer::simplifyTemplatesGetTemplateInstantiations()
|
||||
{
|
||||
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())
|
||||
|
@ -3112,6 +3083,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -307,7 +307,8 @@ Directory name is matched to all parts of the path.</para>
|
|||
<term><option>--suppressions-list=<file></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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue