From b1ee3c5d31e41760dfb8cc5dd60350919a1439ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 7 Dec 2008 19:17:36 +0000 Subject: [PATCH] function variable usage : Added a simple check --- CheckOther.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++- CheckOther.h | 5 ++- testunusedvar.cpp | 42 ++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/CheckOther.cpp b/CheckOther.cpp index a7e8ffd9f..6ea1b4393 100644 --- a/CheckOther.cpp +++ b/CheckOther.cpp @@ -821,5 +821,87 @@ void CheckOther::unreachableCode() 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 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::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| {" ); + } +} diff --git a/CheckOther.h b/CheckOther.h index a8b67b8d3..4d45dac71 100644 --- a/CheckOther.h +++ b/CheckOther.h @@ -72,7 +72,10 @@ public: void CheckIncompleteStatement(); /** Unreachable code below a 'return' */ - void unreachableCode(); + void unreachableCode(); + + /** Unused function variables */ + void functionVariableUsage(); private: void CheckVariableScope_LookupVar( const TOKEN *tok1, const char varname[] ); diff --git a/testunusedvar.cpp b/testunusedvar.cpp index b8809986b..faab6f077 100644 --- a/testunusedvar.cpp +++ b/testunusedvar.cpp @@ -56,6 +56,9 @@ private: TEST_CASE( structmember1 ); TEST_CASE( structmember2 ); TEST_CASE( structmember3 ); + + TEST_CASE( localvar1 ); + TEST_CASE( localvar2 ); } 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 )