Merge branch 'master' of http://github.com/danmar/cppcheck
This commit is contained in:
commit
b02919ae67
|
@ -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..
|
||||
|
|
|
@ -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, "++|--"))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
158
lib/tokenize.cpp
158
lib/tokenize.cpp
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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; };";
|
||||
|
|
|
@ -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..
|
||||
|
|
Loading…
Reference in New Issue