function variable usage : Added a simple check
This commit is contained in:
parent
b2e55216ab
commit
b1ee3c5d31
|
@ -821,5 +821,87 @@ void CheckOther::unreachableCode()
|
||||||
tok = TOKEN::findmatch( tok, "[;{}] return" );
|
tok = TOKEN::findmatch( tok, "[;{}] return" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Usage of function variables
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckOther::functionVariableUsage()
|
||||||
|
{
|
||||||
|
// Parse all executing scopes..
|
||||||
|
const TOKEN *tok1 = TOKEN::findmatch( _tokenizer->tokens(), ") const| {" );
|
||||||
|
while ( tok1 )
|
||||||
|
{
|
||||||
|
// Varname, usage {1=declare, 2=read, 4=write}
|
||||||
|
std::map<std::string, unsigned int> varUsage;
|
||||||
|
static const unsigned int USAGE_DECLARE = 1;
|
||||||
|
static const unsigned int USAGE_READ = 2;
|
||||||
|
static const unsigned int USAGE_WRITE = 4;
|
||||||
|
|
||||||
|
int indentlevel = 0;
|
||||||
|
for ( const TOKEN *tok = tok1; tok; tok = tok->next )
|
||||||
|
{
|
||||||
|
if ( tok->str() == "{" )
|
||||||
|
++indentlevel;
|
||||||
|
else if ( tok->str() == "}" )
|
||||||
|
{
|
||||||
|
--indentlevel;
|
||||||
|
if ( indentlevel <= 0 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( TOKEN::Match(tok, "[;{}] %type% %var% ;|=") )
|
||||||
|
{
|
||||||
|
if ( TOKEN::Match(tok->next, "delete|return") )
|
||||||
|
varUsage[ tok->strAt(2) ] |= USAGE_READ;
|
||||||
|
else
|
||||||
|
varUsage[ tok->strAt(2) ] = USAGE_DECLARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( TOKEN::Match(tok, "[;{}] %var% =") )
|
||||||
|
{
|
||||||
|
varUsage[ tok->strAt(1) ] |= USAGE_WRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check usage of all variables in the current scope..
|
||||||
|
for ( std::map<std::string, unsigned int>::const_iterator it = varUsage.begin(); it != varUsage.end(); ++it )
|
||||||
|
{
|
||||||
|
std::string varname = it->first;
|
||||||
|
unsigned int usage = it->second;
|
||||||
|
|
||||||
|
if ( ! ( usage & USAGE_DECLARE ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( usage == USAGE_DECLARE )
|
||||||
|
{
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << _tokenizer->fileLine(tok1->next) << ": Unused variable '" << varname << "'";
|
||||||
|
_errorLogger->reportErr(errmsg.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( ! (usage & USAGE_READ) )
|
||||||
|
{
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << _tokenizer->fileLine(tok1->next) << ": Variable '" << varname << "' is assigned a value that is never used";
|
||||||
|
_errorLogger->reportErr(errmsg.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( ! (usage & USAGE_WRITE) )
|
||||||
|
{
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << _tokenizer->fileLine(tok1->next) << ": Variable '" << varname << "' is not assigned a value";
|
||||||
|
_errorLogger->reportErr(errmsg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Goto next executing scope..
|
||||||
|
tok1 = TOKEN::findmatch( tok1->next, ") const| {" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,9 @@ public:
|
||||||
|
|
||||||
/** Unreachable code below a 'return' */
|
/** Unreachable code below a 'return' */
|
||||||
void unreachableCode();
|
void unreachableCode();
|
||||||
|
|
||||||
|
/** Unused function variables */
|
||||||
|
void functionVariableUsage();
|
||||||
private:
|
private:
|
||||||
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] );
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ private:
|
||||||
TEST_CASE( structmember1 );
|
TEST_CASE( structmember1 );
|
||||||
TEST_CASE( structmember2 );
|
TEST_CASE( structmember2 );
|
||||||
TEST_CASE( structmember3 );
|
TEST_CASE( structmember3 );
|
||||||
|
|
||||||
|
TEST_CASE( localvar1 );
|
||||||
|
TEST_CASE( localvar2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void structmember1()
|
void structmember1()
|
||||||
|
@ -111,6 +114,45 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void functionVariableUsage( const char code[] )
|
||||||
|
{
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize( istr, "test.cpp" );
|
||||||
|
tokenizer.simplifyTokenList();
|
||||||
|
|
||||||
|
// Clear the error buffer..
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
// Check for unused variables..
|
||||||
|
CheckOther checkOther( &tokenizer, this );
|
||||||
|
checkOther.functionVariableUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void localvar1()
|
||||||
|
{
|
||||||
|
functionVariableUsage( "void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i = 0;\n"
|
||||||
|
"}\n" );
|
||||||
|
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is assigned a value that is never used\n"), errout.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void localvar2()
|
||||||
|
{
|
||||||
|
functionVariableUsage( "void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int i;\n"
|
||||||
|
" return i;\n"
|
||||||
|
"}\n" );
|
||||||
|
ASSERT_EQUALS( std::string("[test.cpp:2]: Variable 'i' is not assigned a value\n"), errout.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST( TestUnusedVar )
|
REGISTER_TEST( TestUnusedVar )
|
||||||
|
|
Loading…
Reference in New Issue