Constructors : Refactoring + Added checking of 'operator='

This commit is contained in:
Daniel Marjamäki 2008-12-07 08:49:35 +00:00
parent c907589deb
commit 5ea2844b85
3 changed files with 88 additions and 56 deletions

View File

@ -111,24 +111,28 @@ struct CheckClass::VAR *CheckClass::ClassChecking_GetVarList(const TOKEN *tok1)
const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel ) const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel )
{ {
const char *_classname[2] = {0,0}; if ( indentlevel < 0 || tok == NULL )
const char *_funcname[2] = {0,0}; return NULL;
_classname[0] = classname;
_funcname[0] = funcname; std::ostringstream classPattern;
classPattern << "class " << classname << " :|{";
if ( indentlevel < 0 || tok == NULL )
return NULL; std::ostringstream internalPattern;
internalPattern << funcname << " (";
std::ostringstream externalPattern;
externalPattern << classname << " :: " << funcname << " (";
for ( ;tok; tok = tok->next ) for ( ;tok; tok = tok->next )
{ {
if ( indentlevel == 0 && if ( indentlevel == 0 && TOKEN::Match(tok, classPattern.str().c_str()) )
( TOKEN::Match(tok, "class %var1% {", _classname) || {
TOKEN::Match(tok, "class %var1% : %type% {", _classname) ) ) while ( tok && tok->str() != "{" )
{ tok = tok->next;
if ( TOKEN::Match(tok, "class %var% {") ) if ( tok )
tok = tok->tokAt(3); tok = tok->next;
else if ( ! tok )
tok = tok->tokAt(5); break;
indentlevel = 1; indentlevel = 1;
} }
@ -168,7 +172,7 @@ const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classn
if ( indentlevel == 1 ) if ( indentlevel == 1 )
{ {
// Member function implemented in the class declaration? // Member function implemented in the class declaration?
if (!TOKEN::Match(tok,"~") && TOKEN::Match(tok->next, "%var1% (", _funcname)) if (!TOKEN::Match(tok,"~") && TOKEN::Match(tok->next, internalPattern.str().c_str()))
{ {
const TOKEN *tok2 = tok; const TOKEN *tok2 = tok;
while ( tok2 && tok2->str() != "{" && tok2->str() != ";" ) while ( tok2 && tok2->str() != "{" && tok2->str() != ";" )
@ -178,7 +182,7 @@ const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classn
} }
} }
else if ( indentlevel == 0 && TOKEN::Match(tok, "%var1% :: %var2% (", _classname, _funcname) ) else if ( indentlevel == 0 && TOKEN::Match(tok, externalPattern.str().c_str()) )
{ {
return tok; return tok;
} }
@ -399,39 +403,12 @@ void CheckClass::CheckConstructors()
// Check that all member variables are initialized.. // Check that all member variables are initialized..
struct VAR *varlist = ClassChecking_GetVarList(tok1); struct VAR *varlist = ClassChecking_GetVarList(tok1);
int indentlevel = 0; // Check constructors
constructor_token = FindClassFunction( tok1, className[0], className[0], indentlevel ); CheckConstructors( tok1, varlist, className[0] );
std::list<std::string> callstack;
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className[0], callstack); // Check assignment operators
while ( constructor_token ) CheckConstructors( tok1, varlist, "operator =" );
{
// Check if any variables are uninitialized
for (struct VAR *var = varlist; var; var = var->next)
{
if ( var->init )
continue;
// Is it a static member variable?
std::ostringstream pattern;
pattern << className[0] << "::" << var->name << "=";
if (TOKEN::findmatch(_tokenizer->tokens(), pattern.str().c_str()))
continue;
// It's non-static and it's not initialized => error
std::ostringstream ostr;
ostr << _tokenizer->fileLine(constructor_token);
ostr << " Uninitialized member variable '" << className[0] << "::" << var->name << "'";
_errorLogger->reportErr(ostr.str());
}
for ( struct VAR *var = varlist; var; var = var->next )
var->init = false;
constructor_token = FindClassFunction( constructor_token->next, className[0], className[0], indentlevel );
callstack.clear();
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className[0], callstack);
}
// Delete the varlist.. // Delete the varlist..
while (varlist) while (varlist)
@ -444,7 +421,44 @@ void CheckClass::CheckConstructors()
tok1 = TOKEN::findmatch( tok1->next, pattern_class ); tok1 = TOKEN::findmatch( tok1->next, pattern_class );
} }
} }
void CheckClass::CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[])
{
const char * const className = tok1->strAt(1);
int indentlevel = 0;
const TOKEN *constructor_token = FindClassFunction( tok1, className, funcname, indentlevel );
std::list<std::string> callstack;
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, funcname, callstack);
while ( constructor_token )
{
// Check if any variables are uninitialized
for (struct VAR *var = varlist; var; var = var->next)
{
if ( var->init )
continue;
// Is it a static member variable?
std::ostringstream pattern;
pattern << className << "::" << var->name << "=";
if (TOKEN::findmatch(_tokenizer->tokens(), pattern.str().c_str()))
continue;
// It's non-static and it's not initialized => error
std::ostringstream ostr;
ostr << _tokenizer->fileLine(constructor_token);
ostr << " Uninitialized member variable '" << className << "::" << var->name << "'";
_errorLogger->reportErr(ostr.str());
}
for ( struct VAR *var = varlist; var; var = var->next )
var->init = false;
constructor_token = FindClassFunction( constructor_token->next, className, funcname, indentlevel );
callstack.clear();
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className, callstack);
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -54,6 +54,9 @@ private:
void InitVar(struct VAR *varlist, const char varname[]); void InitVar(struct VAR *varlist, const char varname[]);
const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel ); const TOKEN *FindClassFunction( const TOKEN *tok, const char classname[], const char funcname[], int &indentlevel );
struct VAR *ClassChecking_GetVarList(const TOKEN *tok1); struct VAR *ClassChecking_GetVarList(const TOKEN *tok1);
// Check constructors for a specified class
void CheckConstructors(const TOKEN *tok1, struct VAR *varlist, const char funcname[]);
const Tokenizer *_tokenizer; const Tokenizer *_tokenizer;
Settings _settings; Settings _settings;

