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 char *_classname[2] = {0,0};
const char *_funcname[2] = {0,0};
_classname[0] = classname;
_funcname[0] = funcname;
if ( indentlevel < 0 || tok == 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 )
{
if ( indentlevel == 0 &&
( TOKEN::Match(tok, "class %var1% {", _classname) ||
TOKEN::Match(tok, "class %var1% : %type% {", _classname) ) )
if ( indentlevel == 0 && TOKEN::Match(tok, classPattern.str().c_str()) )
{
if ( TOKEN::Match(tok, "class %var% {") )
tok = tok->tokAt(3);
else
tok = tok->tokAt(5);
while ( tok && tok->str() != "{" )
tok = tok->next;
if ( tok )
tok = tok->next;
if ( ! tok )
break;
indentlevel = 1;
}
@ -168,7 +172,7 @@ const TOKEN * CheckClass::FindClassFunction( const TOKEN *tok, const char classn
if ( indentlevel == 1 )
{
// 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;
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;
}
@ -400,38 +404,11 @@ void CheckClass::CheckConstructors()
// Check that all member variables are initialized..
struct VAR *varlist = ClassChecking_GetVarList(tok1);
int indentlevel = 0;
constructor_token = FindClassFunction( tok1, className[0], className[0], indentlevel );
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;
// Check constructors
CheckConstructors( tok1, varlist, className[0] );
// 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);
}
// Check assignment operators
CheckConstructors( tok1, varlist, "operator =" );
// Delete the 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 );
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;
Settings _settings;
ErrorLogger *_errorLogger;

View File

@ -62,14 +62,15 @@ private:
TEST_CASE( initvar_with_this ); // BUG 2190300
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_chained_assign ); // BUG 2270433
TEST_CASE( initvar_2constructors ); // BUG 2270353
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() );
}
void initvar_operator_eq()
void initvar_operator_eq1()
{
// Bug 2190376 - False positive, Uninitialized member variable with operator=
@ -184,6 +185,20 @@ private:
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()
{
// Bug 2208157 - False positive: Uninitialized variable, same class name