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] != '/')
|
if (filename[filename.length()-1] != '/')
|
||||||
{
|
{
|
||||||
// File
|
// File
|
||||||
|
#ifdef PATH_MAX
|
||||||
char fname[PATH_MAX];
|
char fname[PATH_MAX];
|
||||||
if (realpath(filename.c_str(), fname) == NULL)
|
if (realpath(filename.c_str(), fname) == NULL)
|
||||||
|
#else
|
||||||
|
char *fname;
|
||||||
|
if ((fname = realpath(filename.c_str(), NULL)) == NULL)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +74,9 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
|
||||||
// Does absolute path exist? then bail out
|
// Does absolute path exist? then bail out
|
||||||
if (std::find(absolute.begin(), absolute.end(), std::string(fname)) != absolute.end())
|
if (std::find(absolute.begin(), absolute.end(), std::string(fname)) != absolute.end())
|
||||||
{
|
{
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
free(fname);
|
||||||
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +85,10 @@ void FileListerUnix::recursiveAddFiles2(std::vector<std::string> &relative,
|
||||||
relative.push_back(filename);
|
relative.push_back(filename);
|
||||||
absolute.push_back(fname);
|
absolute.push_back(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
free(fname);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,12 +42,18 @@ public:
|
||||||
: Check(myName(), tokenizer, settings, errorLogger)
|
: 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)
|
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
||||||
{
|
{
|
||||||
CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger);
|
CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger);
|
||||||
checkAutoVariables.autoVariables();
|
checkAutoVariables.autoVariables();
|
||||||
checkAutoVariables.returnPointerToLocalArray();
|
checkAutoVariables.returnPointerToLocalArray();
|
||||||
checkAutoVariables.returnReference();
|
|
||||||
checkAutoVariables.returncstr();
|
checkAutoVariables.returncstr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -791,7 +791,7 @@ void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &ar
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get index variable and stopsize.
|
// 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)
|
if (MathLib::toLongNumber(max_counter_value) < size)
|
||||||
condition_out_of_bounds = false;
|
condition_out_of_bounds = false;
|
||||||
|
|
||||||
|
|
|
@ -317,12 +317,21 @@ void CheckOther::checkSelfAssignment()
|
||||||
if (!_settings->_checkCodingStyle)
|
if (!_settings->_checkCodingStyle)
|
||||||
return;
|
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 char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
|
||||||
const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
|
const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
|
||||||
while (tok)
|
while (tok)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok->previous(), "[;{}]") &&
|
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());
|
selfAssignmentError(tok, tok->str());
|
||||||
}
|
}
|
||||||
|
|
153
lib/settings.cpp
153
lib/settings.cpp
|
@ -25,6 +25,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cctype> // std::isdigit, std::isalnum, etc
|
#include <cctype> // std::isdigit, std::isalnum, etc
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
Settings::Settings()
|
Settings::Settings()
|
||||||
{
|
{
|
||||||
|
@ -116,6 +117,137 @@ std::string Settings::Suppressions::parseFile(std::istream &istr)
|
||||||
return "";
|
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)
|
std::string Settings::Suppressions::addSuppression(const std::string &errorId, const std::string &file, unsigned int line)
|
||||||
{
|
{
|
||||||
// Check that errorId is valid..
|
// 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);
|
return _suppressions[errorId].addFile(file, line);
|
||||||
_suppressions[errorId][file].sort();
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std::string &file, unsigned int 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())
|
if (_suppressions.find(errorId) == _suppressions.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check are all errors of this type filtered out
|
return _suppressions[errorId].isSuppressed(file, line);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Settings::addEnabled(const std::string &str)
|
std::string Settings::addEnabled(const std::string &str)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
/// @addtogroup Core
|
/// @addtogroup Core
|
||||||
/// @{
|
/// @{
|
||||||
|
@ -135,8 +136,42 @@ public:
|
||||||
class Suppressions
|
class Suppressions
|
||||||
{
|
{
|
||||||
private:
|
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. */
|
/** @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:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Don't show errors listed in the file.
|
* @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
|
// out of line function
|
||||||
if (Token::Match(end, ") const| ;") ||
|
if (Token::Match(end, ") const| ;") ||
|
||||||
Token::Match(end, ") const| = %any% ;"))
|
Token::Match(end, ") const| = %any%"))
|
||||||
{
|
{
|
||||||
// find the function implementation later
|
// find the function implementation later
|
||||||
tok = end->next();
|
tok = end->next();
|
||||||
|
|
897
lib/tokenize.cpp
897
lib/tokenize.cpp
|
@ -854,6 +854,65 @@ static Token *splitDefinitionFromTypedef(Token *tok)
|
||||||
return 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()
|
void Tokenizer::simplifyTypedef()
|
||||||
{
|
{
|
||||||
std::vector<Space> spaceInfo;
|
std::vector<Space> spaceInfo;
|
||||||
|
@ -1473,49 +1532,7 @@ void Tokenizer::simplifyTypedef()
|
||||||
tok2 = copyTokens(tok2, funcStart, funcEnd);
|
tok2 = copyTokens(tok2, funcStart, funcEnd);
|
||||||
|
|
||||||
if (!inCast)
|
if (!inCast)
|
||||||
{
|
tok2 = processFunc(tok2, inOperator);
|
||||||
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->insertToken(")");
|
tok2->insertToken(")");
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
|
@ -1586,45 +1603,7 @@ void Tokenizer::simplifyTypedef()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inCast)
|
if (!inCast)
|
||||||
{
|
tok2 = processFunc(tok2, inOperator);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needParen)
|
if (needParen)
|
||||||
{
|
{
|
||||||
|
@ -2290,14 +2269,10 @@ bool Tokenizer::tokenize(std::istream &code,
|
||||||
// typedef..
|
// typedef..
|
||||||
simplifyTypedef();
|
simplifyTypedef();
|
||||||
|
|
||||||
// Fix internal error by updating links (#2376)
|
// catch bad typedef canonicalization
|
||||||
// TODO: Remove this "createLinks". Make sure that the testcase
|
if (!validate())
|
||||||
// TestSimplifyTokens::simplifyTypedefFunction8
|
|
||||||
// doesn't fail.
|
|
||||||
if (!createLinks())
|
|
||||||
{
|
{
|
||||||
// Source has syntax errors, can't proceed
|
// Source has syntax errors, can't proceed
|
||||||
cppcheckError(0);
|
|
||||||
return false;
|
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;
|
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;
|
std::list<Token *> templates;
|
||||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -2639,30 +2618,13 @@ void Tokenizer::simplifyTemplates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (templates.empty())
|
return templates;
|
||||||
{
|
}
|
||||||
removeTemplates(_tokens);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are templates..
|
std::list<Token *> Tokenizer::simplifyTemplatesGetTemplateInstantiations()
|
||||||
// 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;
|
std::list<Token *> used;
|
||||||
|
|
||||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
// template definition.. skip it
|
// template definition.. skip it
|
||||||
|
@ -2703,18 +2665,14 @@ void Tokenizer::simplifyTemplates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No template instantiations? Then remove all templates.
|
return used;
|
||||||
if (used.empty())
|
}
|
||||||
{
|
|
||||||
removeTemplates(_tokens);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list<Token *> &templates,
|
||||||
|
const std::list<Token *> &instantiations)
|
||||||
// Template arguments with default values
|
{
|
||||||
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
||||||
{
|
{
|
||||||
// template parameters with default value has syntax such as:
|
// template parameters with default value has syntax such as:
|
||||||
// x = y
|
// x = y
|
||||||
|
@ -2750,7 +2708,7 @@ void Tokenizer::simplifyTemplates()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// iterate through all template instantiations
|
// 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;
|
Token *tok = *iter2;
|
||||||
|
|
||||||
|
@ -2780,8 +2738,21 @@ void Tokenizer::simplifyTemplates()
|
||||||
{
|
{
|
||||||
tok->insertToken(",");
|
tok->insertToken(",");
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
tok->insertToken((*it)->strAt(1));
|
const Token *from = (*it)->next();
|
||||||
tok = tok->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;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2793,325 +2764,377 @@ void Tokenizer::simplifyTemplates()
|
||||||
(*it)->deleteThis();
|
(*it)->deleteThis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::vector<const Token *> type;
|
||||||
|
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next())
|
||||||
|
{
|
||||||
|
if (Token::Match(tok, "%var% ,|>"))
|
||||||
|
type.push_back(tok);
|
||||||
|
}
|
||||||
|
// bail out if the end of the file was reached
|
||||||
|
if (!tok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get the position of the template name
|
||||||
|
unsigned char namepos = 0;
|
||||||
|
if (Token::Match(tok, "> class|struct %type% {|:"))
|
||||||
|
namepos = 2;
|
||||||
|
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||||
|
namepos = 2;
|
||||||
|
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
||||||
|
namepos = 3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// debug message that we bail out..
|
||||||
|
if (_settings->debugwarnings)
|
||||||
|
{
|
||||||
|
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::debug,
|
||||||
|
"simplifyTemplates: bailing out",
|
||||||
|
"debug");
|
||||||
|
|
||||||
|
if (_errorLogger)
|
||||||
|
_errorLogger->reportErr(errmsg);
|
||||||
|
else
|
||||||
|
Check::reportError(errmsg);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&"))
|
||||||
|
++namepos;
|
||||||
|
|
||||||
|
// name of template function/class..
|
||||||
|
const std::string name(tok->strAt(namepos));
|
||||||
|
|
||||||
|
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
||||||
|
|
||||||
|
// locate template usage..
|
||||||
|
|
||||||
|
std::string s(name + " <");
|
||||||
|
for (unsigned int i = 0; i < type.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
s += ",";
|
||||||
|
s += " %any% ";
|
||||||
|
}
|
||||||
|
const std::string pattern(s + "> ");
|
||||||
|
|
||||||
|
std::string::size_type sz1 = used.size();
|
||||||
|
unsigned int recursiveCount = 0;
|
||||||
|
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
sz1 = used.size();
|
||||||
|
simplifyCalculations();
|
||||||
|
recursiveCount++;
|
||||||
|
if (recursiveCount > 100)
|
||||||
|
{
|
||||||
|
// bail out..
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token * const tok2 = *iter2;
|
||||||
|
|
||||||
|
if (tok2->str() != name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||||
|
!Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// New type..
|
||||||
|
std::vector<Token> types2;
|
||||||
|
s = "";
|
||||||
|
std::string s1(name + " < ");
|
||||||
|
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next())
|
||||||
|
{
|
||||||
|
if (!tok3->next())
|
||||||
|
{
|
||||||
|
s.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s1 += tok3->str();
|
||||||
|
s1 += " ";
|
||||||
|
if (tok3->str() != ",")
|
||||||
|
types2.push_back(*tok3);
|
||||||
|
// add additional type information
|
||||||
|
if (tok3->isUnsigned())
|
||||||
|
s += "unsigned";
|
||||||
|
else if (tok3->isSigned())
|
||||||
|
s += "signed";
|
||||||
|
if (tok3->isLong())
|
||||||
|
s += "long";
|
||||||
|
s += tok3->str();
|
||||||
|
}
|
||||||
|
s1 += ">";
|
||||||
|
const std::string type2(s);
|
||||||
|
|
||||||
|
if (type2.empty() || type.size() != types2.size())
|
||||||
|
{
|
||||||
|
if (_settings->debugwarnings)
|
||||||
|
{
|
||||||
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||||
|
loc.line = tok2->linenr();
|
||||||
|
loc.setfile(file(tok2));
|
||||||
|
locationList.push_back(loc);
|
||||||
|
|
||||||
|
const ErrorLogger::ErrorMessage errmsg(locationList,
|
||||||
|
Severity::debug,
|
||||||
|
"Failed to instantiate template. The checking continues anyway.",
|
||||||
|
"debug");
|
||||||
|
|
||||||
|
_errorLogger->reportErr(errmsg);
|
||||||
|
}
|
||||||
|
if (type2.empty())
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New classname/funcname..
|
||||||
|
const std::string name2(name + "<" + type2 + ">");
|
||||||
|
|
||||||
|
if (expandedtemplates.find(name2) == expandedtemplates.end())
|
||||||
|
{
|
||||||
|
expandedtemplates.insert(name2);
|
||||||
|
// Copy template..
|
||||||
|
int _indentlevel = 0;
|
||||||
|
int _parlevel = 0;
|
||||||
|
for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next())
|
||||||
|
{
|
||||||
|
if (tok3->str() == "{")
|
||||||
|
++_indentlevel;
|
||||||
|
else if (tok3->str() == "}")
|
||||||
|
--_indentlevel;
|
||||||
|
else if (tok3->str() == "(")
|
||||||
|
++_parlevel;
|
||||||
|
else if (tok3->str() == ")")
|
||||||
|
--_parlevel;
|
||||||
|
|
||||||
|
// Start of template..
|
||||||
|
if (tok3 == tok)
|
||||||
|
{
|
||||||
|
tok3 = tok3->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// member function implemented outside class definition
|
||||||
|
else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str()))
|
||||||
|
{
|
||||||
|
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||||
|
while (tok3->str() != "::")
|
||||||
|
tok3 = tok3->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// not part of template.. go on to next token
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int indentlevel = 0;
|
||||||
|
std::stack<Token *> braces; // holds "{" tokens
|
||||||
|
std::stack<Token *> brackets; // holds "(" tokens
|
||||||
|
std::stack<Token *> brackets2; // holds "[" tokens
|
||||||
|
|
||||||
|
for (; tok3; tok3 = tok3->next())
|
||||||
|
{
|
||||||
|
if (tok3->str() == "{")
|
||||||
|
++indentlevel;
|
||||||
|
|
||||||
|
else if (tok3->str() == "}")
|
||||||
|
{
|
||||||
|
if (indentlevel <= 1 && brackets.empty() && brackets2.empty())
|
||||||
|
{
|
||||||
|
// there is a bug if indentlevel is 0
|
||||||
|
// the "}" token should only be added if indentlevel is 1 but I add it always intentionally
|
||||||
|
// if indentlevel ever becomes 0, cppcheck will write:
|
||||||
|
// ### Error: Invalid number of character {
|
||||||
|
addtoken("}", tok3->linenr(), tok3->fileIndex());
|
||||||
|
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||||
|
braces.pop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--indentlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (tok3->isName())
|
||||||
|
{
|
||||||
|
// search for this token in the type vector
|
||||||
|
unsigned int itype = 0;
|
||||||
|
while (itype < type.size() && type[itype]->str() != tok3->str())
|
||||||
|
++itype;
|
||||||
|
|
||||||
|
// replace type with given type..
|
||||||
|
if (itype < type.size())
|
||||||
|
{
|
||||||
|
addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace name..
|
||||||
|
if (Token::Match(tok3, (name + " !!<").c_str()))
|
||||||
|
{
|
||||||
|
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy
|
||||||
|
addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
||||||
|
if (Token::Match(tok3, "%type% <"))
|
||||||
|
{
|
||||||
|
if (!Token::Match(tok3, (name + " <").c_str()))
|
||||||
|
done = false;
|
||||||
|
used.push_back(_tokensBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// link() newly tokens manually
|
||||||
|
if (tok3->str() == "{")
|
||||||
|
{
|
||||||
|
braces.push(_tokensBack);
|
||||||
|
}
|
||||||
|
else if (tok3->str() == "}")
|
||||||
|
{
|
||||||
|
assert(braces.empty() == false);
|
||||||
|
Token::createMutualLinks(braces.top(), _tokensBack);
|
||||||
|
braces.pop();
|
||||||
|
}
|
||||||
|
else if (tok3->str() == "(")
|
||||||
|
{
|
||||||
|
brackets.push(_tokensBack);
|
||||||
|
}
|
||||||
|
else if (tok3->str() == "[")
|
||||||
|
{
|
||||||
|
brackets2.push(_tokensBack);
|
||||||
|
}
|
||||||
|
else if (tok3->str() == ")")
|
||||||
|
{
|
||||||
|
assert(brackets.empty() == false);
|
||||||
|
Token::createMutualLinks(brackets.top(), _tokensBack);
|
||||||
|
brackets.pop();
|
||||||
|
}
|
||||||
|
else if (tok3->str() == "]")
|
||||||
|
{
|
||||||
|
assert(brackets2.empty() == false);
|
||||||
|
Token::createMutualLinks(brackets2.top(), _tokensBack);
|
||||||
|
brackets2.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(braces.empty());
|
||||||
|
assert(brackets.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all these template usages..
|
||||||
|
for (Token *tok4 = tok2; tok4; tok4 = tok4->next())
|
||||||
|
{
|
||||||
|
if (Token::simpleMatch(tok4, s1.c_str()))
|
||||||
|
{
|
||||||
|
bool match = true;
|
||||||
|
Token * tok5 = tok4->tokAt(2);
|
||||||
|
unsigned int count = 0;
|
||||||
|
while (tok5->str() != ">")
|
||||||
|
{
|
||||||
|
if (tok5->str() != ",")
|
||||||
|
{
|
||||||
|
if (tok5->isUnsigned() != types2[count].isUnsigned() ||
|
||||||
|
tok5->isSigned() != types2[count].isSigned() ||
|
||||||
|
tok5->isLong() != types2[count].isLong())
|
||||||
|
{
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
tok5 = tok5->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match)
|
||||||
|
{
|
||||||
|
tok4->str(name2);
|
||||||
|
while (tok4->next()->str() != ">")
|
||||||
|
{
|
||||||
|
used.remove(tok4->next());
|
||||||
|
tok4->deleteNext();
|
||||||
|
}
|
||||||
|
used.remove(tok4->next());
|
||||||
|
tok4->deleteNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// expand templates
|
||||||
bool done = false;
|
bool done = false;
|
||||||
//while (!done)
|
//while (!done)
|
||||||
{
|
{
|
||||||
done = true;
|
done = true;
|
||||||
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
||||||
{
|
{
|
||||||
Token *tok = *iter1;
|
simplifyTemplatesInstantiate(*iter1, used, expandedtemplates);
|
||||||
std::vector<const Token *> type;
|
|
||||||
for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next())
|
|
||||||
{
|
|
||||||
if (Token::Match(tok, "%var% ,|>"))
|
|
||||||
type.push_back(tok);
|
|
||||||
}
|
|
||||||
// bail out if the end of the file was reached
|
|
||||||
if (!tok)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// get the position of the template name
|
|
||||||
unsigned char namepos = 0;
|
|
||||||
if (Token::Match(tok, "> class|struct %type% {|:"))
|
|
||||||
namepos = 2;
|
|
||||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
|
||||||
namepos = 2;
|
|
||||||
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
|
||||||
namepos = 3;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// debug message that we bail out..
|
|
||||||
if (_settings->debugwarnings)
|
|
||||||
{
|
|
||||||
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::debug,
|
|
||||||
"simplifyTemplates: bailing out",
|
|
||||||
"debug");
|
|
||||||
|
|
||||||
if (_errorLogger)
|
|
||||||
_errorLogger->reportErr(errmsg);
|
|
||||||
else
|
|
||||||
Check::reportError(errmsg);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&"))
|
|
||||||
++namepos;
|
|
||||||
|
|
||||||
// name of template function/class..
|
|
||||||
const std::string name(tok->strAt(namepos));
|
|
||||||
|
|
||||||
const bool isfunc(tok->strAt(namepos + 1) == "(");
|
|
||||||
|
|
||||||
// locate template usage..
|
|
||||||
|
|
||||||
std::string s(name + " <");
|
|
||||||
for (unsigned int i = 0; i < type.size(); ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
s += ",";
|
|
||||||
s += " %any% ";
|
|
||||||
}
|
|
||||||
const std::string pattern(s + "> ");
|
|
||||||
|
|
||||||
std::string::size_type sz1 = used.size();
|
|
||||||
unsigned int recursiveCount = 0;
|
|
||||||
|
|
||||||
for (std::list<Token *>::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
|
|
||||||
{
|
|
||||||
// If the size of "used" has changed, simplify calculations
|
|
||||||
if (sz1 != used.size())
|
|
||||||
{
|
|
||||||
sz1 = used.size();
|
|
||||||
simplifyCalculations();
|
|
||||||
recursiveCount++;
|
|
||||||
if (recursiveCount > 100)
|
|
||||||
{
|
|
||||||
// bail out..
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Token * const tok2 = *iter2;
|
|
||||||
|
|
||||||
if (tok2->str() != name)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
|
||||||
!Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// New type..
|
|
||||||
std::vector<Token> types2;
|
|
||||||
s = "";
|
|
||||||
std::string s1(name + " < ");
|
|
||||||
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next())
|
|
||||||
{
|
|
||||||
if (!tok3->next())
|
|
||||||
{
|
|
||||||
s.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s1 += tok3->str();
|
|
||||||
s1 += " ";
|
|
||||||
if (tok3->str() != ",")
|
|
||||||
types2.push_back(*tok3);
|
|
||||||
// add additional type information
|
|
||||||
if (tok3->isUnsigned())
|
|
||||||
s += "unsigned";
|
|
||||||
else if (tok3->isSigned())
|
|
||||||
s += "signed";
|
|
||||||
if (tok3->isLong())
|
|
||||||
s += "long";
|
|
||||||
s += tok3->str();
|
|
||||||
}
|
|
||||||
s1 += ">";
|
|
||||||
const std::string type2(s);
|
|
||||||
|
|
||||||
if (type2.empty() || type.size() != types2.size())
|
|
||||||
{
|
|
||||||
if (_settings->debugwarnings)
|
|
||||||
{
|
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
|
||||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
|
||||||
loc.line = tok2->linenr();
|
|
||||||
loc.setfile(file(tok2));
|
|
||||||
locationList.push_back(loc);
|
|
||||||
|
|
||||||
const ErrorLogger::ErrorMessage errmsg(locationList,
|
|
||||||
Severity::debug,
|
|
||||||
"Failed to instantiate template. The checking continues anyway.",
|
|
||||||
"debug");
|
|
||||||
|
|
||||||
_errorLogger->reportErr(errmsg);
|
|
||||||
}
|
|
||||||
if (type2.empty())
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// New classname/funcname..
|
|
||||||
const std::string name2(name + "<" + type2 + ">");
|
|
||||||
|
|
||||||
if (expandedtemplates.find(name2) == expandedtemplates.end())
|
|
||||||
{
|
|
||||||
expandedtemplates.insert(name2);
|
|
||||||
// Copy template..
|
|
||||||
int _indentlevel = 0;
|
|
||||||
int _parlevel = 0;
|
|
||||||
for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next())
|
|
||||||
{
|
|
||||||
if (tok3->str() == "{")
|
|
||||||
++_indentlevel;
|
|
||||||
else if (tok3->str() == "}")
|
|
||||||
--_indentlevel;
|
|
||||||
else if (tok3->str() == "(")
|
|
||||||
++_parlevel;
|
|
||||||
else if (tok3->str() == ")")
|
|
||||||
--_parlevel;
|
|
||||||
|
|
||||||
// Start of template..
|
|
||||||
if (tok3 == tok)
|
|
||||||
{
|
|
||||||
tok3 = tok3->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// member function implemented outside class definition
|
|
||||||
else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str()))
|
|
||||||
{
|
|
||||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
|
||||||
while (tok3->str() != "::")
|
|
||||||
tok3 = tok3->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// not part of template.. go on to next token
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int indentlevel = 0;
|
|
||||||
std::stack<Token *> braces; // holds "{" tokens
|
|
||||||
std::stack<Token *> brackets; // holds "(" tokens
|
|
||||||
std::stack<Token *> brackets2; // holds "[" tokens
|
|
||||||
|
|
||||||
for (; tok3; tok3 = tok3->next())
|
|
||||||
{
|
|
||||||
if (tok3->str() == "{")
|
|
||||||
++indentlevel;
|
|
||||||
|
|
||||||
else if (tok3->str() == "}")
|
|
||||||
{
|
|
||||||
if (indentlevel <= 1 && brackets.empty() && brackets2.empty())
|
|
||||||
{
|
|
||||||
// there is a bug if indentlevel is 0
|
|
||||||
// the "}" token should only be added if indentlevel is 1 but I add it always intentionally
|
|
||||||
// if indentlevel ever becomes 0, cppcheck will write:
|
|
||||||
// ### Error: Invalid number of character {
|
|
||||||
addtoken("}", tok3->linenr(), tok3->fileIndex());
|
|
||||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
|
||||||
braces.pop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
--indentlevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (tok3->isName())
|
|
||||||
{
|
|
||||||
// search for this token in the type vector
|
|
||||||
unsigned int itype = 0;
|
|
||||||
while (itype < type.size() && type[itype]->str() != tok3->str())
|
|
||||||
++itype;
|
|
||||||
|
|
||||||
// replace type with given type..
|
|
||||||
if (itype < type.size())
|
|
||||||
{
|
|
||||||
addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace name..
|
|
||||||
if (Token::Match(tok3, (name + " !!<").c_str()))
|
|
||||||
{
|
|
||||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy
|
|
||||||
addtoken(tok3, tok3->linenr(), tok3->fileIndex());
|
|
||||||
if (Token::Match(tok3, "%type% <"))
|
|
||||||
{
|
|
||||||
if (!Token::Match(tok3, (name + " <").c_str()))
|
|
||||||
done = false;
|
|
||||||
used.push_back(_tokensBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
// link() newly tokens manually
|
|
||||||
if (tok3->str() == "{")
|
|
||||||
{
|
|
||||||
braces.push(_tokensBack);
|
|
||||||
}
|
|
||||||
else if (tok3->str() == "}")
|
|
||||||
{
|
|
||||||
assert(braces.empty() == false);
|
|
||||||
Token::createMutualLinks(braces.top(), _tokensBack);
|
|
||||||
braces.pop();
|
|
||||||
}
|
|
||||||
else if (tok3->str() == "(")
|
|
||||||
{
|
|
||||||
brackets.push(_tokensBack);
|
|
||||||
}
|
|
||||||
else if (tok3->str() == "[")
|
|
||||||
{
|
|
||||||
brackets2.push(_tokensBack);
|
|
||||||
}
|
|
||||||
else if (tok3->str() == ")")
|
|
||||||
{
|
|
||||||
assert(brackets.empty() == false);
|
|
||||||
Token::createMutualLinks(brackets.top(), _tokensBack);
|
|
||||||
brackets.pop();
|
|
||||||
}
|
|
||||||
else if (tok3->str() == "]")
|
|
||||||
{
|
|
||||||
assert(brackets2.empty() == false);
|
|
||||||
Token::createMutualLinks(brackets2.top(), _tokensBack);
|
|
||||||
brackets2.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(braces.empty());
|
|
||||||
assert(brackets.empty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace all these template usages..
|
|
||||||
for (Token *tok4 = tok2; tok4; tok4 = tok4->next())
|
|
||||||
{
|
|
||||||
if (Token::simpleMatch(tok4, s1.c_str()))
|
|
||||||
{
|
|
||||||
bool match = true;
|
|
||||||
Token * tok5 = tok4->tokAt(2);
|
|
||||||
unsigned int count = 0;
|
|
||||||
while (tok5->str() != ">")
|
|
||||||
{
|
|
||||||
if (tok5->str() != ",")
|
|
||||||
{
|
|
||||||
if (tok5->isUnsigned() != types2[count].isUnsigned() ||
|
|
||||||
tok5->isSigned() != types2[count].isSigned() ||
|
|
||||||
tok5->isLong() != types2[count].isLong())
|
|
||||||
{
|
|
||||||
match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
tok5 = tok5->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match)
|
|
||||||
{
|
|
||||||
tok4->str(name2);
|
|
||||||
while (tok4->next()->str() != ">")
|
|
||||||
{
|
|
||||||
used.remove(tok4->next());
|
|
||||||
tok4->deleteNext();
|
|
||||||
}
|
|
||||||
used.remove(tok4->next());
|
|
||||||
tok4->deleteNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8725,7 +8748,7 @@ void Tokenizer::simplifyStructDecl()
|
||||||
}
|
}
|
||||||
|
|
||||||
// unnamed anonymous struct/union so remove it
|
// unnamed anonymous struct/union so remove it
|
||||||
else if (tok->next()->str() == ";")
|
else if (tok->next() && tok->next()->str() == ";")
|
||||||
{
|
{
|
||||||
if (tok1->str() == "union")
|
if (tok1->str() == "union")
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
class Token;
|
class Token;
|
||||||
class ErrorLogger;
|
class ErrorLogger;
|
||||||
|
@ -395,6 +397,43 @@ public:
|
||||||
*/
|
*/
|
||||||
void simplifyTemplates();
|
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.
|
* Used after simplifyTemplates to perform a little cleanup.
|
||||||
* Sometimes the simplifyTemplates isn't fully successful and then
|
* 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>
|
<term><option>--suppressions-list=<file></option></term>
|
||||||
<listitem>
|
<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].
|
<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>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<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
|
line flag. Copy and paste the <literal>id</literal> string from the XML
|
||||||
output.</para>
|
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>
|
<para>Here is an example:</para>
|
||||||
|
|
||||||
<programlisting>memleak:file1.cpp
|
<programlisting>memleak:file1.cpp
|
||||||
|
|
|
@ -47,6 +47,10 @@ private:
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
|
CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this);
|
||||||
|
checkAutoVariables.runChecks(&tokenizer, &settings, this);
|
||||||
|
|
||||||
tokenizer.simplifyTokenList();
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
// Assign variable ids
|
// Assign variable ids
|
||||||
|
@ -56,10 +60,8 @@ private:
|
||||||
tokenizer.fillFunctionList();
|
tokenizer.fillFunctionList();
|
||||||
|
|
||||||
// Check auto variables
|
// Check auto variables
|
||||||
CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this);
|
|
||||||
checkAutoVariables.autoVariables();
|
checkAutoVariables.autoVariables();
|
||||||
checkAutoVariables.returnPointerToLocalArray();
|
checkAutoVariables.returnPointerToLocalArray();
|
||||||
checkAutoVariables.returnReference();
|
|
||||||
checkAutoVariables.returncstr();
|
checkAutoVariables.returncstr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +83,7 @@ private:
|
||||||
// return reference..
|
// return reference..
|
||||||
TEST_CASE(returnReference1);
|
TEST_CASE(returnReference1);
|
||||||
TEST_CASE(returnReference2);
|
TEST_CASE(returnReference2);
|
||||||
|
TEST_CASE(returnReference3);
|
||||||
|
|
||||||
// return c_str()..
|
// return c_str()..
|
||||||
TEST_CASE(returncstr1);
|
TEST_CASE(returncstr1);
|
||||||
|
@ -351,6 +354,16 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:11]: (error) Returning reference to temporary\n", errout.str());
|
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()
|
void returncstr1()
|
||||||
{
|
{
|
||||||
check("const char *foo()\n"
|
check("const char *foo()\n"
|
||||||
|
|
|
@ -84,7 +84,6 @@ private:
|
||||||
TEST_CASE(array_index_7);
|
TEST_CASE(array_index_7);
|
||||||
TEST_CASE(array_index_8);
|
TEST_CASE(array_index_8);
|
||||||
TEST_CASE(array_index_9);
|
TEST_CASE(array_index_9);
|
||||||
TEST_CASE(array_index_10);
|
|
||||||
TEST_CASE(array_index_11);
|
TEST_CASE(array_index_11);
|
||||||
TEST_CASE(array_index_12);
|
TEST_CASE(array_index_12);
|
||||||
TEST_CASE(array_index_13);
|
TEST_CASE(array_index_13);
|
||||||
|
@ -135,6 +134,7 @@ private:
|
||||||
TEST_CASE(buffer_overrun_15); // ticket #1787
|
TEST_CASE(buffer_overrun_15); // ticket #1787
|
||||||
TEST_CASE(buffer_overrun_16);
|
TEST_CASE(buffer_overrun_16);
|
||||||
TEST_CASE(buffer_overrun_17); // ticket #2548
|
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
|
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
|
||||||
|
|
||||||
// It is undefined behaviour to point out of bounds of an array
|
// 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()
|
void array_index_11()
|
||||||
{
|
{
|
||||||
check("class ABC\n"
|
check("class ABC\n"
|
||||||
|
@ -1883,6 +1862,21 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer access out-of-bounds\n", errout.str());
|
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()
|
void buffer_overrun_bailoutIfSwitch()
|
||||||
{
|
{
|
||||||
// No false positive
|
// No false positive
|
||||||
|
|
|
@ -191,6 +191,7 @@ private:
|
||||||
TEST_CASE(symboldatabase10); // ticket #2537
|
TEST_CASE(symboldatabase10); // ticket #2537
|
||||||
TEST_CASE(symboldatabase11); // ticket #2539
|
TEST_CASE(symboldatabase11); // ticket #2539
|
||||||
TEST_CASE(symboldatabase12); // ticket #2547
|
TEST_CASE(symboldatabase12); // ticket #2547
|
||||||
|
TEST_CASE(symboldatabase13); // ticket #2577
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the operator Equal
|
// Check the operator Equal
|
||||||
|
@ -5528,6 +5529,16 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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)
|
REGISTER_TEST(TestClass)
|
||||||
|
|
|
@ -1157,14 +1157,12 @@ private:
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int x = x;\n"
|
" int x = x;\n"
|
||||||
" return 0;\n"
|
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"x\" to itself\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"x\" to itself\n", errout.str());
|
||||||
|
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" std::string var = var = \"test\";\n"
|
" std::string var = var = \"test\";\n"
|
||||||
" return 0;\n"
|
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"var\" to itself\n", "", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"var\" to itself\n", "", errout.str());
|
||||||
|
|
||||||
|
@ -1182,6 +1180,13 @@ private:
|
||||||
" *x = x;\n"
|
" *x = x;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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()
|
void testScanf1()
|
||||||
|
|
|
@ -1233,21 +1233,43 @@ private:
|
||||||
|
|
||||||
void if_cond7()
|
void if_cond7()
|
||||||
{
|
{
|
||||||
const char filedata[] = "#define A 1\n"
|
{
|
||||||
"#if A==1\n"
|
const char filedata[] = "#define A 1\n"
|
||||||
"a1;\n"
|
"#if A==1\n"
|
||||||
"#endif\n";
|
"a1;\n"
|
||||||
|
"#endif\n";
|
||||||
|
|
||||||
// Preprocess => actual result..
|
// Preprocess => actual result..
|
||||||
std::istringstream istr(filedata);
|
std::istringstream istr(filedata);
|
||||||
std::map<std::string, std::string> actual;
|
std::map<std::string, std::string> actual;
|
||||||
Settings settings;
|
Settings settings;
|
||||||
Preprocessor preprocessor(&settings, this);
|
Preprocessor preprocessor(&settings, this);
|
||||||
preprocessor.preprocess(istr, actual, "file.c");
|
preprocessor.preprocess(istr, actual, "file.c");
|
||||||
|
|
||||||
// Compare results..
|
// Compare results..
|
||||||
ASSERT_EQUALS(1, (int)actual.size());
|
ASSERT_EQUALS(1, (int)actual.size());
|
||||||
ASSERT_EQUALS("\n\na1;\n\n", actual[""]);
|
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[""]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ private:
|
||||||
TEST_CASE(suppressionsBadId1);
|
TEST_CASE(suppressionsBadId1);
|
||||||
TEST_CASE(suppressionsDosFormat); // Ticket #1836
|
TEST_CASE(suppressionsDosFormat); // Ticket #1836
|
||||||
TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon
|
TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon
|
||||||
|
TEST_CASE(suppressionsGlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
void suppressionsBadId1()
|
void suppressionsBadId1()
|
||||||
|
@ -63,6 +64,41 @@ private:
|
||||||
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 10));
|
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 10));
|
||||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 12));
|
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)
|
REGISTER_TEST(TestSettings)
|
||||||
|
|
|
@ -304,7 +304,8 @@ private:
|
||||||
TEST_CASE(initstruct);
|
TEST_CASE(initstruct);
|
||||||
|
|
||||||
// struct ABC { } abc; => struct ABC { }; ABC abc;
|
// struct ABC { } abc; => struct ABC { }; ABC abc;
|
||||||
TEST_CASE(simplifyStructDecl);
|
TEST_CASE(simplifyStructDecl1);
|
||||||
|
TEST_CASE(simplifyStructDecl2); // ticket #2579
|
||||||
|
|
||||||
// register int var; => int var;
|
// register int var; => int var;
|
||||||
// inline int foo() {} => int foo() {}
|
// inline int foo() {} => int foo() {}
|
||||||
|
@ -6222,7 +6223,7 @@ private:
|
||||||
tok("; struct A a = { .buf = {0} };"));
|
tok("; struct A a = { .buf = {0} };"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplifyStructDecl()
|
void simplifyStructDecl1()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const char code[] = "struct ABC { } abc;";
|
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()
|
void removeUnwantedKeywords()
|
||||||
{
|
{
|
||||||
ASSERT_EQUALS("int var ;", tok("register int var ;", true));
|
ASSERT_EQUALS("int var ;", tok("register int var ;", true));
|
||||||
|
|
|
@ -264,6 +264,7 @@ private:
|
||||||
TEST_CASE(removeattribute);
|
TEST_CASE(removeattribute);
|
||||||
TEST_CASE(cpp0xtemplate1);
|
TEST_CASE(cpp0xtemplate1);
|
||||||
TEST_CASE(cpp0xtemplate2);
|
TEST_CASE(cpp0xtemplate2);
|
||||||
|
TEST_CASE(cpp0xtemplate3);
|
||||||
TEST_CASE(cpp0xdefault);
|
TEST_CASE(cpp0xdefault);
|
||||||
|
|
||||||
TEST_CASE(arraySize);
|
TEST_CASE(arraySize);
|
||||||
|
@ -4634,6 +4635,18 @@ private:
|
||||||
"list < list < int >> ints ;", tokenizeAndStringify(code));
|
"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()
|
void cpp0xdefault()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,6 +46,7 @@ private:
|
||||||
TEST_CASE(uninitvar_references); // references
|
TEST_CASE(uninitvar_references); // references
|
||||||
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
|
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate
|
||||||
TEST_CASE(uninitvar_func); // analyse functions
|
TEST_CASE(uninitvar_func); // analyse functions
|
||||||
|
TEST_CASE(uninitvar_func2); // usage of 'void a(int *p) { *p = 0; }'
|
||||||
TEST_CASE(uninitvar_typeof); // typeof
|
TEST_CASE(uninitvar_typeof); // typeof
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,6 +1421,28 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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()
|
void uninitvar_typeof()
|
||||||
{
|
{
|
||||||
checkUninitVar("void f() {\n"
|
checkUninitVar("void f() {\n"
|
||||||
|
|
Loading…
Reference in New Issue