This commit is contained in:
root 2011-02-21 20:03:09 +01:00
commit b02919ae67
18 changed files with 629 additions and 196 deletions

View File

@ -992,7 +992,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
}
// Check function call..
if (Token::Match(tok, "%var% ("))
if (Token::Match(tok, "%var% (") && total_size > 0)
{
// No varid => function calls are not handled
if (varid == 0)
@ -1405,7 +1405,7 @@ void CheckBufferOverrun::checkStructVariable()
const std::string &structname = tok->next()->str();
const Token *tok2 = tok;
while (tok2->str() != "{")
while (tok2 && tok2->str() != "{")
tok2 = tok2->next();
// Found a struct declaration. Search for arrays..

View File

@ -640,9 +640,7 @@ void CheckClass::privateFunctions()
// Check that all private functions are used..
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func)
{
const Token *ftok = func->arg->link()->next();
while (ftok->str() != "{")
ftok = ftok->next();
const Token *ftok = func->start;
const Token *etok = ftok->link();
for (; ftok != etok; ftok = ftok->next())
@ -869,10 +867,12 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co
}
}
// check of *this is returned
// check if *this is returned
else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") ||
Token::Match(tok->tokAt(1), "(| * this +=") ||
Token::simpleMatch(tok->tokAt(1), "operator= (")))
Token::simpleMatch(tok->tokAt(1), "operator= (") ||
(Token::Match(tok->tokAt(1), "%type% :: operator= (") &&
tok->next()->str() == scope->className)))
operatorEqRetRefThisError(func->token);
}
}
@ -1351,7 +1351,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok)
{
const Token *tok1 = tok;
while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?"))
while (tok->previous() && !Token::Match(tok->previous(), "}|{|;(||public:|protected:|private:|return|:|?"))
{
if (Token::simpleMatch(tok->previous(), "* this"))
return true;
@ -1489,6 +1489,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Token *tok)
isconst = false;
break;
}
else if (Token::simpleMatch(tok1->previous(), ") <<") &&
isMemberVar(scope, tok1->tokAt(-2)))
{
isconst = false;
break;
}
// increment/decrement (member variable?)..
else if (Token::Match(tok1, "++|--"))

View File

@ -350,8 +350,19 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
continue;
}
/**
* @todo There are lots of false negatives here. A dereference
* is only investigated if a few specific conditions are met.
*/
// dereference in assignment
if (Token::Match(tok1, "[{};] %var% = %var% . %var%"))
if (Token::Match(tok1, "[;{}] %var% . %var%"))
{
tok1 = tok1->next();
}
// dereference in assignment
else if (Token::Match(tok1, "[{};] %var% = %var% . %var%"))
{
if (std::string(tok1->strAt(1)) == tok1->strAt(3))
continue;
@ -433,8 +444,8 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
break;
// Check if pointer is null.
// TODO: false negatives for something like: "if (p &&.."?
else if (Token::Match(tok2, "if ( !| %varid% )", varid1))
// TODO: false negatives for "if (!p || .."
else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1))
{
// Is this variable a pointer?
if (isPointer(varid1))
@ -563,14 +574,13 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
// vartok : token for the variable
const Token *vartok = 0;
if (Token::Match(tok, "if ( ! %var% ) {"))
if (Token::Match(tok, "if ( ! %var% )|&&"))
vartok = tok->tokAt(3);
else if (Token::Match(tok, "if ( NULL|0 == %var% ) {"))
else if (Token::Match(tok, "if ( NULL|0 == %var% )|&&"))
vartok = tok->tokAt(4);
else if (Token::Match(tok, "if ( %var% == NULL|0 ) {"))
else if (Token::Match(tok, "if ( %var% == NULL|0 )|&&"))
vartok = tok->tokAt(2);
else if (Token::Match(tok, "if|while ( %var% ) {") &&
!Token::simpleMatch(tok->tokAt(4)->link(), "} else"))
else if (Token::Match(tok, "if|while ( %var% )|&&"))
vartok = tok->tokAt(2);
else
continue;
@ -590,7 +600,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
// start token = inside the if-body
const Token *tok1 = tok->next()->link()->tokAt(2);
if (Token::Match(tok, "if|while ( %var% )"))
if (Token::Match(tok, "if|while ( %var% )|&&"))
{
// pointer might be null
null = false;

View File

@ -321,7 +321,7 @@ void CheckOther::checkSelfAssignment()
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), "[,);]"))
if (tok->isStandardType() && Token::Match(tok->tokAt(2), "[,);]") && tok->next()->varId())
pod.insert(tok->next()->varId());
}

View File

