Uninitialized member variables : Don't give false positives for private constructors
This commit is contained in:
parent
1a5d694834
commit
8a06b71949
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
Loading…
Reference in New Issue