Refactorized CheckUnusedVar
This commit is contained in:
parent
b6b97fa43d
commit
6dc2a6e7ab
|
@ -1398,7 +1398,7 @@ void CheckOther::checkWrongPrintfScanfArguments()
|
||||||
case 'G':
|
case 'G':
|
||||||
if (varTypeTok && varTypeTok->str() == "const")
|
if (varTypeTok && varTypeTok->str() == "const")
|
||||||
varTypeTok = varTypeTok->next();
|
varTypeTok = varTypeTok->next();
|
||||||
if (varTypeTok && (isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "float|double") || variableInfo->isPointer() || variableInfo->isArray()))
|
if (varTypeTok && ((isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "float|double")) || variableInfo->isPointer() || variableInfo->isArray()))
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, *i);
|
invalidPrintfArgTypeError_float(tok, numFormat, *i);
|
||||||
else if (Token::Match(argListTok, "%str%"))
|
else if (Token::Match(argListTok, "%str%"))
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, *i);
|
invalidPrintfArgTypeError_float(tok, numFormat, *i);
|
||||||
|
|
|
@ -28,70 +28,19 @@ namespace {
|
||||||
CheckUnusedVar instance;
|
CheckUnusedVar instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This class is used to capture the control flow within a function.
|
|
||||||
*/
|
|
||||||
class ScopeInfo {
|
|
||||||
public:
|
|
||||||
ScopeInfo() : _token(NULL), _parent(NULL) { }
|
|
||||||
ScopeInfo(const Token *token, ScopeInfo *parent_) : _token(token), _parent(parent_) { }
|
|
||||||
~ScopeInfo();
|
|
||||||
|
|
||||||
ScopeInfo *parent() {
|
|
||||||
return _parent;
|
|
||||||
}
|
|
||||||
ScopeInfo *addChild(const Token *token);
|
|
||||||
void remove(ScopeInfo *scope);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Token *_token;
|
|
||||||
ScopeInfo *_parent;
|
|
||||||
std::list<ScopeInfo *> _children;
|
|
||||||
};
|
|
||||||
|
|
||||||
ScopeInfo::~ScopeInfo()
|
|
||||||
{
|
|
||||||
while (!_children.empty()) {
|
|
||||||
delete *_children.begin();
|
|
||||||
_children.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopeInfo *ScopeInfo::addChild(const Token *token)
|
|
||||||
{
|
|
||||||
ScopeInfo *temp = new ScopeInfo(token, this);
|
|
||||||
|
|
||||||
_children.push_back(temp);
|
|
||||||
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScopeInfo::remove(ScopeInfo *scope)
|
|
||||||
{
|
|
||||||
std::list<ScopeInfo *>::iterator it;
|
|
||||||
|
|
||||||
for (it = _children.begin(); it != _children.end(); ++it) {
|
|
||||||
if (*it == scope) {
|
|
||||||
delete *it;
|
|
||||||
_children.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class is used create a list of variables within a function.
|
* @brief This class is used create a list of variables within a function.
|
||||||
*/
|
*/
|
||||||
class Variables {
|
class Variables {
|
||||||
public:
|
public:
|
||||||
enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray, pointerPointer };
|
enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray, pointerPointer, none };
|
||||||
|
|
||||||
/** 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,
|
||||||
VariableType type = standard,
|
VariableType type = standard,
|
||||||
ScopeInfo *scope = NULL,
|
const Scope *scope = NULL,
|
||||||
bool read = false,
|
bool read = false,
|
||||||
bool write = false,
|
bool write = false,
|
||||||
bool modified = false,
|
bool modified = false,
|
||||||
|
@ -118,13 +67,13 @@ public:
|
||||||
|
|
||||||
const Token *_name;
|
const Token *_name;
|
||||||
VariableType _type;
|
VariableType _type;
|
||||||
ScopeInfo *_scope;
|
const Scope *_scope;
|
||||||
bool _read;
|
bool _read;
|
||||||
bool _write;
|
bool _write;
|
||||||
bool _modified; // read/modify/write
|
bool _modified; // read/modify/write
|
||||||
bool _allocateMemory;
|
bool _allocateMemory;
|
||||||
std::set<unsigned int> _aliases;
|
std::set<unsigned int> _aliases;
|
||||||
std::set<ScopeInfo *> _assignments;
|
std::set<const Scope*> _assignments;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<unsigned int, VariableUsage> VariableMap;
|
typedef std::map<unsigned int, VariableUsage> VariableMap;
|
||||||
|
@ -132,10 +81,10 @@ public:
|
||||||
void clear() {
|
void clear() {
|
||||||
_varUsage.clear();
|
_varUsage.clear();
|
||||||
}
|
}
|
||||||
VariableMap &varUsage() {
|
const VariableMap &varUsage() {
|
||||||
return _varUsage;
|
return _varUsage;
|
||||||
}
|
}
|
||||||
void addVar(const Token *name, VariableType type, ScopeInfo *scope, bool write_);
|
void addVar(const Token *name, VariableType type, const Scope *scope, bool write_);
|
||||||
void allocateMemory(unsigned int varid);
|
void allocateMemory(unsigned int varid);
|
||||||
void read(unsigned int varid);
|
void read(unsigned int varid);
|
||||||
void readAliases(unsigned int varid);
|
void readAliases(unsigned int varid);
|
||||||
|
@ -158,6 +107,7 @@ private:
|
||||||
VariableMap _varUsage;
|
VariableMap _varUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias the 2 given variables. Either replace the existing aliases if
|
* Alias the 2 given variables. Either replace the existing aliases if
|
||||||
* they exist or merge them. You would replace an existing alias when this
|
* they exist or merge them. You would replace an existing alias when this
|
||||||
|
@ -177,11 +127,9 @@ void Variables::alias(unsigned int varid1, unsigned int varid2, bool replace)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<unsigned int>::iterator i;
|
|
||||||
|
|
||||||
if (replace) {
|
if (replace) {
|
||||||
// remove var1 from all aliases
|
// remove var1 from all aliases
|
||||||
for (i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i) {
|
for (std::set<unsigned int>::iterator i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i) {
|
||||||
VariableUsage *temp = find(*i);
|
VariableUsage *temp = find(*i);
|
||||||
|
|
||||||
if (temp)
|
if (temp)
|
||||||
|
@ -193,7 +141,7 @@ void Variables::alias(unsigned int varid1, unsigned int varid2, bool replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// var1 gets all var2s aliases
|
// var1 gets all var2s aliases
|
||||||
for (i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i) {
|
for (std::set<unsigned int>::iterator i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i) {
|
||||||
if (*i != varid1)
|
if (*i != varid1)
|
||||||
var1->_aliases.insert(*i);
|
var1->_aliases.insert(*i);
|
||||||
}
|
}
|
||||||
|
@ -246,7 +194,7 @@ void Variables::eraseAll(unsigned int varid)
|
||||||
|
|
||||||
void Variables::addVar(const Token *name,
|
void Variables::addVar(const Token *name,
|
||||||
VariableType type,
|
VariableType type,
|
||||||
ScopeInfo *scope,
|
const Scope *scope,
|
||||||
bool write_)
|
bool write_)
|
||||||
{
|
{
|
||||||
if (name->varId() > 0)
|
if (name->varId() > 0)
|
||||||
|
@ -391,15 +339,15 @@ Variables::VariableUsage *Variables::find(unsigned int varid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int doAssignment(Variables &variables, const Token *tok, bool dereference, ScopeInfo *scope)
|
static int doAssignment(Variables &variables, const Token *tok, bool dereference, const Scope *scope)
|
||||||
{
|
{
|
||||||
int next = 0;
|
|
||||||
|
|
||||||
// a = a + b;
|
// a = a + b;
|
||||||
if (Token::Match(tok, "%var% = %var% !!;") && tok->str() == tok->strAt(2)) {
|
if (Token::Match(tok, "%var% = %var% !!;") && tok->str() == tok->strAt(2)) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int next = 0;
|
||||||
|
|
||||||
// check for aliased variable
|
// check for aliased variable
|
||||||
const unsigned int varid1 = tok->varId();
|
const unsigned int varid1 = tok->varId();
|
||||||
Variables::VariableUsage *var1 = variables.find(varid1);
|
Variables::VariableUsage *var1 = variables.find(varid1);
|
||||||
|
@ -504,13 +452,8 @@ static int doAssignment(Variables &variables, const Token *tok, bool dereference
|
||||||
|
|
||||||
// not in same scope as declaration
|
// not in same scope as declaration
|
||||||
else {
|
else {
|
||||||
std::set<ScopeInfo *>::iterator assignment;
|
|
||||||
|
|
||||||
// check for an assignment in this scope
|
|
||||||
assignment = var1->_assignments.find(scope);
|
|
||||||
|
|
||||||
// no other assignment in this scope
|
// no other assignment in this scope
|
||||||
if (assignment == var1->_assignments.end()) {
|
if (var1->_assignments.find(scope) == var1->_assignments.end()) {
|
||||||
// nothing to replace
|
// nothing to replace
|
||||||
if (var1->_assignments.empty())
|
if (var1->_assignments.empty())
|
||||||
replace = false;
|
replace = false;
|
||||||
|
@ -559,13 +502,8 @@ static int doAssignment(Variables &variables, const Token *tok, bool dereference
|
||||||
if (var1->_scope == scope)
|
if (var1->_scope == scope)
|
||||||
variables.clearAliases(varid1);
|
variables.clearAliases(varid1);
|
||||||
else {
|
else {
|
||||||
std::set<ScopeInfo *>::iterator assignment;
|
|
||||||
|
|
||||||
// check for an assignment in this scope
|
|
||||||
assignment = var1->_assignments.find(scope);
|
|
||||||
|
|
||||||
// no other assignment in this scope
|
// no other assignment in this scope
|
||||||
if (assignment == var1->_assignments.end()) {
|
if (var1->_assignments.find(scope) == var1->_assignments.end()) {
|
||||||
/**
|
/**
|
||||||
* @todo determine if existing aliases should be discarded
|
* @todo determine if existing aliases should be discarded
|
||||||
*/
|
*/
|
||||||
|
@ -605,408 +543,133 @@ static int doAssignment(Variables &variables, const Token *tok, bool dereference
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nextIsStandardType(const Token *tok)
|
static bool isRecordTypeWithoutSideEffects(const Variable& var)
|
||||||
{
|
{
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "static")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
return tok->isStandardType();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool nextIsStandardTypeOrVoid(const Token *tok)
|
|
||||||
{
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "static")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
return tok->isStandardType() || tok->str() == "void";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckUnusedVar::isRecordTypeWithoutSideEffects(const Token *tok)
|
|
||||||
{
|
|
||||||
const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId());
|
|
||||||
|
|
||||||
// a type that has no side effects (no constructors and no members with constructors)
|
// a type that has no side effects (no constructors and no members with constructors)
|
||||||
/** @todo false negative: check base class for side effects */
|
/** @todo false negative: check base class for side effects */
|
||||||
/** @todo false negative: check constructors for side effects */
|
/** @todo false negative: check constructors for side effects */
|
||||||
if (var && var->type() && var->type()->numConstructors == 0 &&
|
if (var.type() && var.type()->numConstructors == 0 &&
|
||||||
(var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) &&
|
(var.type()->varlist.empty() || var.type()->needInitialization == Scope::True) &&
|
||||||
var->type()->derivedFrom.empty())
|
var.type()->derivedFrom.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isPartOfClassStructUnion(const Token* tok)
|
||||||
|
{
|
||||||
|
for (; tok; tok = tok->previous()) {
|
||||||
|
if (tok->str() == "}" || tok->str() == ")")
|
||||||
|
tok = tok->link();
|
||||||
|
else if (tok->str() == "(")
|
||||||
|
return(false);
|
||||||
|
else if (tok->str() == "{") {
|
||||||
|
return(tok->strAt(-1) == "struct" || tok->strAt(-2) == "struct" || tok->strAt(-1) == "class" || tok->strAt(-2) == "class" || tok->strAt(-1) == "union" || tok->strAt(-2) == "union");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Usage of function variables
|
// Usage of function variables
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void CheckUnusedVar::checkFunctionVariableUsage()
|
void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables)
|
||||||
{
|
{
|
||||||
if (!_settings->isEnabled("style"))
|
if (scope->type == Scope::eClass || scope->type == Scope::eUnion || scope->type == Scope::eStruct)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Parse all executing scopes..
|
// Find declarations
|
||||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
|
||||||
|
Variables::VariableType type = Variables::none;
|
||||||
std::list<Scope>::const_iterator scope;
|
if (i->isArray() && (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*"))
|
||||||
|
type = Variables::pointerArray;
|
||||||
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
|
else if (i->isArray() && i->nameToken()->previous()->str() == "&")
|
||||||
// only check functions
|
type = Variables::referenceArray;
|
||||||
if (scope->type != Scope::eFunction)
|
else if (i->isArray())
|
||||||
|
type = Variables::array;
|
||||||
|
else if (i->nameToken()->previous()->str() == "&")
|
||||||
|
type = Variables::reference;
|
||||||
|
else if (i->nameToken()->previous()->str() == "*" && i->nameToken()->strAt(-2) == "*")
|
||||||
|
type = Variables::pointerPointer;
|
||||||
|
else if (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*")
|
||||||
|
type = Variables::pointer;
|
||||||
|
else if (i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(*i) || Token::simpleMatch(i->nameToken()->tokAt(-3), "std :: string"))
|
||||||
|
type = Variables::standard;
|
||||||
|
if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
|
||||||
continue;
|
continue;
|
||||||
|
const Token* defValTok = i->nameToken()->next();
|
||||||
// First token for the current scope..
|
for (; defValTok; defValTok = defValTok->next()) {
|
||||||
const Token *const tok1 = scope->classStart;
|
if (defValTok->str() == "[")
|
||||||
|
defValTok = defValTok->link();
|
||||||
// varId, usage {read, write, modified}
|
else if (defValTok->str() == "(" || defValTok->str() == "=") {
|
||||||
Variables variables;
|
variables.addVar(i->nameToken(), type, scope, true);
|
||||||
|
|
||||||
// scopes
|
|
||||||
ScopeInfo scopes;
|
|
||||||
ScopeInfo *info = &scopes;
|
|
||||||
|
|
||||||
unsigned int indentlevel = 0;
|
|
||||||
for (const Token *tok = tok1; tok; tok = tok->next()) {
|
|
||||||
if (tok->str() == "{") {
|
|
||||||
// replace the head node when found
|
|
||||||
if (indentlevel == 0)
|
|
||||||
scopes = ScopeInfo(tok, NULL);
|
|
||||||
// add the new scope
|
|
||||||
else
|
|
||||||
info = info->addChild(tok);
|
|
||||||
++indentlevel;
|
|
||||||
} else if (tok->str() == "}") {
|
|
||||||
--indentlevel;
|
|
||||||
|
|
||||||
info = info->parent();
|
|
||||||
|
|
||||||
if (indentlevel == 0)
|
|
||||||
break;
|
break;
|
||||||
} else if (Token::Match(tok, "struct|union|class {") ||
|
} else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
|
||||||
Token::Match(tok, "struct|union|class %type% {|:")) {
|
variables.addVar(i->nameToken(), type, scope, i->isStatic());
|
||||||
while (tok->str() != "{")
|
break;
|
||||||
tok = tok->next();
|
}
|
||||||
|
}
|
||||||
|
if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read.
|
||||||
|
variables.read(i->nameToken()->tokAt(2)->varId());
|
||||||
|
|
||||||
|
if (Token::simpleMatch(defValTok, "= {")) {
|
||||||
|
for (const Token* tok = defValTok; tok && tok != defValTok->linkAt(1); tok = tok->next())
|
||||||
|
if (Token::Match(tok, "%var%")) // Variables used to initialize the array read.
|
||||||
|
variables.read(tok->varId());
|
||||||
|
} else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read.
|
||||||
|
variables.readAll(defValTok->next()->varId()); // ReadAll?
|
||||||
|
else if (defValTok->str() == "=") {
|
||||||
|
doAssignment(variables, i->nameToken(), false, scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check variable usage
|
||||||
|
for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) {
|
||||||
|
if (tok->str() == "for" || tok->str() == "catch") {
|
||||||
|
for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
|
||||||
|
if ((*i)->classDef == tok) { // Find associated scope
|
||||||
|
checkFunctionVariableUsage_iterateScopes(*i, variables); // Scan child scope
|
||||||
|
tok = (*i)->classStart->link();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tok->str() == "{") {
|
||||||
|
for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
|
||||||
|
if ((*i)->classStart == tok) { // Find associated scope
|
||||||
|
checkFunctionVariableUsage_iterateScopes(*i, variables); // Scan child scope
|
||||||
tok = tok->link();
|
tok = tok->link();
|
||||||
if (! tok)
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tok)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, "[;{}] asm ( %str% )")) {
|
if (Token::Match(tok, "asm ( %str% )")) {
|
||||||
variables.clear();
|
variables.clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// standard type declaration with possible initialization
|
if (Token::Match(tok, "%type% const| *|&| const| *| const| %var% ;|[|,|)|=|(") && tok->str() != "return" && tok->str() != "throw") { // Declaration: Skip
|
||||||
// int i; int j = 0; static int k;
|
const Token* old = tok;
|
||||||
if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") &&
|
|
||||||
!Token::Match(tok->next(), "return|throw")) {
|
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
while (Token::Match(tok, "const|*|&"))
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
tok = Token::findmatch(tok, "[,;)=(]");
|
||||||
if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next())) {
|
if (tok && Token::Match(tok, "( %var% )")) // Simple initialization through copy ctor
|
||||||
variables.addVar(tok->next(), Variables::standard, info,
|
tok = tok->next();
|
||||||
tok->strAt(2) == "=" || isStatic);
|
else if (tok && Token::Match(tok, "= %var% ;")) // Simple initialization
|
||||||
|
tok = tok->next();
|
||||||
|
if (!tok)
|
||||||
|
break;
|
||||||
|
if (tok->str() == ")" && tok->link() && Token::Match(tok->link()->previous(), "if|for|while"))
|
||||||
|
tok = old;
|
||||||
}
|
}
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard const type declaration
|
|
||||||
// const int i = x;
|
|
||||||
else if (Token::Match(tok, "[;{}] const %type% %var% =")) {
|
|
||||||
tok = tok->tokAt(2);
|
|
||||||
|
|
||||||
if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next()))
|
|
||||||
variables.addVar(tok->next(), Variables::standard, info, true);
|
|
||||||
|
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::string declaration with possible initialization
|
|
||||||
// std::string s; std::string s = "string";
|
|
||||||
else if (Token::Match(tok, "[;{}] static| std :: string %var% ;|=")) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
tok = tok->tokAt(3);
|
|
||||||
variables.addVar(tok, Variables::standard, info,
|
|
||||||
tok->next()->str() == "=" || isStatic);
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard struct type declaration with possible initialization
|
|
||||||
// struct S s; struct S s = { 0 }; static struct S s;
|
|
||||||
else if (Token::Match(tok, "[;{}] static| struct %type% %var% ;|=") &&
|
|
||||||
(isRecordTypeWithoutSideEffects(tok->strAt(1) == "static" ? tok->tokAt(4) : tok->tokAt(3)))) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
variables.addVar(tok->next(), Variables::standard, info,
|
|
||||||
tok->strAt(2) == "=" || isStatic);
|
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard type declaration and initialization using constructor
|
|
||||||
// int i(0); static int j(0);
|
|
||||||
else if (Token::Match(tok, "[;{}] static| %type% %var% ( %any% ) ;") &&
|
|
||||||
nextIsStandardType(tok)) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "static")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
variables.addVar(tok->next(), Variables::standard, info, true);
|
|
||||||
|
|
||||||
// check if a local variable is used to initialize this variable
|
|
||||||
if (tok->tokAt(3)->varId() > 0)
|
|
||||||
variables.readAll(tok->tokAt(3)->varId());
|
|
||||||
tok = tok->tokAt(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard type declaration of array of with possible initialization
|
|
||||||
// int i[10]; int j[2] = { 0, 1 }; static int k[2] = { 2, 3 };
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| %type% *| %var% [ %any% ] ;|=") &&
|
|
||||||
nextIsStandardType(tok)) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() != "return" && tok->str() != "throw") {
|
|
||||||
bool isPointer = bool(tok->strAt(1) == "*");
|
|
||||||
const Token * const nametok = tok->tokAt(isPointer ? 2 : 1);
|
|
||||||
|
|
||||||
variables.addVar(nametok, isPointer ? Variables::pointerArray : Variables::array, info,
|
|
||||||
nametok->strAt(4) == "=" || isStatic);
|
|
||||||
|
|
||||||
// check for reading array size from local variable
|
|
||||||
if (nametok->tokAt(2)->varId() != 0)
|
|
||||||
variables.read(nametok->tokAt(2)->varId());
|
|
||||||
|
|
||||||
// look at initializers
|
|
||||||
if (Token::simpleMatch(nametok->tokAt(4), "= {")) {
|
|
||||||
tok = nametok->tokAt(6);
|
|
||||||
while (tok->str() != "}") {
|
|
||||||
if (Token::Match(tok, "%var%"))
|
|
||||||
variables.read(tok->varId());
|
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
tok = nametok->tokAt(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointer or reference declaration with possible initialization
|
|
||||||
// int * i; int * j = 0; static int * k = 0;
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% ;|=")) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->strAt(1) == "::")
|
|
||||||
tok = tok->tokAt(2);
|
|
||||||
|
|
||||||
if (tok->str() != "return" && tok->str() != "throw") {
|
|
||||||
Variables::VariableType type;
|
|
||||||
|
|
||||||
if (tok->next()->str() == "*")
|
|
||||||
type = Variables::pointer;
|
|
||||||
else
|
|
||||||
type = Variables::reference;
|
|
||||||
|
|
||||||
bool written = tok->strAt(3) == "=";
|
|
||||||
|
|
||||||
variables.addVar(tok->tokAt(2), type, info, written || isStatic);
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// check for assignment
|
|
||||||
if (written)
|
|
||||||
offset = doAssignment(variables, tok->tokAt(2), false, info);
|
|
||||||
|
|
||||||
tok = tok->tokAt(2 + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointer to pointer declaration with possible initialization
|
|
||||||
// int ** i; int ** j = 0; static int ** k = 0;
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| %type% * * %var% ;|=")) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() != "return") {
|
|
||||||
bool written = tok->strAt(4) == "=";
|
|
||||||
|
|
||||||
variables.addVar(tok->tokAt(3), Variables::pointerPointer, info, written || isStatic);
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// check for assignment
|
|
||||||
if (written)
|
|
||||||
offset = doAssignment(variables, tok->tokAt(3), false, info);
|
|
||||||
|
|
||||||
tok = tok->tokAt(3 + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointer or reference of struct or union declaration with possible initialization
|
|
||||||
// struct s * i; struct s * j = 0; static struct s * k = 0;
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% ;|=")) {
|
|
||||||
Variables::VariableType type;
|
|
||||||
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->strAt(2) == "*")
|
|
||||||
type = Variables::pointer;
|
|
||||||
else
|
|
||||||
type = Variables::reference;
|
|
||||||
|
|
||||||
const bool written = tok->strAt(4) == "=";
|
|
||||||
|
|
||||||
variables.addVar(tok->tokAt(3), type, info, written || isStatic);
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// check for assignment
|
|
||||||
if (written)
|
|
||||||
offset = doAssignment(variables, tok->tokAt(3), false, info);
|
|
||||||
|
|
||||||
tok = tok->tokAt(3 + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointer or reference declaration with initialization using constructor
|
|
||||||
// int * i(j); int * k(i); static int * l(i);
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| %type% &|* %var% ( %any% ) ;") &&
|
|
||||||
nextIsStandardTypeOrVoid(tok)) {
|
|
||||||
Variables::VariableType type;
|
|
||||||
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "static")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->next()->str() == "*")
|
|
||||||
type = Variables::pointer;
|
|
||||||
else
|
|
||||||
type = Variables::reference;
|
|
||||||
|
|
||||||
unsigned int varid = 0;
|
|
||||||
|
|
||||||
// check for aliased variable
|
|
||||||
if (Token::Match(tok->tokAt(4), "%var%"))
|
|
||||||
varid = tok->tokAt(4)->varId();
|
|
||||||
|
|
||||||
variables.addVar(tok->tokAt(2), type, info, true);
|
|
||||||
|
|
||||||
// check if a local variable is used to initialize this variable
|
|
||||||
if (varid > 0) {
|
|
||||||
Variables::VariableUsage *var = variables.find(varid);
|
|
||||||
|
|
||||||
if (type == Variables::pointer) {
|
|
||||||
variables.use(tok->tokAt(4)->varId());
|
|
||||||
|
|
||||||
if (var && (var->_type == Variables::array ||
|
|
||||||
var->_type == Variables::pointer))
|
|
||||||
var->_aliases.insert(tok->varId());
|
|
||||||
} else {
|
|
||||||
variables.readAll(tok->tokAt(4)->varId());
|
|
||||||
if (var)
|
|
||||||
var->_aliases.insert(tok->varId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tok = tok->tokAt(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// array of pointer or reference declaration with possible initialization
|
|
||||||
// int * p[10]; int * q[10] = { 0 }; static int * * r[10] = { 0 };
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% [ %any% ] ;|=")) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() != "return") {
|
|
||||||
variables.addVar(tok->tokAt(2),
|
|
||||||
tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray, info,
|
|
||||||
tok->strAt(6) == "=" || isStatic);
|
|
||||||
|
|
||||||
// check for reading array size from local variable
|
|
||||||
if (tok->tokAt(4)->varId() != 0)
|
|
||||||
variables.read(tok->tokAt(4)->varId());
|
|
||||||
|
|
||||||
tok = tok->tokAt(5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// array of pointer or reference of struct or union declaration with possible initialization
|
|
||||||
// struct S * p[10]; struct T * q[10] = { 0 }; static struct S * r[10] = { 0 };
|
|
||||||
else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% [ %any% ] ;|=")) {
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
const bool isStatic = tok->str() == "static";
|
|
||||||
if (isStatic)
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (tok->str() == "const")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
variables.addVar(tok->tokAt(3),
|
|
||||||
tok->strAt(2) == "*" ? Variables::pointerArray : Variables::referenceArray, info,
|
|
||||||
tok->strAt(7) == "=" || isStatic);
|
|
||||||
|
|
||||||
// check for reading array size from local variable
|
|
||||||
if (tok->tokAt(5)->varId() != 0)
|
|
||||||
variables.read(tok->tokAt(5)->varId());
|
|
||||||
|
|
||||||
tok = tok->tokAt(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Freeing memory (not considered "using" the pointer if it was also allocated in this function)
|
// Freeing memory (not considered "using" the pointer if it was also allocated in this function)
|
||||||
else if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") ||
|
if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") ||
|
||||||
Token::Match(tok, "delete %var% ;") ||
|
Token::Match(tok, "delete %var% ;") ||
|
||||||
Token::Match(tok, "delete [ ] %var% ;")) {
|
Token::Match(tok, "delete [ ] %var% ;")) {
|
||||||
unsigned int varid = 0;
|
unsigned int varid = 0;
|
||||||
|
@ -1015,10 +678,10 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
tok = tok->tokAt(3);
|
tok = tok->tokAt(3);
|
||||||
} else if (tok->strAt(1) == "[") {
|
} else if (tok->strAt(1) == "[") {
|
||||||
varid = tok->tokAt(3)->varId();
|
varid = tok->tokAt(3)->varId();
|
||||||
tok = tok->tokAt(4);
|
tok = tok->tokAt(3);
|
||||||
} else {
|
} else {
|
||||||
varid = tok->next()->varId();
|
varid = tok->next()->varId();
|
||||||
tok = tok->tokAt(2);
|
tok = tok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
Variables::VariableUsage *var = variables.find(varid);
|
Variables::VariableUsage *var = variables.find(varid);
|
||||||
|
@ -1060,7 +723,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
const unsigned int varid1 = tok->varId();
|
const unsigned int varid1 = tok->varId();
|
||||||
const Token *start = tok;
|
const Token *start = tok;
|
||||||
|
|
||||||
tok = tok->tokAt(doAssignment(variables, tok, dereference, info));
|
tok = tok->tokAt(doAssignment(variables, tok, dereference, scope));
|
||||||
|
|
||||||
if (pre || post)
|
if (pre || post)
|
||||||
variables.use(varid1);
|
variables.use(varid1);
|
||||||
|
@ -1092,7 +755,8 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
|
|
||||||
// is it a user defined type?
|
// is it a user defined type?
|
||||||
if (!type->isStandardType()) {
|
if (!type->isStandardType()) {
|
||||||
if (!isRecordTypeWithoutSideEffects(start))
|
const Variable* variable = _tokenizer->getSymbolDatabase()->getVariableFromVarId(start->varId());
|
||||||
|
if (!variable || !isRecordTypeWithoutSideEffects(*variable))
|
||||||
allocate = false;
|
allocate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1157,15 +821,15 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
|
|
||||||
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
|
||||||
else if (Token::Match(tok, "[;{}] %var% >>"))
|
else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]"))
|
||||||
variables.use(tok->next()->varId()); // use = read + write
|
variables.read(tok->varId());
|
||||||
|
|
||||||
// function parameter
|
// function parameter
|
||||||
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
|
||||||
else if (Token::Match(tok, "[(,] %var% [,)]") && tok->previous()->str() != "*")
|
else if (Token::Match(tok, "[(,] %var% [,)]") && tok->previous()->str() != "*") {
|
||||||
variables.use(tok->next()->varId()); // use = read + write
|
variables.use(tok->next()->varId()); // use = read + write
|
||||||
else if (Token::Match(tok, "[(,] (") &&
|
} else if (Token::Match(tok, "[(,] (") &&
|
||||||
Token::Match(tok->next()->link(), ") %var% [,)]"))
|
Token::Match(tok->next()->link(), ") %var% [,)]"))
|
||||||
variables.use(tok->next()->link()->next()->varId()); // use = read + write
|
variables.use(tok->next()->link()->next()->varId()); // use = read + write
|
||||||
|
|
||||||
|
@ -1183,24 +847,24 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
variables.use(tok->varId()); // use = read + write
|
variables.use(tok->varId()); // use = read + write
|
||||||
|
|
||||||
else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) &&
|
else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) &&
|
||||||
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")))
|
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")) && tok->strAt(2) != "=")
|
||||||
variables.readAll(tok->next()->varId());
|
variables.readAll(tok->next()->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp()))
|
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp()))
|
||||||
variables.readAll(tok->varId());
|
variables.readAll(tok->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "; %var% ;"))
|
else if (Token::Match(tok, "%var% ;") && Token::Match(tok->previous(), "[;{}:]"))
|
||||||
variables.readAll(tok->next()->varId());
|
variables.readAll(tok->varId());
|
||||||
|
|
||||||
else if (Token::Match(tok, "++|-- %var%")) {
|
else if (Token::Match(tok, "++|-- %var%")) {
|
||||||
if (tok->strAt(-1) != ";")
|
if (!Token::Match(tok->previous(), "[;{}:]"))
|
||||||
variables.use(tok->next()->varId());
|
variables.use(tok->next()->varId());
|
||||||
else
|
else
|
||||||
variables.modified(tok->next()->varId());
|
variables.modified(tok->next()->varId());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok, "%var% ++|--")) {
|
else if (Token::Match(tok, "%var% ++|--")) {
|
||||||
if (tok->strAt(-1) != ";")
|
if (!Token::Match(tok->previous(), "[;{}:]"))
|
||||||
variables.use(tok->varId());
|
variables.use(tok->varId());
|
||||||
else
|
else
|
||||||
variables.modified(tok->varId());
|
variables.modified(tok->varId());
|
||||||
|
@ -1216,10 +880,29 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
|
{
|
||||||
|
if (!_settings->isEnabled("style"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Parse all executing scopes..
|
||||||
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
|
for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
|
||||||
|
// only check functions
|
||||||
|
if (scope->type != Scope::eFunction)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// varId, usage {read, write, modified}
|
||||||
|
Variables variables;
|
||||||
|
|
||||||
|
checkFunctionVariableUsage_iterateScopes(&*scope, variables);
|
||||||
|
|
||||||
|
|
||||||
// Check usage of all variables in the current scope..
|
// Check usage of all variables in the current scope..
|
||||||
Variables::VariableMap::const_iterator it;
|
for (Variables::VariableMap::const_iterator it = variables.varUsage().begin(); it != variables.varUsage().end(); ++it) {
|
||||||
for (it = variables.varUsage().begin(); it != variables.varUsage().end(); ++it) {
|
|
||||||
const Variables::VariableUsage &usage = it->second;
|
const Variables::VariableUsage &usage = it->second;
|
||||||
const std::string &varname = usage._name->str();
|
const std::string &varname = usage._name->str();
|
||||||
|
|
||||||
|
@ -1369,4 +1052,3 @@ void CheckUnusedVar::unusedStructMemberError(const Token *tok, const std::string
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used");
|
reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
class Token;
|
class Token;
|
||||||
|
class Scope;
|
||||||
|
class Variables;
|
||||||
|
|
||||||
/// @addtogroup Checks
|
/// @addtogroup Checks
|
||||||
/// @{
|
/// @{
|
||||||
|
@ -59,6 +61,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief %Check for unused function variables */
|
/** @brief %Check for unused function variables */
|
||||||
|
void checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables);
|
||||||
|
void checkVariableUsage(const Scope* const scope, const Token* start, Variables& variables);
|
||||||
void checkFunctionVariableUsage();
|
void checkFunctionVariableUsage();
|
||||||
|
|
||||||
/** @brief %Check that all struct members are used */
|
/** @brief %Check that all struct members are used */
|
||||||
|
@ -96,10 +100,6 @@ public:
|
||||||
"* unassigned variable\n"
|
"* unassigned variable\n"
|
||||||
"* unused struct member\n";
|
"* unused struct member\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/** @brief check if token is a record type without side effects */
|
|
||||||
bool isRecordTypeWithoutSideEffects(const Token *tok);
|
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -83,6 +83,7 @@ private:
|
||||||
TEST_CASE(localvar35); // ticket #2535
|
TEST_CASE(localvar35); // ticket #2535
|
||||||
TEST_CASE(localvar36); // ticket #2805
|
TEST_CASE(localvar36); // ticket #2805
|
||||||
TEST_CASE(localvar37); // ticket #3078
|
TEST_CASE(localvar37); // ticket #3078
|
||||||
|
TEST_CASE(localvar38);
|
||||||
TEST_CASE(localvaralias1);
|
TEST_CASE(localvaralias1);
|
||||||
TEST_CASE(localvaralias2); // ticket #1637
|
TEST_CASE(localvaralias2); // ticket #1637
|
||||||
TEST_CASE(localvaralias3); // ticket #1639
|
TEST_CASE(localvaralias3); // ticket #1639
|
||||||
|
@ -1359,6 +1360,16 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void localvar38() {
|
||||||
|
functionVariableUsage("std::string f() {\n"
|
||||||
|
" const char code[] = \"foo\";\n"
|
||||||
|
" const std::string s1(sizeof_(code));\n"
|
||||||
|
" const std::string s2 = sizeof_(code);\n"
|
||||||
|
" return(s1+s2);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void localvaralias1() {
|
void localvaralias1() {
|
||||||
functionVariableUsage("void foo()\n"
|
functionVariableUsage("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -2287,9 +2298,7 @@ private:
|
||||||
" } while(a--);\n"
|
" } while(a--);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: x\n"
|
TODO_ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: x\n"
|
||||||
"[test.cpp:4]: (style) Unused variable: z\n",
|
"[test.cpp:4]: (style) Unused variable: z\n", "", errout.str());
|
||||||
|
|
||||||
"", errout.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvarStruct4() {
|
void localvarStruct4() {
|
||||||
|
@ -2477,6 +2486,12 @@ private:
|
||||||
" for (;a;);\n"
|
" for (;a;);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("void foo() {\n"
|
||||||
|
" for (int i = 0; (pci = cdi_list_get(pciDevices, i)); i++)\n"
|
||||||
|
" {}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void localvarShift1() {
|
void localvarShift1() {
|
||||||
|
|
Loading…
Reference in New Issue