Constructors : Refactoring + Added checking of 'operator='
This commit is contained in:
parent
c907589deb
commit
5ea2844b85
118
CheckClass.cpp
118
CheckClass.cpp
|
@ -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;
|
||||
|
||||
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 ( TOKEN::Match(tok, "class %var% {") )
|
||||
tok = tok->tokAt(3);
|
||||
else
|
||||
tok = tok->tokAt(5);
|
||||
if ( indentlevel == 0 && TOKEN::Match(tok, classPattern.str().c_str()) )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -399,39 +403,12 @@ 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;
|
||||
|
||||
// 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 constructors
|
||||
CheckConstructors( tok1, varlist, className[0] );
|
||||
|
||||
// Check assignment operators
|
||||
CheckConstructors( tok1, varlist, "operator =" );
|
||||
|
||||
// Delete the varlist..
|
||||
while (varlist)
|
||||
|
@ -444,7 +421,44 @@ void CheckClass::CheckConstructors()
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -54,6 +54,9 @@ private:
|
|||
void InitVar(struct VAR *varlist, const char varname[]);
|
||||
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;
|
||||
|
|
|
@ -58,18 +58,19 @@ private:
|
|||
TEST_CASE( simple1 );
|
||||
TEST_CASE( simple2 );
|
||||
TEST_CASE( simple3 );
|
||||
TEST_CASE( simple4 );
|
||||
TEST_CASE( simple4 );
|
||||
|
||||
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=
|
||||
|
||||
|
@ -183,6 +184,20 @@ private:
|
|||
std::string err( errout.str() );
|
||||
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()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue