2010-01-16 08:47:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
*
* 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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checkclass.h"
# include "tokenize.h"
# include "token.h"
# include "errorlogger.h"
# include <locale>
# include <cstring>
# include <string>
# include <sstream>
# include <algorithm>
//---------------------------------------------------------------------------
// Register CheckClass..
namespace
{
CheckClass instance ;
}
//---------------------------------------------------------------------------
CheckClass : : Var * CheckClass : : getVarList ( const Token * tok1 , bool withClasses , bool isStruct )
{
// Get variable list..
Var * varlist = NULL ;
unsigned int indentlevel = 0 ;
bool priv = ! isStruct ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! tok - > next ( ) )
2010-01-16 08:47:46 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2010-01-16 08:47:46 +01:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( indentlevel ! = 1 )
2010-01-16 08:47:46 +01:00
continue ;
2010-03-28 10:58:03 +02:00
// Borland C++: Skip all variables in the __published section.
// These are automaticly initialized.
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " __published: " )
2010-01-16 08:47:46 +01:00
{
priv = false ;
2010-04-02 07:30:58 +02:00
for ( ; tok ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-03-28 10:58:03 +02:00
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " private:|protected:|public: " ) )
2010-01-16 08:47:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( tok )
2010-01-16 08:47:46 +01:00
continue ;
else
break ;
}
// "private:" "public:" "protected:" etc
2010-02-14 19:58:17 +01:00
const bool b ( ( tok - > str ( ) [ 0 ] ! = ' : ' ) & & tok - > str ( ) . find ( " : " ) ! = std : : string : : npos ) ;
2010-01-16 08:47:46 +01:00
2010-04-02 07:30:58 +02:00
if ( b )
2010-01-16 08:47:46 +01:00
priv = bool ( tok - > str ( ) = = " private: " ) ;
// Search for start of statement..
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " [;{}] " ) & & ! b )
2010-01-16 08:47:46 +01:00
continue ;
// This is the start of a statement
const Token * next = tok - > next ( ) ;
2010-02-14 19:58:17 +01:00
std : : string varname ;
2010-01-16 08:47:46 +01:00
// If next token contains a ":".. it is not part of a variable declaration
2010-04-02 07:30:58 +02:00
if ( next - > str ( ) . find ( " : " ) ! = std : : string : : npos )
2010-01-16 08:47:46 +01:00
continue ;
2010-03-28 10:58:03 +02:00
// Borland C++: Ignore properties..
2010-04-02 07:30:58 +02:00
if ( next - > str ( ) = = " __property " )
2010-03-28 10:58:03 +02:00
continue ;
2010-04-02 08:02:47 +02:00
// Is it a static variable?
bool isStatic = false ;
if ( next - > str ( ) = = " static " )
{
isStatic = true ;
next = next - > next ( ) ;
}
2010-03-26 19:06:00 +01:00
// Is it a mutable variable?
bool isMutable = false ;
2010-04-02 07:30:58 +02:00
if ( next - > str ( ) = = " mutable " )
2010-03-26 19:06:00 +01:00
{
isMutable = true ;
next = next - > next ( ) ;
}
2010-01-16 08:47:46 +01:00
// Is it a variable declaration?
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( next , " %type% %var% ; " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( withClasses )
2010-01-16 08:47:46 +01:00
varname = next - > strAt ( 1 ) ;
2010-04-02 07:30:58 +02:00
else if ( next - > isStandardType ( ) )
2010-01-16 08:47:46 +01:00
varname = next - > strAt ( 1 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : findmatch ( _tokenizer - > tokens ( ) , ( " enum " + next - > str ( ) ) . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
varname = next - > strAt ( 1 ) ;
}
2010-03-26 18:16:33 +01:00
// Structure?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " struct|union %type% %var% ; " ) )
2010-03-26 18:16:33 +01:00
{
varname = next - > strAt ( 2 ) ;
}
2010-01-16 08:47:46 +01:00
// Pointer?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% * %var% ; " ) )
2010-01-16 08:47:46 +01:00
{
varname = next - > strAt ( 2 ) ;
}
// Pointer?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% %type% * %var% ; " ) )
2010-01-16 08:47:46 +01:00
{
varname = next - > strAt ( 3 ) ;
}
// Array?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% %var% [ " ) & & next - > next ( ) - > str ( ) ! = " operator " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! withClasses )
2010-04-01 17:01:52 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , ( " class|struct " + next - > str ( ) ) . c_str ( ) ) )
2010-04-01 17:01:52 +02:00
continue ;
}
2010-01-16 08:47:46 +01:00
varname = next - > strAt ( 1 ) ;
}
// Pointer array?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% * %var% [ " ) )
2010-01-16 08:47:46 +01:00
{
varname = next - > strAt ( 2 ) ;
}
// std::string..
2010-04-02 07:30:58 +02:00
else if ( withClasses & & Token : : Match ( next , " %type% :: %type% %var% ; " ) )
2010-01-16 08:47:46 +01:00
{
varname = next - > strAt ( 3 ) ;
}
// Container..
2010-04-02 07:30:58 +02:00
else if ( withClasses & & ( Token : : Match ( next , " %type% :: %type% < " ) | |
Token : : Match ( next , " %type% < " ) ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
while ( next & & next - > str ( ) ! = " > " )
2010-01-16 08:47:46 +01:00
next = next - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( next , " > %var% ; " ) )
2010-01-16 08:47:46 +01:00
varname = next - > strAt ( 1 ) ;
}
// If the varname was set in one of the two if-block above, create a entry for this variable..
2010-04-02 07:30:58 +02:00
if ( ! varname . empty ( ) & & varname ! = " operator " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 08:02:47 +02:00
Var * var = new Var ( varname , false , priv , isMutable , isStatic , varlist ) ;
2010-01-16 08:47:46 +01:00
varlist = var ;
}
}
return varlist ;
}
//---------------------------------------------------------------------------
2010-02-14 19:58:17 +01:00
void CheckClass : : initVar ( Var * varlist , const std : : string & varname )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( var - > name = = varname )
2010-01-16 08:47:46 +01:00
{
var - > init = true ;
2010-01-22 19:29:24 +01:00
return ;
2010-01-16 08:47:46 +01:00
}
}
}
//---------------------------------------------------------------------------
2010-02-14 19:58:17 +01:00
void CheckClass : : initializeVarList ( const Token * tok1 , const Token * ftok , Var * varlist , const std : : string & classname , std : : list < std : : string > & callstack , bool isStruct )
2010-01-16 08:47:46 +01:00
{
bool Assign = false ;
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( ; ftok ; ftok = ftok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! ftok - > next ( ) )
2010-01-16 08:47:46 +01:00
break ;
// Class constructor.. initializing variables like this
// clKalle::clKalle() : var(value) { }
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Assign & & Token : : Match ( ftok , " %var% ( " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
Assign | = ( ftok - > str ( ) = = " : " ) ;
}
2010-04-02 07:30:58 +02:00
if ( ftok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
{
+ + indentlevel ;
Assign = false ;
}
2010-04-02 07:30:58 +02:00
else if ( ftok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2010-01-16 08:47:46 +01:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( indentlevel < 1 )
2010-01-16 08:47:46 +01:00
continue ;
// Variable getting value from stream?
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( ftok , " >> %var% " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 1 ) ) ;
}
// Before a new statement there is "[{};)=]" or "else"
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( ftok , " [{};()=] " ) & & ftok - > str ( ) ! = " else " )
2010-01-16 08:47:46 +01:00
continue ;
// Using the operator= function to initialize all variables..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( ftok - > next ( ) , " * this = " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
var - > init = true ;
break ;
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( ftok - > next ( ) , " %var% " ) & &
! Token : : Match ( ftok - > next ( ) , " this . %var% " ) & &
! Token : : Match ( ftok - > next ( ) , " * %var% = " ) & &
! Token : : Match ( ftok - > next ( ) , " ( * this ) . %var% " ) )
2010-01-16 08:47:46 +01:00
continue ;
// Goto the first token in this statement..
ftok = ftok - > next ( ) ;
// Skip "( * this )"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( ftok , " ( * this ) . " ) )
2010-01-16 08:47:46 +01:00
{
ftok = ftok - > tokAt ( 5 ) ;
}
// Skip "this->"
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( ftok , " this . " ) )
2010-01-16 08:47:46 +01:00
ftok = ftok - > tokAt ( 2 ) ;
// Skip "classname :: "
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( ftok , " %var% :: " ) )
2010-01-16 08:47:46 +01:00
ftok = ftok - > tokAt ( 2 ) ;
// Clearing all variables..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( ftok , " memset ( this , " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
var - > init = true ;
2010-03-26 17:19:33 +01:00
return ;
2010-01-16 08:47:46 +01:00
}
2010-02-10 19:28:51 +01:00
// Clearing array..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " memset ( %var% , " ) )
2010-02-10 19:28:51 +01:00
{
initVar ( varlist , ftok - > strAt ( 2 ) ) ;
ftok = ftok - > next ( ) - > link ( ) ;
continue ;
}
2010-01-16 08:47:46 +01:00
// Calling member function?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " %var% ( " ) )
2010-01-16 08:47:46 +01:00
{
2010-03-26 17:19:33 +01:00
// Passing "this" => assume that everything is initialized
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = ftok - > next ( ) - > link ( ) ; tok2 & & tok2 ! = ftok ; tok2 = tok2 - > previous ( ) )
2010-03-26 17:19:33 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " this " )
2010-03-26 17:19:33 +01:00
{
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-03-26 17:19:33 +01:00
var - > init = true ;
return ;
}
}
2010-04-02 07:30:58 +02:00
if ( ftok - > str ( ) = = " if " )
2010-03-26 17:19:33 +01:00
continue ;
2010-01-16 08:47:46 +01:00
// No recursive calls!
2010-04-02 07:30:58 +02:00
if ( std : : find ( callstack . begin ( ) , callstack . end ( ) , ftok - > str ( ) ) = = callstack . end ( ) )
2010-01-16 08:47:46 +01:00
{
int i = 0 ;
2010-01-29 22:22:18 +01:00
const Token * ftok2 = _tokenizer - > findClassFunction ( tok1 , classname , ftok - > strAt ( 0 ) , i , isStruct ) ;
2010-04-02 07:30:58 +02:00
if ( ftok2 )
2010-01-16 08:47:46 +01:00
{
2010-03-13 20:24:39 +01:00
callstack . push_back ( ftok - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
initializeVarList ( tok1 , ftok2 , varlist , classname , callstack , isStruct ) ;
2010-03-13 20:24:39 +01:00
callstack . pop_back ( ) ;
2010-01-16 08:47:46 +01:00
}
else // there is a called member function, but it is not defined where we can find it, so we assume it initializes everything
{
2010-01-22 18:51:25 +01:00
// check if the function is part of this class..
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " class " ) + classname + " { " ) . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
for ( tok = tok ? tok - > tokAt ( 3 ) : 0 ; tok ; tok = tok - > next ( ) )
2010-01-22 18:51:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-22 18:51:25 +01:00
{
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-01-22 18:51:25 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2010-01-22 18:51:25 +01:00
{
break ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = ftok - > str ( ) | | tok - > str ( ) = = " friend " )
2010-01-22 18:51:25 +01:00
{
tok = 0 ;
break ;
}
}
// bail out..
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-01-22 18:51:25 +01:00
{
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-22 18:51:25 +01:00
var - > init = true ;
break ;
}
// the function is external and it's neither friend nor inherited virtual function.
// assume all variables that are passed to it are initialized..
2010-03-13 20:24:39 +01:00
unsigned int indentlevel2 = 0 ;
2010-04-02 07:30:58 +02:00
for ( tok = ftok - > tokAt ( 2 ) ; tok ; tok = tok - > next ( ) )
2010-01-22 18:51:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2010-03-13 20:24:39 +01:00
+ + indentlevel2 ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2010-01-22 18:51:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel2 = = 0 )
2010-01-22 18:51:25 +01:00
break ;
2010-03-13 20:24:39 +01:00
- - indentlevel2 ;
2010-01-22 18:51:25 +01:00
}
2010-04-02 07:30:58 +02:00
if ( tok - > isName ( ) )
2010-01-22 18:51:25 +01:00
{
2010-01-22 19:29:24 +01:00
initVar ( varlist , tok - > strAt ( 0 ) ) ;
2010-01-22 18:51:25 +01:00
}
}
continue ;
2010-01-16 08:47:46 +01:00
}
}
}
// Assignment of member variable?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " %var% = " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
// Assignment of array item of member variable?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " %var% [ %any% ] = " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
// Assignment of array item of member variable?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " %var% [ %any% ] [ %any% ] = " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
// Assignment of array item of member variable?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( ftok , " * %var% = " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 1 ) ) ;
}
2010-04-02 07:36:18 +02:00
// Assignment of struct member of member variable?
else if ( Token : : Match ( ftok , " %var% . %any% = " ) )
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
2010-01-16 08:47:46 +01:00
// The functions 'clear' and 'Clear' are supposed to initialize variable.
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( ftok , " %var% . clear|Clear ( " ) )
2010-01-16 08:47:46 +01:00
{
initVar ( varlist , ftok - > strAt ( 0 ) ) ;
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: Check that all class constructors are ok.
//---------------------------------------------------------------------------
void CheckClass : : constructors ( )
{
const char pattern_class [ ] = " class|struct %var% [{:] " ;
// Locate class
const Token * tok1 = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern_class ) ;
2010-04-02 07:30:58 +02:00
while ( tok1 )
2010-01-16 08:47:46 +01:00
{
2010-02-14 19:58:17 +01:00
const std : : string className = tok1 - > strAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
const Token * classNameToken = tok1 - > tokAt ( 1 ) ;
bool isStruct = tok1 - > str ( ) = = " struct " ;
/** @todo handling of private constructors should be improved */
bool hasPrivateConstructor = false ;
{
int indentlevel = 0 ;
bool isPrivate = ! isStruct ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
// Indentation
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 0 )
2010-01-16 08:47:46 +01:00
break ;
}
// Parse class contents (indentlevel == 1)..
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 1 )
2010-01-16 08:47:46 +01:00
{
// What section are we in.. private/non-private
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " private: " )
2010-01-16 08:47:46 +01:00
isPrivate = true ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " protected: " | | tok - > str ( ) = = " public: " )
2010-01-16 08:47:46 +01:00
isPrivate = false ;
// Is there a private constructor?
2010-04-02 07:30:58 +02:00
else if ( isPrivate & & Token : : simpleMatch ( tok , ( classNameToken - > str ( ) + " ( " ) . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
hasPrivateConstructor = true ;
break ;
}
}
}
}
2010-04-02 07:30:58 +02:00
if ( hasPrivateConstructor & & ! _settings - > _showAll )
2010-01-16 08:47:46 +01:00
{
/** @todo Handle private constructors. Right now to avoid
* false positives we just bail out */
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
continue ;
}
// Are there a class constructor?
std : : string tempPattern = " %any% " + classNameToken - > str ( ) + " ( " ;
const Token * constructor_token = Token : : findmatch ( tok1 , tempPattern . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
while ( constructor_token & & constructor_token - > str ( ) = = " ~ " )
2010-01-16 08:47:46 +01:00
constructor_token = Token : : findmatch ( constructor_token - > next ( ) , tempPattern . c_str ( ) ) ;
// There are no constructor.
2010-04-02 07:30:58 +02:00
if ( ! constructor_token )
2010-01-16 08:47:46 +01:00
{
// If "--style" has been given, give a warning
2010-04-02 07:30:58 +02:00
if ( _settings - > _checkCodingStyle )
2010-01-16 08:47:46 +01:00
{
// Get class variables...
Var * varlist = getVarList ( tok1 , false , isStruct ) ;
// If there is a private variable, there should be a constructor..
2010-04-02 07:30:58 +02:00
for ( const Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
{
2010-04-02 08:02:47 +02:00
if ( var - > priv & & ! var - > isStatic )
2010-01-16 08:47:46 +01:00
{
noConstructorError ( tok1 , classNameToken - > str ( ) , isStruct ) ;
break ;
}
}
// Delete the varlist..
2010-04-02 07:30:58 +02:00
while ( varlist )
2010-01-16 08:47:46 +01:00
{
Var * nextvar = varlist - > next ;
delete varlist ;
varlist = nextvar ;
}
}
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
continue ;
}
// Check constructors
checkConstructors ( tok1 , className , hasPrivateConstructor , isStruct ) ;
// Check assignment operators
checkConstructors ( tok1 , " operator = " , hasPrivateConstructor , isStruct ) ;
tok1 = Token : : findmatch ( tok1 - > next ( ) , pattern_class ) ;
}
}
2010-02-14 19:58:17 +01:00
void CheckClass : : checkConstructors ( const Token * tok1 , const std : : string & funcname , bool hasPrivateConstructor , bool isStruct )
2010-01-16 08:47:46 +01:00
{
2010-02-14 19:58:17 +01:00
const std : : string className = tok1 - > strAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
// Check that all member variables are initialized..
2010-02-14 19:58:17 +01:00
bool withClasses = bool ( _settings - > _showAll & & funcname = = " operator = " ) ;
2010-01-16 08:47:46 +01:00
Var * varlist = getVarList ( tok1 , withClasses , isStruct ) ;
int indentlevel = 0 ;
2010-01-29 22:22:18 +01:00
const Token * constructor_token = _tokenizer - > findClassFunction ( tok1 , className , funcname , indentlevel , isStruct ) ;
2010-01-16 08:47:46 +01:00
std : : list < std : : string > callstack ;
initializeVarList ( tok1 , constructor_token , varlist , className , callstack , isStruct ) ;
2010-04-02 07:30:58 +02:00
while ( constructor_token )
2010-01-16 08:47:46 +01:00
{
// Check if any variables are uninitialized
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
{
2010-04-09 18:35:54 +02:00
if ( var - > init | | var - > isStatic )
2010-01-16 08:47:46 +01:00
continue ;
// It's non-static and it's not initialized => error
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( constructor_token , " operator = ( " ) | |
Token : : simpleMatch ( constructor_token - > tokAt ( 2 ) , " operator = ( " ) )
2010-01-16 08:47:46 +01:00
{
const Token * operStart = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( constructor_token , " operator = ( " ) )
2010-01-16 08:47:46 +01:00
operStart = constructor_token - > tokAt ( 2 ) ;
else
operStart = constructor_token - > tokAt ( 4 ) ;
bool classNameUsed = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * operTok = operStart ; operTok ! = operStart - > link ( ) ; operTok = operTok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( operTok - > str ( ) = = className )
2010-01-16 08:47:46 +01:00
{
classNameUsed = true ;
break ;
}
}
2010-04-02 07:30:58 +02:00
if ( classNameUsed )
2010-01-16 08:47:46 +01:00
operatorEqVarError ( constructor_token , className , var - > name ) ;
}
2010-04-02 08:02:47 +02:00
else if ( ! var - > isStatic )
2010-01-16 08:47:46 +01:00
uninitVarError ( constructor_token , className , var - > name , hasPrivateConstructor ) ;
}
2010-04-02 07:30:58 +02:00
for ( Var * var = varlist ; var ; var = var - > next )
2010-01-16 08:47:46 +01:00
var - > init = false ;
2010-01-29 22:22:18 +01:00
constructor_token = _tokenizer - > findClassFunction ( constructor_token - > next ( ) , className , funcname , indentlevel , isStruct ) ;
2010-01-16 08:47:46 +01:00
callstack . clear ( ) ;
initializeVarList ( tok1 , constructor_token , varlist , className , callstack , isStruct ) ;
}
// Delete the varlist..
2010-04-02 07:30:58 +02:00
while ( varlist )
2010-01-16 08:47:46 +01:00
{
Var * nextvar = varlist - > next ;
delete varlist ;
varlist = nextvar ;
}
}
//---------------------------------------------------------------------------
// ClassCheck: Unused private functions
//---------------------------------------------------------------------------
void CheckClass : : privateFunctions ( )
{
// Locate some class
2010-04-02 07:30:58 +02:00
for ( const Token * tok1 = Token : : findmatch ( _tokenizer - > tokens ( ) , " class|struct %var% { " ) ; tok1 ; tok1 = Token : : findmatch ( tok1 - > next ( ) , " class|struct %var% { " ) )
2010-01-16 08:47:46 +01: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
2010-04-02 07:30:58 +02:00
if ( tok1 - > fileIndex ( ) ! = 0 )
2010-01-16 08:47:46 +01:00
continue ;
const std : : string & classname = tok1 - > next ( ) - > str ( ) ;
// Get private functions..
std : : list < const Token * > FuncList ;
FuncList . clear ( ) ;
bool isStruct = tok1 - > str ( ) = = " struct " ;
bool priv = ! isStruct ;
unsigned int indent_level = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " friend %var% " ) )
2010-01-16 08:47:46 +01:00
{
/** @todo Handle friend classes */
FuncList . clear ( ) ;
break ;
}
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
+ + indent_level ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent_level < = 1 )
2010-01-16 08:47:46 +01:00
break ;
- - indent_level ;
}
2010-04-02 07:30:58 +02:00
else if ( indent_level ! = 1 )
2010-01-16 08:47:46 +01:00
continue ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " private: " )
2010-01-16 08:47:46 +01:00
priv = true ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " public: " )
2010-01-16 08:47:46 +01:00
priv = false ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " protected: " )
2010-01-16 08:47:46 +01:00
priv = false ;
2010-04-02 07:30:58 +02:00
else if ( priv )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " typedef %type% ( " ) )
2010-01-16 08:47:46 +01:00
tok = tok - > tokAt ( 2 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [:,] %var% ( " ) )
2010-01-16 08:47:46 +01:00
tok = tok - > tokAt ( 2 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " %var% ( " ) & &
! Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) ( " ) & &
! Token : : Match ( tok , classname . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
FuncList . push_back ( tok ) ;
}
}
/** @todo embedded class have access to private functions */
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " class " )
2010-01-16 08:47:46 +01:00
{
FuncList . clear ( ) ;
break ;
}
}
// Check that all private functions are used..
bool HasFuncImpl = false ;
bool inclass = false ;
indent_level = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * ftok = _tokenizer - > tokens ( ) ; ftok ; ftok = ftok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ftok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
+ + indent_level ;
2010-04-02 07:30:58 +02:00
else if ( ftok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent_level > 0 )
2010-01-16 08:47:46 +01:00
- - indent_level ;
2010-04-02 07:30:58 +02:00
if ( indent_level = = 0 )
2010-01-16 08:47:46 +01:00
inclass = false ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( ftok , ( " class " + classname + " :|{ " ) . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
indent_level = 0 ;
inclass = true ;
}
// Check member class functions to see what functions are used..
2010-04-08 19:06:54 +02:00
if ( ( inclass & & indent_level = = 1 & & Token : : Match ( ftok , " %var% ( " ) ) | |
2010-04-02 07:30:58 +02:00
( Token : : Match ( ftok , ( classname + " :: ~| %var% ( " ) . c_str ( ) ) ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
while ( ftok & & ftok - > str ( ) ! = " ) " )
2010-01-16 08:47:46 +01:00
ftok = ftok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! ftok )
2010-01-16 08:47:46 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( ftok , " ) : %var% ( " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
while ( ! Token : : Match ( ftok - > next ( ) , " [{};] " ) )
2010-04-08 19:06:54 +02:00
{
if ( Token : : Match ( ftok , " ::|,|( %var% ,|) " ) )
{
// Remove function from FuncList
std : : list < const Token * > : : iterator it = FuncList . begin ( ) ;
while ( it ! = FuncList . end ( ) )
{
if ( ftok - > next ( ) - > str ( ) = = ( * it ) - > str ( ) )
FuncList . erase ( it + + ) ;
else
it + + ;
}
}
2010-01-16 08:47:46 +01:00
ftok = ftok - > next ( ) ;
2010-04-08 19:06:54 +02:00
}
2010-01-16 08:47:46 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( ftok , " ) const| { " ) )
2010-01-16 08:47:46 +01:00
continue ;
2010-04-02 07:30:58 +02:00
if ( ftok - > fileIndex ( ) = = 0 )
2010-01-16 08:47:46 +01:00
HasFuncImpl = true ;
// Parse function..
int indentlevel2 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = ftok ; tok2 ; tok2 = tok2 - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
+ + indentlevel2 ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
{
- - indentlevel2 ;
2010-04-02 07:30:58 +02:00
if ( indentlevel2 < 1 )
2010-01-16 08:47:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %var% ( " ) )
2010-01-16 08:47:46 +01:00
{
// Remove function from FuncList
std : : list < const Token * > : : iterator it = FuncList . begin ( ) ;
2010-04-02 07:30:58 +02:00
while ( it ! = FuncList . end ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = ( * it ) - > str ( ) )
2010-01-16 08:47:46 +01:00
FuncList . erase ( it + + ) ;
else
it + + ;
}
}
}
}
}
2010-04-02 07:30:58 +02:00
while ( HasFuncImpl & & ! FuncList . empty ( ) )
2010-01-16 08:47:46 +01:00
{
// Final check; check if the function pointer is used somewhere..
const std : : string _pattern ( " return|(|)|,|= " + FuncList . front ( ) - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , _pattern . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
unusedPrivateFunctionError ( FuncList . front ( ) , classname , FuncList . front ( ) - > str ( ) ) ;
}
FuncList . pop_front ( ) ;
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: Check that memset is not used on classes
//---------------------------------------------------------------------------
void CheckClass : : noMemset ( )
{
// Locate all 'memset' tokens..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " memset|memcpy|memmove " ) )
2010-01-16 08:47:46 +01:00
continue ;
2010-02-14 19:58:17 +01:00
std : : string type ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " memset ( %var% , %num% , sizeof ( %type% ) ) " ) )
2010-01-16 08:47:46 +01:00
type = tok - > strAt ( 8 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " memset ( & %var% , %num% , sizeof ( %type% ) ) " ) )
2010-01-16 08:47:46 +01:00
type = tok - > strAt ( 9 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " memset ( %var% , %num% , sizeof ( struct %type% ) ) " ) )
2010-01-16 08:47:46 +01:00
type = tok - > strAt ( 9 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " memset ( & %var% , %num% , sizeof ( struct %type% ) ) " ) )
2010-01-16 08:47:46 +01:00
type = tok - > strAt ( 10 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " %type% ( %var% , %var% , sizeof ( %type% ) ) " ) )
2010-01-16 08:47:46 +01:00
type = tok - > strAt ( 8 ) ;
// No type defined => The tokens didn't match
2010-04-02 07:30:58 +02:00
if ( type . empty ( ) )
2010-01-16 08:47:46 +01:00
continue ;
2010-02-04 19:40:35 +01:00
// Warn if type is a class or struct that contains any std::* variables
const std : : string pattern2 ( std : : string ( " struct|class " ) + type + " { " ) ;
2010-04-02 07:30:58 +02:00
for ( const Token * tstruct = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern2 . c_str ( ) ) ; tstruct ; tstruct = tstruct - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tstruct - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
break ;
2010-02-04 21:49:58 +01:00
// struct with function? skip function body..
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tstruct , " ) { " ) )
2010-01-16 08:47:46 +01:00
{
2010-02-04 21:49:58 +01:00
tstruct = tstruct - > next ( ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tstruct )
2010-02-04 21:49:58 +01:00
break ;
2010-01-16 08:47:46 +01:00
}
2010-02-04 19:40:35 +01:00
2010-02-04 21:49:58 +01:00
// before a statement there must be either:
// * private:|protected:|public:
// * { } ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tstruct , " [;{}] " ) | |
tstruct - > str ( ) . find ( " : " ) ! = std : : string : : npos )
2010-02-04 19:40:35 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tstruct - > next ( ) , " std :: %type% %var% ; " ) )
2010-02-04 21:49:58 +01:00
memsetStructError ( tok , tok - > str ( ) , tstruct - > strAt ( 3 ) ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tstruct - > next ( ) , " std :: %type% < " ) )
2010-02-04 21:49:58 +01:00
{
// backup the type
const std : : string typestr ( tstruct - > strAt ( 3 ) ) ;
// check if it's a pointer variable..
unsigned int level = 0 ;
2010-04-02 07:30:58 +02:00
while ( 0 ! = ( tstruct = tstruct - > next ( ) ) )
2010-02-04 21:49:58 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tstruct - > str ( ) = = " < " )
2010-02-04 21:49:58 +01:00
+ + level ;
2010-04-02 07:30:58 +02:00
else if ( tstruct - > str ( ) = = " > " )
2010-02-04 21:49:58 +01:00
{
2010-04-02 07:30:58 +02:00
if ( level < = 1 )
2010-02-04 21:49:58 +01:00
break ;
- - level ;
}
2010-04-02 07:30:58 +02:00
else if ( tstruct - > str ( ) = = " ( " )
2010-02-04 21:49:58 +01:00
tstruct = tstruct - > link ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( ! tstruct )
2010-02-04 21:49:58 +01:00
break ;
// found error => report
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tstruct , " > %var% ; " ) )
2010-02-04 21:49:58 +01:00
memsetStructError ( tok , tok - > str ( ) , typestr ) ;
}
2010-02-04 19:40:35 +01:00
}
2010-01-16 08:47:46 +01:00
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// ClassCheck: "void operator=("
//---------------------------------------------------------------------------
void CheckClass : : operatorEq ( )
{
const Token * tok2 = _tokenizer - > tokens ( ) ;
const Token * tok ;
2010-04-06 20:35:21 +02:00
while ( ( tok = Token : : findmatch ( tok2 , " void operator = ( " ) ) ! = NULL )
2010-01-16 08:47:46 +01:00
{
const Token * tok1 = tok ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ! Token : : Match ( tok1 , " class|struct %var% " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = " public: " )
2010-01-16 08:47:46 +01:00
{
operatorEqReturnError ( tok ) ;
break ;
}
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = " private: " | | tok1 - > str ( ) = = " protected: " )
2010-01-16 08:47:46 +01:00
break ;
tok1 = tok1 - > previous ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( tok1 & & Token : : Match ( tok1 , " struct %var% " ) )
2010-01-16 08:47:46 +01:00
operatorEqReturnError ( tok ) ;
tok2 = tok - > next ( ) ;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// ClassCheck: "C& operator=(const C&) { ... return *this; }"
// operator= should return a reference to *this
//---------------------------------------------------------------------------
// match two lists of tokens
static bool nameMatch ( const Token * tok1 , const Token * tok2 , int length )
{
2010-04-02 07:30:58 +02:00
for ( int i = 0 ; i < length ; i + + )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( i ) = = 0 | | tok2 - > tokAt ( i ) = = 0 )
2010-01-16 08:47:46 +01:00
return false ;
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( i ) - > str ( ) ! = tok2 - > tokAt ( i ) - > str ( ) )
2010-01-16 08:47:46 +01:00
return false ;
}
return true ;
}
// create a class name from a list of tokens
static void nameStr ( const Token * name , int length , std : : string & str )
{
2010-04-02 07:30:58 +02:00
for ( int i = 0 ; i < length ; i + + )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( i ! = 0 )
2010-01-16 08:47:46 +01:00
str + = " " ;
str + = name - > tokAt ( i ) - > str ( ) ;
}
}
2010-04-03 09:17:16 +02:00
void CheckClass : : operatorEqRetRefThis_finderr ( const Token * tok , const std : : string & classname )
{
// find the ')'
const Token * tok1 = tok - > tokAt ( 2 ) - > link ( ) ;
// is there an implementation?
if ( Token : : simpleMatch ( tok1 , " ) { " ) )
{
bool foundReturn = false ;
const Token * last = tok1 - > next ( ) - > link ( ) ;
for ( tok1 = tok1 - > tokAt ( 2 ) ; tok1 & & tok1 ! = last ; tok1 = tok1 - > next ( ) )
{
// check for return of reference to this
if ( tok1 - > str ( ) = = " return " )
{
foundReturn = true ;
std : : string cast ( " ( " + classname + " & ) " ) ;
if ( Token : : Match ( tok1 - > next ( ) , cast . c_str ( ) ) )
tok1 = tok1 - > tokAt ( 4 ) ;
if ( ! ( Token : : Match ( tok1 - > tokAt ( 1 ) , " (| * this ;|= " ) | |
Token : : Match ( tok1 - > tokAt ( 1 ) , " (| * this += " ) | |
Token : : Match ( tok1 - > tokAt ( 1 ) , " operator = ( " ) ) )
operatorEqRetRefThisError ( tok ) ;
}
}
if ( ! foundReturn )
operatorEqRetRefThisError ( tok ) ;
}
}
2010-01-16 08:47:46 +01:00
void CheckClass : : operatorEqRetRefThis ( )
{
const Token * tok2 = _tokenizer - > tokens ( ) ;
const Token * tok ;
2010-04-06 20:35:21 +02:00
while ( ( tok = Token : : findmatch ( tok2 , " operator = ( " ) ) ! = NULL )
2010-01-16 08:47:46 +01:00
{
const Token * tok1 = tok ;
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 2 ) & & Token : : Match ( tok1 - > tokAt ( - 2 ) , " %type% :: " ) )
2010-01-16 08:47:46 +01:00
{
// make sure this is an assignment operator
int nameLength = 1 ;
tok1 = tok1 - > tokAt ( - 2 ) ;
// check backwards for proper function signature
2010-04-02 07:30:58 +02:00
while ( tok1 - > tokAt ( - 2 ) & & Token : : Match ( tok1 - > tokAt ( - 2 ) , " %type% :: " ) )
2010-01-16 08:47:46 +01:00
{
tok1 = tok1 - > tokAt ( - 2 ) ;
nameLength + = 2 ;
}
2010-04-06 21:53:05 +02:00
const Token * className = tok1 ;
2010-01-16 08:47:46 +01:00
std : : string nameString ;
2010-04-06 21:53:05 +02:00
nameStr ( className , nameLength , nameString ) ;
2010-01-16 08:47:46 +01:00
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 1 ) & & tok1 - > tokAt ( - 1 ) - > str ( ) = = " & " )
2010-01-16 08:47:46 +01:00
{
// check class name
2010-04-06 21:53:05 +02:00
if ( tok1 - > tokAt ( - ( 1 + nameLength ) ) & & nameMatch ( className , tok1 - > tokAt ( - ( 1 + nameLength ) ) , nameLength ) )
2010-01-16 08:47:46 +01:00
{
2010-04-06 21:53:05 +02:00
operatorEqRetRefThis_finderr ( tok , className - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
}
}
else
{
// make sure this is an assignment operator
tok1 = tok ;
// check backwards for proper function signature
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 1 ) & & tok1 - > tokAt ( - 1 ) - > str ( ) = = " & " )
2010-01-16 08:47:46 +01:00
{
2010-04-06 21:53:05 +02:00
const Token * className = 0 ;
2010-01-16 08:47:46 +01:00
bool isPublic = false ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ! Token : : Match ( tok1 , " class|struct %var% " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! isPublic )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = " public: " )
2010-01-16 08:47:46 +01:00
isPublic = true ;
}
tok1 = tok1 - > previous ( ) ;
}
2010-04-03 09:17:16 +02:00
if ( Token : : Match ( tok1 , " struct|class %var% " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-03 09:17:16 +02:00
// data members in structs are public by default
isPublic = bool ( tok1 - > str ( ) = = " struct " ) ;
2010-04-06 21:53:05 +02:00
className = tok1 - > tokAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
}
2010-04-06 21:53:05 +02:00
if ( tok - > tokAt ( - 2 ) & & tok - > tokAt ( - 2 ) - > str ( ) = = className - > str ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-06 21:53:05 +02:00
operatorEqRetRefThis_finderr ( tok , className - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
}
}
tok2 = tok - > next ( ) ;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// ClassCheck: "C& operator=(const C& rhs) { if (this == &rhs) ... }"
// operator= should check for assignment to self
//
// For simple classes, an assignment to self check is only a potential optimization.
//
// For classes that allocate dynamic memory, assignment to self can be a real error
// if it is deallocated and allocated again without being checked for.
//
// This check is not valid for classes with multiple inheritance because a
// class can have multiple addresses so there is no trivial way to check for
// assignment to self.
//---------------------------------------------------------------------------
static bool hasDeallocation ( const Token * first , const Token * last )
{
// This function is called when no simple check was found for assignment
// to self. We are currently looking for a specific sequence of:
// deallocate member ; ... member = allocate
// This check is far from ideal because it can cause false negatives.
// Unfortunately, this is necessary to prevent false positives.
// This check needs to do careful analysis someday to get this
// correct with a high degree of certainty.
2010-04-02 07:30:58 +02:00
for ( const Token * tok = first ; tok & & ( tok ! = last ) ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
// check for deallocating memory
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " {|;|, free ( %var% " ) )
2010-01-16 08:47:46 +01:00
{
const Token * var = tok - > tokAt ( 3 ) ;
// we should probably check that var is a pointer in this class
const Token * tok1 = tok - > tokAt ( 4 ) ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ( tok1 ! = last ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " %var% = " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = var - > str ( ) )
2010-01-16 08:47:46 +01:00
return true ;
}
tok1 = tok1 - > next ( ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " {|;|, delete [ ] %var% " ) )
2010-01-16 08:47:46 +01:00
{
const Token * var = tok - > tokAt ( 4 ) ;
// we should probably check that var is a pointer in this class
const Token * tok1 = tok - > tokAt ( 5 ) ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ( tok1 ! = last ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " %var% = new %type% [ " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = var - > str ( ) )
2010-01-16 08:47:46 +01:00
return true ;
}
tok1 = tok1 - > next ( ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " {|;|, delete %var% " ) )
2010-01-16 08:47:46 +01:00
{
const Token * var = tok - > tokAt ( 2 ) ;
// we should probably check that var is a pointer in this class
const Token * tok1 = tok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ( tok1 ! = last ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " %var% = new " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = var - > str ( ) )
2010-01-16 08:47:46 +01:00
return true ;
}
tok1 = tok1 - > next ( ) ;
}
}
}
return false ;
}
static bool hasAssignSelf ( const Token * first , const Token * last , const Token * rhs )
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = first ; tok & & tok ! = last ; tok = tok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( " ) )
2010-01-16 08:47:46 +01:00
{
const Token * tok1 = tok - > tokAt ( 2 ) ;
const Token * tok2 = tok - > tokAt ( 1 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok1 & & tok2 )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
for ( ; tok1 & & tok1 ! = tok2 ; tok1 = tok1 - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " this ==|!= & %var% " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( 3 ) - > str ( ) = = rhs - > str ( ) )
2010-01-16 08:47:46 +01:00
return true ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok1 , " & %var% ==|!= this " ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( 1 ) - > str ( ) = = rhs - > str ( ) )
2010-01-16 08:47:46 +01:00
return true ;
}
}
}
}
}
return false ;
}
static bool hasMultipleInheritanceInline ( const Token * tok )
{
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " { " )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " , " )
2010-01-16 08:47:46 +01:00
return true ;
tok = tok - > next ( ) ;
}
return false ;
}
static bool hasMultipleInheritanceGlobal ( const Token * start , const std : : string & name )
{
const Token * tok = start ;
std : : string pattern ;
std : : string className = name ;
// check for nested classes
2010-04-02 07:30:58 +02:00
while ( className . find ( " :: " ) ! = std : : string : : npos )
2010-01-16 08:47:46 +01:00
{
std : : string tempName ;
// there is probably a better way to do this
2010-04-02 07:30:58 +02:00
while ( className [ 0 ] ! = ' ' )
2010-01-16 08:47:46 +01:00
{
tempName + = className [ 0 ] ;
className . erase ( 0 , 1 ) ;
}
className . erase ( 0 , 4 ) ;
pattern = " class|struct " + tempName ;
tok = Token : : findmatch ( tok , pattern . c_str ( ) ) ;
}
pattern = " class|struct " + className ;
tok = Token : : findmatch ( tok , pattern . c_str ( ) ) ;
return hasMultipleInheritanceInline ( tok ) ;
}
void CheckClass : : operatorEqToSelf ( )
{
const Token * tok2 = _tokenizer - > tokens ( ) ;
const Token * tok ;
2010-04-06 20:35:21 +02:00
while ( ( tok = Token : : findmatch ( tok2 , " operator = ( " ) ) ! = NULL )
2010-01-16 08:47:46 +01:00
{
const Token * tok1 = tok ;
// make sure this is an assignment operator
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 2 ) & & Token : : Match ( tok1 - > tokAt ( - 2 ) , " %type% :: " ) )
2010-01-16 08:47:46 +01:00
{
int nameLength = 1 ;
tok1 = tok1 - > tokAt ( - 2 ) ;
// check backwards for proper function signature
2010-04-02 07:30:58 +02:00
while ( tok1 - > tokAt ( - 2 ) & & Token : : Match ( tok1 - > tokAt ( - 2 ) , " %type% :: " ) )
2010-01-16 08:47:46 +01:00
{
tok1 = tok1 - > tokAt ( - 2 ) ;
nameLength + = 2 ;
}
2010-04-06 21:53:05 +02:00
const Token * className = tok1 ;
2010-01-16 08:47:46 +01:00
std : : string nameString ;
2010-04-06 21:53:05 +02:00
nameStr ( className , nameLength , nameString ) ;
2010-01-16 08:47:46 +01:00
2010-04-02 07:30:58 +02:00
if ( ! hasMultipleInheritanceGlobal ( _tokenizer - > tokens ( ) , nameString ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 1 ) & & tok1 - > tokAt ( - 1 ) - > str ( ) = = " & " )
2010-01-16 08:47:46 +01:00
{
// check returned class name
2010-04-06 21:53:05 +02:00
if ( tok1 - > tokAt ( - ( 1 + nameLength ) ) & & nameMatch ( className , tok1 - > tokAt ( - ( 1 + nameLength ) ) , nameLength ) )
2010-01-16 08:47:46 +01:00
{
// check forward for proper function signature
2010-02-07 13:34:39 +01:00
std : : string pattern = " const " + nameString + " & %var% ) " ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 3 ) , pattern . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
const Token * rhs = tok - > tokAt ( 5 + nameLength ) ;
2010-04-06 21:53:05 +02:00
if ( nameMatch ( className , tok - > tokAt ( 4 ) , nameLength ) )
2010-01-16 08:47:46 +01:00
{
tok1 = tok - > tokAt ( 2 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok1 & & tok1 - > tokAt ( 1 ) & & tok1 - > tokAt ( 1 ) - > str ( ) = = " { " & & tok1 - > tokAt ( 1 ) - > link ( ) )
2010-01-16 08:47:46 +01:00
{
const Token * first = tok1 - > tokAt ( 1 ) ;
const Token * last = first - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! hasAssignSelf ( first , last , rhs ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( hasDeallocation ( first , last ) )
2010-01-16 08:47:46 +01:00
operatorEqToSelfError ( tok ) ;
}
}
}
}
}
}
}
}
else
{
tok1 = tok ;
// check backwards for proper function signature
2010-04-02 07:30:58 +02:00
if ( tok1 - > tokAt ( - 1 ) & & tok1 - > tokAt ( - 1 ) - > str ( ) = = " & " )
2010-01-16 08:47:46 +01:00
{
2010-04-06 21:53:05 +02:00
const Token * className = 0 ;
2010-04-02 07:30:58 +02:00
while ( tok1 & & ! Token : : Match ( tok1 , " class|struct %var% " ) )
2010-01-16 08:47:46 +01:00
tok1 = tok1 - > previous ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " struct|class %var% " ) )
2010-04-06 21:53:05 +02:00
className = tok1 - > tokAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
2010-04-02 07:30:58 +02:00
if ( ! hasMultipleInheritanceInline ( tok1 ) )
2010-01-16 08:47:46 +01:00
{
2010-04-06 21:53:05 +02:00
if ( Token : : simpleMatch ( tok - > tokAt ( - 2 ) , className - > str ( ) . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
{
// check forward for proper function signature
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 3 ) , " const %type% & %var% ) " ) )
2010-01-16 08:47:46 +01:00
{
const Token * rhs = tok - > tokAt ( 6 ) ;
2010-04-06 21:53:05 +02:00
if ( tok - > tokAt ( 4 ) - > str ( ) = = className - > str ( ) )
2010-01-16 08:47:46 +01:00
{
tok1 = tok - > tokAt ( 2 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok1 & & Token : : simpleMatch ( tok1 - > next ( ) , " { " ) )
2010-01-16 08:47:46 +01:00
{
2010-02-07 13:34:39 +01:00
const Token * first = tok1 - > next ( ) ;
2010-01-16 08:47:46 +01:00
const Token * last = first - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! hasAssignSelf ( first , last , rhs ) )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( hasDeallocation ( first , last ) )
2010-01-16 08:47:46 +01:00
operatorEqToSelfError ( tok ) ;
}
}
}
}
}
}
}
}
tok2 = tok - > next ( ) ;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// A destructor in a base class should be virtual
//---------------------------------------------------------------------------
void CheckClass : : virtualDestructor ( )
{
const char pattern_classdecl [ ] = " class %var% : %var% " ;
const Token * derived = _tokenizer - > tokens ( ) ;
2010-04-02 07:30:58 +02:00
while ( ( derived = Token : : findmatch ( derived , pattern_classdecl ) ) ! = NULL )
2010-01-16 08:47:46 +01:00
{
// Check that the derived class has a non empty destructor..
{
std : : ostringstream destructorPattern ;
destructorPattern < < " ~ " < < derived - > strAt ( 1 ) < < " ( ) { " ;
const Token * derived_destructor = Token : : findmatch ( _tokenizer - > tokens ( ) , destructorPattern . str ( ) . c_str ( ) ) ;
// No destructor..
2010-04-02 07:30:58 +02:00
if ( ! derived_destructor )
2010-01-16 08:47:46 +01:00
{
derived = derived - > next ( ) ;
continue ;
}
// Empty destructor..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( derived_destructor , " ~ %var% ( ) { } " ) )
2010-01-16 08:47:46 +01:00
{
derived = derived - > next ( ) ;
continue ;
}
}
const Token * derivedClass = derived - > tokAt ( 1 ) ;
// Iterate through each base class...
derived = derived - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( derived , " %var% " ) )
2010-01-16 08:47:46 +01:00
{
bool isPublic ( derived - > str ( ) = = " public " ) ;
// What kind of inheritance is it.. public|protected|private
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( derived , " public|protected|private " ) )
2010-01-16 08:47:46 +01:00
derived = derived - > next ( ) ;
// Name of base class..
2010-02-14 19:58:17 +01:00
const std : : string baseName = derived - > strAt ( 0 ) ;
2010-01-16 08:47:46 +01:00
// Update derived so it's ready for the next loop.
do
{
2010-04-02 07:30:58 +02:00
if ( derived - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( derived - > str ( ) = = " , " )
2010-01-16 08:47:46 +01:00
{
derived = derived - > next ( ) ;
break ;
}
derived = derived - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
while ( derived ) ;
2010-01-16 08:47:46 +01:00
// If not public inheritance, skip checking of this base class..
2010-04-02 07:30:58 +02:00
if ( ! isPublic )
2010-01-16 08:47:46 +01:00
continue ;
// Find the destructor declaration for the base class.
2010-02-14 19:58:17 +01:00
const Token * base = Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " %any% ~ " ) + baseName + " ( " ) . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
while ( base & & base - > str ( ) = = " :: " )
2010-02-14 19:58:17 +01:00
base = Token : : findmatch ( base - > next ( ) , ( std : : string ( " %any% ~ " ) + baseName + " ( " ) . c_str ( ) ) ;
2010-01-16 08:47:46 +01:00
const Token * reverseTok = base ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( base , " %var% " ) & & base - > str ( ) ! = " virtual " )
2010-01-16 08:47:46 +01:00
base = base - > previous ( ) ;
// Check that there is a destructor..
2010-04-02 07:30:58 +02:00
if ( ! base )
2010-01-16 08:47:46 +01:00
{
// Is the class declaration available?
2010-02-14 19:58:17 +01:00
base = Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " class " ) + baseName + " { " ) . c_str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( base )
2010-01-16 08:47:46 +01:00
{
2010-02-14 19:58:17 +01:00
virtualDestructorError ( base , baseName , derivedClass - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
continue ;
}
// There is a destructor. Check that it's virtual..
2010-04-02 07:30:58 +02:00
else if ( base - > str ( ) = = " virtual " )
2010-01-16 08:47:46 +01:00
continue ;
// 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"
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , ( std : : string ( " class " ) + baseName + " { " ) . c_str ( ) ) )
2010-01-16 08:47:46 +01:00
continue ;
// 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 ;
2010-04-02 07:30:58 +02:00
while ( reverseTok )
2010-01-16 08:47:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( reverseTok - > str ( ) = = " public: " )
2010-01-16 08:47:46 +01:00
{
2010-02-14 19:58:17 +01:00
virtualDestructorError ( base , baseName , derivedClass - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( reverseTok - > str ( ) = = " protected: " | |
reverseTok - > str ( ) = = " private: " )
2010-01-16 08:47:46 +01:00
{
// No bug, protected/private destructor is allowed
break ;
}
2010-04-02 07:30:58 +02:00
else if ( reverseTok - > str ( ) = = " { " )
2010-01-16 08:47:46 +01:00
{
indent + + ;
2010-04-02 07:30:58 +02:00
if ( indent > = 1 )
2010-01-16 08:47:46 +01:00
{
// 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 ;
}
}
2010-04-02 07:30:58 +02:00
else if ( reverseTok - > str ( ) = = " } " )
2010-01-16 08:47:46 +01:00
indent - - ;
reverseTok = reverseTok - > previous ( ) ;
}
}
}
}
//---------------------------------------------------------------------------
void CheckClass : : thisSubtractionError ( const Token * tok )
{
reportError ( tok , Severity : : possibleStyle , " thisSubtraction " , " Suspicious pointer subtraction " ) ;
}
void CheckClass : : thisSubtraction ( )
{
const Token * tok = _tokenizer - > tokens ( ) ;
2010-04-02 07:30:58 +02:00
for ( ; ; )
2010-01-16 08:47:46 +01:00
{
tok = Token : : findmatch ( tok , " this - %var% " ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-01-16 08:47:46 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok - > previous ( ) , " * " ) )
2010-01-16 08:47:46 +01:00
thisSubtractionError ( tok ) ;
tok = tok - > next ( ) ;
}
}
2010-03-05 17:06:25 +01:00
//---------------------------------------------------------------------------
2010-01-16 08:47:46 +01:00
2010-03-05 17:06:25 +01:00
struct NestInfo
{
std : : string className ;
const Token * classEnd ;
int levelEnd ;
} ;
2010-02-20 09:55:51 +01:00
// Can a function be const?
2010-01-23 09:19:22 +01:00
void CheckClass : : checkConst ( )
{
2010-04-02 07:30:58 +02:00
if ( ! _settings - > _checkCodingStyle )
2010-01-23 09:38:35 +01:00
return ;
2010-03-05 17:06:25 +01:00
std : : vector < NestInfo > nestInfo ;
int level = 0 ;
2010-03-12 18:30:20 +01:00
Var * varlist = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2010-01-23 09:19:22 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " & & ! nestInfo . empty ( ) )
2010-03-05 17:06:25 +01:00
level + + ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " & & ! nestInfo . empty ( ) )
2010-03-05 17:06:25 +01:00
{
level - - ;
2010-04-02 07:30:58 +02:00
if ( level = = nestInfo . back ( ) . levelEnd )
2010-03-05 17:06:25 +01:00
nestInfo . pop_back ( ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " class|struct %var% { " ) )
2010-01-23 09:19:22 +01:00
{
2010-03-12 18:30:20 +01:00
const Token * classTok = tok ;
2010-01-23 09:19:22 +01:00
// get class name..
2010-03-05 17:06:25 +01:00
std : : string classname ( tok - > strAt ( 1 ) ) ;
2010-01-23 09:19:22 +01:00
// goto initial {'
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " { " )
2010-01-23 09:19:22 +01:00
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-01-23 09:19:22 +01:00
break ;
2010-03-05 17:06:25 +01:00
const Token * classEnd = tok - > link ( ) ;
NestInfo info ;
info . className = classname ;
info . classEnd = classEnd ;
info . levelEnd = level + + ;
nestInfo . push_back ( info ) ;
2010-03-12 18:30:20 +01:00
// Delete the varlist..
2010-04-02 07:30:58 +02:00
while ( varlist )
2010-03-12 18:30:20 +01:00
{
Var * nextvar = varlist - > next ;
delete varlist ;
varlist = nextvar ;
}
// Get class variables...
varlist = getVarList ( classTok , true , classTok - > str ( ) = = " struct " ) ;
2010-01-23 09:19:22 +01:00
// parse in this class definition to see if there are any simple getter functions
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2010-01-23 09:19:22 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2010-01-23 09:19:22 +01:00
tok2 = tok2 - > link ( ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2010-01-23 09:19:22 +01:00
break ;
2010-01-24 13:45:56 +01:00
// start of statement?
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok2 - > previous ( ) , " [;{}] " ) )
2010-01-24 13:45:56 +01:00
continue ;
// skip private: public: etc
2010-04-02 07:30:58 +02:00
if ( tok2 - > isName ( ) & & tok2 - > str ( ) . find ( " : " ) ! = std : : string : : npos )
2010-03-19 17:40:23 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > next ( ) - > str ( ) = = " } " )
2010-03-19 17:40:23 +01:00
continue ;
tok2 = tok2 - > next ( ) ;
}
2010-01-24 13:45:56 +01:00
2010-01-24 18:26:39 +01:00
// static functions can't be const
// virtual functions may be non-const for a reason
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " static|virtual " ) )
2010-01-24 18:26:39 +01:00
continue ;
2010-02-21 10:19:28 +01:00
2010-04-09 19:15:39 +02:00
// don't warn for unknown types..
// LPVOID, HDC, etc
if ( tok2 - > isName ( ) )
{
bool allupper = true ;
const std : : string s ( tok2 - > str ( ) ) ;
for ( std : : string : : size_type pos = 0 ; pos < s . size ( ) ; + + pos )
{
unsigned char ch = s [ pos ] ;
2010-04-10 09:46:50 +02:00
if ( ! ( ch = = ' _ ' | | ( ch > = ' A ' & & ch < = ' Z ' ) ) )
2010-04-09 19:15:39 +02:00
{
allupper = false ;
break ;
}
}
if ( allupper )
continue ;
}
2010-01-24 18:26:39 +01:00
2010-01-23 09:19:22 +01:00
// member function?
2010-04-02 07:30:58 +02:00
if ( isMemberFunc ( tok2 ) )
2010-01-23 09:19:22 +01:00
{
2010-01-23 22:36:04 +01:00
// goto function name..
2010-04-02 07:30:58 +02:00
while ( tok2 - > next ( ) - > str ( ) ! = " ( " )
2010-01-23 22:36:04 +01:00
tok2 = tok2 - > next ( ) ;
2010-01-23 09:19:22 +01:00
// get function name
2010-01-23 22:36:04 +01:00
const std : : string functionName ( ( tok2 - > isName ( ) ? " " : " operator " ) + tok2 - > str ( ) ) ;
2010-03-05 17:06:25 +01:00
// skip constructor
2010-04-02 07:30:58 +02:00
if ( functionName = = classname )
2010-01-23 20:47:29 +01:00
continue ;
2010-01-23 09:19:22 +01:00
// goto the ')'
2010-01-23 22:36:04 +01:00
tok2 = tok2 - > next ( ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2010-01-23 09:19:22 +01:00
break ;
2010-01-23 22:36:04 +01:00
// is this a non-const function that is implemented inline?
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , " ) { " ) )
2010-01-23 09:19:22 +01:00
{
2010-03-05 17:06:25 +01:00
const Token * paramEnd = tok2 ;
// if nothing non-const was found. write error..
2010-04-02 07:30:58 +02:00
if ( checkConstFunc ( classname , varlist , paramEnd ) )
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
for ( int i = nestInfo . size ( ) - 2 ; i > = 0 ; i - - )
2010-03-05 17:06:25 +01:00
classname = std : : string ( nestInfo [ i ] . className + " :: " + classname ) ;
checkConstError ( tok2 , classname , functionName ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok2 , " ) ; " )) // not inline
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
for ( int i = nestInfo . size ( ) - 1 ; i > = 0 ; i - - )
2010-01-23 09:19:22 +01:00
{
2010-03-05 17:06:25 +01:00
const Token * found = nestInfo [ i ] . classEnd ;
std : : string pattern ( functionName + " ( " ) ;
2010-04-06 21:53:05 +02:00
int namespaceLevel = 0 ;
for ( int j = nestInfo . size ( ) - 1 ; j > = i ; j - - , namespaceLevel + + )
2010-03-05 17:06:25 +01:00
pattern = std : : string ( nestInfo [ j ] . className + " :: " + pattern ) ;
2010-04-06 20:35:21 +02:00
while ( ( found = Token : : findmatch ( found - > next ( ) , pattern . c_str ( ) ) ) ! = NULL )
2010-01-23 09:19:22 +01:00
{
2010-04-06 21:53:05 +02:00
const Token * paramEnd = found - > tokAt ( 1 + ( 2 * namespaceLevel ) ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! paramEnd )
2010-03-05 17:06:25 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( paramEnd - > next ( ) - > str ( ) ! = " { " )
2010-01-23 09:19:22 +01:00
break ;
2010-01-23 20:59:20 +01:00
2010-04-06 21:53:05 +02:00
if ( sameFunc ( namespaceLevel , tok2 , paramEnd ) )
2010-02-08 07:25:19 +01:00
{
2010-03-05 17:06:25 +01:00
// if nothing non-const was found. write error..
2010-04-02 07:30:58 +02:00
if ( checkConstFunc ( classname , varlist , paramEnd ) )
2010-02-08 07:25:19 +01:00
{
2010-04-02 07:30:58 +02:00
for ( int k = nestInfo . size ( ) - 2 ; k > = 0 ; k - - )
2010-03-05 17:06:25 +01:00
classname = std : : string ( nestInfo [ k ] . className + " :: " + classname ) ;
2010-03-10 07:47:01 +01:00
checkConstError2 ( found , tok2 , classname , functionName ) ;
2010-02-08 07:25:19 +01:00
}
}
2010-01-23 20:59:20 +01:00
}
2010-03-05 17:06:25 +01:00
}
}
}
}
}
}
2010-03-12 18:30:20 +01:00
// Delete the varlist..
2010-04-02 07:30:58 +02:00
while ( varlist )
2010-03-12 18:30:20 +01:00
{
Var * nextvar = varlist - > next ;
delete varlist ;
varlist = nextvar ;
}
2010-03-05 17:06:25 +01:00
}
2010-01-23 20:59:20 +01:00
2010-03-05 17:06:25 +01:00
bool CheckClass : : sameFunc ( int nest , const Token * firstEnd , const Token * secondEnd )
{
// check return type (search backwards until previous statement)
const Token * firstStart = firstEnd - > link ( ) - > tokAt ( - 2 ) ;
const Token * secondStart = secondEnd - > link ( ) - > tokAt ( ( - 2 * nest ) - 2 ) ;
2010-01-24 13:33:30 +01:00
2010-03-05 17:06:25 +01:00
bool firstDone = false ;
bool secondDone = false ;
2010-02-20 09:55:51 +01:00
2010-04-02 07:30:58 +02:00
while ( true )
2010-03-05 17:06:25 +01:00
{
firstDone = false ;
secondDone = false ;
2010-01-23 09:19:22 +01:00
2010-04-02 07:30:58 +02:00
if ( ! firstStart | | Token : : Match ( firstStart , " ;|}|{|public:|protected:|private: " ) )
2010-03-05 17:06:25 +01:00
firstDone = true ;
2010-04-02 07:30:58 +02:00
if ( ! secondStart | | Token : : Match ( secondStart , " ;|}|{|public:|protected:|private: " ) )
2010-03-05 17:06:25 +01:00
secondDone = true ;
2010-04-02 07:30:58 +02:00
if ( firstDone ! = secondDone )
2010-03-05 17:06:25 +01:00
return false ;
// both done and match
2010-04-02 07:30:58 +02:00
if ( firstDone )
2010-03-05 17:06:25 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( secondStart - > str ( ) ! = firstStart - > str ( ) )
2010-03-05 17:06:25 +01:00
return false ;
firstStart = firstStart - > previous ( ) ;
secondStart = secondStart - > previous ( ) ;
}
// check parameter types (names can be different or missing)
firstStart = firstEnd - > link ( ) - > next ( ) ;
secondStart = secondEnd - > link ( ) - > next ( ) ;
2010-04-02 07:30:58 +02:00
while ( true )
2010-03-05 17:06:25 +01:00
{
firstDone = false ;
secondDone = false ;
bool again = true ;
2010-04-02 07:30:58 +02:00
while ( again )
2010-03-05 17:06:25 +01:00
{
again = false ;
2010-04-02 07:30:58 +02:00
if ( firstStart = = firstEnd )
2010-03-05 17:06:25 +01:00
firstDone = true ;
2010-04-02 07:30:58 +02:00
if ( secondStart = = secondEnd )
2010-03-05 17:06:25 +01:00
secondDone = true ;
// possible difference in number of parameters
2010-04-02 07:30:58 +02:00
if ( firstDone ! = secondDone )
2010-03-05 17:06:25 +01:00
{
// check for missing names
2010-04-02 07:30:58 +02:00
if ( firstDone )
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( secondStart - > varId ( ) ! = 0 )
2010-03-05 17:06:25 +01:00
again = true ;
}
else
{
2010-04-02 07:30:58 +02:00
if ( firstStart - > varId ( ) ! = 0 )
2010-03-05 17:06:25 +01:00
again = true ;
2010-01-23 09:19:22 +01:00
}
2010-03-05 17:06:25 +01:00
2010-04-02 07:30:58 +02:00
if ( ! again )
2010-03-05 17:06:25 +01:00
return false ;
2010-01-23 09:19:22 +01:00
}
2010-03-05 17:06:25 +01:00
// both done and match
2010-04-02 07:30:58 +02:00
if ( firstDone & & ! again )
2010-03-05 17:06:25 +01:00
return true ;
2010-04-02 07:30:58 +02:00
if ( firstStart - > varId ( ) ! = 0 )
2010-03-05 17:06:25 +01:00
{
// skip variable name
firstStart = firstStart - > next ( ) ;
again = true ;
}
2010-04-02 07:30:58 +02:00
if ( secondStart - > varId ( ) ! = 0 )
2010-03-05 17:06:25 +01:00
{
// skip variable name
secondStart = secondStart - > next ( ) ;
again = true ;
}
}
2010-04-02 07:30:58 +02:00
if ( firstStart - > str ( ) ! = secondStart - > str ( ) )
2010-03-05 17:06:25 +01:00
return false ;
// retry after skipped variable names
2010-04-02 07:30:58 +02:00
if ( ! again )
2010-03-05 17:06:25 +01:00
{
firstStart = firstStart - > next ( ) ;
secondStart = secondStart - > next ( ) ;
2010-01-23 09:19:22 +01:00
}
}
2010-03-05 17:06:25 +01:00
return true ;
}
2010-03-28 11:46:42 +02:00
// A const member function can return either a copy of or
// a const reference or pointer to something.
// Is this a member function with these signatures:
// type var ( returns a copy of something
// const type var ( returns a const copy of something
// const type & var ( returns a const reference to something
// const type * var ( returns a const pointer to something
// type operator any ( returns a copy of something
// const type operator any ( returns a const copy of something
// const type & operator any ( returns a const reference to something
// const type * operator any ( returns a const pointer to something
// Type can be anything from a standard type to a complex template.
bool CheckClass : : isMemberFunc ( const Token * tok )
{
bool isConst = false ;
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " const " )
2010-03-28 11:46:42 +02:00
{
isConst = true ;
tok = tok - > next ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %type% " ) )
2010-03-28 11:46:42 +02:00
{
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
2010-03-28 11:46:42 +02:00
return true ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " operator %any% ( " ) )
2010-03-28 11:46:42 +02:00
return true ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok , " :: %type% " ) )
2010-03-28 11:46:42 +02:00
tok = tok - > tokAt ( 2 ) ;
// template with parameter(s)?
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " < %type% " ) )
2010-03-28 11:46:42 +02:00
{
unsigned int level = 1 ;
tok = tok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
while ( tok )
2010-03-28 11:46:42 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " < " )
2010-03-28 11:46:42 +02:00
level + + ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " > " )
2010-03-28 11:46:42 +02:00
{
level - - ;
2010-04-02 07:30:58 +02:00
if ( level = = 0 )
2010-03-28 11:46:42 +02:00
{
tok = tok - > next ( ) ;
break ;
}
}
tok = tok - > next ( ) ;
}
}
// template with default type
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " < > " ) )
2010-03-28 11:46:42 +02:00
tok = tok - > tokAt ( 2 ) ;
// operator something
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " operator %any% ( " ) )
2010-03-28 11:46:42 +02:00
return true ;
2010-04-02 07:30:58 +02:00
if ( isConst )
2010-03-28 11:46:42 +02:00
{
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok , " *|& " ) )
2010-03-28 11:46:42 +02:00
{
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " const " )
2010-03-28 11:46:42 +02:00
tok = tok - > next ( ) ;
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% ( " ) )
2010-03-28 11:46:42 +02:00
return true ;
}
return false ;
}
2010-04-01 16:59:35 +02:00
bool CheckClass : : isMemberVar ( const std : : string & classname , const Var * varlist , const Token * tok )
2010-03-12 18:30:20 +01:00
{
2010-04-02 07:30:58 +02:00
while ( tok - > previous ( ) & & ! Token : : Match ( tok - > previous ( ) , " }|{|;|public:|protected:|private:|return|:|? " ) )
2010-03-12 18:30:20 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > previous ( ) , " * this " ) )
2010-03-12 18:30:20 +01:00
return true ;
tok = tok - > previous ( ) ;
}
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " this " )
2010-03-12 18:30:20 +01:00
return true ;
2010-04-01 16:59:35 +02:00
// ignore class namespace
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = classname & & tok - > next ( ) - > str ( ) = = " :: " )
2010-04-01 16:59:35 +02:00
tok = tok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
for ( const Var * var = varlist ; var ; var = var - > next )
2010-03-12 18:30:20 +01:00
{
2010-04-02 07:30:58 +02:00
if ( var - > name = = tok - > str ( ) )
2010-03-26 19:06:00 +01:00
{
return ! var - > isMutable ;
}
2010-03-12 18:30:20 +01:00
}
return false ;
}
2010-04-01 16:59:35 +02:00
bool CheckClass : : checkConstFunc ( const std : : string & classname , const Var * varlist , const Token * tok )
2010-03-05 17:06:25 +01:00
{
// if the function doesn't have any assignment nor function call,
// it can be a const function..
unsigned int indentlevel = 0 ;
bool isconst = true ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok1 = tok ; tok1 ; tok1 = tok1 - > next ( ) )
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > str ( ) = = " { " )
2010-03-05 17:06:25 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok1 - > str ( ) = = " } " )
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 1 )
2010-03-05 17:06:25 +01:00
break ;
- - indentlevel ;
}
// assignment.. = += |= ..
2010-04-02 07:30:58 +02:00
else if ( tok1 - > str ( ) = = " = " | |
( tok1 - > str ( ) . find ( " = " ) = = 1 & &
tok1 - > str ( ) . find_first_of ( " <!> " ) = = std : : string : : npos ) )
2010-03-05 17:06:25 +01:00
{
2010-04-02 07:30:58 +02:00
if ( isMemberVar ( classname , varlist , tok1 - > previous ( ) ) )
2010-03-05 17:06:25 +01:00
{
2010-03-12 18:30:20 +01:00
isconst = false ;
break ;
2010-03-05 17:06:25 +01:00
}
}
2010-04-02 22:03:07 +02:00
// streaming: <<
else if ( tok1 - > str ( ) = = " << " & & isMemberVar ( classname , varlist , tok1 - > previous ( ) ) )
{
isconst = false ;
break ;
}
2010-03-05 17:06:25 +01:00
// increment/decrement (member variable?)..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok1 , " ++|-- " ) )
2010-03-05 17:06:25 +01:00
{
isconst = false ;
break ;
}
// function call..
2010-04-02 07:30:58 +02:00
else if ( tok1 - > str ( ) ! = " return " & & Token : : Match ( tok1 , " %var% ( " ) )
2010-03-05 17:06:25 +01:00
{
isconst = false ;
break ;
}
// delete..
2010-04-02 07:30:58 +02:00
else if ( tok1 - > str ( ) = = " delete " )
2010-03-05 17:06:25 +01:00
{
isconst = false ;
break ;
}
}
return isconst ;
2010-01-23 09:19:22 +01:00
}
void CheckClass : : checkConstError ( const Token * tok , const std : : string & classname , const std : : string & funcname )
{
reportError ( tok , Severity : : style , " functionConst " , " The function ' " + classname + " :: " + funcname + " ' can be const " ) ;
}
2010-03-10 07:47:01 +01:00
void CheckClass : : checkConstError2 ( const Token * tok1 , const Token * tok2 , const std : : string & classname , const std : : string & funcname )
{
std : : list < const Token * > toks ;
toks . push_back ( tok1 ) ;
toks . push_back ( tok2 ) ;
reportError ( toks , Severity : : style , " functionConst " , " The function ' " + classname + " :: " + funcname + " ' can be const " ) ;
}
2010-01-16 08:47:46 +01:00
void CheckClass : : noConstructorError ( const Token * tok , const std : : string & classname , bool isStruct )
{
reportError ( tok , Severity : : style , " noConstructor " , " The " + std : : string ( isStruct ? " struct " : " class " ) + " ' " + classname + " ' has no constructor. Member variables not initialized. " ) ;
}
void CheckClass : : uninitVarError ( const Token * tok , const std : : string & classname , const std : : string & varname , bool hasPrivateConstructor )
{
reportError ( tok , hasPrivateConstructor ? Severity : : possibleStyle : Severity : : style , " uninitVar " , " Member variable not initialized in the constructor ' " + classname + " :: " + varname + " ' " ) ;
}
void CheckClass : : operatorEqVarError ( const Token * tok , const std : : string & classname , const std : : string & varname )
{
reportError ( tok , Severity : : possibleStyle , " operatorEqVarError " , " Member variable ' " + classname + " :: " + varname + " ' is not assigned a value in ' " + classname + " ::operator= " + " ' " ) ;
}
void CheckClass : : unusedPrivateFunctionError ( const Token * tok , const std : : string & classname , const std : : string & funcname )
{
reportError ( tok , Severity : : style , " unusedPrivateFunction " , " Unused private function ' " + classname + " :: " + funcname + " ' " ) ;
}
void CheckClass : : memsetClassError ( const Token * tok , const std : : string & memfunc )
{
reportError ( tok , Severity : : error , " memsetClass " , " Using ' " + memfunc + " ' on class " ) ;
}
void CheckClass : : memsetStructError ( const Token * tok , const std : : string & memfunc , const std : : string & classname )
{
reportError ( tok , Severity : : error , " memsetStruct " , " Using ' " + memfunc + " ' on struct that contains a 'std:: " + classname + " ' " ) ;
}
void CheckClass : : operatorEqReturnError ( const Token * tok )
{
reportError ( tok , Severity : : style , " operatorEq " , " 'operator=' should return something " ) ;
}
void CheckClass : : virtualDestructorError ( const Token * tok , const std : : string & Base , const std : : string & Derived )
{
reportError ( tok , Severity : : error , " virtualDestructor " , " Class " + Base + " which is inherited by class " + Derived + " does not have a virtual destructor " ) ;
}
void CheckClass : : operatorEqRetRefThisError ( const Token * tok )
{
reportError ( tok , Severity : : style , " operatorEqRetRefThis " , " 'operator=' should return reference to self " ) ;
}
void CheckClass : : operatorEqToSelfError ( const Token * tok )
{
reportError ( tok , Severity : : possibleStyle , " operatorEqToSelf " , " 'operator=' should check for assignment to self " ) ;
}