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

View File

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

View File

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

View File

@ -321,7 +321,7 @@ void CheckOther::checkSelfAssignment()
std::set<unsigned int> pod; std::set<unsigned int> pod;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) 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()); pod.insert(tok->next()->varId());
} }

View File

@ -275,6 +275,40 @@ void ExecutionPath::checkScope(const Token *tok, std::list<ExecutionPath *> &che
++it; ++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 // parse loop bodies
check->parseLoopBody(tok2->next(), checks); check->parseLoopBody(tok2->next(), checks);
} }

View File

@ -338,20 +338,32 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
continue; continue;
} }
// We have finished a line that didn't contain any comment // First skip over any whitespace that may be present
// (the '\n' is swallowed when a // comment is detected) if (std::isspace(ch))
if ((ch == '\n' || str.compare(i,2,"//")==0) && !suppressionIDs.empty())
{ {
// Add the suppressions. if (ch == ' ' && previous == ' ')
for (size_t j(0); j < suppressionIDs.size(); ++j)
{ {
const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno)); // Skip double white space
if (!errmsg.empty()) }
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.. // 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) else if (str.compare(i, 2, "/*", 0, 2) == 0)
{ {
size_t commentStart = i + 2;
unsigned char chPrev = 0; unsigned char chPrev = 0;
++i; ++i;
while (i < str.length() && (chPrev != '*' || ch != '/')) while (i < str.length() && (chPrev != '*' || ch != '/'))
@ -395,126 +408,139 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
++lineno; ++lineno;
} }
} }
}
// String or char constants.. if (settings && settings->_inlineSuppressions)
else if (ch == '\"' || ch == '\'')
{
code << char(ch);
char chNext;
do
{ {
++i; std::string comment(str, commentStart, i - commentStart);
chNext = str[i]; std::istringstream iss(comment);
if (chNext == '\\') 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; ++i;
char chSeq = str[i]; chNext = str[i];
if (chSeq == '\n') if (chNext == '\\')
++newlines; {
++i;
char chSeq = str[i];
if (chSeq == '\n')
++newlines;
else
{
code << chNext;
code << chSeq;
previous = static_cast<unsigned char>(chSeq);
}
}
else else
{ {
code << chNext; code << chNext;
code << chSeq; previous = static_cast<unsigned char>(chNext);
previous = static_cast<unsigned char>(chSeq);
} }
} }
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 else
{ {
code << chNext; code << "R";
previous = static_cast<unsigned char>(chNext); 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 else
{ {
code << char(ch); code << char(ch);
previous = 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 != variables.end())
{ {
if (!it->second.empty()) 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) == "(") && 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->next() || tok->strAt(1) == "||" || tok->strAt(1) == "&&" || tok->strAt(1) == ")"))
tok->str("1"); tok->str("1");

View File

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

View File

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

View File

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

View File

@ -320,7 +320,7 @@ public:
* utility function for simplifyKnownVariables. Perform simplification * utility function for simplifyKnownVariables. Perform simplification
* of a given variable * 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 */ /** Replace a "goto" with the statements */
void simplifyGoto(); void simplifyGoto();

View File

@ -135,6 +135,7 @@ private:
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_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 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
@ -1891,6 +1892,20 @@ private:
errout.str()); 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() void buffer_overrun_bailoutIfSwitch()
{ {
// No false positive // No false positive

View File

@ -113,6 +113,7 @@ private:
TEST_CASE(operatorEqToSelf6); // ticket # 1550 TEST_CASE(operatorEqToSelf6); // ticket # 1550
TEST_CASE(operatorEqToSelf7); TEST_CASE(operatorEqToSelf7);
TEST_CASE(operatorEqToSelf8); // ticket #2179 TEST_CASE(operatorEqToSelf8); // ticket #2179
TEST_CASE(operatorEqToSelf9); // ticket #2592
TEST_CASE(memsetOnStruct); TEST_CASE(memsetOnStruct);
TEST_CASE(memsetVector); TEST_CASE(memsetVector);
TEST_CASE(memsetOnClass); TEST_CASE(memsetOnClass);
@ -163,6 +164,7 @@ private:
TEST_CASE(const41); // ticket #2255 TEST_CASE(const41); // ticket #2255
TEST_CASE(const42); // ticket #2282 TEST_CASE(const42); // ticket #2282
TEST_CASE(const43); // ticket #2377 TEST_CASE(const43); // ticket #2377
TEST_CASE(const44); // ticket #2595
TEST_CASE(assigningPointerToPointerIsNotAConstOperation); TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
TEST_CASE(assigningArrayElementIsNotAConstOperation); TEST_CASE(assigningArrayElementIsNotAConstOperation);
TEST_CASE(constoperator1); // operator< can often be const TEST_CASE(constoperator1); // operator< can often be const
@ -192,6 +194,7 @@ private:
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 TEST_CASE(symboldatabase13); // ticket #2577
TEST_CASE(symboldatabase14); // ticket #2589
} }
// Check the operator Equal // Check the operator Equal
@ -1298,6 +1301,26 @@ private:
ASSERT_EQUALS("", errout.str()); 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 // Check that base classes have virtual destructors
void checkVirtualDestructor(const char code[]) void checkVirtualDestructor(const char code[])
{ {
@ -4959,6 +4982,21 @@ private:
ASSERT_EQUALS("", errout.str()); 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() void assigningPointerToPointerIsNotAConstOperation()
{ {
checkConst("struct s\n" checkConst("struct s\n"
@ -5550,6 +5588,14 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void symboldatabase14()
{
// ticket #2589 - segmentation fault
checkConst("struct B : A\n");
ASSERT_EQUALS("", errout.str());
}
}; };
REGISTER_TEST(TestClass) REGISTER_TEST(TestClass)

View File

@ -193,13 +193,42 @@ private:
"}\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: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" check("void foo(struct ABC *abc) {\n"
"{\n"
" bar(abc->a);\n" " bar(abc->a);\n"
" if (!abc)\n" " if (!abc)\n"
" ;\n" " ;\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 // ok dereferencing in a condition
check("void foo(struct ABC *abc)\n" check("void foo(struct ABC *abc)\n"
@ -718,6 +747,21 @@ private:
"}\n"); "}\n");
TODO_ASSERT_EQUALS("error", TODO_ASSERT_EQUALS("error",
"", errout.str()); "", 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() void nullpointer7()
@ -787,6 +831,19 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str()); 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" check("void foo(abc *p) {\n"
" if (!p) {\n" " if (!p) {\n"
" }\n" " }\n"

View File

@ -119,6 +119,7 @@ private:
TEST_CASE(if_cond9); TEST_CASE(if_cond9);
TEST_CASE(if_cond10); TEST_CASE(if_cond10);
TEST_CASE(if_cond11); TEST_CASE(if_cond11);
TEST_CASE(if_cond12);
TEST_CASE(if_or_1); TEST_CASE(if_or_1);
TEST_CASE(if_or_2); TEST_CASE(if_or_2);
@ -1340,6 +1341,15 @@ private:
ASSERT_EQUALS("", errout.str()); 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() void if_or_1()

View File

@ -110,6 +110,7 @@ private:
TEST_CASE(template19); TEST_CASE(template19);
TEST_CASE(template20); TEST_CASE(template20);
TEST_CASE(template21); TEST_CASE(template21);
TEST_CASE(template22);
TEST_CASE(template_unhandled); TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter); TEST_CASE(template_default_parameter);
TEST_CASE(template_default_type); TEST_CASE(template_default_type);
@ -237,6 +238,7 @@ private:
TEST_CASE(simplifyTypedef77); // ticket #2554 TEST_CASE(simplifyTypedef77); // ticket #2554
TEST_CASE(simplifyTypedef78); // ticket #2568 TEST_CASE(simplifyTypedef78); // ticket #2568
TEST_CASE(simplifyTypedef79); // ticket #2348 TEST_CASE(simplifyTypedef79); // ticket #2348
TEST_CASE(simplifyTypedef80); // ticket #2587
TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction1);
TEST_CASE(simplifyTypedefFunction2); // ticket #1685 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() void template_unhandled()
{ {
// An unhandled template usage should be simplified.. // An unhandled template usage should be simplified..
@ -4876,6 +4891,23 @@ private:
ASSERT_EQUALS(expected, sizeof_(code)); 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() void simplifyTypedefFunction1()
{ {
{ {
@ -5767,11 +5799,7 @@ private:
"}\n"; "}\n";
const char expected[] = "int f ( ) " const char expected[] = "int f ( ) "
"{" "{"
" int i ;" " ; return 5 ; "
" int * p ;"
" p = & i ;"
" i = 5 ;"
" return 5 ; "
"}"; "}";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }

View File

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

View File

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

View File

@ -801,6 +801,21 @@ private:
"}\n"); "}\n");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: pItem\n", TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: pItem\n",
"", errout.str()); "", 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.. // switch..