Constructors : Refactoring + Added checking of 'operator='
This commit is contained in:
parent
c907589deb
commit
5ea2844b85
104
CheckClass.cpp
104
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue