2008-12-18 22:28:57 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2008-12-18 22:28:57 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
//---------------------------------------------------------------------------
# include "checkclass.h"
2009-03-20 17:30:24 +01:00
# include "tokenize.h"
# include "token.h"
# include "errorlogger.h"
2008-12-18 22:28:57 +01:00
# include <locale>
2009-01-23 21:55:06 +01:00
# include <cstring>
2008-12-18 22:28:57 +01:00
# include <string>
# include <sstream>
# include <algorithm>
//---------------------------------------------------------------------------
2009-03-24 20:47:43 +01:00
// Register CheckClass..
namespace
{
CheckClass instance ;
}
2008-12-18 22:28:57 +01:00
//---------------------------------------------------------------------------
2009-07-08 17:14:34 +02:00
CheckClass : : Var * CheckClass : : getVarList ( const Token * tok1 , bool withClasses )
2008-12-18 22:28:57 +01:00
{
// Get variable list..
2009-07-08 17:14:34 +02:00
Var * varlist = NULL ;
2008-12-18 22:28:57 +01:00
unsigned int indentlevel = 0 ;
2009-12-19 17:58:52 +01:00
bool priv = true ;
2009-01-03 21:29:20 +01:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2008-12-18 22:28:57 +01:00
{
if ( ! tok - > next ( ) )
break ;
2008-12-20 20:57:03 +01:00
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
if ( indentlevel < = 1 )
break ;
2008-12-20 20:57:03 +01:00
- - indentlevel ;
2008-12-18 22:28:57 +01:00
}
2009-01-05 16:49:57 +01:00
if ( indentlevel ! = 1 )
2008-12-20 20:57:03 +01:00
continue ;
2008-12-18 22:28:57 +01:00
2009-08-31 19:40:49 +02:00
if ( tok - > str ( ) = = " __published: " )
{
2009-12-19 17:58:52 +01:00
priv = false ;
2009-08-31 19:40:49 +02:00
for ( ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
}
if ( indentlevel = = 1 & & Token : : Match ( tok - > next ( ) , " private:|protected:|public: " ) )
break ;
}
if ( tok )
continue ;
else
break ;
}
2009-01-10 15:29:59 +01:00
// "private:" "public:" "protected:" etc
2009-08-31 19:40:49 +02:00
const bool b ( ( * tok - > strAt ( 0 ) ! = ' : ' ) & & strchr ( tok - > strAt ( 0 ) , ' : ' ) ! = 0 ) ;
2008-12-18 22:28:57 +01:00
2009-12-19 17:58:52 +01:00
if ( b )
priv = bool ( tok - > str ( ) = = " private: " ) ;
2008-12-20 20:57:03 +01:00
// Search for start of statement..
2009-01-05 16:49:57 +01:00
if ( ! Token : : Match ( tok , " [;{}] " ) & & ! b )
2008-12-20 20:57:03 +01:00
continue ;
2008-12-18 22:28:57 +01:00
2008-12-20 20:57:03 +01:00
// This is the start of a statement
2009-01-03 21:29:20 +01:00
const Token * next = tok - > next ( ) ;
2008-12-20 20:57:03 +01:00
const char * varname = 0 ;
2008-12-18 22:28:57 +01:00
2009-02-21 09:24:57 +01:00
// If next token contains a ":".. it is not part of a variable declaration
if ( next - > str ( ) . find ( " : " ) ! = std : : string : : npos )
2009-05-18 22:30:43 +02:00
continue ;
2009-02-21 14:35:55 +01:00
2009-05-17 19:27:16 +02:00
// Variable declarations that start with "static" shall be ignored..
if ( next - > str ( ) = = " static " )
2009-05-18 22:30:43 +02:00
continue ;
2009-02-21 09:24:57 +01:00
2009-06-05 02:34:12 +02:00
// Type definitions shall be ignored..
if ( next - > str ( ) = = " typedef " )
continue ;
2008-12-20 20:57:03 +01:00
// Is it a variable declaration?
2009-05-17 19:27:16 +02:00
if ( Token : : Match ( next , " %type% %var% ; " ) )
2008-12-20 20:57:03 +01:00
{
2009-05-01 07:28:58 +02:00
if ( withClasses )
varname = next - > strAt ( 1 ) ;
else if ( next - > isStandardType ( ) )
2008-12-20 20:57:03 +01:00
varname = next - > strAt ( 1 ) ;
2009-01-14 20:34:10 +01:00
else if ( Token : : findmatch ( _tokenizer - > tokens ( ) , ( " enum " + next - > str ( ) ) . c_str ( ) ) )
varname = next - > strAt ( 1 ) ;
2008-12-20 20:57:03 +01:00
}
2008-12-18 22:28:57 +01:00
2008-12-20 20:57:03 +01:00
// Pointer?
2009-01-05 16:49:57 +01:00
else if ( Token : : Match ( next , " %type% * %var% ; " ) )
2008-12-20 20:57:03 +01:00
{
varname = next - > strAt ( 2 ) ;
}
2009-03-12 21:33:10 +01:00
// Pointer?
else if ( Token : : Match ( next , " %type% %type% * %var% ; " ) )
{
varname = next - > strAt ( 3 ) ;
}
2009-11-10 19:30:37 +01:00
// Array?
2009-09-16 20:07:03 +02:00
else if ( Token : : Match ( next , " %type% %var% [ " ) & & next - > next ( ) - > str ( ) ! = " operator " )
2009-08-23 21:54:41 +02:00
{
2009-11-10 19:30:37 +01:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , ( " class " + next - > str ( ) ) . c_str ( ) ) )
continue ;
2009-08-23 21:54:41 +02:00
varname = next - > strAt ( 1 ) ;
}
2009-11-10 19:35:54 +01:00
// Pointer array?
else if ( Token : : Match ( next , " %type% * %var% [ " ) )
{
varname = next - > strAt ( 2 ) ;
}
2009-05-01 07:28:58 +02:00
// std::string..
else if ( withClasses & & Token : : Match ( next , " std :: string %var% ; " ) )
{
varname = next - > strAt ( 3 ) ;
}
// Container..
else if ( withClasses & & Token : : Match ( next , " std :: %type% < " ) )
{
while ( next & & next - > str ( ) ! = " > " )
next = next - > next ( ) ;
if ( Token : : Match ( next , " > %var% ; " ) )
varname = next - > strAt ( 1 ) ;
}
2008-12-20 20:57:03 +01:00
// If the varname was set in one of the two if-block above, create a entry for this variable..
if ( varname )
{
2009-12-19 17:58:52 +01:00
Var * var = new Var ( varname , false , priv , varlist ) ;
varlist = var ;
2008-12-18 22:28:57 +01:00
}
}
return varlist ;
}
//---------------------------------------------------------------------------
2009-07-08 17:14:34 +02:00
void CheckClass : : initVar ( Var * varlist , const char varname [ ] )
2008-12-18 22:28:57 +01:00
{
2009-07-08 17:14:34 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
if ( strcmp ( var - > name , varname ) = = 0 )
2008-12-18 22:28:57 +01:00
{
var - > init = true ;
break ;
}
}
}
//---------------------------------------------------------------------------
2009-07-08 17:14:34 +02:00
void CheckClass : : initializeVarList ( const Token * tok1 , const Token * ftok , Var * varlist , const char classname [ ] , std : : list < std : : string > & callstack )
2008-12-18 22:28:57 +01:00
{
bool Assign = false ;
unsigned int indentlevel = 0 ;
for ( ; ftok ; ftok = ftok - > next ( ) )
{
if ( ! ftok - > next ( ) )
break ;
// Class constructor.. initializing variables like this
// clKalle::clKalle() : var(value) { }
2009-01-05 16:49:57 +01:00
if ( indentlevel = = 0 )
2008-12-18 22:28:57 +01:00
{
2009-01-03 21:29:20 +01:00
if ( Assign & & Token : : Match ( ftok , " %var% ( " ) )
2008-12-18 22:28:57 +01:00
{
2009-08-25 21:04:48 +02:00
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
2008-12-18 22:28:57 +01:00
}
2008-12-20 20:57:03 +01:00
Assign | = ( ftok - > str ( ) = = " : " ) ;
2008-12-18 22:28:57 +01:00
}
2008-12-20 20:57:03 +01:00
if ( ftok - > str ( ) = = " { " )
2008-12-18 22:28:57 +01:00
{
2009-01-01 23:22:28 +01:00
+ + indentlevel ;
2008-12-18 22:28:57 +01:00
Assign = false ;
}
2009-12-13 09:35:08 +01:00
else if ( ftok - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
if ( indentlevel < = 1 )
break ;
2009-01-01 23:22:28 +01:00
- - indentlevel ;
2008-12-18 22:28:57 +01:00
}
2009-01-05 16:49:57 +01:00
if ( indentlevel < 1 )
2008-12-18 22:28:57 +01:00
continue ;
2009-01-17 21:17:57 +01:00
// Variable getting value from stream?
if ( Token : : Match ( ftok , " >> %var% " ) )
{
2009-08-25 21:04:48 +02:00
initVar ( varlist , ftok - > strAt ( 1 ) ) ;
2009-01-17 21:17:57 +01:00
}
2008-12-18 22:28:57 +01:00
// Before a new statement there is "[{};)=]" or "else"
2009-01-05 16:49:57 +01:00
if ( ! Token : : Match ( ftok , " [{};)=] " ) & & ftok - > str ( ) ! = " else " )
2008-12-18 22:28:57 +01:00
continue ;
// Using the operator= function to initialize all variables..
2009-01-05 16:49:57 +01:00
if ( Token : : simpleMatch ( ftok - > next ( ) , " * this = " ) )
2008-12-18 22:28:57 +01:00
{
2009-07-08 17:14:34 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
var - > init = true ;
break ;
}
2009-12-11 21:34:04 +01:00
if ( ! Token : : Match ( ftok - > next ( ) , " %var% " ) & &
! Token : : Match ( ftok - > next ( ) , " this . %var% " ) & &
2009-12-13 09:35:08 +01:00
! Token : : Match ( ftok - > next ( ) , " * %var% = " ) & &
2009-12-11 21:34:04 +01:00
! Token : : Match ( ftok - > next ( ) , " ( * this ) . %var% " ) )
2008-12-18 22:28:57 +01:00
continue ;
// Goto the first token in this statement..
ftok = ftok - > next ( ) ;
2009-12-11 21:34:04 +01:00
// Skip "( * this )"
if ( Token : : simpleMatch ( ftok , " ( * this ) . " ) )
{
ftok = ftok - > tokAt ( 5 ) ;
}
2008-12-18 22:28:57 +01:00
// Skip "this->"
2009-01-05 16:49:57 +01:00
if ( Token : : simpleMatch ( ftok , " this . " ) )
2008-12-18 22:28:57 +01:00
ftok = ftok - > tokAt ( 2 ) ;
2009-08-26 22:33:23 +02:00
// Skip "classname :: "
if ( Token : : Match ( ftok , " %var% :: " ) )
ftok = ftok - > tokAt ( 2 ) ;
2008-12-18 22:28:57 +01:00
// Clearing all variables..
2009-01-05 16:49:57 +01:00
if ( Token : : simpleMatch ( ftok , " memset ( this , " ) )
2008-12-18 22:28:57 +01:00
{
2009-07-08 17:14:34 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
var - > init = true ;
break ;
}
// Calling member function?
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( ftok , " %var% ( " ) )
2008-12-18 22:28:57 +01:00
{
// No recursive calls!
2009-01-05 16:49:57 +01:00
if ( std : : find ( callstack . begin ( ) , callstack . end ( ) , ftok - > str ( ) ) = = callstack . end ( ) )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
callstack . push_back ( ftok - > str ( ) ) ;
2008-12-18 22:28:57 +01:00
int i = 0 ;
2009-08-25 21:04:48 +02:00
const Token * ftok2 = Tokenizer : : findClassFunction ( tok1 , classname , ftok - > strAt ( 0 ) , i ) ;
2009-09-03 22:28:00 +02:00
if ( ftok2 )
{
initializeVarList ( tok1 , ftok2 , varlist , classname , callstack ) ;
}
else // there is a called member function, but it is not defined where we can find it, so we assume it initializes everything
{
for ( Var * var = varlist ; var ; var = var - > next )
var - > init = true ;
break ;
// we don't report this, as somewhere along the line we hope that the class and member function
// are checked together. It is possible that this will not be the case (where there are enough
// nested functions defined in different files), but that isn't really likely.
}
2008-12-18 22:28:57 +01:00
}
}
// Assignment of member variable?
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( ftok , " %var% = " ) )
2008-12-18 22:28:57 +01:00
{
2009-08-25 21:04:48 +02:00
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
2008-12-18 22:28:57 +01:00
}
2009-08-23 21:54:41 +02:00
// Assignment of array item of member variable?
else if ( Token : : Match ( ftok , " %var% [ %any% ] = " ) )
{
2009-08-25 21:04:48 +02:00
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
2009-08-23 21:54:41 +02:00
}
2009-12-13 09:35:08 +01:00
// Assignment of array item of member variable?
else if ( Token : : Match ( ftok , " * %var% = " ) )
{
initVar ( varlist , ftok - > strAt ( 1 ) ) ;
}
2008-12-18 22:28:57 +01:00
// The functions 'clear' and 'Clear' are supposed to initialize variable.
2009-01-05 16:49:57 +01:00
if ( Token : : Match ( ftok , " %var% . clear|Clear ( " ) )
2008-12-18 22:28:57 +01:00
{
2009-08-25 21:04:48 +02:00
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
2008-12-18 22:28:57 +01:00
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: Check that all class constructors are ok.
//---------------------------------------------------------------------------
2008-12-20 09:48:52 +01:00
void CheckClass : : constructors ( )
2008-12-18 22:28:57 +01:00
{
2009-07-03 20:22:14 +02:00
const char pattern_class [ ] = " class %var% [{:] " ;
2008-12-18 22:28:57 +01:00
// Locate class
2009-01-05 16:49:57 +01:00
const Token * tok1 = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern_class ) ;
2008-12-18 22:28:57 +01:00
while ( tok1 )
{
const char * className [ 2 ] ;
2009-01-05 16:49:57 +01:00
className [ 0 ] = tok1 - > strAt ( 1 ) ;
2008-12-18 22:28:57 +01:00
className [ 1 ] = 0 ;
2009-01-05 16:49:57 +01:00
const Token * classNameToken = tok1 - > tokAt ( 1 ) ;
2008-12-18 22:28:57 +01:00
2009-07-14 08:17:12 +02:00
/** @todo handling of private constructors should be improved */
2008-12-18 22:28:57 +01:00
bool hasPrivateConstructor = false ;
{
int indentlevel = 0 ;
bool isPrivate = true ;
2009-01-05 16:49:57 +01:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2008-12-18 22:28:57 +01:00
{
// Indentation
2009-01-05 16:49:57 +01:00
if ( tok - > str ( ) = = " { " )
2008-12-18 22:28:57 +01:00
+ + indentlevel ;
2009-01-05 16:49:57 +01:00
else if ( tok - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
- - indentlevel ;
if ( indentlevel < = 0 )
break ;
}
// Parse class contents (indentlevel == 1)..
2009-01-05 16:49:57 +01:00
if ( indentlevel = = 1 )
2008-12-18 22:28:57 +01:00
{
// What section are we in.. private/non-private
2009-01-05 16:49:57 +01:00
if ( tok - > str ( ) = = " private: " )
2008-12-18 22:28:57 +01:00
isPrivate = true ;
2009-01-05 16:49:57 +01:00
else if ( tok - > str ( ) = = " protected: " | | tok - > str ( ) = = " public: " )
2008-12-18 22:28:57 +01:00
isPrivate = false ;
// Is there a private constructor?
2009-01-05 16:49:57 +01:00
else if ( isPrivate & & Token : : simpleMatch ( tok , ( classNameToken - > str ( ) + " ( " ) . c_str ( ) ) )
2008-12-18 22:28:57 +01:00
{
hasPrivateConstructor = true ;
break ;
}
}
}
}
2009-12-06 18:35:32 +01:00
if ( hasPrivateConstructor & & ! _settings - > _showAll )
2008-12-18 22:28:57 +01:00
{
2009-07-14 08:17:12 +02:00
/** @todo Handle private constructors. Right now to avoid
* false positives we just bail out */
2009-01-05 16:49:57 +01:00
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
2008-12-18 22:28:57 +01:00
continue ;
}
// Are there a class constructor?
2009-01-04 21:33:12 +01:00
std : : string tempPattern = " %any% " + classNameToken - > str ( ) + " ( " ;
2009-01-05 16:49:57 +01:00
const Token * constructor_token = Token : : findmatch ( tok1 , tempPattern . c_str ( ) ) ;
2009-07-27 11:24:24 +02:00
while ( constructor_token & & constructor_token - > str ( ) = = " ~ " )
2009-01-05 16:49:57 +01:00
constructor_token = Token : : findmatch ( constructor_token - > next ( ) , tempPattern . c_str ( ) ) ;
2008-12-18 22:28:57 +01:00
// There are no constructor.
2009-01-05 16:49:57 +01:00
if ( ! constructor_token )
2008-12-18 22:28:57 +01:00
{
// If "--style" has been given, give a warning
2009-12-19 17:58:52 +01:00
if ( _settings - > _checkCodingStyle )
2008-12-18 22:28:57 +01:00
{
2009-12-19 17:58:52 +01:00
// Get class variables...
2009-07-08 17:14:34 +02:00
Var * varlist = getVarList ( tok1 , false ) ;
2009-12-19 17:58:52 +01:00
// If there is a private variable, there should be a constructor..
2009-12-20 09:02:25 +01:00
for ( const Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
{
2009-12-19 17:58:52 +01:00
if ( var - > priv )
{
noConstructorError ( tok1 , classNameToken - > str ( ) ) ;
break ;
}
2008-12-18 22:28:57 +01:00
}
2009-12-19 17:58:52 +01:00
2008-12-18 22:28:57 +01:00
// Delete the varlist..
while ( varlist )
{
2009-07-08 17:14:34 +02:00
Var * nextvar = varlist - > next ;
2008-12-18 22:28:57 +01:00
delete varlist ;
varlist = nextvar ;
}
}
2009-01-05 16:49:57 +01:00
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
2008-12-18 22:28:57 +01:00
continue ;
}
// Check constructors
2009-12-06 18:35:32 +01:00
checkConstructors ( tok1 , className [ 0 ] , hasPrivateConstructor ) ;
2008-12-18 22:28:57 +01:00
// Check assignment operators
2009-12-06 18:35:32 +01:00
checkConstructors ( tok1 , " operator = " , hasPrivateConstructor ) ;
2008-12-18 22:28:57 +01:00
2009-01-05 16:49:57 +01:00
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
2008-12-18 22:28:57 +01:00
}
}
2009-12-06 18:35:32 +01:00
void CheckClass : : checkConstructors ( const Token * tok1 , const char funcname [ ] , bool hasPrivateConstructor )
2008-12-18 22:28:57 +01:00
{
const char * const className = tok1 - > strAt ( 1 ) ;
2009-05-01 07:28:58 +02:00
// Check that all member variables are initialized..
2009-05-01 07:36:35 +02:00
bool withClasses = bool ( _settings - > _showAll & & std : : string ( funcname ) = = " operator = " ) ;
2009-07-08 17:14:34 +02:00
Var * varlist = getVarList ( tok1 , withClasses ) ;
2009-05-01 07:28:58 +02:00
2008-12-18 22:28:57 +01:00
int indentlevel = 0 ;
2009-07-05 22:16:43 +02:00
const Token * constructor_token = Tokenizer : : findClassFunction ( tok1 , className , funcname , indentlevel ) ;
2008-12-18 22:28:57 +01:00
std : : list < std : : string > callstack ;
2009-07-05 22:16:43 +02:00
initializeVarList ( tok1 , constructor_token , varlist , className , callstack ) ;
2009-01-05 16:49:57 +01:00
while ( constructor_token )
2008-12-18 22:28:57 +01:00
{
// Check if any variables are uninitialized
2009-07-08 17:14:34 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
if ( var - > init )
2008-12-18 22:28:57 +01:00
continue ;
// Is it a static member variable?
std : : ostringstream pattern ;
2009-07-17 18:50:49 +02:00
pattern < < className < < " :: " < < var - > name < < " = " ;
2009-01-03 21:29:20 +01:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . str ( ) . c_str ( ) ) )
2008-12-18 22:28:57 +01:00
continue ;
// It's non-static and it's not initialized => error
2009-06-16 23:58:16 +02:00
if ( Token : : simpleMatch ( constructor_token , " operator = ( " ) | |
Token : : simpleMatch ( constructor_token - > tokAt ( 2 ) , " operator = ( " ) )
{
const Token * operStart = 0 ;
if ( Token : : simpleMatch ( constructor_token , " operator = ( " ) )
operStart = constructor_token - > tokAt ( 2 ) ;
else
operStart = constructor_token - > tokAt ( 4 ) ;
bool classNameUsed = false ;
for ( const Token * operTok = operStart ; operTok ! = operStart - > link ( ) ; operTok = operTok - > next ( ) )
{
if ( operTok - > str ( ) = = className )
{
classNameUsed = true ;
break ;
}
}
if ( classNameUsed )
operatorEqVarError ( constructor_token , className , var - > name ) ;
}
2009-03-31 19:00:56 +02:00
else
2009-12-06 18:35:32 +01:00
uninitVarError ( constructor_token , className , var - > name , hasPrivateConstructor ) ;
2008-12-18 22:28:57 +01:00
}
2009-07-08 17:14:34 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2008-12-18 22:28:57 +01:00
var - > init = false ;
2009-07-05 22:16:43 +02:00
constructor_token = Tokenizer : : findClassFunction ( constructor_token - > next ( ) , className , funcname , indentlevel ) ;
2008-12-18 22:28:57 +01:00
callstack . clear ( ) ;
2009-07-05 22:16:43 +02:00
initializeVarList ( tok1 , constructor_token , varlist , className , callstack ) ;
2008-12-18 22:28:57 +01:00
}
2009-05-01 07:28:58 +02:00
// Delete the varlist..
while ( varlist )
{
2009-07-08 17:14:34 +02:00
Var * nextvar = varlist - > next ;
2009-05-01 07:28:58 +02:00
delete varlist ;
varlist = nextvar ;
}
2008-12-18 22:28:57 +01:00
}
//---------------------------------------------------------------------------
// ClassCheck: Unused private functions
//---------------------------------------------------------------------------
2008-12-20 09:48:52 +01:00
void CheckClass : : privateFunctions ( )
2008-12-18 22:28:57 +01:00
{
// Locate some class
2009-01-03 21:29:20 +01:00
for ( const Token * tok1 = Token : : findmatch ( _tokenizer - > tokens ( ) , " class %var% { " ) ; tok1 ; tok1 = Token : : findmatch ( tok1 - > next ( ) , " class %var% { " ) )
2008-12-18 22:28:57 +01:00
{
2009-07-14 08:17:12 +02:00
/** @todo check that the whole class implementation is seen */
// until the todo above is fixed we only check classes that are
// declared in the source file
2009-07-12 14:23:01 +02:00
if ( tok1 - > fileIndex ( ) ! = 0 )
continue ;
2008-12-20 17:30:24 +01:00
const std : : string & classname = tok1 - > next ( ) - > str ( ) ;
2008-12-18 22:28:57 +01:00
// Get private functions..
2009-01-10 18:35:41 +01:00
std : : list < const Token * > FuncList ;
2008-12-18 22:28:57 +01:00
FuncList . clear ( ) ;
bool priv = false ;
unsigned int indent_level = 0 ;
2009-01-03 21:29:20 +01:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
if ( Token : : Match ( tok , " friend %var% " ) )
2008-12-18 22:28:57 +01:00
{
2009-07-14 08:17:12 +02:00
/** @todo Handle friend classes */
2008-12-18 22:28:57 +01:00
FuncList . clear ( ) ;
break ;
}
2008-12-20 18:52:15 +01:00
if ( tok - > str ( ) = = " { " )
2009-01-01 23:22:28 +01:00
+ + indent_level ;
2008-12-20 18:52:15 +01:00
else if ( tok - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
if ( indent_level < = 1 )
break ;
2009-01-01 23:22:28 +01:00
- - indent_level ;
2008-12-18 22:28:57 +01:00
}
2009-09-16 23:04:13 +02:00
2009-07-07 08:30:23 +02:00
else if ( indent_level ! = 1 )
continue ;
2008-12-20 18:52:15 +01:00
else if ( tok - > str ( ) = = " private: " )
2008-12-18 22:28:57 +01:00
priv = true ;
2008-12-20 18:52:15 +01:00
else if ( tok - > str ( ) = = " public: " )
2008-12-18 22:28:57 +01:00
priv = false ;
2008-12-20 18:52:15 +01:00
else if ( tok - > str ( ) = = " protected: " )
2008-12-18 22:28:57 +01:00
priv = false ;
2009-07-07 08:30:23 +02:00
else if ( priv )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
if ( Token : : Match ( tok , " typedef %type% ( " ) )
2009-09-16 23:04:13 +02:00
tok = tok - > tokAt ( 2 ) - > link ( ) ;
2008-12-18 22:28:57 +01:00
2009-04-14 21:46:13 +02:00
else if ( Token : : Match ( tok , " [:,] %var% ( " ) )
2009-09-16 23:04:13 +02:00
tok = tok - > tokAt ( 2 ) - > link ( ) ;
2009-04-14 21:46:13 +02:00
else if ( Token : : Match ( tok , " %var% ( " ) & &
! Token : : Match ( tok , classname . c_str ( ) ) )
2008-12-18 22:28:57 +01:00
{
2009-01-10 18:35:41 +01:00
FuncList . push_back ( tok ) ;
2008-12-18 22:28:57 +01:00
}
}
2009-09-25 20:42:22 +02:00
/** @todo embedded class have access to private functions */
if ( tok - > str ( ) = = " class " )
{
FuncList . clear ( ) ;
break ;
}
2008-12-18 22:28:57 +01:00
}
// Check that all private functions are used..
bool HasFuncImpl = false ;
2009-02-25 19:03:17 +01:00
bool inclass = false ;
indent_level = 0 ;
for ( const Token * ftok = _tokenizer - > tokens ( ) ; ftok ; ftok = ftok - > next ( ) )
2008-12-18 22:28:57 +01:00
{
2009-02-25 19:03:17 +01:00
if ( ftok - > str ( ) = = " { " )
+ + indent_level ;
else if ( ftok - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
2009-02-25 19:03:17 +01:00
if ( indent_level > 0 )
- - indent_level ;
if ( indent_level = = 0 )
inclass = false ;
2008-12-18 22:28:57 +01:00
}
2009-02-25 19:03:17 +01:00
if ( Token : : Match ( ftok , ( " class " + classname + " :|{ " ) . c_str ( ) ) )
{
indent_level = 0 ;
inclass = true ;
}
2008-12-18 22:28:57 +01:00
2009-02-25 19:03:17 +01:00
// Check member class functions to see what functions are used..
if ( ( inclass & & indent_level = = 1 & & Token : : Match ( ftok , " ) const| { " ) ) | |
2009-03-02 18:16:02 +01:00
( Token : : Match ( ftok , ( classname + " :: ~| %var% ( " ) . c_str ( ) ) ) )
2008-12-18 22:28:57 +01:00
{
2009-02-25 19:03:17 +01:00
while ( ftok & & ftok - > str ( ) ! = " ) " )
ftok = ftok - > next ( ) ;
if ( ! ftok )
break ;
2009-03-02 21:40:24 +01:00
if ( Token : : Match ( ftok , " ) : %var% ( " ) )
{
while ( ! Token : : Match ( ftok - > next ( ) , " [{};] " ) )
ftok = ftok - > next ( ) ;
}
2009-02-25 19:03:17 +01:00
if ( ! Token : : Match ( ftok , " ) const| { " ) )
continue ;
2008-12-18 22:28:57 +01:00
2009-02-25 19:03:17 +01:00
if ( ftok - > fileIndex ( ) = = 0 )
HasFuncImpl = true ;
// Parse function..
int indentlevel2 = 0 ;
for ( const Token * tok2 = ftok ; tok2 ; tok2 = tok2 - > next ( ) )
2008-12-18 22:28:57 +01:00
{
2009-02-25 19:03:17 +01:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
else if ( tok2 - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
{
2009-02-25 19:03:17 +01:00
- - indentlevel2 ;
if ( indentlevel2 < 1 )
2008-12-18 22:28:57 +01:00
break ;
}
2009-02-25 19:03:17 +01:00
else if ( Token : : Match ( tok2 , " %var% ( " ) )
2009-01-10 18:35:41 +01:00
{
// Remove function from FuncList
2009-07-07 08:55:14 +02:00
std : : list < const Token * > : : iterator it = FuncList . begin ( ) ;
while ( it ! = FuncList . end ( ) )
2009-01-10 18:35:41 +01:00
{
2009-02-25 19:03:17 +01:00
if ( tok2 - > str ( ) = = ( * it ) - > str ( ) )
2009-07-07 08:55:14 +02:00
FuncList . erase ( it + + ) ;
else
it + + ;
2009-01-10 18:35:41 +01:00
}
}
2008-12-18 22:28:57 +01:00
}
}
}
while ( HasFuncImpl & & ! FuncList . empty ( ) )
{
// Final check; check if the function pointer is used somewhere..
2009-01-10 18:35:41 +01:00
const std : : string _pattern ( " return|(|)|,|= " + FuncList . front ( ) - > str ( ) ) ;
2009-01-03 21:29:20 +01:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , _pattern . c_str ( ) ) )
2008-12-18 22:28:57 +01:00
{
2009-03-21 17:58:13 +01:00
unusedPrivateFunctionError ( FuncList . front ( ) , classname , FuncList . front ( ) - > str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
FuncList . pop_front ( ) ;
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: Check that memset is not used on classes
//---------------------------------------------------------------------------
2008-12-20 09:48:52 +01:00
void CheckClass : : noMemset ( )
2008-12-18 22:28:57 +01:00
{
// Locate all 'memset' tokens..
2009-01-03 21:29:20 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2008-12-18 22:28:57 +01:00
{
2009-01-05 16:49:57 +01:00
if ( ! Token : : Match ( tok , " memset|memcpy|memmove " ) )
2008-12-18 22:28:57 +01:00
continue ;
const char * type = NULL ;
2009-01-03 21:29:20 +01:00
if ( Token : : Match ( tok , " memset ( %var% , %num% , sizeof ( %type% ) ) " ) )
2008-12-18 22:28:57 +01:00
type = tok - > strAt ( 8 ) ;
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( tok , " memset ( & %var% , %num% , sizeof ( %type% ) ) " ) )
2008-12-18 22:28:57 +01:00
type = tok - > strAt ( 9 ) ;
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( tok , " memset ( %var% , %num% , sizeof ( struct %type% ) ) " ) )
2008-12-18 22:28:57 +01:00
type = tok - > strAt ( 9 ) ;
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( tok , " memset ( & %var% , %num% , sizeof ( struct %type% ) ) " ) )
2008-12-18 22:28:57 +01:00
type = tok - > strAt ( 10 ) ;
2009-01-03 21:29:20 +01:00
else if ( Token : : Match ( tok , " %type% ( %var% , %var% , sizeof ( %type% ) ) " ) )
2008-12-18 22:28:57 +01:00
type = tok - > strAt ( 8 ) ;
// No type defined => The tokens didn't match
if ( ! ( type & & type [ 0 ] ) )
continue ;
// Warn if type is a class..
2008-12-20 17:30:24 +01:00
const std : : string pattern1 ( std : : string ( " class " ) + type ) ;
2009-01-05 16:49:57 +01:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern1 . c_str ( ) ) )
2008-12-18 22:28:57 +01:00
{
2009-03-21 17:58:13 +01:00
memsetClassError ( tok , tok - > str ( ) ) ;
2008-12-18 22:28:57 +01:00
continue ;
}
// Warn if type is a struct that contains any std::*
2009-09-02 22:51:07 +02:00
const std : : string pattern2 ( std : : string ( " struct " ) + type + " { " ) ;
2009-01-03 21:29:20 +01:00
for ( const Token * tstruct = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern2 . c_str ( ) ) ; tstruct ; tstruct = tstruct - > next ( ) )
2008-12-18 22:28:57 +01:00
{
2008-12-20 20:57:03 +01:00
if ( tstruct - > str ( ) = = " } " )
2008-12-18 22:28:57 +01:00
break ;
2009-01-03 21:29:20 +01:00
if ( Token : : Match ( tstruct , " std :: %type% %var% ; " ) )
2008-12-18 22:28:57 +01:00
{
2009-03-21 17:58:13 +01:00
memsetStructError ( tok , tok - > str ( ) , tstruct - > strAt ( 2 ) ) ;
2008-12-18 22:28:57 +01:00
break ;
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// ClassCheck: "void operator=("
//---------------------------------------------------------------------------
2008-12-20 09:48:52 +01:00
void CheckClass : : operatorEq ( )
2008-12-18 22:28:57 +01:00
{
2009-01-10 18:57:31 +01:00
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , " void operator = ( " ) ;
if ( tok )
2008-12-18 22:28:57 +01:00
{
2009-08-09 19:57:48 +02:00
const Token * tok1 = tok ;
while ( tok1 & & ! Token : : Match ( tok1 , " class %var% " ) )
{
if ( tok1 - > str ( ) = = " public: " )
{
operatorEqReturnError ( tok ) ;
break ;
}
if ( tok1 - > str ( ) = = " private: " | | tok1 - > str ( ) = = " protected: " )
break ;
tok1 = tok1 - > previous ( ) ;
}
2008-12-18 22:28:57 +01:00
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// A destructor in a base class should be virtual
//---------------------------------------------------------------------------
void CheckClass : : virtualDestructor ( )
{
const char pattern_classdecl [ ] = " class %var% : %var% " ;
2009-01-03 21:29:20 +01:00
const Token * derived = _tokenizer - > tokens ( ) ;
while ( ( derived = Token : : findmatch ( derived , pattern_classdecl ) ) ! = NULL )
2008-12-17 21:38:09 +01:00
{
// Check that the derived class has a non empty destructor..
{
std : : ostringstream destructorPattern ;
destructorPattern < < " ~ " < < derived - > strAt ( 1 ) < < " ( ) { " ;
2009-01-05 16:49:57 +01:00
const Token * derived_destructor = Token : : findmatch ( _tokenizer - > tokens ( ) , destructorPattern . str ( ) . c_str ( ) ) ;
2008-12-17 21:38:09 +01:00
// No destructor..
2009-01-05 16:49:57 +01:00
if ( ! derived_destructor )
2008-12-17 21:38:09 +01:00
{
derived = derived - > next ( ) ;
continue ;
}
2008-12-19 22:15:06 +01:00
2008-12-17 21:38:09 +01:00
// Empty destructor..
2009-01-05 16:49:57 +01:00
if ( Token : : Match ( derived_destructor , " ~ %var% ( ) { } " ) )
2008-12-17 21:38:09 +01:00
{
derived = derived - > next ( ) ;
continue ;
}
}
2008-12-19 22:15:06 +01:00
2009-01-03 21:29:20 +01:00
const Token * derivedClass = derived - > tokAt ( 1 ) ;
2008-12-20 21:52:15 +01:00
2008-12-18 22:28:57 +01:00
// Iterate through each base class...
derived = derived - > tokAt ( 3 ) ;
2009-01-05 16:49:57 +01:00
while ( Token : : Match ( derived , " %var% " ) )
2008-12-18 22:28:57 +01:00
{
2009-07-27 11:24:24 +02:00
bool isPublic ( derived - > str ( ) = = " public " ) ;
2008-12-18 22:28:57 +01:00
// What kind of inheritance is it.. public|protected|private
2009-01-05 16:49:57 +01:00
if ( Token : : Match ( derived , " public|protected|private " ) )
2008-12-18 22:28:57 +01:00
derived = derived - > next ( ) ;
// Name of base class..
const char * baseName [ 2 ] ;
baseName [ 0 ] = derived - > strAt ( 0 ) ;
baseName [ 1 ] = 0 ;
// Update derived so it's ready for the next loop.
2009-08-10 16:58:13 +02:00
do
{
if ( derived - > str ( ) = = " { " )
break ;
if ( derived - > str ( ) = = " , " )
{
derived = derived - > next ( ) ;
break ;
}
2008-12-18 22:28:57 +01:00
derived = derived - > next ( ) ;
2009-08-10 16:58:13 +02:00
}
while ( derived ) ;
2008-12-18 22:28:57 +01:00
// If not public inheritance, skip checking of this base class..
2009-01-05 16:49:57 +01:00
if ( ! isPublic )
2008-12-18 22:28:57 +01:00
continue ;
// Find the destructor declaration for the base class.
2009-01-05 16:49:57 +01:00
const Token * base = Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " %any% ~ " ) + baseName [ 0 ] + " ( " ) . c_str ( ) ) ;
2009-07-27 11:24:24 +02:00
while ( base & & base - > str ( ) = = " :: " )
2009-05-06 22:22:26 +02:00
base = Token : : findmatch ( base - > next ( ) , ( std : : string ( " %any% ~ " ) + baseName [ 0 ] + " ( " ) . c_str ( ) ) ;
2008-12-18 22:28:57 +01:00
2009-05-06 22:22:26 +02:00
const Token * reverseTok = base ;
2009-07-27 11:25:41 +02:00
while ( Token : : Match ( base , " %var% " ) & & base - > str ( ) ! = " virtual " )
2008-12-18 22:28:57 +01:00
base = base - > previous ( ) ;
// Check that there is a destructor..
2009-01-05 16:49:57 +01:00
if ( ! base )
2008-12-18 22:28:57 +01:00
{
// Is the class declaration available?
2009-08-04 21:23:22 +02:00
base = Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " class " ) + baseName [ 0 ] + " { " ) . c_str ( ) ) ;
2009-01-05 16:49:57 +01:00
if ( base )
2008-12-18 22:28:57 +01:00
{
2009-03-21 17:58:13 +01:00
virtualDestructorError ( base , baseName [ 0 ] , derivedClass - > str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2009-08-04 21:23:22 +02:00
continue ;
2008-12-18 22:28:57 +01:00
}
// There is a destructor. Check that it's virtual..
2009-05-06 22:22:26 +02:00
else if ( base - > str ( ) = = " virtual " )
continue ;
2009-08-04 21:23:22 +02:00
// TODO: This is just a temporary fix, better solution is needed.
// Skip situations where base class has base classes of its own, because
// some of the base classes might have virtual destructor.
// Proper solution is to check all of the base classes. If base class is not
// found or if one of the base classes has virtual destructor, error should not
// be printed. See TODO test case "virtualDestructorInherited"
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " class " ) + baseName [ 0 ] + " { " ) . c_str ( ) ) )
continue ;
2009-05-06 22:22:26 +02:00
// Make sure that the destructor is public (protected or private
// would not compile if inheritance is used in a way that would
// cause the bug we are trying to find here.)
int indent = 0 ;
while ( reverseTok )
2008-12-18 22:28:57 +01:00
{
2009-05-06 22:22:26 +02:00
if ( reverseTok - > str ( ) = = " public: " )
{
virtualDestructorError ( base , baseName [ 0 ] , derivedClass - > str ( ) ) ;
break ;
}
else if ( reverseTok - > str ( ) = = " protected: " | |
reverseTok - > str ( ) = = " private: " )
{
// No bug, protected/private destructor is allowed
break ;
}
else if ( reverseTok - > str ( ) = = " { " )
{
indent + + ;
if ( indent > = 1 )
{
// We have found the start of the class without any sign
// of "public :" so we can assume that the destructor is not
// public and there is no bug in the code we are checking.
break ;
}
}
else if ( reverseTok - > str ( ) = = " } " )
indent - - ;
reverseTok = reverseTok - > previous ( ) ;
2008-12-18 22:28:57 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2009-09-12 15:25:02 +02:00
void CheckClass : : thisSubtractionError ( const Token * tok )
{
reportError ( tok , Severity : : possibleStyle , " thisSubtraction " , " Suspicious pointer subtraction " ) ;
}
void CheckClass : : thisSubtraction ( )
{
2009-11-04 20:36:27 +01:00
const Token * tok = _tokenizer - > tokens ( ) ;
for ( ; ; )
2009-09-12 15:25:02 +02:00
{
2009-11-04 20:36:27 +01:00
tok = Token : : findmatch ( tok , " this - %var% " ) ;
if ( ! tok )
break ;
2009-09-12 15:25:02 +02:00
2009-11-04 20:36:27 +01:00
if ( ! Token : : simpleMatch ( tok - > previous ( ) , " * " ) )
thisSubtractionError ( tok ) ;
2009-03-21 17:58:13 +01:00
2009-11-04 20:36:27 +01:00
tok = tok - > next ( ) ;
}
}
2009-03-21 17:58:13 +01:00
void CheckClass : : noConstructorError ( const Token * tok , const std : : string & classname )
{
2009-09-29 20:27:17 +02:00
reportError ( tok , Severity : : style , " noConstructor " , " The class ' " + classname + " ' has no constructor. Member variables not initialized. " ) ;
2009-03-21 17:58:13 +01:00
}
2009-12-06 18:35:32 +01:00
void CheckClass : : uninitVarError ( const Token * tok , const std : : string & classname , const std : : string & varname , bool hasPrivateConstructor )
2009-03-21 17:58:13 +01:00
{
2009-12-06 18:35:32 +01:00
reportError ( tok , hasPrivateConstructor ? Severity : : possibleStyle : Severity : : style , " uninitVar " , " Member variable not initialized in the constructor ' " + classname + " :: " + varname + " ' " ) ;
2009-03-21 17:58:13 +01:00
}
2009-03-31 19:00:56 +02:00
void CheckClass : : operatorEqVarError ( const Token * tok , const std : : string & classname , const std : : string & varname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : possibleStyle , " operatorEqVarError " , " Member variable ' " + classname + " :: " + varname + " ' is not assigned a value in ' " + classname + " ::operator= " + " ' " ) ;
2009-03-31 19:00:56 +02:00
}
2009-03-21 17:58:13 +01:00
void CheckClass : : unusedPrivateFunctionError ( const Token * tok , const std : : string & classname , const std : : string & funcname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " unusedPrivateFunction " , " Unused private function ' " + classname + " :: " + funcname + " ' " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckClass : : memsetClassError ( const Token * tok , const std : : string & memfunc )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " memsetClass " , " Using ' " + memfunc + " ' on class " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckClass : : memsetStructError ( const Token * tok , const std : : string & memfunc , const std : : string & classname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " memsetStruct " , " Using ' " + memfunc + " ' on struct that contains a 'std:: " + classname + " ' " ) ;
2009-03-21 17:58:13 +01:00
}
2009-03-31 19:00:56 +02:00
void CheckClass : : operatorEqReturnError ( const Token * tok )
2009-03-21 17:58:13 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " operatorEq " , " 'operator=' should return something " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckClass : : virtualDestructorError ( const Token * tok , const std : : string & Base , const std : : string & Derived )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " virtualDestructor " , " Class " + Base + " which is inherited by class " + Derived + " does not have a virtual destructor " ) ;
2009-03-21 17:58:13 +01:00
}