Fixed #1622 (False positive: buf is not assigned a value (pointer aliasing))
This commit is contained in:
parent
cccccff96f
commit
70d475f8c2
|
@ -425,23 +425,26 @@ static bool isOp(const Token *tok)
|
||||||
class Variables
|
class Variables
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray };
|
||||||
|
|
||||||
/** Store information about variable usage */
|
/** Store information about variable usage */
|
||||||
class VariableUsage
|
class VariableUsage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VariableUsage(const Token *name = 0,
|
VariableUsage(const Token *name = 0,
|
||||||
const Token *type = 0,
|
VariableType type = standard,
|
||||||
bool read = false,
|
bool read = false,
|
||||||
bool write = false,
|
bool write = false,
|
||||||
bool modified = false,
|
bool modified = false,
|
||||||
bool aliased = false) :
|
unsigned int alias = 0) :
|
||||||
_name(name),
|
_name(name),
|
||||||
_type(type),
|
_type(type),
|
||||||
_read(read),
|
_read(read),
|
||||||
_write(write),
|
_write(write),
|
||||||
_modified(modified),
|
_modified(modified)
|
||||||
_aliased(aliased)
|
|
||||||
{
|
{
|
||||||
|
if (alias)
|
||||||
|
_aliases.insert(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** variable is used.. set both read+write */
|
/** variable is used.. set both read+write */
|
||||||
|
@ -458,11 +461,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *_name;
|
const Token *_name;
|
||||||
const Token *_type;
|
VariableType _type;
|
||||||
bool _read;
|
bool _read;
|
||||||
bool _write;
|
bool _write;
|
||||||
bool _modified; // read/modify/write
|
bool _modified; // read/modify/write
|
||||||
bool _aliased; // pointer or reference
|
std::set<unsigned int> _aliases;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<unsigned int, VariableUsage> VariableMap;
|
typedef std::map<unsigned int, VariableUsage> VariableMap;
|
||||||
|
@ -471,44 +474,167 @@ public:
|
||||||
{
|
{
|
||||||
_varUsage.clear();
|
_varUsage.clear();
|
||||||
}
|
}
|
||||||
void addVar(const Token *name,
|
VariableMap &varUsage()
|
||||||
const Token *type,
|
|
||||||
bool write_ = false,
|
|
||||||
bool aliased = false)
|
|
||||||
{
|
|
||||||
_varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, false, write_, false, aliased)));
|
|
||||||
}
|
|
||||||
const VariableMap &varUsage() const
|
|
||||||
{
|
{
|
||||||
return _varUsage;
|
return _varUsage;
|
||||||
}
|
}
|
||||||
|
void addVar(const Token *name, VariableType type, bool write_ = false, unsigned int varid = 0);
|
||||||
void read(unsigned int varid);
|
void read(unsigned int varid);
|
||||||
|
void readAliases(unsigned int varid);
|
||||||
|
void readAll(unsigned int varid);
|
||||||
void write(unsigned int varid);
|
void write(unsigned int varid);
|
||||||
|
void writeAliases(unsigned int varid);
|
||||||
|
void writeAll(unsigned int varid);
|
||||||
void use(unsigned int varid);
|
void use(unsigned int varid);
|
||||||
void modified(unsigned int varid);
|
void modified(unsigned int varid);
|
||||||
VariableUsage *find(unsigned int varid);
|
VariableUsage *find(unsigned int varid);
|
||||||
|
void alias(unsigned int varid1, unsigned int varid2);
|
||||||
|
void erase(unsigned int varid)
|
||||||
|
{
|
||||||
|
_varUsage.erase(varid);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VariableMap _varUsage;
|
VariableMap _varUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Variables::alias(unsigned int varid1, unsigned int varid2)
|
||||||
|
{
|
||||||
|
std::set<unsigned int>::iterator i;
|
||||||
|
|
||||||
|
VariableUsage *var1 = find(varid1);
|
||||||
|
|
||||||
|
// remove var1 from all aliases
|
||||||
|
for (i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i)
|
||||||
|
{
|
||||||
|
VariableUsage *temp = find(*i);
|
||||||
|
|
||||||
|
temp->_aliases.erase(var1->_name->varId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all aliases from var1
|
||||||
|
var1->_aliases.clear();
|
||||||
|
|
||||||
|
VariableUsage *var2 = find(varid2);
|
||||||
|
|
||||||
|
// var1 gets all var2s aliases
|
||||||
|
for (i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i)
|
||||||
|
{
|
||||||
|
if (*i != varid1)
|
||||||
|
var1->_aliases.insert(*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// var2 is an alias of var1
|
||||||
|
var2->_aliases.insert(varid1);
|
||||||
|
var1->_aliases.insert(varid2);
|
||||||
|
|
||||||
|
if (var2->_type == Variables::pointer)
|
||||||
|
var2->_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variables::addVar(const Token *name,
|
||||||
|
VariableType type,
|
||||||
|
bool write_,
|
||||||
|
unsigned int varid )
|
||||||
|
{
|
||||||
|
_varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, false, write_, false, varid)));
|
||||||
|
|
||||||
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
|
if (usage)
|
||||||
|
usage->_aliases.insert(name->varId());
|
||||||
|
}
|
||||||
|
|
||||||
void Variables::read(unsigned int varid)
|
void Variables::read(unsigned int varid)
|
||||||
{
|
{
|
||||||
VariableUsage *usage = find(varid);
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
if (usage)
|
if (usage)
|
||||||
{
|
|
||||||
usage->_read = true;
|
usage->_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variables::readAliases(unsigned int varid)
|
||||||
|
{
|
||||||
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
|
if (usage)
|
||||||
|
{
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->_read = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Variables::readAll(unsigned int varid)
|
||||||
|
{
|
||||||
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
|
if (usage)
|
||||||
|
{
|
||||||
|
usage->_read = true;
|
||||||
|
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->_read = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Variables::write(unsigned int varid)
|
void Variables::write(unsigned int varid)
|
||||||
{
|
{
|
||||||
VariableUsage *usage = find(varid);
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
|
if (usage)
|
||||||
|
usage->_write = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variables::writeAliases(unsigned int varid)
|
||||||
|
{
|
||||||
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
|
if (usage)
|
||||||
|
{
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->_write = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variables::writeAll(unsigned int varid)
|
||||||
|
{
|
||||||
|
VariableUsage *usage = find(varid);
|
||||||
|
|
||||||
if (usage)
|
if (usage)
|
||||||
{
|
{
|
||||||
usage->_write = true;
|
usage->_write = true;
|
||||||
|
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->_write = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,8 +645,19 @@ void Variables::use(unsigned int varid)
|
||||||
if (usage)
|
if (usage)
|
||||||
{
|
{
|
||||||
usage->use();
|
usage->use();
|
||||||
|
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->use();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Variables::modified(unsigned int varid)
|
void Variables::modified(unsigned int varid)
|
||||||
{
|
{
|
||||||
VariableUsage *usage = find(varid);
|
VariableUsage *usage = find(varid);
|
||||||
|
@ -528,6 +665,16 @@ void Variables::modified(unsigned int varid)
|
||||||
if (usage)
|
if (usage)
|
||||||
{
|
{
|
||||||
usage->_modified = true;
|
usage->_modified = true;
|
||||||
|
|
||||||
|
std::set<unsigned int>::iterator aliases;
|
||||||
|
|
||||||
|
for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
|
||||||
|
{
|
||||||
|
VariableUsage *aliased = find(*aliases);
|
||||||
|
|
||||||
|
if (aliased)
|
||||||
|
aliased->_modified = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,14 +683,128 @@ Variables::VariableUsage *Variables::find(unsigned int varid)
|
||||||
if (varid)
|
if (varid)
|
||||||
{
|
{
|
||||||
VariableMap::iterator i = _varUsage.find(varid);
|
VariableMap::iterator i = _varUsage.find(varid);
|
||||||
|
|
||||||
if (i != _varUsage.end())
|
if (i != _varUsage.end())
|
||||||
return &i->second;
|
return &i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int doAssignment(Variables &variables, const Token *tok, bool pointer)
|
||||||
|
{
|
||||||
|
int next = 0;
|
||||||
|
|
||||||
|
// check for aliased variable
|
||||||
|
unsigned int varid1 = tok->varId();
|
||||||
|
Variables::VariableUsage *var1 = variables.find(varid1);
|
||||||
|
|
||||||
|
if (var1)
|
||||||
|
{
|
||||||
|
Variables::VariableUsage *var2 = 0;
|
||||||
|
|
||||||
|
if (Token::Match(tok->tokAt(2), "&| %var%") ||
|
||||||
|
Token::Match(tok->tokAt(2), "( %type% * ) &| %var%") ||
|
||||||
|
Token::Match(tok->tokAt(2), "( %type% * ) ( &| %var%") ||
|
||||||
|
Token::Match(tok->tokAt(2), "%any% < %type% * > ( &| %var%"))
|
||||||
|
{
|
||||||
|
unsigned int varid2;
|
||||||
|
bool addressOf = false;
|
||||||
|
|
||||||
|
// check for C style cast
|
||||||
|
if (tok->tokAt(2)->str() == "(")
|
||||||
|
{
|
||||||
|
if (tok->tokAt(6)->str() == "&")
|
||||||
|
{
|
||||||
|
addressOf = true;
|
||||||
|
next = 7;
|
||||||
|
}
|
||||||
|
else if (tok->tokAt(6)->str() == "(")
|
||||||
|
{
|
||||||
|
if (tok->tokAt(7)->str() == "&")
|
||||||
|
{
|
||||||
|
addressOf = true;
|
||||||
|
next = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next = 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next = 6;
|
||||||
|
}
|
||||||
|
// check for C++ style cast
|
||||||
|
else if (tok->tokAt(2)->str().find("cast") != std::string::npos)
|
||||||
|
{
|
||||||
|
if (tok->tokAt(8)->str() == "&")
|
||||||
|
{
|
||||||
|
addressOf = true;
|
||||||
|
next = 9;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no cast
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tok->tokAt(2)->str() == "&")
|
||||||
|
{
|
||||||
|
addressOf = true;
|
||||||
|
next = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if variable is local
|
||||||
|
varid2 = tok->tokAt(next)->varId();
|
||||||
|
var2 = variables.find(varid2);
|
||||||
|
|
||||||
|
if (var1->_type != Variables::reference && !addressOf)
|
||||||
|
{
|
||||||
|
if (var2)
|
||||||
|
{
|
||||||
|
if (var1->_type == Variables::pointer)
|
||||||
|
{
|
||||||
|
if (!(var2->_type == Variables::array || var2->_type == Variables::pointer))
|
||||||
|
variables.read(varid2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (var2->_type == Variables::pointer && tok->tokAt(next +1)->str() == "[")
|
||||||
|
variables.readAliases(varid2);
|
||||||
|
|
||||||
|
variables.read(varid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var2) // local variable
|
||||||
|
{
|
||||||
|
if (var1->_type == Variables::pointer && !pointer)
|
||||||
|
{
|
||||||
|
if (addressOf ||
|
||||||
|
var2->_type == Variables::array ||
|
||||||
|
var2->_type == Variables::pointer)
|
||||||
|
{
|
||||||
|
variables.alias(varid1, varid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (var1->_type == Variables::reference)
|
||||||
|
{
|
||||||
|
variables.alias(varid1, varid2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // not a local variable
|
||||||
|
{
|
||||||
|
// aliased variables in a larger scope are not supported yet
|
||||||
|
if (varid2)
|
||||||
|
variables.erase(varid1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOther::functionVariableUsage()
|
void CheckOther::functionVariableUsage()
|
||||||
{
|
{
|
||||||
if (!_settings->_checkCodingStyle)
|
if (!_settings->_checkCodingStyle)
|
||||||
|
@ -557,13 +818,13 @@ void CheckOther::functionVariableUsage()
|
||||||
token = token->next();
|
token = token->next();
|
||||||
|
|
||||||
// First token for the current scope..
|
// First token for the current scope..
|
||||||
const Token * const tok1 = token;
|
const Token *const tok1 = token;
|
||||||
|
|
||||||
// Find next scope that will be checked next time..
|
// Find next scope that will be checked next time..
|
||||||
token = Token::findmatch(token->link(), ") const| {");
|
token = Token::findmatch(token->link(), ") const| {");
|
||||||
|
|
||||||
// varId, usage {read, write, modified}
|
// varId, usage {read, write, modified}
|
||||||
Variables variables;
|
Variables variables;
|
||||||
|
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (const Token *tok = tok1; tok; tok = tok->next())
|
for (const Token *tok = tok1; tok; tok = tok->next())
|
||||||
|
@ -597,7 +858,8 @@ void CheckOther::functionVariableUsage()
|
||||||
if (Token::Match(tok, "[;{}] %type% %var% ;|=") &&
|
if (Token::Match(tok, "[;{}] %type% %var% ;|=") &&
|
||||||
tok->next()->isStandardType())
|
tok->next()->isStandardType())
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(2), tok->next(), tok->tokAt(3)->str() == "=");
|
variables.addVar(tok->tokAt(2), Variables::standard,
|
||||||
|
tok->tokAt(3)->str() == "=");
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,11 +868,11 @@ void CheckOther::functionVariableUsage()
|
||||||
else if (Token::Match(tok, "[;{}] %type% %var% ( %any% ) ;") &&
|
else if (Token::Match(tok, "[;{}] %type% %var% ( %any% ) ;") &&
|
||||||
tok->next()->isStandardType())
|
tok->next()->isStandardType())
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(2), tok->next(), true);
|
variables.addVar(tok->tokAt(2), Variables::standard, true);
|
||||||
|
|
||||||
// check if a local variable is used to initialize this variable
|
// check if a local variable is used to initialize this variable
|
||||||
if (tok->tokAt(4)->varId() > 0)
|
if (tok->tokAt(4)->varId() > 0)
|
||||||
variables.read(tok->tokAt(4)->varId());
|
variables.readAll(tok->tokAt(4)->varId());
|
||||||
tok = tok->tokAt(5);
|
tok = tok->tokAt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +881,8 @@ void CheckOther::functionVariableUsage()
|
||||||
else if (Token::Match(tok, "[;{}] %type% %var% [ %num% ] ;|=") &&
|
else if (Token::Match(tok, "[;{}] %type% %var% [ %num% ] ;|=") &&
|
||||||
tok->next()->isStandardType())
|
tok->next()->isStandardType())
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(2), tok->next(), tok->tokAt(6)->str() == "=", false);
|
variables.addVar(tok->tokAt(2), Variables::array,
|
||||||
|
tok->tokAt(6)->str() == "=");
|
||||||
tok = tok->tokAt(5);
|
tok = tok->tokAt(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,8 +892,24 @@ void CheckOther::functionVariableUsage()
|
||||||
{
|
{
|
||||||
if (tok->next()->str() != "return")
|
if (tok->next()->str() != "return")
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(3), tok->next(), tok->tokAt(4)->str() == "=", true);
|
Variables::VariableType type;
|
||||||
tok = tok->tokAt(3);
|
|
||||||
|
if (tok->tokAt(2)->str() == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else
|
||||||
|
type = Variables::reference;
|
||||||
|
|
||||||
|
bool written = tok->tokAt(4)->str() == "=";
|
||||||
|
|
||||||
|
variables.addVar(tok->tokAt(3), type, written, 0);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// check for assignment
|
||||||
|
if (written)
|
||||||
|
offset = doAssignment(variables, tok->tokAt(3), false);
|
||||||
|
|
||||||
|
tok = tok->tokAt(3 + offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,24 +917,72 @@ void CheckOther::functionVariableUsage()
|
||||||
// const int * i; const int * j = 0;
|
// const int * i; const int * j = 0;
|
||||||
else if (Token::Match(tok, "[;{}] const %type% *|& %var% ;|="))
|
else if (Token::Match(tok, "[;{}] const %type% *|& %var% ;|="))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(4), tok->tokAt(2), tok->tokAt(5)->str() == "=", true);
|
Variables::VariableType type;
|
||||||
tok = tok->tokAt(4);
|
|
||||||
|
if (tok->tokAt(3)->str() == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else
|
||||||
|
type = Variables::reference;
|
||||||
|
|
||||||
|
bool written = tok->tokAt(5)->str() == "=";
|
||||||
|
|
||||||
|
variables.addVar(tok->tokAt(4), type, written, 0);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// check for assignment
|
||||||
|
if (written)
|
||||||
|
offset = doAssignment(variables, tok->tokAt(3), false);
|
||||||
|
|
||||||
|
tok = tok->tokAt(4 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pointer or reference of struct or union declaration with possible initialization
|
// pointer or reference of struct or union declaration with possible initialization
|
||||||
// struct s * i; struct s * j = 0;
|
// struct s * i; struct s * j = 0;
|
||||||
else if (Token::Match(tok, "[;{}] struct|union %type% *|& %var% ;|="))
|
else if (Token::Match(tok, "[;{}] struct|union %type% *|& %var% ;|="))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(4), tok->tokAt(2), tok->tokAt(5)->str() == "=", true);
|
Variables::VariableType type;
|
||||||
tok = tok->tokAt(4);
|
|
||||||
|
if (tok->tokAt(3)->str() == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else
|
||||||
|
type = Variables::reference;
|
||||||
|
|
||||||
|
bool written = tok->tokAt(5)->str() == "=";
|
||||||
|
|
||||||
|
variables.addVar(tok->tokAt(4), type, written, 0);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// check for assignment
|
||||||
|
if (written)
|
||||||
|
offset = doAssignment(variables, tok->tokAt(3), false);
|
||||||
|
|
||||||
|
tok = tok->tokAt(4 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const pointer or reference of struct or union declaration with possible initialization
|
// const pointer or reference of struct or union declaration with possible initialization
|
||||||
// const struct s * i; const struct s * j = 0;
|
// const struct s * i; const struct s * j = 0;
|
||||||
else if (Token::Match(tok, "[;{}] const struct|union %type% *|& %var% ;|="))
|
else if (Token::Match(tok, "[;{}] const struct|union %type% *|& %var% ;|="))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(5), tok->tokAt(3), tok->tokAt(6)->str() == "=", true);
|
Variables::VariableType type;
|
||||||
tok = tok->tokAt(5);
|
|
||||||
|
if (tok->tokAt(4)->str() == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else
|
||||||
|
type = Variables::reference;
|
||||||
|
|
||||||
|
bool written = tok->tokAt(6)->str() == "=";
|
||||||
|
|
||||||
|
variables.addVar(tok->tokAt(5), type, written, 0);
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// check for assignment
|
||||||
|
if (written)
|
||||||
|
offset = doAssignment(variables, tok->tokAt(3), false);
|
||||||
|
|
||||||
|
tok = tok->tokAt(5 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pointer or reference declaration with initialization using constructor
|
// pointer or reference declaration with initialization using constructor
|
||||||
|
@ -663,44 +990,152 @@ void CheckOther::functionVariableUsage()
|
||||||
else if (Token::Match(tok, "[;{}] %type% &|* %var% ( %any% ) ;") &&
|
else if (Token::Match(tok, "[;{}] %type% &|* %var% ( %any% ) ;") &&
|
||||||
(tok->next()->isStandardType() || tok->next()->str() == "void"))
|
(tok->next()->isStandardType() || tok->next()->str() == "void"))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(3), tok->next(), true, true);
|
Variables::VariableType type;
|
||||||
|
|
||||||
|
if (tok->tokAt(2)->str() == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else
|
||||||
|
type = Variables::reference;
|
||||||
|
|
||||||
|
unsigned int varid = 0;
|
||||||
|
|
||||||
|
// check for aliased variable
|
||||||
|
if (Token::Match(tok->tokAt(5), "%var%"))
|
||||||
|
varid = tok->tokAt(5)->varId();
|
||||||
|
|
||||||
|
variables.addVar(tok->tokAt(3), type, true, varid);
|
||||||
|
|
||||||
// check if a local variable is used to initialize this variable
|
// check if a local variable is used to initialize this variable
|
||||||
if (tok->tokAt(5)->varId() > 0)
|
if (varid > 0)
|
||||||
{
|
{
|
||||||
if (tok->tokAt(2)->str() == "&")
|
Variables::VariableUsage *var = variables.find(varid);
|
||||||
variables.read(tok->tokAt(5)->varId());
|
|
||||||
else
|
if (type == Variables::pointer)
|
||||||
|
{
|
||||||
variables.use(tok->tokAt(5)->varId());
|
variables.use(tok->tokAt(5)->varId());
|
||||||
|
|
||||||
|
if (var && (var->_type == Variables::array ||
|
||||||
|
var->_type == Variables::pointer))
|
||||||
|
var->_aliases.insert(tok->varId());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variables.readAll(tok->tokAt(5)->varId());
|
||||||
|
if (var)
|
||||||
|
var->_aliases.insert(tok->varId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tok = tok->tokAt(6);
|
tok = tok->tokAt(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "[;{}] %type% *|& %var% [ %num% ] ;|=") &&
|
// array of pointer or reference declaration with possible initialization
|
||||||
(tok->next()->isStandardType() || tok->next()->str() == "void"))
|
// int * p[10]; int * q[10] = { 0 };
|
||||||
|
else if (Token::Match(tok, "[;{}] %type% *|& %var% [ %num% ] ;|="))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(3), tok->next(), tok->tokAt(7)->str() == "=", true);
|
if (tok->next()->str() != "return")
|
||||||
|
{
|
||||||
|
variables.addVar(tok->tokAt(3),
|
||||||
|
tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
|
||||||
|
tok->tokAt(7)->str() == "=", false);
|
||||||
|
tok = tok->tokAt(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const array of pointer or reference declaration with possible initialization
|
||||||
|
// const int * p[10]; const int * q[10] = { 0 };
|
||||||
|
else if (Token::Match(tok, "[;{}] const %type% *|& %var% [ %num% ] ;|="))
|
||||||
|
{
|
||||||
|
variables.addVar(tok->tokAt(4),
|
||||||
|
tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
|
||||||
|
tok->tokAt(8)->str() == "=", false);
|
||||||
|
tok = tok->tokAt(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// array of pointer or reference of struct or union declaration with possible initialization
|
||||||
|
// struct S * p[10]; struct T * q[10] = { 0 };
|
||||||
|
else if (Token::Match(tok, "[;{}] struct|union %type% *|& %var% [ %num% ] ;|="))
|
||||||
|
{
|
||||||
|
variables.addVar(tok->tokAt(4),
|
||||||
|
tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
|
||||||
|
tok->tokAt(8)->str() == "=", false);
|
||||||
tok = tok->tokAt(6);
|
tok = tok->tokAt(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "[;{}] const %type% *|& %var% [ %num% ] ;|=") &&
|
// const array of pointer or reference of struct or union declaration with possible initialization
|
||||||
(tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void"))
|
// const struct S * p[10]; const struct T * q[10] = { 0 };
|
||||||
|
else if (Token::Match(tok, "[;{}] const struct|union %type% *|& %var% [ %num% ] ;|="))
|
||||||
{
|
{
|
||||||
variables.addVar(tok->tokAt(4), tok->next(), tok->tokAt(8)->str() == "=", true);
|
variables.addVar(tok->tokAt(5),
|
||||||
|
tok->tokAt(4)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
|
||||||
|
tok->tokAt(9)->str() == "=", false);
|
||||||
tok = tok->tokAt(7);
|
tok = tok->tokAt(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "delete|return %var%"))
|
else if (Token::Match(tok, "delete|return %var%"))
|
||||||
variables.read(tok->next()->varId());
|
variables.readAll(tok->next()->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "%var% ="))
|
// assignment
|
||||||
variables.write(tok->varId());
|
else if (Token::Match(tok, "*| %var% ="))
|
||||||
|
{
|
||||||
|
bool pointer = false;
|
||||||
|
|
||||||
|
if (tok->str() == "*")
|
||||||
|
{
|
||||||
|
pointer = true;
|
||||||
|
tok = tok->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int varid1 = tok->varId();
|
||||||
|
const Token *start = tok;
|
||||||
|
|
||||||
|
tok = tok->tokAt(doAssignment(variables, tok, pointer));
|
||||||
|
|
||||||
|
if (pointer)
|
||||||
|
{
|
||||||
|
variables.writeAliases(varid1);
|
||||||
|
variables.read(varid1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Variables::VariableUsage *var = variables.find(varid1);
|
||||||
|
|
||||||
|
if (var && var->_type == Variables::reference)
|
||||||
|
{
|
||||||
|
variables.writeAliases(varid1);
|
||||||
|
variables.read(varid1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
variables.write(varid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// checked for chained assignments
|
||||||
|
if (tok != start && tok->next()->str() == "=")
|
||||||
|
{
|
||||||
|
Variables::VariableUsage *var = variables.find(tok->varId());
|
||||||
|
|
||||||
|
if (var && var->_type != Variables::reference)
|
||||||
|
var->_read = true;
|
||||||
|
|
||||||
|
tok = tok->previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "%var% [") && Token::Match(tok->next()->link(), "] ="))
|
else if (Token::Match(tok, "%var% [") && Token::Match(tok->next()->link(), "] ="))
|
||||||
variables.write(tok->varId());
|
{
|
||||||
|
unsigned int varid = tok->varId();
|
||||||
|
Variables::VariableUsage *var = variables.find(varid);
|
||||||
|
|
||||||
else if (Token::Match(tok, "else %var% ="))
|
if (var)
|
||||||
variables.write(tok->next()->varId());
|
{
|
||||||
|
if (var->_type == Variables::pointer)
|
||||||
|
{
|
||||||
|
variables.read(varid);
|
||||||
|
variables.writeAliases(varid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
variables.writeAll(varid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, ">>|& %var%"))
|
else if (Token::Match(tok, ">>|& %var%"))
|
||||||
variables.use(tok->next()->varId()); // use = read + write
|
variables.use(tok->next()->varId()); // use = read + write
|
||||||
|
@ -713,16 +1148,16 @@ void CheckOther::functionVariableUsage()
|
||||||
|
|
||||||
else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) &&
|
else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) &&
|
||||||
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false")))
|
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false")))
|
||||||
variables.read(tok->next()->varId());
|
variables.readAll(tok->next()->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "-=|+=|*=|/=|&=|^= %var%") || Token::Match(tok, "|= %var%"))
|
else if (Token::Match(tok, "-=|+=|*=|/=|&=|^= %var%") || Token::Match(tok, "|= %var%"))
|
||||||
variables.modified(tok->next()->varId());
|
variables.modified(tok->next()->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || isOp(tok->next())))
|
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || isOp(tok->next())))
|
||||||
variables.read(tok->varId());
|
variables.readAll(tok->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "; %var% ;"))
|
else if (Token::Match(tok, "; %var% ;"))
|
||||||
variables.read(tok->next()->varId());
|
variables.readAll(tok->next()->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "++|-- %var%"))
|
else if (Token::Match(tok, "++|-- %var%"))
|
||||||
variables.modified(tok->next()->varId());
|
variables.modified(tok->next()->varId());
|
||||||
|
@ -744,7 +1179,7 @@ void CheckOther::functionVariableUsage()
|
||||||
else if (usage._modified & !usage._write)
|
else if (usage._modified & !usage._write)
|
||||||
unassignedVariableError(usage._name, varname);
|
unassignedVariableError(usage._name, varname);
|
||||||
|
|
||||||
else if (!usage._read && !usage._modified && !usage._aliased)
|
else if (!usage._read && !usage._modified)
|
||||||
unreadVariableError(usage._name, varname);
|
unreadVariableError(usage._name, varname);
|
||||||
|
|
||||||
else if (!usage._write)
|
else if (!usage._write)
|
||||||
|
|
|
@ -327,23 +327,86 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i(0);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" bool i = false;\n"
|
" bool i = false;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" bool i = true;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" char *i;\n"
|
||||||
|
" i = fgets();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
// undefined variables are not reported because they may be classes with constructors
|
||||||
|
functionVariableUsage("undefined foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" undefined i = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i = undefined;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int * i = 0;\n"
|
" int * i = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" void * i = 0;\n"
|
" void * i = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const void * i = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" struct S * i = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const struct S * i = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" undefined * i = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i = 0;\n"
|
||||||
|
" int j = i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'j' is assigned a value that is never used\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar2()
|
void localvar2()
|
||||||
|
@ -361,6 +424,77 @@ private:
|
||||||
" return i;\n"
|
" return i;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
// undefined variables are not reported because they may be classes with constructors
|
||||||
|
functionVariableUsage("undefined foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" undefined i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("undefined *foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" undefined * i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int *foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int * i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("const int *foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const int * i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("struct S *foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" struct S * i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("const struct S *foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const struct S * i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'i' is not assigned a value\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" f(a[0]);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" f(a[0], 0);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" f(0, a[0]);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" f(0, a[0], 0);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar3()
|
void localvar3()
|
||||||
|
@ -383,6 +517,13 @@ private:
|
||||||
" f(i);\n"
|
" f(i);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS(std::string(""), errout.str());
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i = 0;\n"
|
||||||
|
" f(&i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar5()
|
void localvar5()
|
||||||
|
@ -397,6 +538,14 @@ private:
|
||||||
|
|
||||||
void localvar6()
|
void localvar6()
|
||||||
{
|
{
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int b[10];\n"
|
||||||
|
" for (int i=0;i<10;++i)\n"
|
||||||
|
" b[i] = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a = 0;\n"
|
" int a = 0;\n"
|
||||||
|
@ -471,6 +620,12 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const struct A * i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int * i[2];\n"
|
" int * i[2];\n"
|
||||||
|
@ -495,6 +650,42 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" struct A * i[2];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const struct A * i[2];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i = 0;\n"
|
||||||
|
" int &j = i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'j' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i;\n"
|
||||||
|
" int &j = i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'j' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i;\n"
|
||||||
|
" int &j = i;\n"
|
||||||
|
" j = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" A * i;\n"
|
" A * i;\n"
|
||||||
|
@ -523,26 +714,6 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
|
||||||
"{\n"
|
|
||||||
" int i = 0;\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
|
||||||
"{\n"
|
|
||||||
" int i(0);\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
|
||||||
"{\n"
|
|
||||||
" char *i;\n"
|
|
||||||
" i = fgets();\n"
|
|
||||||
"}\n");
|
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
|
|
||||||
ASSERT_EQUALS("", errout.str()); // current value - catch changes
|
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char *i;\n"
|
" char *i;\n"
|
||||||
|
@ -573,6 +744,28 @@ private:
|
||||||
" p[i] = 0;\n"
|
" p[i] = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int x;\n"
|
||||||
|
" a[0] = 0;\n"
|
||||||
|
" x = a[0];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'x' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a, b, c;\n"
|
||||||
|
" a = b = c = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int * foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" return &undefined[0];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvar9()
|
void localvar9()
|
||||||
|
@ -654,8 +847,7 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
" x = a;\n"
|
" x = a;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str()); // catch changes
|
ASSERT_EQUALS("", errout.str());
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
|
||||||
|
|
||||||
// The variable 'a' is initialized. But the initialized value is
|
// The variable 'a' is initialized. But the initialized value is
|
||||||
// never used. It is only initialized for security reasons.
|
// never used. It is only initialized for security reasons.
|
||||||
|
@ -671,17 +863,100 @@ private:
|
||||||
" x = a;\n"
|
" x = a;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvaralias()
|
void localvaralias()
|
||||||
{
|
{
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a;\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: a\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int *b = a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: a\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int a;\n"
|
" int a;\n"
|
||||||
" int *b = &a;\n"
|
" int *b = &a;\n"
|
||||||
" *b = 0;\n"
|
" *b = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a;\n"
|
||||||
|
" char *b = (char *)&a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a;\n"
|
||||||
|
" char *b = static_cast<char *>(&a);\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
// a is not a local variable and b is aliased to it (not supported yet)
|
||||||
|
functionVariableUsage("int a;\n"
|
||||||
|
"void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS(std::string("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
// a is not a local variable and b is aliased to it (not supported yet)
|
||||||
|
functionVariableUsage("void foo(int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
// a is not a local variable and b is aliased to it (not supported yet)
|
||||||
|
functionVariableUsage("class A\n"
|
||||||
|
"{\n"
|
||||||
|
" int a;\n"
|
||||||
|
" void foo()\n"
|
||||||
|
" {\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS(std::string("[test.cpp:6]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int a;\n"
|
||||||
|
"void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo(int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("class A\n"
|
||||||
|
"{\n"
|
||||||
|
" int a;\n"
|
||||||
|
" void foo()\n"
|
||||||
|
" {\n"
|
||||||
|
" int *b = &a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
ASSERT_EQUALS(std::string(""), errout.str());
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
|
@ -690,8 +965,143 @@ private:
|
||||||
" int *b = a;\n"
|
" int *b = a;\n"
|
||||||
" *b = 0;\n"
|
" *b = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n"), errout.str());
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
TODO_ASSERT_EQUALS(std::string(""), errout.str());
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" char *b = (char *)a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" char *b = static_cast<char *>(a);\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int a[10];\n"
|
||||||
|
"void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo(int a[10])\n"
|
||||||
|
"{\n"
|
||||||
|
" int *b = a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("class A\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" void foo()\n"
|
||||||
|
" {\n"
|
||||||
|
" int *b = a;\n"
|
||||||
|
" *b = 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string(""), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int *b = a;\n"
|
||||||
|
" int *c = b;\n"
|
||||||
|
" *c = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int b[10];\n"
|
||||||
|
" int *c = a;\n"
|
||||||
|
" int *d = b;\n"
|
||||||
|
" *d = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: a\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"
|
||||||
|
"[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int b[10];\n"
|
||||||
|
" int *c = a;\n"
|
||||||
|
" c = b;\n"
|
||||||
|
" *c = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: a\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10];\n"
|
||||||
|
" int b[10];\n"
|
||||||
|
" int *c = a;\n"
|
||||||
|
" c = b;\n"
|
||||||
|
" *c = 0;\n"
|
||||||
|
" c = a;\n"
|
||||||
|
" *c = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"
|
||||||
|
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" b[-10] = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" b[-10] = 0;\n"
|
||||||
|
" int * c = b - 10;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"
|
||||||
|
"[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" int * c = b - 10;\n"
|
||||||
|
" x = c[0];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" int * c = b - 10;\n"
|
||||||
|
" c[1] = 0;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" int * c = b - 10;\n"
|
||||||
|
" c[1] = c[0];\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a[10], * b = a + 10;\n"
|
||||||
|
" int * c = b - 10;\n"
|
||||||
|
" int d = c[0];\n"
|
||||||
|
" f(d);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is not assigned a value\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvarasm()
|
void localvarasm()
|
||||||
|
|
Loading…
Reference in New Issue