View File

@ -58,18 +58,19 @@ private:
TEST_CASE( simple1 ); TEST_CASE( simple1 );
TEST_CASE( simple2 ); TEST_CASE( simple2 );
TEST_CASE( simple3 ); TEST_CASE( simple3 );
TEST_CASE( simple4 ); TEST_CASE( simple4 );
TEST_CASE( initvar_with_this ); // BUG 2190300 TEST_CASE( initvar_with_this ); // BUG 2190300
TEST_CASE( initvar_if ); // BUG 2190290 TEST_CASE( initvar_if ); // BUG 2190290
TEST_CASE( initvar_operator_eq ); // BUG 2190376 TEST_CASE( initvar_operator_eq1 ); // BUG 2190376
TEST_CASE( initvar_operator_eq2 ); // BUG 2190376
TEST_CASE( initvar_same_classname ); // BUG 2208157 TEST_CASE( initvar_same_classname ); // BUG 2208157
TEST_CASE( initvar_chained_assign ); // BUG 2270433 TEST_CASE( initvar_chained_assign ); // BUG 2270433
TEST_CASE( initvar_2constructors ); // BUG 2270353 TEST_CASE( initvar_2constructors ); // BUG 2270353
TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor TEST_CASE( initvar_private_constructor ); // BUG 2354171 - private constructor
TEST_CASE( initvar_destructor ); TEST_CASE( initvar_destructor ); // No variables need to be initialized in a destructor
} }
@ -160,7 +161,7 @@ private:
ASSERT_EQUALS( std::string(""), errout.str() ); ASSERT_EQUALS( std::string(""), errout.str() );
} }
void initvar_operator_eq() void initvar_operator_eq1()
{ {
// Bug 2190376 - False positive, Uninitialized member variable with operator= // Bug 2190376 - False positive, Uninitialized member variable with operator=
@ -183,6 +184,20 @@ private:
std::string err( errout.str() ); std::string err( errout.str() );
ASSERT_EQUALS( std::string(""), err ); ASSERT_EQUALS( std::string(""), err );
} }
void initvar_operator_eq2()
{
check( "class Fred\n"
"{\n"
"public:\n"
" Fred() { i = 0; }\n"
" void operator=() { }\n"
" int i;\n"
"};\n" );
ASSERT_EQUALS( std::string("[test.cpp:5] Uninitialized member variable 'Fred::i'\n"), errout.str() );
}
void initvar_same_classname() void initvar_same_classname()
{ {