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};
const char *_funcname[2] = {0,0};
_classname[0] = classname;
_funcname[0] = funcname;
if ( indentlevel < 0 || tok == NULL ) if ( indentlevel < 0 || tok == NULL )
return NULL; return NULL;
std::ostringstream classPattern;
classPattern << "class " << classname << " :|{";
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) ) )
{ {
if ( TOKEN::Match(tok, "class %var% {") ) while ( tok && tok->str() != "{" )
tok = tok->tokAt(3); tok = tok->next;
else if ( tok )
tok = tok->tokAt(5); tok = tok->next;
if ( ! tok )
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;
} }
@ -400,38 +404,11 @@ 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);
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? // Check assignment operators
std::ostringstream pattern; CheckConstructors( tok1, varlist, "operator =" );
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)
@ -445,6 +422,43 @@ void CheckClass::CheckConstructors()
} }
} }
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

@ -55,6 +55,9 @@ private:
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;
ErrorLogger *_errorLogger; ErrorLogger *_errorLogger;

View File

@ -62,14 +62,15 @@ private:
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=
@ -184,6 +185,20 @@ private:
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()
{ {
// Bug 2208157 - False positive: Uninitialized variable, same class name // Bug 2208157 - False positive: Uninitialized variable, same class name