Uninitialized member variables : Don't give false positives for private constructors

This commit is contained in:
Daniel Marjamäki 2008-12-06 19:14:04 +00:00
parent 1a5d694834
commit 8a06b71949
2 changed files with 91 additions and 33 deletions

View File

@ -309,36 +309,79 @@ void CheckClass::ClassChecking_VarList_Initialize(const TOKEN *tok1, const TOKEN
void CheckClass::CheckConstructors() void CheckClass::CheckConstructors()
{ {
const char pattern_class[] = "class %var% {";
// Locate class // Locate class
const char *pattern_classname[] = {"class","","{",NULL}; const TOKEN *tok1 = TOKEN::findmatch( _tokenizer->tokens(), pattern_class );
const TOKEN *tok1 = TOKEN::findtoken(_tokenizer->tokens(), pattern_classname);
while (tok1) while (tok1)
{ {
const char *classname = tok1->next->aaaa(); const char *className[2];
if ( !(tok1->next->isName()) ) className[0] = tok1->strAt( 1 );
className[1] = 0;
// TODO: handling of private constructors should be improved.
bool hasPrivateConstructor = false;
{ {
tok1 = TOKEN::findtoken( tok1->next, pattern_classname ); int indentlevel = 0;
bool isPrivate = true;
for ( const TOKEN *tok = tok1; tok; tok = tok->next )
{
// Indentation
if ( tok->str() == "{" )
++indentlevel;
else if ( tok->str() == "}" )
{
--indentlevel;
if (indentlevel <= 0)
break;
}
// Parse class contents (indentlevel == 1)..
if ( indentlevel == 1 )
{
// What section are we in.. private/non-private
if ( tok->str() == "private:" )
isPrivate = true;
else if ( tok->str() == "protected:" || tok->str() == "public:" )
isPrivate = false;
// Is there a private constructor?
else if ( isPrivate && TOKEN::Match(tok, "%var1% (", className) )
{
hasPrivateConstructor = true;
break;
}
}
}
}
if ( hasPrivateConstructor )
{
// TODO: Handle private constructors.
// Right now to avoid false positives I just bail out
tok1 = TOKEN::findmatch( tok1->next, pattern_class );
continue; continue;
} }
// Are there a class constructor? // Are there a class constructor?
const char *constructor_pattern[] = {"","clKalle","(",NULL}; const TOKEN *constructor_token = TOKEN::findmatch( tok1, "%any% %var1% (", className );
constructor_pattern[1] = classname; while ( TOKEN::Match( constructor_token, "~" ) )
const TOKEN *constructor_token = TOKEN::findtoken( _tokenizer->tokens(), constructor_pattern ); constructor_token = TOKEN::findmatch( constructor_token->next, "%any% %var1% (", className );
while ( constructor_token && constructor_token->aaaa0() == '~' )
constructor_token = TOKEN::findtoken( constructor_token->next, constructor_pattern ); // There are no constructor.
if ( ! constructor_token ) if ( ! constructor_token )
{ {
// There's no class constructor // If "--style" has been given, give a warning
if ( _settings._checkCodingStyle ) if ( _settings._checkCodingStyle )
{ {
// Check that all member variables are initialized.. // If the class has member variables there should be an constructor
struct VAR *varlist = ClassChecking_GetVarList(tok1); struct VAR *varlist = ClassChecking_GetVarList(tok1);
if ( varlist ) if ( varlist )
{ {
std::ostringstream ostr; std::ostringstream ostr;
ostr << _tokenizer->fileLine(tok1); ostr << _tokenizer->fileLine(tok1);
ostr << " The class '" << classname << "' has no constructor"; ostr << " The class '" << className[0] << "' has no constructor";
_errorLogger->reportErr(ostr.str()); _errorLogger->reportErr(ostr.str());
} }
// Delete the varlist.. // Delete the varlist..
@ -350,7 +393,7 @@ void CheckClass::CheckConstructors()
} }
} }
tok1 = TOKEN::findtoken( tok1->next, pattern_classname ); tok1 = TOKEN::findmatch( tok1->next, pattern_class );
continue; continue;
} }
@ -358,26 +401,25 @@ void CheckClass::CheckConstructors()
struct VAR *varlist = ClassChecking_GetVarList(tok1); struct VAR *varlist = ClassChecking_GetVarList(tok1);
int indentlevel = 0; int indentlevel = 0;
constructor_token = FindClassFunction( tok1, classname, classname, indentlevel ); constructor_token = FindClassFunction( tok1, className[0], className[0], indentlevel );
std::list<std::string> callstack; std::list<std::string> callstack;
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, classname, callstack); ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className[0], callstack);
while ( constructor_token ) while ( constructor_token )
{ {
// Check if any variables are uninitialized // Check if any variables are uninitialized
for (struct VAR *var = varlist; var; var = var->next) for (struct VAR *var = varlist; var; var = var->next)
{ {
// Is it a static member variable? // Is it a static member variable?
const char *pattern[] = {"","::","","=",NULL}; std::ostringstream pattern;
pattern[0] = classname; pattern << className[0] << "::" << var->name << "=";
pattern[2] = var->name; if (TOKEN::findmatch(_tokenizer->tokens(), pattern.str().c_str()))
if (TOKEN::findtoken(_tokenizer->tokens(), pattern))
continue; continue;
if (!var->init) if (!var->init)
{ {
std::ostringstream ostr; std::ostringstream ostr;
ostr << _tokenizer->fileLine(constructor_token); ostr << _tokenizer->fileLine(constructor_token);
ostr << " Uninitialized member variable '" << classname << "::" << var->name << "'"; ostr << " Uninitialized member variable '" << className[0] << "::" << var->name << "'";
_errorLogger->reportErr(ostr.str()); _errorLogger->reportErr(ostr.str());
} }
} }
@ -385,9 +427,9 @@ void CheckClass::CheckConstructors()
for ( struct VAR *var = varlist; var; var = var->next ) for ( struct VAR *var = varlist; var; var = var->next )
var->init = false; var->init = false;
constructor_token = FindClassFunction( constructor_token->next, classname, classname, indentlevel ); constructor_token = FindClassFunction( constructor_token->next, className[0], className[0], indentlevel );
callstack.clear(); callstack.clear();
ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, classname, callstack); ClassChecking_VarList_Initialize(tok1, constructor_token, varlist, className[0], callstack);
} }
// Delete the varlist.. // Delete the varlist..
@ -398,7 +440,7 @@ void CheckClass::CheckConstructors()
varlist = nextvar; varlist = nextvar;
} }
tok1 = TOKEN::findtoken( tok1->next, pattern_classname ); tok1 = TOKEN::findmatch( tok1->next, pattern_class );
} }
} }

View File

@ -66,6 +66,8 @@ private:
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
} }
@ -262,6 +264,20 @@ private:
ASSERT_EQUALS( std::string(""), err ); ASSERT_EQUALS( std::string(""), err );
} }
void initvar_private_constructor()
{
check( "class Fred\n"
"{\n"
"private:\n"
" int var;\n"
" Fred();\n"
"};\n"
"Fred::Fred()\n"
"{ }" );
ASSERT_EQUALS( std::string(""), errout.str() );
}
}; };
REGISTER_TEST( TestConstructors ) REGISTER_TEST( TestConstructors )