@ -275,6 +275,40 @@ void ExecutionPath::checkScope(const Token *tok, std::list<ExecutionPath *> &che
++it;
}
// #2231 - loop body only contains a conditional initialization..
if (Token::simpleMatch(tok2->next(), "if ("))
{
// Start { for the if block
const Token *tok3 = tok2->tokAt(2)->link();
if (Token::simpleMatch(tok3,") {"))
{
tok3 = tok3->next();
// End } for the if block
const Token *tok4 = tok3->link();
if (Token::Match(tok3, "{ %var% =") &&
Token::simpleMatch(tok4, "} }") &&
Token::simpleMatch(tok4->tokAt(-2), "break ;"))
{
// Is there a assignment and then a break?
const Token *t = Token::findmatch(tok3, ";");
if (t && t->tokAt(3) == tok4)
{
for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end(); ++it)
{
if ((*it)->varId == tok3->next()->varId())
{
(*it)->numberOfIf++;
break;
}
}
tok = tok2->link();
continue;
}
}
}
}
// parse loop bodies
check->parseLoopBody(tok2->next(), checks);
}

View File

@ -338,20 +338,32 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
continue;
}
// We have finished a line that didn't contain any comment
// (the '\n' is swallowed when a // comment is detected)
if ((ch == '\n' || str.compare(i,2,"//")==0) && !suppressionIDs.empty())
// First skip over any whitespace that may be present
if (std::isspace(ch))
{
// Add the suppressions.
for (size_t j(0); j < suppressionIDs.size(); ++j)
if (ch == ' ' && previous == ' ')
{
const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno));
if (!errmsg.empty())
// Skip double white space
}
else
{
code << char(ch);
previous = ch;
}
// if there has been <backspace><newline> sequences, add extra newlines..
if (ch == '\n')
{
++lineno;
if (newlines > 0)
{
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
code << std::string(newlines, '\n');
newlines = 0;
previous = '\n';
}
}
suppressionIDs.clear();
continue;
}
// Remove comments..
@ -382,6 +394,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
}
else if (str.compare(i, 2, "/*", 0, 2) == 0)
{
size_t commentStart = i + 2;
unsigned char chPrev = 0;
++i;
while (i < str.length() && (chPrev != '*' || ch != '/'))
@ -395,126 +408,139 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
++lineno;
}
}
}
// String or char constants..
else if (ch == '\"' || ch == '\'')
{
code << char(ch);
char chNext;
do
if (settings && settings->_inlineSuppressions)
{
++i;
chNext = str[i];
if (chNext == '\\')
std::string comment(str, commentStart, i - commentStart);
std::istringstream iss(comment);
std::string word;
iss >> word;
if (word == "cppcheck-suppress")
{
iss >> word;
if (iss)
suppressionIDs.push_back(word);
}
}
}
else
{
// Not whitespace and not a comment. Must be code here!
// Add any pending inline suppressions that have accumulated.
if (!suppressionIDs.empty())
{
if (settings != NULL)
{
// Add the suppressions.
for (size_t j(0); j < suppressionIDs.size(); ++j)
{
const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno));
if (!errmsg.empty())
{
writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg);
}
}
}
suppressionIDs.clear();
}
// String or char constants..
if (ch == '\"' || ch == '\'')
{
code << char(ch);
char chNext;
do
{
++i;
char chSeq = str[i];
if (chSeq == '\n')
++newlines;
chNext = str[i];
if (chNext == '\\')
{
++i;
char chSeq = str[i];
if (chSeq == '\n')
++newlines;
else
{
code << chNext;
code << chSeq;
previous = static_cast<unsigned char>(chSeq);
}
}
else
{
code << chNext;
code << chSeq;
previous = static_cast<unsigned char>(chSeq);
previous = static_cast<unsigned char>(chNext);
}
}
while (i < str.length() && chNext != ch && chNext != '\n');
}
// Rawstring..
else if (str.compare(i,2,"R\"")==0)
{
std::string delim;
for (std::string::size_type i2 = i+2; i2 < str.length(); ++i2)
{
if (i2 > 16 ||
std::isspace(str[i2]) ||
std::iscntrl(str[i2]) ||
str[i2] == ')' ||
str[i2] == '\\')
{
delim = " ";
break;
}
else if (str[i2] == '(')
break;
delim += str[i2];
}
const std::string::size_type endpos = str.find(")" + delim + "\"", i);
if (delim != " " && endpos != std::string::npos)
{
unsigned int rawstringnewlines = 0;
code << '\"';
for (std::string::size_type p = i + 3 + delim.size(); p < endpos; ++p)
{
if (str[p] == '\n')
{
rawstringnewlines++;
code << "\\n";
}
else if (std::iscntrl((unsigned char)str[p]) ||
std::isspace((unsigned char)str[p]))
{
code << " ";
}
else if (str[p] == '\\')
{
code << "\\";
}
else if (str[p] == '\"' || str[p] == '\'')
{
code << "\\" << (char)str[p];
}
else
{
code << (char)str[p];
}
}
code << "\"";
if (rawstringnewlines > 0)
code << std::string(rawstringnewlines, '\n');
i = endpos + delim.size() + 2;
}
else
{
code << chNext;
previous = static_cast<unsigned char>(chNext);
code << "R";
previous = 'R';
}
}
while (i < str.length() && chNext != ch && chNext != '\n');
}
// Rawstring..
else if (str.compare(i,2,"R\"")==0)
{
std::string delim;
for (std::string::size_type i2 = i+2; i2 < str.length(); ++i2)
{
if (i2 > 16 ||
std::isspace(str[i2]) ||
std::iscntrl(str[i2]) ||
str[i2] == ')' ||
str[i2] == '\\')
{
delim = " ";
break;
}
else if (str[i2] == '(')
break;
delim += str[i2];
}
const std::string::size_type endpos = str.find(")" + delim + "\"", i);
if (delim != " " && endpos != std::string::npos)
{
unsigned int rawstringnewlines = 0;
code << '\"';
for (std::string::size_type p = i + 3 + delim.size(); p < endpos; ++p)
{
if (str[p] == '\n')
{
rawstringnewlines++;
code << "\\n";
}
else if (std::iscntrl((unsigned char)str[p]) ||
std::isspace((unsigned char)str[p]))
{
code << " ";
}
else if (str[p] == '\\')
{
code << "\\";
}
else if (str[p] == '\"' || str[p] == '\'')
{
code << "\\" << (char)str[p];
}
else
{
code << (char)str[p];
}
}
code << "\"";
if (rawstringnewlines > 0)
code << std::string(rawstringnewlines, '\n');
i = endpos + delim.size() + 2;
}
else
{
code << "R";
previous = 'R';
}
}
// Just some code..
else
{
if (ch == ' ' && previous == ' ')
{
// Skip double white space
}
else
{
code << char(ch);
previous = ch;
}
// if there has been <backspace><newline> sequences, add extra newlines..
if (ch == '\n')
{
++lineno;
if (newlines > 0)
{
code << std::string(newlines, '\n');
newlines = 0;
previous = '\n';
}
}
}
}
@ -1304,7 +1330,33 @@ void Preprocessor::simplifyCondition(const std::map<std::string, std::string> &v
if (it != variables.end())
{
if (!it->second.empty())
tok->str(it->second);
{
// Tokenize the value
Tokenizer tokenizer2(&settings,NULL);
std::istringstream istr2(it->second);
tokenizer2.tokenize(istr2,"","",true);
// Copy the value tokens
std::stack<Token *> link;
for (const Token *tok2 = tokenizer2.tokens(); tok2; tok2 = tok2->next())
{
tok->str(tok2->str());
if (Token::Match(tok2,"[{([]"))
link.push(tok);
else if (!link.empty() && Token::Match(tok2,"[})]]"))
{
Token::createMutualLinks(link.top(), tok);
link.pop();
}
if (tok2->next())
{
tok->insertToken("");
tok = tok->next();
}
}
}
else if ((!tok->previous() || tok->strAt(-1) == "||" || tok->strAt(-1) == "&&" || tok->strAt(-1) == "(") &&
(!tok->next() || tok->strAt(1) == "||" || tok->strAt(1) == "&&" || tok->strAt(1) == ")"))
tok->str("1");

View File

@ -57,6 +57,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// goto initial '{'
tok2 = initBaseInfo(new_scope, tok);
// make sure we have valid code
if (!tok2)
{
delete new_scope;
break;
}
}
new_scope->classStart = tok2;
@ -213,7 +220,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.isConst = true;
// pure virtual function
if (Token::Match(end, ") const| = %any% ;"))
if (Token::Match(end, ") const| = %any%"))
function.isPure = true;
// count the number of constructors
@ -241,6 +248,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.isInline = true;
function.hasBody = true;
// find start of function '{'
while (end && end->str() != "{")
end = end->next();
// save start of function
function.start = end;
scope->functionList.push_back(function);
const Token *tok2 = funcStart;
@ -761,6 +775,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token *
func->hasBody = true;
func->token = *tok;
func->arg = argStart;
const Token *start = argStart->link()->next();
while (start && start->str() != "{")
start = start->next();
func->start = start;
}
}
else if (func->tokenDef->str() == (*tok)->str() && (*tok)->previous()->str() != "~")
@ -776,6 +794,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token *
func->hasBody = true;
func->token = *tok;
func->arg = argStart;
const Token *start = argStart->link()->next();
while (start && start->str() != "{")
start = start->next();
func->start = start;
}
}
@ -786,6 +808,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token *
func->hasBody = true;
func->token = *tok;
func->arg = argStart;
const Token *start = argStart->link()->next()->next()->link()->next();
while (start && start->str() != "{")
start = start->next();
func->start = start;
}
}
}
@ -872,6 +898,10 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok)
tok2 = tok2->next();
// check for invalid code
if (!tok2->next())
return NULL;
if (tok2->str() == "public")
{
base.access = Public;
@ -1142,6 +1172,7 @@ void Scope::getVariableList()
// This is the start of a statement
const Token *vartok = NULL;
const Token *typetok = NULL;
const Token *typestart = tok;
// Is it const..?
bool isConst = false;
@ -1211,7 +1242,7 @@ void Scope::getVariableList()
if (typetok)
scope = check->findVariableType(this, typetok);
addVariable(vartok, varaccess, isMutable, isStatic, isConst, isClass, scope);
addVariable(vartok, typestart, varaccess, isMutable, isStatic, isConst, isClass, scope);
}
}
}
@ -1422,7 +1453,8 @@ Scope * Scope::findInNestedListRecursive(const std::string & name)
for (it = nestedList.begin(); it != nestedList.end(); ++it)
{
Scope *child = (*it)->findInNestedListRecursive(name);
return child;
if (child)
return child;
}
return 0;
}

View File

@ -73,10 +73,11 @@ class Variable
}
public:
Variable(const Token *name_, std::size_t index_, AccessControl access_,
bool mutable_, bool static_, bool const_, bool class_,
const Scope *type_)
Variable(const Token *name_, const Token *start_, std::size_t index_,
AccessControl access_, bool mutable_, bool static_, bool const_,
bool class_, const Scope *type_)
: _name(name_),
_start(start_),
_index(index_),
_access(access_),
_flags(0),
@ -97,6 +98,15 @@ public:
return _name;
}
/**
* Get type start token.
* @return type start token
*/
const Token *typeStartToken() const
{
return _start;
}
/**
* Get name string.
* @return name string
@ -200,6 +210,9 @@ private:
/** @brief variable name token */
const Token *_name;
/** @brief variable type start token */
const Token *_start;
/** @brief order declared */
std::size_t _index;
@ -223,6 +236,7 @@ public:
argDef(NULL),
token(NULL),
arg(NULL),
start(NULL),
access(Public),
hasBody(false),
isInline(false),
@ -245,6 +259,7 @@ public:
const Token *argDef; // function argument start '(' in class definition
const Token *token; // function name token in implementation
const Token *arg; // function argument start '('
const Token *start; // function start '{'
AccessControl access; // public/protected/private
bool hasBody; // has implementation
bool isInline; // implementation in class definition
@ -317,9 +332,9 @@ public:
*/
Scope * findInNestedListRecursive(const std::string & name);
void addVariable(const Token *token_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_)
void addVariable(const Token *token_, const Token *start_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_)
{
varlist.push_back(Variable(token_, varlist.size(), access_, mutable_, static_, const_, class_, type_));
varlist.push_back(Variable(token_, start_, varlist.size(), access_, mutable_, static_, const_, class_, type_));
}
/** @brief initialize varlist */

View File

@ -1,4 +1,4 @@
/*
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2011 Daniel Marjamäki and Cppcheck team.
*
@ -837,19 +837,29 @@ static Token *splitDefinitionFromTypedef(Token *tok)
tok1->insertToken(";");
tok1 = tok1->next();
tok1->insertToken("typedef");
tok1 = tok1->next();
Token * tok3 = tok1;
if (isConst)
if (tok1->next()->str() == ";" && tok1 && tok1->previous()->str() == "}")
{
tok1->insertToken("const");
tok1 = tok1->next();
tok->deleteThis();
tok1->deleteThis();
return NULL;
}
else
{
tok1->insertToken("typedef");
tok1 = tok1->next();
Token * tok3 = tok1;
if (isConst)
{
tok1->insertToken("const");
tok1 = tok1->next();
}
tok1->insertToken(tok->next()->str()); // struct, union or enum
tok1 = tok1->next();
tok1->insertToken(name.c_str());
tok->deleteThis();
tok = tok3;
}
tok1->insertToken(tok->next()->str()); // struct, union or enum
tok1 = tok1->next();
tok1->insertToken(name.c_str());
tok->deleteThis();
tok = tok3;
return tok;
}
@ -2457,21 +2467,31 @@ void Tokenizer::labels()
* is the token pointing at a template parameters block
* < int , 3 > => yes
* \param tok start token that must point at "<"
* \return true if the tokens look like template parameters
* \return number of parameters (invalid parameters => 0)
*/
static bool templateParameters(const Token *tok)
static unsigned int templateParameters(const Token *tok)
{
unsigned int numberOfParameters = 0;
if (!tok)
return false;
return 0;
if (tok->str() != "<")
return false;
return 0;
tok = tok->next();
while (tok)
{
++numberOfParameters;
// skip std::
while (Token::Match(tok, "%var% ::"))
tok = tok->tokAt(2);
if (!tok)
return 0;
// num/type ..
if (!tok->isNumber() && !tok->isName())
return false;
return 0;
tok = tok->next();
// optional "*"
@ -2480,12 +2500,12 @@ static bool templateParameters(const Token *tok)
// ,/>
if (tok->str() == ">")
return true;
return numberOfParameters;
if (tok->str() != ",")
break;
tok = tok->next();
}
return false;
return 0;
}
@ -2768,6 +2788,33 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list<Token
}
}
/**
* Match template declaration/instantiation
* @param instance template instantiation
* @param name name of template
* @param numberOfArguments number of template arguments
* @param patternAfter pattern that must match the tokens after the ">"
* @return match => true
*/
static bool simplifyTemplatesInstantiateMatch(const Token *instance, const std::string &name, unsigned int numberOfArguments, const char patternAfter[])
{
if (!Token::simpleMatch(instance, (name + " <").c_str()))
return false;
if (numberOfArguments != templateParameters(instance->next()))
return false;
if (patternAfter)
{
const Token *tok = Token::findmatch(instance, ">");
if (!tok || !Token::Match(tok->next(), patternAfter))
return false;
}
// nothing mismatching was found..
return true;
}
void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
std::list<Token *> &used,
std::set<std::string> &expandedtemplates)
@ -2826,16 +2873,6 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
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;
@ -2855,17 +2892,16 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
}
Token * const tok2 = *iter2;
if (tok2->str() != name)
continue;
if (Token::Match(tok2->previous(), "[;{}=]") &&
!Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str()))
!simplifyTemplatesInstantiateMatch(*iter2, name, type.size(), isfunc ? "(" : "*| %var%"))
continue;
// New type..
std::vector<Token> types2;
s = "";
std::vector<const Token *> types2;
std::string s;
std::string s1(name + " < ");
for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next())
{
@ -2876,8 +2912,8 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
}
s1 += tok3->str();
s1 += " ";
if (tok3->str() != ",")
types2.push_back(*tok3);
if (Token::Match(tok3->previous(), "[<,]"))
types2.push_back(tok3);
// add additional type information
if (tok3->isUnsigned())
s += "unsigned";
@ -2939,7 +2975,9 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
}
// member function implemented outside class definition
else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str()))
else if (_indentlevel == 0 &&
_parlevel == 0 &&
simplifyTemplatesInstantiateMatch(tok3, name, type.size(), ":: ~| %var% ("))
{
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
while (tok3->str() != "::")
@ -2987,7 +3025,12 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
// replace type with given type..
if (itype < type.size())
{
addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex());
for (const Token *typetok = types2[itype];
typetok && !Token::Match(typetok, "[,>]");
typetok = typetok->next())
{
addtoken(typetok, tok3->linenr(), tok3->fileIndex());
}
continue;
}
}
@ -3055,18 +3098,26 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok,
bool match = true;
Token * tok5 = tok4->tokAt(2);
unsigned int count = 0;
const Token *typetok = (!types2.empty()) ? types2[0] : 0;
while (tok5->str() != ">")
{
if (tok5->str() != ",")
{
if (tok5->isUnsigned() != types2[count].isUnsigned() ||
tok5->isSigned() != types2[count].isSigned() ||
tok5->isLong() != types2[count].isLong())
if (!typetok ||
tok5->isUnsigned() != typetok->isUnsigned() ||
tok5->isSigned() != typetok->isSigned() ||
tok5->isLong() != typetok->isLong())
{
match = false;
break;
}
count++;
typetok = typetok ? typetok->next() : 0;
}
else
{
++count;
typetok = (count < types2.size()) ? types2[count] : 0;
}
tok5 = tok5->next();
}
@ -6257,7 +6308,7 @@ bool Tokenizer::simplifyKnownVariables()
if (tok2->str() == tok2->strAt(2))
continue;
const bool pointeralias(tok2->tokAt(2)->isName() || tok2->tokAt(2)->str() == "&");
const Token * const valueToken = tok2->tokAt(2);
std::string value;
unsigned int valueVarId = 0;
@ -6268,7 +6319,7 @@ bool Tokenizer::simplifyKnownVariables()
if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end()))
continue;
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, pointeralias, indentlevel);
ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel);
}
}
@ -6360,8 +6411,10 @@ bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2,
return true;
}
bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel)
bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel)
{
const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% ["));
bool ret = false;
Token* bailOutFromLoop = 0;
@ -6540,6 +6593,11 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign
tok3->deleteNext();
tok3->deleteNext();
}
if (Token::Match(valueToken, "& %var% ;"))
{
tok3->insertToken("&");
tok3 = tok3->next();
}
tok3 = tok3->next();
tok3->str(value);
tok3->varId(valueVarId);
@ -8078,7 +8136,7 @@ void Tokenizer::cppcheckError(const Token *tok) const
const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::error,
"### Internal error in Cppcheck. Please report it.",
"Analysis failed. If the code is valid then please report this failure.",
"cppcheckError");
if (_errorLogger)
@ -9015,7 +9073,7 @@ void Tokenizer::simplifyBitfields()
{
Token *last = 0;
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %num% ;|,"))
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,"))
{
int offset = 0;
if (tok->next()->str() == "const")
@ -9024,7 +9082,7 @@ void Tokenizer::simplifyBitfields()
last = tok->tokAt(5 + offset);
Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset));
}
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %num% ;"))
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;"))
{
int offset = 0;
if (tok->next()->str() == "const")
@ -9179,9 +9237,11 @@ void Tokenizer::simplifyBorland()
// Remove Qt signals and slots
void Tokenizer::simplifyQtSignalsSlots()
{
Token *tok = _tokens;
while ((tok = const_cast<Token *>(Token::findmatch(tok, "class %var% :"))))
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (!Token::Match(tok, "class %var% :"))
continue;
if (tok->previous() && tok->previous()->str() == "enum")
{
tok = tok->tokAt(2);

View File

@ -320,7 +320,7 @@ public:
* utility function for simplifyKnownVariables. Perform simplification
* of a given variable
*/
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel);
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel);
/** Replace a "goto" with the statements */
void simplifyGoto();

View File

@ -135,6 +135,7 @@ private:
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_19); // #2597 - class member with unknown type
TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch
// It is undefined behaviour to point out of bounds of an array
@ -1891,6 +1892,20 @@ private:
errout.str());
}
void buffer_overrun_19() // #2597 - class member with unknown type
{
check("class A {\n"
"public:\n"
" u8 buf[10];\n"
" A();"
"};\n"
"\n"
"A::A() {\n"
" memset(buf, 0, 10);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void buffer_overrun_bailoutIfSwitch()
{
// No false positive

View File

@ -113,6 +113,7 @@ private:
TEST_CASE(operatorEqToSelf6); // ticket # 1550
TEST_CASE(operatorEqToSelf7);
TEST_CASE(operatorEqToSelf8); // ticket #2179
TEST_CASE(operatorEqToSelf9); // ticket #2592
TEST_CASE(memsetOnStruct);
TEST_CASE(memsetVector);
TEST_CASE(memsetOnClass);
@ -163,6 +164,7 @@ private:
TEST_CASE(const41); // ticket #2255
TEST_CASE(const42); // ticket #2282
TEST_CASE(const43); // ticket #2377
TEST_CASE(const44); // ticket #2595
TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
TEST_CASE(assigningArrayElementIsNotAConstOperation);
TEST_CASE(constoperator1); // operator< can often be const
@ -192,6 +194,7 @@ private:
TEST_CASE(symboldatabase11); // ticket #2539
TEST_CASE(symboldatabase12); // ticket #2547
TEST_CASE(symboldatabase13); // ticket #2577
TEST_CASE(symboldatabase14); // ticket #2589
}
// Check the operator Equal
@ -1298,6 +1301,26 @@ private:
ASSERT_EQUALS("", errout.str());
}
void operatorEqToSelf9()
{
checkOpertorEqToSelf(
"class Foo\n"
"{\n"
"public:\n"
" Foo& operator=(Foo* pOther);\n"
" Foo& operator=(Foo& other);\n"
"};\n"
"Foo& Foo::operator=(Foo* pOther)\n"
"{\n"
" return *this;\n"
"}\n"
"Foo& Foo::operator=(Foo& other)\n"
"{\n"
" return Foo::operator=(&other);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
// Check that base classes have virtual destructors
void checkVirtualDestructor(const char code[])
{
@ -4959,6 +4982,21 @@ private:
ASSERT_EQUALS("", errout.str());
}
void const44() // ticket 2595
{
checkConst("class A\n"
"{\n"
"public:\n"
" bool bOn;\n"
" bool foo()\n"
" {\n"
" return 0 != (bOn = bOn && true);\n"
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
}
void assigningPointerToPointerIsNotAConstOperation()
{
checkConst("struct s\n"
@ -5550,6 +5588,14 @@ private:
ASSERT_EQUALS("", errout.str());
}
void symboldatabase14()
{
// ticket #2589 - segmentation fault
checkConst("struct B : A\n");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestClass)

View File

@ -193,13 +193,42 @@ private:
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 4\n", errout.str());
check("void foo(struct ABC *abc)\n"
"{\n"
check("void foo(struct ABC *abc) {\n"
" bar(abc->a);\n"
" if (!abc)\n"
" ;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 4\n", errout.str());
ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str());
check("void foo(ABC *abc) {\n"
" abc->do_something();\n"
" if (abc)\n"
" ;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str());
check("void foo(ABC *abc) {\n"
" if (abc->a == 3) {\n"
" return;\n"
" }\n"
" if (abc) {}\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 5\n", "", errout.str());
// TODO: False negative if member of member is dereferenced
check("void foo(ABC *abc) {\n"
" abc->next->a = 0;\n"
" if (abc->next)\n"
" ;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", "", errout.str());
check("void foo(ABC *abc) {\n"
" abc->a = 0;\n"
" if (abc && abc->b == 0)\n"
" ;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str());
// ok dereferencing in a condition
check("void foo(struct ABC *abc)\n"
@ -718,6 +747,21 @@ private:
"}\n");
TODO_ASSERT_EQUALS("error",
"", errout.str());
// #2231 - error if assignment in loop is not used
check("void f() {\n"
" char *p = 0;\n"
"\n"
" for (int x = 0; x < 3; ++x) {\n"
" if (y[x] == 0) {\n"
" p = malloc(10);\n"
" break;\n"
" }\n"
" }\n"
"\n"
" *p = 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:11]: (error) Possible null pointer dereference: p\n", errout.str());
}
void nullpointer7()
@ -787,6 +831,19 @@ private:
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str());
check("void foo(char *p) {\n"
" if (p && *p == 0) {\n"
" }\n"
" printf(\"%c\", *p);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str());
check("void foo(char *p) {\n"
" if (p && *p == 0) {\n"
" } else { *p = 0; }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: p\n", errout.str());
check("void foo(abc *p) {\n"
" if (!p) {\n"
" }\n"

View File

@ -119,6 +119,7 @@ private:
TEST_CASE(if_cond9);
TEST_CASE(if_cond10);
TEST_CASE(if_cond11);
TEST_CASE(if_cond12);
TEST_CASE(if_or_1);
TEST_CASE(if_or_2);
@ -1340,6 +1341,15 @@ private:
ASSERT_EQUALS("", errout.str());
}
void if_cond12()
{
const char filedata[] = "#define A (1)\n"
"#if A == 1\n"
";\n"
"#endif\n";
ASSERT_EQUALS("\n\n;\n\n", Preprocessor::getcode(filedata,"","",NULL,NULL));
}
void if_or_1()

View File

@ -110,6 +110,7 @@ private:
TEST_CASE(template19);
TEST_CASE(template20);
TEST_CASE(template21);
TEST_CASE(template22);
TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter);
TEST_CASE(template_default_type);
@ -237,6 +238,7 @@ private:
TEST_CASE(simplifyTypedef77); // ticket #2554
TEST_CASE(simplifyTypedef78); // ticket #2568
TEST_CASE(simplifyTypedef79); // ticket #2348
TEST_CASE(simplifyTypedef80); // ticket #2587
TEST_CASE(simplifyTypedefFunction1);
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
@ -1984,6 +1986,19 @@ private:
}
}
void template22()
{
const char code[] = "template <classname T> struct Fred { T a; };\n"
"Fred<std::string> fred;";
const std::string expected("; "
"Fred<std::string> fred ; "
"struct Fred<std::string> { std :: string a ; }");
ASSERT_EQUALS(expected, sizeof_(code));
}
void template_unhandled()
{
// An unhandled template usage should be simplified..
@ -4876,6 +4891,23 @@ private:
ASSERT_EQUALS(expected, sizeof_(code));
}
void simplifyTypedef80() // ticket #2587
{
const char code[] = "typedef struct s { };\n"
"void f() {\n"
" sizeof(struct s);\n"
"};\n";
const std::string expected = "struct s { } ; "
"void f ( ) { "
"sizeof ( struct s ) ; "
"} ;";
ASSERT_EQUALS(expected, sizeof_(code));
// Check for output..
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
}
void simplifyTypedefFunction1()
{
{
@ -5767,11 +5799,7 @@ private:
"}\n";
const char expected[] = "int f ( ) "
"{"
" int i ;"
" int * p ;"
" p = & i ;"
" i = 5 ;"
" return 5 ; "
" ; return 5 ; "
"}";
ASSERT_EQUALS(expected, tok(code));
}

View File

@ -172,6 +172,35 @@ private:
"");
ASSERT_EQUALS("", errout.str());
// suppress uninitvar inline
(this->*check)("void f() {\n"
" int a;\n"
" // cppcheck-suppress uninitvar\n"
"\n"
" a++;\n"
"}\n",
"");
ASSERT_EQUALS("", errout.str());
// suppress uninitvar inline
(this->*check)("void f() {\n"
" int a;\n"
" /* cppcheck-suppress uninitvar */\n"
" a++;\n"
"}\n",
"");
ASSERT_EQUALS("", errout.str());
// suppress uninitvar inline
(this->*check)("void f() {\n"
" int a;\n"
" /* cppcheck-suppress uninitvar */\n"
"\n"
" a++;\n"
"}\n",
"");
ASSERT_EQUALS("", errout.str());
// suppress uninitvar inline, without error present
(this->*check)("void f() {\n"
" int a;\n"

View File

@ -127,6 +127,7 @@ private:
TEST_CASE(simplifyKnownVariables38); // ticket #2399 - simplify conditions
TEST_CASE(simplifyKnownVariables39);
TEST_CASE(simplifyKnownVariables40);
TEST_CASE(simplifyKnownVariables41); // p=&x; if (p) ..
TEST_CASE(simplifyKnownVariablesBailOutAssign);
TEST_CASE(simplifyKnownVariablesBailOutFor1);
TEST_CASE(simplifyKnownVariablesBailOutFor2);
@ -278,6 +279,7 @@ private:
TEST_CASE(bitfields3);
TEST_CASE(bitfields4); // ticket #1956
TEST_CASE(bitfields5); // ticket #1956
TEST_CASE(bitfields6); // ticket #2595
TEST_CASE(microsoftMFC);
@ -2020,6 +2022,16 @@ private:
ASSERT_EQUALS("void f ( ) {\n;\nchar c2 ; c2 = { 'a' } ;\n}", tokenizeAndStringify(code, true));
}
void simplifyKnownVariables41()
{
const char code[] = "void f() {\n"
" int x = 0;\n"
" const int *p; p = &x;\n"
" if (p) { return 0; }\n"
"}";
ASSERT_EQUALS("void f ( ) {\nint x ; x = 0 ;\nconst int * p ; p = & x ;\nif ( & x ) { return 0 ; }\n}", tokenizeAndStringify(code, true));
}
void simplifyKnownVariablesBailOutAssign()
{
const char code[] = "int foo() {\n"
@ -5072,6 +5084,18 @@ private:
ASSERT_EQUALS("struct A { virtual void f ( ) { } int f1 ; } ;", tokenizeAndStringify(code3,false));
}
void bitfields6() // ticket #2595
{
const char code1[] = "struct A { bool b : true; };";
ASSERT_EQUALS("struct A { bool b ; } ;", tokenizeAndStringify(code1,false));
const char code2[] = "struct A { bool b : true, c : true; };";
ASSERT_EQUALS("struct A { bool b ; bool c ; } ;", tokenizeAndStringify(code2,false));
const char code3[] = "struct A { bool : true; };";
ASSERT_EQUALS("struct A { } ;", tokenizeAndStringify(code3,false));
}
void microsoftMFC()
{
const char code1[] = "class MyDialog : public CDialog { DECLARE_MESSAGE_MAP() private: CString text; };";

View File

@ -801,6 +801,21 @@ private:
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: pItem\n",
"", errout.str());
// #2231 - conditional initialization in loop..
checkUninitVar("int foo(char *a) {\n"
" int x;\n"
"\n"
" for (int i = 0; i < 10; ++i) {\n"
" if (a[i] == 'x') {\n"
" x = i;\n"
" break;\n"
" }\n"
" }\n"
"\n"
" return x;\n"
"}");
ASSERT_EQUALS("[test.cpp:11]: (error) Uninitialized variable: x\n", errout.str());
}
// switch..