2010-01-16 08:47:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2010-04-13 21:23:17 +02:00
* Copyright ( C ) 2007 - 2010 Daniel Marjamäki and Cppcheck team .
2010-01-16 08:47:46 +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
* 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 ;
}
2010-07-26 16:46:37 +02:00
//---------------------------------------------------------------------------
CheckClass : : CheckClass ( const Tokenizer * tokenizer , const Settings * settings , ErrorLogger * errorLogger )
2010-08-07 12:41:11 +02:00
: Check ( tokenizer , settings , errorLogger ) ,
hasSymbolDatabase ( false )
2010-07-26 16:46:37 +02:00
{
2010-08-07 12:41:11 +02:00
}
2010-09-02 07:40:20 +02:00
static bool isFunction ( const Token * tok , const Token * * funcStart , const Token * * argStart )
2010-08-30 17:14:20 +02:00
{
2010-09-02 07:40:20 +02:00
// function returning function pointer? '... ( ... %var% ( ... ))( ... ) {'
if ( tok - > str ( ) = = " ( " & &
tok - > link ( ) - > previous ( ) - > str ( ) = = " ) " & &
2010-11-02 18:28:55 +01:00
tok - > link ( ) - > next ( ) & &
2010-09-02 07:40:20 +02:00
tok - > link ( ) - > next ( ) - > str ( ) = = " ( " & &
2010-11-02 18:28:55 +01:00
tok - > link ( ) - > next ( ) - > link ( ) - > next ( ) & &
2010-09-02 07:40:20 +02:00
Token : : Match ( tok - > link ( ) - > next ( ) - > link ( ) - > next ( ) , " {|;|const|= " ) )
{
* funcStart = tok - > link ( ) - > previous ( ) - > link ( ) - > previous ( ) ;
* argStart = tok - > link ( ) - > previous ( ) - > link ( ) ;
return true ;
}
2010-08-30 17:14:20 +02:00
// regular function?
2010-09-02 07:40:20 +02:00
else if ( Token : : Match ( tok , " %var% ( " ) & & Token : : Match ( tok - > next ( ) - > link ( ) , " ) const| ; | { | = | : " ))
2010-08-30 17:14:20 +02:00
{
2010-09-02 07:40:20 +02:00
* funcStart = tok ;
2010-08-30 17:14:20 +02:00
* argStart = tok - > next ( ) ;
return true ;
}
// simple operator?
else if ( Token : : Match ( tok , " operator %any% ( " ) & & Token : : Match ( tok - > tokAt ( 2 ) - > link ( ) , " ) const| ; | { | = | : " ))
{
2010-09-02 07:40:20 +02:00
* funcStart = tok - > next ( ) ;
2010-08-30 17:14:20 +02:00
* argStart = tok - > tokAt ( 2 ) ;
return true ;
}
// complex operator?
else if ( tok - > str ( ) = = " operator " )
{
// operator[] or operator()?
2010-09-01 16:47:53 +02:00
if ( ( Token : : simpleMatch ( tok - > next ( ) , " ( ) ( " ) | | Token : : simpleMatch ( tok - > next ( ) , " [ ] ( " ) ) & &
2010-08-30 17:14:20 +02:00
Token : : Match ( tok - > tokAt ( 3 ) - > link ( ) , " ) const| ;|{|=|: " ) )
{
2010-09-02 07:40:20 +02:00
* funcStart = tok - > next ( ) ;
2010-08-30 17:14:20 +02:00
* argStart = tok - > tokAt ( 3 ) ;
return true ;
}
// operator new/delete []?
else if ( Token : : Match ( tok - > next ( ) , " new|delete [ ] ( " ) & & Token : : Match ( tok - > tokAt ( 4 ) - > link ( ) , " ) ; | { " ))
{
2010-09-02 07:40:20 +02:00
* funcStart = tok - > next ( ) ;
2010-08-30 17:14:20 +02:00
* argStart = tok - > tokAt ( 4 ) ;
return true ;
}
}
return false ;
}
2010-11-02 18:28:55 +01:00
void CheckClass : : addFunction ( SpaceInfo * * info , const Token * * tok )
{
const Token * tok1 = ( * tok ) - > tokAt ( - 2 ) ;
int count = 0 ;
bool added = false ;
std : : string path ;
unsigned int path_length = 0 ;
// back up to head of path
2010-11-04 06:58:37 +01:00
while ( tok1 - > previous ( ) & & tok1 - > previous ( ) - > str ( ) = = " :: " )
2010-11-02 18:28:55 +01:00
{
path = tok1 - > str ( ) + " :: " + path ;
tok1 = tok1 - > tokAt ( - 2 ) ;
count + + ;
path_length + + ;
}
if ( count )
{
path = tok1 - > str ( ) + " :: " + path ;
path_length + + ;
}
std : : list < SpaceInfo * > : : iterator it1 ;
// search for match
for ( it1 = spaceInfoList . begin ( ) ; it1 ! = spaceInfoList . end ( ) ; + + it1 )
{
SpaceInfo * info1 = * it1 ;
// is this class at global scope?
if ( * info )
{
if ( ! info1 - > nestedIn )
continue ;
}
else
{
if ( info1 - > nestedIn )
continue ;
}
bool match = false ;
if ( info1 - > className = = tok1 - > str ( ) & &
( ( * info ) ? ( info1 - > nestedIn - > className = = ( * info ) - > className ) : true ) )
{
SpaceInfo * info2 = info1 ;
while ( info2 & & count > 0 )
{
count - - ;
tok1 = tok1 - > tokAt ( 2 ) ;
info2 = info2 - > findInNestedList ( tok1 - > str ( ) ) ;
}
if ( count = = 0 & & info2 )
{
match = true ;
info1 = info2 ;
}
}
if ( match )
{
std : : list < Func > : : iterator func ;
for ( func = info1 - > functionList . begin ( ) ; func ! = info1 - > functionList . end ( ) ; + + func )
{
if ( ! func - > hasBody )
{
if ( func - > isOperator & &
( * tok ) - > str ( ) = = " operator " & &
func - > tokenDef - > str ( ) = = ( * tok ) - > strAt ( 1 ) )
{
if ( argsMatch ( func - > tokenDef - > tokAt ( 2 ) , ( * tok ) - > tokAt ( 3 ) , path , path_length ) )
{
func - > hasBody = true ;
func - > token = ( * tok ) - > next ( ) ;
}
}
else if ( func - > tokenDef - > str ( ) = = ( * tok ) - > str ( ) )
{
if ( argsMatch ( func - > tokenDef - > next ( ) , ( * tok ) - > next ( ) , path , path_length ) )
{
2010-11-06 20:27:12 +01:00
// normal function?
if ( ! func - > retFuncPtr & & ( * tok ) - > next ( ) - > link ( ) )
{
if ( ( func - > isConst & & ( * tok ) - > next ( ) - > link ( ) - > next ( ) - > str ( ) = = " const " ) | |
( ! func - > isConst & & ( * tok ) - > next ( ) - > link ( ) - > next ( ) - > str ( ) ! = " const " ) )
{
func - > hasBody = true ;
func - > token = ( * tok ) ;
}
}
// function returning function pointer?
else if ( func - > retFuncPtr )
{
// todo check for const
func - > hasBody = true ;
func - > token = ( * tok ) ;
}
2010-11-02 18:28:55 +01:00
}
}
if ( func - > hasBody )
{
addNewFunction ( info , tok ) ;
added = true ;
break ;
}
}
}
}
}
// check for class function for unknown class
if ( ! added )
addNewFunction ( info , tok ) ;
}
void CheckClass : : addNewFunction ( SpaceInfo * * info , const Token * * tok )
{
const Token * tok1 = * tok ;
SpaceInfo * new_info = new SpaceInfo ( this , tok1 , * info ) ;
// skip to start of function
while ( tok1 - > str ( ) ! = " { " )
tok1 = tok1 - > next ( ) ;
new_info - > classStart = tok1 ;
new_info - > classEnd = tok1 - > link ( ) ;
* info = new_info ;
// add space
spaceInfoList . push_back ( new_info ) ;
* tok = tok1 ;
}
2010-11-04 06:58:37 +01:00
void CheckClass : : addIfFunction ( SpaceInfo * * info , const Token * * tok )
{
const Token * funcStart = 0 ;
const Token * argStart = 0 ;
// function?
if ( isFunction ( * tok , & funcStart , & argStart ) )
{
// has body?
if ( Token : : Match ( argStart - > link ( ) , " ) const| {|: " ) )
{
// class function
if ( ( * tok ) - > previous ( ) & & ( * tok ) - > previous ( ) - > str ( ) = = " :: " )
addFunction ( info , tok ) ;
// regular function
else
addNewFunction ( info , tok ) ;
}
2010-11-06 13:31:56 +01:00
// function returning function pointer with body
else if ( Token : : simpleMatch ( argStart - > link ( ) , " ) ) ( " ) & &
Token : : Match ( argStart - > link ( ) - > tokAt ( 2 ) - > link ( ) , " ) const| { " ) )
{
const Token * tok1 = funcStart ;
// class function
if ( tok1 - > previous ( ) - > str ( ) = = " :: " )
addFunction ( info , & tok1 ) ;
// regular function
else
addNewFunction ( info , & tok1 ) ;
* tok = tok1 ;
}
2010-11-04 06:58:37 +01:00
}
}
2010-08-07 12:41:11 +02:00
void CheckClass : : createSymbolDatabase ( )
{
// Multiple calls => bail out
if ( hasSymbolDatabase )
return ;
hasSymbolDatabase = true ;
2010-07-26 16:46:37 +02:00
// find all namespaces (class,struct and namespace)
SpaceInfo * info = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Locate next class
if ( Token : : Match ( tok , " class|struct|namespace %var% [{:] " ) )
{
2010-08-28 11:23:23 +02:00
SpaceInfo * new_info = new SpaceInfo ( this , tok , info ) ;
2010-08-16 18:55:39 +02:00
const Token * tok2 = tok - > tokAt ( 2 ) ;
2010-11-02 18:28:55 +01:00
// only create variable list and base list for classes and structures
if ( new_info - > type = = SpaceInfo : : Class | | new_info - > type = = SpaceInfo : : Struct )
2010-08-16 18:55:39 +02:00
{
2010-08-28 11:23:23 +02:00
new_info - > getVarList ( ) ;
2010-08-16 18:55:39 +02:00
// goto initial '{'
tok2 = initBaseInfo ( new_info , tok ) ;
}
2010-07-26 16:46:37 +02:00
new_info - > classStart = tok2 ;
2010-11-02 18:28:55 +01:00
new_info - > classEnd = tok2 - > link ( ) ;
2010-07-26 16:46:37 +02:00
info = new_info ;
// add namespace
2010-11-02 18:28:55 +01:00
spaceInfoList . push_back ( info ) ;
2010-07-26 16:46:37 +02:00
tok = tok2 ;
}
2010-08-14 08:16:53 +02:00
// check if in space
else if ( info )
2010-07-26 16:46:37 +02:00
{
2010-08-14 08:16:53 +02:00
// check for end of space
2010-07-26 16:46:37 +02:00
if ( tok = = info - > classEnd )
{
2010-08-28 11:23:23 +02:00
info = info - > nestedIn ;
2010-11-02 18:28:55 +01:00
continue ;
2010-07-26 16:46:37 +02:00
}
2010-08-14 08:16:53 +02:00
// check if in class or structure
2010-11-02 18:28:55 +01:00
else if ( info - > type = = SpaceInfo : : Class | | info - > type = = SpaceInfo : : Struct )
2010-07-26 16:46:37 +02:00
{
2010-09-02 07:40:20 +02:00
const Token * funcStart = 0 ;
2010-08-30 17:14:20 +02:00
const Token * argStart = 0 ;
2010-07-26 16:46:37 +02:00
// What section are we in..
if ( tok - > str ( ) = = " private: " )
info - > access = Private ;
else if ( tok - > str ( ) = = " protected: " )
info - > access = Protected ;
else if ( tok - > str ( ) = = " public: " )
info - > access = Public ;
2010-08-18 22:42:04 +02:00
else if ( Token : : Match ( tok , " public|protected|private %var% : " ) )
{
if ( tok - > str ( ) = = " private " )
info - > access = Private ;
else if ( tok - > str ( ) = = " protected " )
info - > access = Protected ;
else if ( tok - > str ( ) = = " public " )
info - > access = Public ;
tok = tok - > tokAt ( 2 ) ;
}
2010-07-26 16:46:37 +02:00
2010-11-02 18:28:55 +01:00
// class function?
else if ( tok - > previous ( ) - > str ( ) ! = " :: " & & isFunction ( tok , & funcStart , & argStart ) )
2010-07-26 16:46:37 +02:00
{
Func function ;
2010-08-30 17:14:20 +02:00
// save the function definition argument start '('
function . argDef = argStart ;
2010-07-26 16:46:37 +02:00
// save the access type
function . access = info - > access ;
// save the function name location
2010-09-02 07:40:20 +02:00
function . tokenDef = funcStart ;
2010-07-26 16:46:37 +02:00
// operator function
2010-09-02 07:40:20 +02:00
if ( function . tokenDef - > previous ( ) - > str ( ) = = " operator " )
2010-07-26 16:46:37 +02:00
{
function . isOperator = true ;
// 'operator =' is special
if ( function . tokenDef - > str ( ) = = " = " )
function . type = Func : : OperatorEqual ;
}
// class constructor/destructor
else if ( function . tokenDef - > str ( ) = = info - > className )
{
if ( function . tokenDef - > previous ( ) - > str ( ) = = " ~ " )
function . type = Func : : Destructor ;
2010-08-09 17:50:26 +02:00
else if ( ( Token : : Match ( function . tokenDef , " %var% ( const %var% & ) " ) | |
Token : : Match ( function . tokenDef , " %var% ( const %var% & %var% ) " ) ) & &
2010-07-26 16:46:37 +02:00
function . tokenDef - > strAt ( 3 ) = = info - > className )
function . type = Func : : CopyConstructor ;
else
function . type = Func : : Constructor ;
2010-08-09 17:50:26 +02:00
if ( function . tokenDef - > previous ( ) - > str ( ) = = " explicit " )
function . isExplicit = true ;
2010-07-26 16:46:37 +02:00
}
2010-09-02 07:40:20 +02:00
// function returning function pointer
else if ( tok - > str ( ) = = " ( " )
{
function . retFuncPtr = true ;
}
2010-07-26 16:46:37 +02:00
const Token * tok1 = tok ;
// look for end of previous statement
while ( tok1 - > previous ( ) & & ! Token : : Match ( tok1 - > previous ( ) , " ;|}|{|public:|protected:|private: " ) )
{
// virtual function
if ( tok1 - > previous ( ) - > str ( ) = = " virtual " )
{
function . isVirtual = true ;
break ;
}
// static function
else if ( tok1 - > previous ( ) - > str ( ) = = " static " )
{
function . isStatic = true ;
break ;
}
2010-08-07 16:08:44 +02:00
// friend function
else if ( tok1 - > previous ( ) - > str ( ) = = " friend " )
{
function . isFriend = true ;
break ;
}
2010-07-26 16:46:37 +02:00
tok1 = tok1 - > previous ( ) ;
}
2010-09-02 07:40:20 +02:00
const Token * end ;
if ( ! function . retFuncPtr )
end = function . argDef - > link ( ) ;
else
end = tok - > link ( ) - > next ( ) - > link ( ) ;
2010-07-26 16:46:37 +02:00
// const function
2010-09-02 07:40:20 +02:00
if ( end - > next ( ) - > str ( ) = = " const " )
2010-07-26 16:46:37 +02:00
function . isConst = true ;
2010-08-09 17:50:26 +02:00
// pure virtual function
2010-09-02 07:40:20 +02:00
if ( Token : : Match ( end , " ) const| = 0 ; " ) )
2010-08-09 17:50:26 +02:00
function . isPure = true ;
2010-07-26 16:46:37 +02:00
// count the number of constructors
if ( function . type = = Func : : Constructor | | function . type = = Func : : CopyConstructor )
info - > numConstructors + + ;
// assume implementation is inline (definition and implementation same)
function . token = function . tokenDef ;
// out of line function
2010-09-02 07:40:20 +02:00
if ( Token : : Match ( end , " ) const| ; " ) | |
Token : : Match ( end , " ) const| = 0 ; " ) )
2010-07-26 16:46:37 +02:00
{
2010-09-01 16:47:53 +02:00
// find the function implementation later
2010-09-02 07:40:20 +02:00
tok = end - > next ( ) ;
2010-07-26 16:46:37 +02:00
}
// inline function
else
{
function . isInline = true ;
function . hasBody = true ;
2010-08-30 17:14:20 +02:00
function . arg = function . argDef ;
2010-07-26 16:46:37 +02:00
// skip over function body
2010-09-02 07:40:20 +02:00
tok = end - > next ( ) ;
2010-08-31 17:51:10 +02:00
while ( tok & & tok - > str ( ) ! = " { " )
2010-07-26 16:46:37 +02:00
tok = tok - > next ( ) ;
2010-08-31 17:51:10 +02:00
if ( ! tok )
return ;
2010-07-26 16:46:37 +02:00
tok = tok - > link ( ) ;
}
2010-09-01 16:47:53 +02:00
info - > functionList . push_back ( function ) ;
2010-07-26 16:46:37 +02:00
}
2010-08-11 22:36:04 +02:00
2010-11-02 18:28:55 +01:00
// nested class function?
else if ( tok - > previous ( ) - > str ( ) = = " :: " & & isFunction ( tok , & funcStart , & argStart ) )
addFunction ( & info , & tok ) ;
2010-08-11 22:36:04 +02:00
// friend class declaration?
else if ( Token : : Match ( tok , " friend class| %any% ; " ) )
{
FriendInfo friendInfo ;
friendInfo . name = tok - > strAt ( 1 ) = = " class " ? tok - > strAt ( 2 ) : tok - > strAt ( 1 ) ;
/** @todo fill this in later after parsing is complete */
friendInfo . spaceInfo = 0 ;
info - > friendList . push_back ( friendInfo ) ;
}
2010-07-26 16:46:37 +02:00
}
2010-11-02 18:28:55 +01:00
else if ( info - > type = = SpaceInfo : : Namespace )
2010-11-04 06:58:37 +01:00
addIfFunction ( & info , & tok ) ;
2010-11-02 18:28:55 +01:00
}
// not in SpaceInfo
else
2010-11-04 06:58:37 +01:00
addIfFunction ( & info , & tok ) ;
2010-07-26 16:46:37 +02:00
}
2010-08-13 07:35:30 +02:00
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator it ;
2010-08-13 07:35:30 +02:00
2010-11-02 18:28:55 +01:00
for ( it = spaceInfoList . begin ( ) ; it ! = spaceInfoList . end ( ) ; + + it )
2010-08-13 07:35:30 +02:00
{
2010-11-02 18:28:55 +01:00
info = * it ;
2010-08-13 07:35:30 +02:00
// skip namespaces
2010-11-02 18:28:55 +01:00
if ( info - > type = = SpaceInfo : : Namespace | | info - > type = = SpaceInfo : : Function )
2010-08-13 07:35:30 +02:00
continue ;
2010-09-01 16:47:53 +02:00
// finish filling in base class info
2010-08-13 07:35:30 +02:00
for ( unsigned int i = 0 ; i < info - > derivedFrom . size ( ) ; + + i )
{
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator it1 ;
2010-08-13 07:35:30 +02:00
2010-11-02 18:28:55 +01:00
for ( it1 = spaceInfoList . begin ( ) ; it1 ! = spaceInfoList . end ( ) ; + + it1 )
2010-08-13 07:35:30 +02:00
{
2010-11-02 18:28:55 +01:00
SpaceInfo * spaceInfo = * it1 ;
2010-08-13 07:35:30 +02:00
/** @todo handle derived base classes and namespaces */
2010-11-02 18:28:55 +01:00
if ( spaceInfo - > type = = SpaceInfo : : Class | | spaceInfo - > type = = SpaceInfo : : Struct )
2010-08-13 07:35:30 +02:00
{
2010-08-31 17:57:42 +02:00
// do class names match?
2010-08-13 07:35:30 +02:00
if ( spaceInfo - > className = = info - > derivedFrom [ i ] . name )
{
2010-08-31 17:57:42 +02:00
// are they in the same namespace or different namespaces with same name?
if ( ( spaceInfo - > nestedIn = = info - > nestedIn ) | |
2010-11-02 18:28:55 +01:00
( ( spaceInfo - > nestedIn & & spaceInfo - > nestedIn - > type = = SpaceInfo : : Namespace ) & &
( info - > nestedIn & & info - > nestedIn - > type = = SpaceInfo : : Namespace ) & &
2010-08-31 17:57:42 +02:00
( spaceInfo - > nestedIn - > className = = info - > nestedIn - > className ) ) )
2010-08-13 07:35:30 +02:00
{
info - > derivedFrom [ i ] . spaceInfo = spaceInfo ;
break ;
}
}
}
}
}
}
2010-07-26 16:46:37 +02:00
}
CheckClass : : ~ CheckClass ( )
{
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator it ;
2010-07-26 16:46:37 +02:00
2010-11-02 18:28:55 +01:00
for ( it = spaceInfoList . begin ( ) ; it ! = spaceInfoList . end ( ) ; + + it )
delete * it ;
2010-07-26 16:46:37 +02:00
}
2010-01-16 08:47:46 +01:00
2010-08-10 18:01:33 +02:00
const Token * CheckClass : : initBaseInfo ( SpaceInfo * info , const Token * tok )
2010-08-09 17:50:26 +02:00
{
// goto initial '{'
const Token * tok2 = tok - > tokAt ( 2 ) ;
2010-08-16 18:55:39 +02:00
int level = 0 ;
2010-08-09 17:50:26 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " { " )
{
2010-08-16 18:55:39 +02:00
// skip unsupported templates
if ( tok2 - > str ( ) = = " < " )
level + + ;
else if ( tok2 - > str ( ) = = " > " )
level - - ;
2010-08-09 17:50:26 +02:00
// check for base classes
2010-08-16 18:55:39 +02:00
else if ( level = = 0 & & Token : : Match ( tok2 , " :|, " ) )
2010-08-09 17:50:26 +02:00
{
BaseInfo base ;
tok2 = tok2 - > next ( ) ;
if ( tok2 - > str ( ) = = " public " )
{
base . access = Public ;
tok2 = tok2 - > next ( ) ;
}
else if ( tok2 - > str ( ) = = " protected " )
{
base . access = Protected ;
tok2 = tok2 - > next ( ) ;
}
else if ( tok2 - > str ( ) = = " private " )
{
base . access = Private ;
tok2 = tok2 - > next ( ) ;
}
else
{
if ( tok - > str ( ) = = " class " )
base . access = Private ;
else if ( tok - > str ( ) = = " struct " )
base . access = Public ;
}
// handle derived base classes
while ( Token : : Match ( tok2 , " %var% :: " ) )
{
base . name + = tok2 - > str ( ) ;
base . name + = " :: " ;
tok2 = tok2 - > tokAt ( 2 ) ;
}
base . name + = tok2 - > str ( ) ;
2010-08-10 18:01:33 +02:00
base . spaceInfo = 0 ;
2010-08-09 17:50:26 +02:00
// save pattern for base class name
2010-08-10 18:01:33 +02:00
info - > derivedFrom . push_back ( base ) ;
2010-08-09 17:50:26 +02:00
}
tok2 = tok2 - > next ( ) ;
}
return tok2 ;
}
2010-08-28 11:23:23 +02:00
//---------------------------------------------------------------------------
2010-08-09 17:50:26 +02:00
2010-08-28 11:23:23 +02:00
CheckClass : : SpaceInfo : : SpaceInfo ( CheckClass * check_ , const Token * classDef_ , CheckClass : : SpaceInfo * nestedIn_ ) :
check ( check_ ) ,
classDef ( classDef_ ) ,
2010-09-01 16:47:53 +02:00
classStart ( NULL ) ,
classEnd ( NULL ) ,
2010-08-28 11:23:23 +02:00
nestedIn ( nestedIn_ ) ,
numConstructors ( 0 )
{
2010-11-02 18:28:55 +01:00
if ( classDef - > str ( ) = = " class " )
{
type = SpaceInfo : : Class ;
className = classDef - > next ( ) - > str ( ) ;
access = Private ;
}
else if ( classDef - > str ( ) = = " struct " )
{
type = SpaceInfo : : Struct ;
className = classDef - > next ( ) - > str ( ) ;
access = Public ;
}
else if ( classDef - > str ( ) = = " union " )
{
type = SpaceInfo : : Union ;
className = classDef - > next ( ) - > str ( ) ;
access = Public ;
}
else if ( classDef - > str ( ) = = " namespace " )
{
type = SpaceInfo : : Namespace ;
className = classDef - > next ( ) - > str ( ) ;
access = Public ;
}
else
{
type = SpaceInfo : : Function ;
className = classDef - > str ( ) ;
access = Public ;
}
2010-08-28 11:23:23 +02:00
if ( nestedIn )
nestedIn - > nestedList . push_back ( this ) ;
}
void CheckClass : : SpaceInfo : : getVarList ( )
2010-01-16 08:47:46 +01:00
{
// Get variable list..
2010-08-11 22:36:04 +02:00
const Token * tok1 = classDef ;
2010-01-16 08:47:46 +01:00
unsigned int indentlevel = 0 ;
2010-08-18 22:42:04 +02:00
AccessControl varaccess = tok1 - > str ( ) = = " struct " ? Public : Private ;
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
{
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-08-18 22:42:04 +02:00
bool b = false ;
if ( tok - > str ( ) = = " public: " )
{
varaccess = Public ;
b = true ;
}
else if ( tok - > str ( ) = = " protected: " )
{
varaccess = Protected ;
b = true ;
}
else if ( tok - > str ( ) = = " private: " )
{
varaccess = Private ;
b = true ;
}
else if ( Token : : Match ( tok , " public|protected|private %var% : " ) )
{
if ( tok - > str ( ) = = " public " )
varaccess = Public ;
else if ( tok - > str ( ) = = " protected " )
varaccess = Protected ;
else if ( tok - > str ( ) = = " private " )
varaccess = Private ;
tok = tok - > tokAt ( 2 ) ;
b = true ;
}
2010-01-16 08:47:46 +01:00
// 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-08-13 07:34:34 +02:00
const Token * vartok = 0 ;
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-08-18 22:42:04 +02:00
if ( Token : : Match ( next , " public|protected|private %var% : " ) )
{
if ( next - > str ( ) = = " public " )
varaccess = Public ;
else if ( next - > str ( ) = = " protected " )
varaccess = Protected ;
else if ( next - > str ( ) = = " private " )
varaccess = Private ;
tok = tok - > tokAt ( 2 ) ;
continue ;
}
// Is it a forward declaration?
if ( Token : : Match ( next , " class|struct|union %var% ; " ) )
{
tok = tok - > tokAt ( 2 ) ;
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-06-29 12:51:18 +02:00
// Is it const..?
if ( next - > str ( ) = = " const " )
{
next = next - > next ( ) ;
}
2010-04-02 08:02:47 +02:00
// Is it a static variable?
2010-06-29 12:51:18 +02:00
const bool isStatic ( Token : : simpleMatch ( next , " static " ) ) ;
if ( isStatic )
2010-04-02 08:02:47 +02:00
{
next = next - > next ( ) ;
}
2010-03-26 19:06:00 +01:00
// Is it a mutable variable?
2010-06-29 12:51:18 +02:00
const bool isMutable ( Token : : simpleMatch ( next , " mutable " ) ) ;
if ( isMutable )
2010-03-26 19:06:00 +01:00
{
next = next - > next ( ) ;
}
2010-05-16 20:26:32 +02:00
// Is it const..?
if ( next - > str ( ) = = " const " )
{
next = next - > next ( ) ;
}
2010-08-13 07:34:34 +02:00
// It it a nested derived class or structure?
if ( Token : : Match ( next , " class|struct %type% : " ) )
{
next = next - > tokAt ( 2 ) ;
while ( next - > str ( ) ! = " { " )
next = next - > next ( ) ;
continue ;
}
2010-01-16 08:47:46 +01:00
// Is it a variable declaration?
2010-07-17 12:25:14 +02:00
bool isClass = false ;
2010-04-18 15:40:31 +02:00
if ( Token : : Match ( next , " %type% %var% ;|: " ) )
2010-01-16 08:47:46 +01:00
{
2010-07-17 12:25:14 +02:00
if ( ! next - > isStandardType ( ) )
isClass = true ;
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
}
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
{
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 2 ) ;
2010-03-26 18:16:33 +01:00
}
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-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% %type% * %var% ; " ) )
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 3 ) ;
2010-05-20 06:52:59 +02:00
else if ( Token : : Match ( next , " %type% :: %type% * %var% ; " ) )
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 4 ) ;
2010-08-31 17:59:17 +02:00
else if ( Token : : Match ( next , " %type% :: %type% :: %type% * %var% ; " ) )
vartok = next - > tokAt ( 6 ) ;
2010-01-16 08:47:46 +01:00
// 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-07-17 12:25:14 +02:00
if ( ! next - > isStandardType ( ) )
isClass = true ;
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 1 ) ;
2010-01-16 08:47:46 +01:00
}
// Pointer array?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( next , " %type% * %var% [ " ) )
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 2 ) ;
2010-05-20 06:52:59 +02:00
else if ( Token : : Match ( next , " %type% :: %type% * %var% [ " ) )
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 4 ) ;
2010-08-31 17:59:17 +02:00
else if ( Token : : Match ( next , " %type% :: %type% :: %type% * %var% [ " ) )
vartok = next - > tokAt ( 6 ) ;
2010-01-16 08:47:46 +01:00
// std::string..
2010-07-17 12:25:14 +02:00
else if ( Token : : Match ( next , " %type% :: %type% %var% ; " ) )
2010-01-16 08:47:46 +01:00
{
2010-07-17 12:25:14 +02:00
isClass = true ;
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 3 ) ;
2010-01-16 08:47:46 +01:00
}
2010-08-31 17:59:17 +02:00
else if ( Token : : Match ( next , " %type% :: %type% :: %type% %var% ; " ) )
{
isClass = true ;
vartok = next - > tokAt ( 5 ) ;
}
2010-01-16 08:47:46 +01:00
// Container..
2010-07-17 12:25:14 +02:00
else if ( Token : : Match ( next , " %type% :: %type% < " ) | |
Token : : Match ( next , " %type% < " ) )
2010-01-16 08:47:46 +01:00
{
2010-05-20 17:45:10 +02:00
// find matching ">"
int level = 0 ;
for ( ; next ; next = next - > next ( ) )
{
if ( next - > str ( ) = = " < " )
level + + ;
else if ( next - > str ( ) = = " > " )
{
level - - ;
if ( level = = 0 )
break ;
}
}
if ( next & & Token : : Match ( next , " > %var% ; " ) )
2010-10-27 19:28:15 +02:00
{
isClass = true ;
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 1 ) ;
2010-10-27 19:28:15 +02:00
}
2010-05-25 06:55:49 +02:00
else if ( next & & Token : : Match ( next , " > * %var% ; " ) )
2010-08-13 07:34:34 +02:00
vartok = next - > tokAt ( 2 ) ;
2010-01-16 08:47:46 +01:00
}
2010-08-13 07:34:34 +02:00
// If the vartok was set in the if-blocks above, create a entry for this variable..
2010-10-28 18:01:51 +02:00
if ( vartok & & vartok - > str ( ) ! = " operator " )
2010-08-13 07:34:34 +02:00
{
2010-08-28 11:23:23 +02:00
if ( vartok - > varId ( ) = = 0 & & check - > _settings - > debugwarnings )
2010-08-13 07:34:34 +02:00
{
2010-08-27 20:28:00 +02:00
check - > reportError ( vartok , Severity : : debug , " debug " , " CheckClass::SpaceInfo::getVarList found variable \' " + vartok - > str ( ) + " \' with varid 0. " ) ;
2010-08-13 07:34:34 +02:00
}
2010-09-09 07:26:40 +02:00
addVar ( vartok , varaccess , isMutable , isStatic , isClass ) ;
2010-08-13 07:34:34 +02:00
}
2010-01-16 08:47:46 +01:00
}
}
2010-08-11 22:36:04 +02:00
2010-01-16 08:47:46 +01:00
//---------------------------------------------------------------------------
2010-09-09 07:26:40 +02:00
void CheckClass : : SpaceInfo : : assignVar ( const std : : string & varname )
{
std : : list < Var > : : iterator i ;
for ( i = varlist . begin ( ) ; i ! = varlist . end ( ) ; + + i )
{
if ( i - > token - > str ( ) = = varname )
{
i - > assign = true ;
return ;
}
}
}
2010-08-11 22:36:04 +02:00
void CheckClass : : SpaceInfo : : initVar ( const std : : string & varname )
2010-01-16 08:47:46 +01:00
{
2010-08-11 22:36:04 +02:00
std : : list < Var > : : iterator i ;
for ( i = varlist . begin ( ) ; i ! = varlist . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-08-13 07:34:34 +02:00
if ( i - > token - > str ( ) = = varname )
2010-01-16 08:47:46 +01:00
{
2010-08-11 22:36:04 +02:00
i - > init = true ;
2010-01-22 19:29:24 +01:00
return ;
2010-01-16 08:47:46 +01:00
}
}
}
2010-08-11 22:36:04 +02:00
2010-09-09 07:26:40 +02:00
void CheckClass : : SpaceInfo : : assignAllVar ( )
{
std : : list < Var > : : iterator i ;
for ( i = varlist . begin ( ) ; i ! = varlist . end ( ) ; + + i )
i - > assign = true ;
}
void CheckClass : : SpaceInfo : : clearAllVar ( )
2010-08-11 22:36:04 +02:00
{
std : : list < Var > : : iterator i ;
for ( i = varlist . begin ( ) ; i ! = varlist . end ( ) ; + + i )
2010-09-09 07:26:40 +02:00
{
i - > assign = false ;
i - > init = false ;
}
2010-08-11 22:36:04 +02:00
}
2010-01-16 08:47:46 +01:00
//---------------------------------------------------------------------------
2010-09-12 22:40:51 +02:00
bool CheckClass : : SpaceInfo : : isBaseClassFunc ( const Token * tok )
{
// Iterate through each base class...
for ( unsigned int i = 0 ; i < derivedFrom . size ( ) ; + + i )
{
const SpaceInfo * info = derivedFrom [ i ] . spaceInfo ;
// Check if base class exists in database
if ( info )
{
std : : list < Func > : : const_iterator it ;
for ( it = info - > functionList . begin ( ) ; it ! = info - > functionList . end ( ) ; + + it )
{
if ( it - > tokenDef - > str ( ) = = tok - > str ( ) )
return true ;
}
}
// Base class not found so assume it is in it.
else
return true ;
}
return false ;
}
2010-08-11 22:36:04 +02:00
void CheckClass : : SpaceInfo : : initializeVarList ( const Func & func , std : : list < std : : string > & callstack )
2010-01-16 08:47:46 +01:00
{
bool Assign = false ;
unsigned int indentlevel = 0 ;
2010-08-11 22:36:04 +02:00
const Token * ftok = func . token ;
2010-01-16 08:47:46 +01:00
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
{
2010-09-10 07:02:49 +02:00
initVar ( ftok - > str ( ) ) ;
2010-06-06 08:29:35 +02:00
// assignment in the initializer..
// : var(value = x)
if ( Token : : Match ( ftok - > tokAt ( 2 ) , " %var% = " ) )
2010-09-09 07:26:40 +02:00
assignVar ( ftok - > strAt ( 2 ) ) ;
2010-01-16 08:47:46 +01:00
}
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
{
2010-09-09 07:26:40 +02:00
assignVar ( ftok - > strAt ( 1 ) ) ;
2010-01-16 08:47:46 +01:00
}
2010-07-14 18:50:29 +02:00
// Before a new statement there is "[{};)=]"
if ( ! Token : : Match ( ftok , " [{};()=] " ) )
2010-01-16 08:47:46 +01:00
continue ;
2010-07-14 18:50:29 +02:00
if ( Token : : simpleMatch ( ftok , " ( ! " ) )
ftok = ftok - > next ( ) ;
2010-01-16 08:47:46 +01:00
// 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-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-01-16 08:47:46 +01:00
break ;
}
2010-06-24 20:09:26 +02:00
if ( Token : : Match ( ftok - > next ( ) , " %var% . %var% ( " ) )
ftok = ftok - > tokAt ( 2 ) ;
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-09-09 07:26:40 +02:00
assignAllVar ( ) ;
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
{
2010-09-09 07:26:40 +02:00
assignVar ( ftok - > strAt ( 2 ) ) ;
2010-02-10 19:28:51 +01:00
ftok = ftok - > next ( ) - > link ( ) ;
continue ;
}
2010-01-16 08:47:46 +01:00
// Calling member function?
2010-07-14 19:00:52 +02:00
else if ( Token : : Match ( ftok , " %var% ( " ) & & ftok - > str ( ) ! = " if " )
2010-01-16 08:47:46 +01:00
{
2010-03-26 17:19:33 +01:00
// Passing "this" => assume that everything is initialized
2010-08-28 11:23:23 +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-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-03-26 17:19:33 +01:00
return ;
}
}
2010-06-13 10:23:59 +02:00
// recursive call / calling overloaded function
// assume that all variables are initialized
if ( std : : find ( callstack . begin ( ) , callstack . end ( ) , ftok - > str ( ) ) ! = callstack . end ( ) )
2010-01-16 08:47:46 +01:00
{
2010-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-06-13 10:23:59 +02:00
return ;
}
2010-08-11 22:36:04 +02:00
// check if member function
std : : list < Func > : : const_iterator it ;
for ( it = functionList . begin ( ) ; it ! = functionList . end ( ) ; + + it )
2010-06-13 10:23:59 +02:00
{
2010-10-10 07:57:26 +02:00
if ( ftok - > str ( ) = = it - > tokenDef - > str ( ) & & it - > type ! = Func : : Constructor )
2010-08-11 22:36:04 +02:00
break ;
2010-06-13 10:23:59 +02:00
}
2010-08-11 22:36:04 +02:00
// member function found
if ( it ! = functionList . end ( ) )
2010-06-13 10:23:59 +02:00
{
2010-08-11 22:36:04 +02:00
// member function has implementation
if ( it - > hasBody )
2010-07-17 12:26:05 +02:00
{
2010-08-11 22:36:04 +02:00
// initialize variable use list using member function
callstack . push_back ( ftok - > str ( ) ) ;
initializeVarList ( * it , callstack ) ;
callstack . pop_back ( ) ;
2010-07-17 12:26:05 +02:00
}
2010-08-11 22:36:04 +02:00
// there is a called member function, but it has no implementation, so we assume it initializes everything
else
2010-06-13 10:23:59 +02:00
{
2010-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-06-13 10:23:59 +02:00
}
2010-08-11 22:36:04 +02:00
}
// not member function
else
{
// could be a base class virtual function, so we assume it initializes everything
2010-09-14 07:16:53 +02:00
if ( func . type ! = Func : : Constructor & & isBaseClassFunc ( ftok ) )
{
/** @todo False Negative: we should look at the base class functions to see if they
* call any derived class virtual functions that change the derived class state
*/
2010-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-09-14 07:16:53 +02:00
}
2010-08-11 22:36:04 +02:00
// has friends, so we assume it initializes everything
if ( ! friendList . empty ( ) )
2010-09-09 07:26:40 +02:00
assignAllVar ( ) ;
2010-01-22 18:51:25 +01:00
2010-06-13 10:23:59 +02:00
// the function is external and it's neither friend nor inherited virtual function.
// assume all variables that are passed to it are initialized..
2010-08-11 22:36:04 +02:00
else
2010-06-13 10:23:59 +02:00
{
2010-08-11 22:36:04 +02:00
unsigned int indentlevel2 = 0 ;
for ( const Token * tok = ftok - > tokAt ( 2 ) ; tok ; tok = tok - > next ( ) )
2010-01-22 18:51:25 +01:00
{
2010-08-11 22:36:04 +02:00
if ( tok - > str ( ) = = " ( " )
+ + indentlevel2 ;
else if ( tok - > str ( ) = = " ) " )
{
if ( indentlevel2 = = 0 )
break ;
- - indentlevel2 ;
}
if ( tok - > isName ( ) )
{
2010-09-10 07:02:49 +02:00
assignVar ( tok - > str ( ) ) ;
2010-08-11 22:36:04 +02:00
}
2010-01-22 18:51:25 +01:00
}
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
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
// 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
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
// 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
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
// 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
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > next ( ) - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
2010-04-02 07:36:18 +02:00
// Assignment of struct member of member variable?
else if ( Token : : Match ( ftok , " %var% . %any% = " ) )
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > str ( ) ) ;
2010-04-02 07:36:18 +02:00
}
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
{
2010-09-10 07:02:49 +02:00
assignVar ( ftok - > str ( ) ) ;
2010-01-16 08:47:46 +01:00
}
}
}
2010-07-26 16:46:37 +02:00
bool CheckClass : : argsMatch ( const Token * first , const Token * second , const std : : string & path , unsigned int depth ) const
2010-07-14 19:00:52 +02:00
{
bool match = false ;
while ( first - > str ( ) = = second - > str ( ) )
{
// at end of argument list
if ( first - > str ( ) = = " ) " )
{
match = true ;
break ;
}
2010-01-16 08:47:46 +01:00
2010-07-14 19:00:52 +02:00
// skip default value assignment
else if ( first - > next ( ) - > str ( ) = = " = " )
first = first - > tokAt ( 2 ) ;
2010-01-16 08:47:46 +01:00
2010-07-14 19:00:52 +02:00
// definition missing variable name
else if ( first - > next ( ) - > str ( ) = = " , " & & second - > next ( ) - > str ( ) ! = " , " )
second = second - > next ( ) ;
else if ( first - > next ( ) - > str ( ) = = " ) " & & second - > next ( ) - > str ( ) ! = " ) " )
second = second - > next ( ) ;
2010-01-16 08:47:46 +01:00
2010-07-26 16:46:37 +02:00
// function missing variable name
else if ( second - > next ( ) - > str ( ) = = " , " & & first - > next ( ) - > str ( ) ! = " , " )
first = first - > next ( ) ;
else if ( second - > next ( ) - > str ( ) = = " ) " & & first - > next ( ) - > str ( ) ! = " ) " )
first = first - > next ( ) ;
2010-07-14 19:00:52 +02:00
// argument list has different number of arguments
else if ( second - > str ( ) = = " ) " )
break ;
// variable names are different
else if ( ( Token : : Match ( first - > next ( ) , " %var% ,|)|= " ) & &
Token : : Match ( second - > next ( ) , " %var% ,|) " ) ) & &
( first - > next ( ) - > str ( ) ! = second - > next ( ) - > str ( ) ) )
{
// skip variable names
first = first - > next ( ) ;
second = second - > next ( ) ;
// skip default value assignment
if ( first - > next ( ) - > str ( ) = = " = " )
first = first - > tokAt ( 2 ) ;
}
2010-07-18 20:43:51 +02:00
// variable with class path
else if ( depth & & Token : : Match ( first - > next ( ) , " %var% " ) )
{
std : : string param = path + first - > next ( ) - > str ( ) ;
if ( Token : : Match ( second - > next ( ) , param . c_str ( ) ) )
{
2010-08-06 21:02:43 +02:00
second = second - > tokAt ( int ( depth ) * 2 ) ;
2010-07-18 20:43:51 +02:00
}
else if ( depth > 1 )
{
std : : string short_path = path ;
// remove last " :: "
short_path . resize ( short_path . size ( ) - 4 ) ;
// remove last name
while ( ! short_path . empty ( ) & & short_path [ short_path . size ( ) - 1 ] ! = ' ' )
short_path . resize ( short_path . size ( ) - 1 ) ;
param = short_path + first - > next ( ) - > str ( ) ;
if ( Token : : Match ( second - > next ( ) , param . c_str ( ) ) )
{
2010-08-06 21:02:43 +02:00
second = second - > tokAt ( ( int ( depth ) - 1 ) * 2 ) ;
2010-07-18 20:43:51 +02:00
}
}
}
2010-07-14 19:00:52 +02:00
first = first - > next ( ) ;
second = second - > next ( ) ;
}
return match ;
}
2010-01-16 08:47:46 +01:00
2010-07-26 16:46:37 +02:00
//---------------------------------------------------------------------------
// ClassCheck: Check that all class constructors are ok.
//---------------------------------------------------------------------------
2010-07-15 10:16:16 +02:00
2010-01-16 08:47:46 +01:00
void CheckClass : : constructors ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-08-07 12:41:11 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator i ;
2010-07-26 16:46:37 +02:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
SpaceInfo * info = * i ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
// don't check namespaces
2010-11-02 18:28:55 +01:00
if ( info - > type = = SpaceInfo : : Namespace | | info - > type = = SpaceInfo : : Function )
2010-08-09 17:50:26 +02:00
continue ;
2010-07-26 16:46:37 +02:00
// There are no constructors.
if ( info - > numConstructors = = 0 )
2010-07-15 10:16:16 +02:00
{
2010-07-26 16:46:37 +02:00
// If there is a private variable, there should be a constructor..
2010-08-11 22:36:04 +02:00
std : : list < Var > : : const_iterator var ;
for ( var = info - > varlist . begin ( ) ; var ! = info - > varlist . end ( ) ; + + var )
2010-07-14 19:00:52 +02:00
{
2010-08-18 22:42:04 +02:00
if ( var - > access = = Private & & ! var - > isClass & & ! var - > isStatic )
2010-07-15 10:16:16 +02:00
{
2010-07-26 16:46:37 +02:00
noConstructorError ( info - > classDef , info - > className , info - > classDef - > str ( ) = = " struct " ) ;
break ;
2010-01-16 08:47:46 +01:00
}
}
2010-07-26 16:46:37 +02:00
}
2010-01-16 08:47:46 +01:00
2010-07-26 16:46:37 +02:00
std : : list < Func > : : const_iterator it ;
2010-01-16 08:47:46 +01:00
2010-07-26 16:46:37 +02:00
for ( it = info - > functionList . begin ( ) ; it ! = info - > functionList . end ( ) ; + + it )
{
if ( ! it - > hasBody | | ! ( it - > type = = Func : : Constructor | | it - > type = = Func : : CopyConstructor | | it - > type = = Func : : OperatorEqual ) )
continue ;
// Mark all variables not used
2010-09-09 07:26:40 +02:00
info - > clearAllVar ( ) ;
2010-07-14 19:00:52 +02:00
2010-07-26 16:46:37 +02:00
std : : list < std : : string > callstack ;
2010-08-11 22:36:04 +02:00
info - > initializeVarList ( * it , callstack ) ;
2010-07-14 19:00:52 +02:00
2010-07-26 16:46:37 +02:00
// Check if any variables are uninitialized
2010-08-11 22:36:04 +02:00
std : : list < Var > : : const_iterator var ;
for ( var = info - > varlist . begin ( ) ; var ! = info - > varlist . end ( ) ; + + var )
2010-07-14 19:00:52 +02:00
{
2010-07-26 16:46:37 +02:00
// skip classes for regular constructor
if ( var - > isClass & & it - > type = = Func : : Constructor )
2010-07-14 19:00:52 +02:00
continue ;
2010-09-09 07:26:40 +02:00
if ( var - > assign | | var - > init | | var - > isStatic )
2010-07-26 16:46:37 +02:00
continue ;
2010-07-15 10:16:16 +02:00
2010-07-26 16:46:37 +02:00
// It's non-static and it's not initialized => error
if ( it - > type = = Func : : OperatorEqual )
2010-01-16 08:47:46 +01:00
{
2010-07-26 16:46:37 +02:00
const Token * operStart = 0 ;
if ( it - > token - > str ( ) = = " = " )
operStart = it - > token - > tokAt ( 1 ) ;
else
operStart = it - > token - > tokAt ( 3 ) ;
bool classNameUsed = false ;
for ( const Token * operTok = operStart ; operTok ! = operStart - > link ( ) ; operTok = operTok - > next ( ) )
2010-01-16 08:47:46 +01:00
{
2010-07-26 16:46:37 +02:00
if ( operTok - > str ( ) = = info - > className )
2010-07-14 19:00:52 +02:00
{
2010-07-26 16:46:37 +02:00
classNameUsed = true ;
break ;
2010-07-14 19:00:52 +02:00
}
2010-07-15 10:16:16 +02:00
}
2010-01-16 08:47:46 +01:00
2010-07-26 16:46:37 +02:00
if ( classNameUsed )
2010-08-13 07:34:34 +02:00
operatorEqVarError ( it - > token , info - > className , var - > token - > str ( ) ) ;
2010-07-26 16:46:37 +02:00
}
2010-09-09 07:21:51 +02:00
else if ( it - > access ! = Private )
2010-08-13 07:34:34 +02:00
uninitVarError ( it - > token , info - > className , var - > token - > str ( ) ) ;
2010-07-15 10:16:16 +02:00
}
2010-07-14 19:00:52 +02:00
}
2010-01-16 08:47:46 +01:00
}
}
//---------------------------------------------------------------------------
// ClassCheck: Unused private functions
//---------------------------------------------------------------------------
void CheckClass : : privateFunctions ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-09-30 21:22:49 +02:00
// don't check code that contains templates. Templates that are
// "unused" are removed from the code. #2067
if ( _tokenizer - > codeWithTemplates ( ) )
return ;
2010-09-07 18:37:43 +02:00
// dont check borland classes with properties..
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , " ; __property ; " ) )
return ;
2010-09-02 07:40:20 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator i ;
2010-06-13 07:17:50 +02:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
SpaceInfo * info = * i ;
2010-09-02 07:40:20 +02:00
// don't check namespaces
2010-11-02 18:28:55 +01:00
if ( info - > type = = SpaceInfo : : Namespace | | info - > type = = SpaceInfo : : Function )
2010-09-02 07:40:20 +02:00
continue ;
// dont check derived classes
if ( ! info - > derivedFrom . empty ( ) )
continue ;
// Locate some class
const Token * tok1 = info - > classDef ;
2010-09-02 19:22:54 +02:00
// check that the whole class implementation is seen
bool whole = true ;
std : : list < Func > : : const_iterator func ;
for ( func = info - > functionList . begin ( ) ; func ! = info - > functionList . end ( ) ; + + func )
{
if ( ! func - > hasBody )
{
// empty private copy constructors and assignment operators are OK
if ( ( func - > type = = Func : : CopyConstructor | | func - > type = = Func : : OperatorEqual ) & & func - > access = = Private )
continue ;
whole = false ;
break ;
}
}
if ( ! whole )
2010-01-16 08:47:46 +01:00
continue ;
const std : : string & classname = tok1 - > next ( ) - > str ( ) ;
std : : list < const Token * > FuncList ;
2010-09-02 07:40:20 +02:00
/** @todo embedded class have access to private functions */
if ( info - > nestedList . empty ( ) )
2010-01-16 08:47:46 +01:00
{
2010-09-02 19:22:54 +02:00
for ( func = info - > functionList . begin ( ) ; func ! = info - > functionList . end ( ) ; + + func )
2010-01-16 08:47:46 +01:00
{
2010-09-02 07:40:20 +02:00
// Get private functions..
2010-09-02 19:22:54 +02:00
if ( func - > type = = Func : : Function & &
func - > access = = Private & & func - > hasBody )
FuncList . push_back ( func - > tokenDef ) ;
2010-01-16 08:47:46 +01:00
}
}
// Check that all private functions are used..
bool HasFuncImpl = false ;
bool inclass = false ;
2010-09-02 07:40:20 +02:00
int 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-09-20 19:43:03 +02:00
else if ( ftok - > str ( ) = = " class " & &
ftok - > next ( ) - > str ( ) = = classname & &
Token : : Match ( ftok - > tokAt ( 2 ) , " :|{ " ) )
2010-01-16 08:47:46 +01:00
{
indent_level = 0 ;
inclass = true ;
}
// Check member class functions to see what functions are used..
2010-09-20 19:43:03 +02:00
else if ( ( inclass & & indent_level = = 1 & & Token : : Match ( ftok , " %var% ( " ) ) | |
( ftok - > str ( ) = = classname & & Token : : Match ( ftok - > next ( ) , " :: ~| %var% ( " ) ) )
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
2010-10-17 14:15:29 +02:00
+ + it ;
2010-04-08 19:06:54 +02:00
}
}
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
2010-10-17 14:15:29 +02:00
+ + it ;
2010-01-16 08:47:46 +01:00
}
}
}
}
}
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-08-15 07:44:08 +02:00
// or if the function address is used somewhere...
// eg. sigc::mem_fun(this, &className::classFunction)
const std : : string _pattern2 ( " & " + classname + " :: " + FuncList . front ( ) - > str ( ) ) ;
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , _pattern . c_str ( ) ) & &
! Token : : findmatch ( _tokenizer - > tokens ( ) , _pattern2 . 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
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2010-09-11 08:23:30 +02:00
// ClassCheck: "void operator=(" and "const type & operator=("
2010-01-16 08:47:46 +01:00
//---------------------------------------------------------------------------
void CheckClass : : operatorEq ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-08-07 12:41:11 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : const_iterator i ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-07-26 16:46:37 +02:00
std : : list < Func > : : const_iterator it ;
2010-11-02 18:28:55 +01:00
for ( it = ( * i ) - > functionList . begin ( ) ; it ! = ( * i ) - > functionList . end ( ) ; + + it )
2010-01-16 08:47:46 +01:00
{
2010-07-26 16:46:37 +02:00
if ( it - > type = = Func : : OperatorEqual & & it - > access ! = Private )
2010-01-16 08:47:46 +01:00
{
2010-07-26 16:46:37 +02:00
if ( it - > token - > strAt ( - 2 ) = = " void " )
operatorEqReturnError ( it - > token - > tokAt ( - 2 ) ) ;
2010-01-16 08:47:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: "C& operator=(const C&) { ... return *this; }"
// operator= should return a reference to *this
//---------------------------------------------------------------------------
2010-09-11 08:23:30 +02:00
void CheckClass : : checkReturnPtrThis ( const SpaceInfo * info , const Func * func , const Token * tok , const Token * last )
{
bool foundReturn = false ;
for ( ; tok & & tok ! = last ; tok = tok - > next ( ) )
{
// check for return of reference to this
if ( tok - > str ( ) = = " return " )
{
foundReturn = true ;
std : : string cast ( " ( " + info - > className + " & ) " ) ;
if ( Token : : Match ( tok - > next ( ) , cast . c_str ( ) ) )
tok = tok - > tokAt ( 4 ) ;
// check if a function is called
if ( Token : : Match ( tok - > tokAt ( 1 ) , " %any% ( " ) & &
tok - > tokAt ( 2 ) - > link ( ) - > next ( ) - > str ( ) = = " ; " )
{
std : : list < Func > : : const_iterator it ;
// check if it is a member function
for ( it = info - > functionList . begin ( ) ; it ! = info - > functionList . end ( ) ; + + it )
{
// check for a regular function with the same name and a bofy
if ( it - > type = = Func : : Function & & it - > hasBody & &
it - > token - > str ( ) = = tok - > next ( ) - > str ( ) )
{
// check for the proper return type
if ( it - > tokenDef - > previous ( ) - > str ( ) = = " & " & &
it - > tokenDef - > strAt ( - 2 ) = = info - > className )
{
// make sure it's not a const function
if ( it - > arg - > link ( ) - > next ( ) - > str ( ) ! = " const " )
checkReturnPtrThis ( info , & * it , it - > arg - > link ( ) - > next ( ) , it - > arg - > link ( ) - > next ( ) - > link ( ) ) ;
}
}
}
}
// check of *this is returned
else if ( ! ( Token : : Match ( tok - > tokAt ( 1 ) , " (| * this ; | = " ) ||
Token : : Match ( tok - > tokAt ( 1 ) , " (| * this += " ) | |
Token : : Match ( tok - > tokAt ( 1 ) , " operator = ( " ) ) )
operatorEqRetRefThisError ( func - > token ) ;
}
}
if ( ! foundReturn )
operatorEqRetRefThisError ( func - > token ) ;
}
2010-01-16 08:47:46 +01:00
void CheckClass : : operatorEqRetRefThis ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-08-07 12:41:11 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : const_iterator i ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
const SpaceInfo * info = * i ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
if ( info - > type = = SpaceInfo : : Class | | info - > type = = SpaceInfo : : Struct )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
std : : list < Func > : : const_iterator func ;
for ( func = info - > functionList . begin ( ) ; func ! = info - > functionList . end ( ) ; + + func )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
if ( func - > type = = Func : : OperatorEqual & & func - > hasBody )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
// make sure return signature is correct
if ( Token : : Match ( func - > tokenDef - > tokAt ( - 4 ) , " ;|}|{|public:|protected:|private: %type% & " ) & &
func - > tokenDef - > strAt ( - 3 ) = = info - > className )
{
// find the ')'
const Token * tok = func - > token - > next ( ) - > link ( ) ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
checkReturnPtrThis ( info , & ( * func ) , tok - > tokAt ( 2 ) , tok - > next ( ) - > link ( ) ) ;
}
2010-01-16 08:47:46 +01:00
}
}
}
}
}
2010-07-26 16:46:37 +02:00
2010-01-16 08:47:46 +01:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 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.
//---------------------------------------------------------------------------
2010-08-28 11:23:23 +02:00
static bool hasDeallocation ( const Token * first , const Token * last )
2010-01-16 08:47:46 +01:00
{
// 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-08-28 11:23:23 +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
{
2010-08-28 11:23:23 +02:00
const Token * var = tok - > tokAt ( 3 ) ;
2010-01-16 08:47:46 +01:00
// we should probably check that var is a pointer in this class
2010-08-28 11:23:23 +02:00
const Token * tok1 = tok - > tokAt ( 4 ) ;
2010-01-16 08:47:46 +01:00
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
{
2010-08-28 11:23:23 +02:00
const Token * var = tok - > tokAt ( 4 ) ;
2010-01-16 08:47:46 +01:00
// we should probably check that var is a pointer in this class
2010-08-28 11:23:23 +02:00
const Token * tok1 = tok - > tokAt ( 5 ) ;
2010-01-16 08:47:46 +01:00
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
{
2010-08-28 11:23:23 +02:00
const Token * var = tok - > tokAt ( 2 ) ;
2010-01-16 08:47:46 +01:00
// we should probably check that var is a pointer in this class
2010-08-28 11:23:23 +02:00
const Token * tok1 = tok - > tokAt ( 3 ) ;
2010-01-16 08:47:46 +01:00
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 ;
}
2010-08-28 11:23:23 +02:00
static bool hasAssignSelf ( const Token * first , const Token * last , const Token * rhs )
2010-01-16 08:47:46 +01:00
{
2010-08-28 11:23:23 +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
{
2010-08-28 11:23:23 +02:00
const Token * tok1 = tok - > tokAt ( 2 ) ;
const Token * tok2 = tok - > tokAt ( 1 ) - > link ( ) ;
2010-01-16 08:47:46 +01:00
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 ;
}
void CheckClass : : operatorEqToSelf ( )
{
2010-05-10 21:22:59 +02:00
if ( ! _settings - > _checkCodingStyle )
2010-04-21 08:38:25 +02:00
return ;
2010-08-09 17:50:26 +02:00
createSymbolDatabase ( ) ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : const_iterator i ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-08-09 17:50:26 +02:00
{
2010-11-02 18:28:55 +01:00
const SpaceInfo * info = * i ;
2010-08-09 17:50:26 +02:00
std : : list < Func > : : const_iterator it ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
// skip classes with multiple inheritance
if ( info - > derivedFrom . size ( ) > 1 )
continue ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
for ( it = info - > functionList . begin ( ) ; it ! = info - > functionList . end ( ) ; + + it )
{
if ( it - > type = = Func : : OperatorEqual & & it - > hasBody )
2010-01-16 08:47:46 +01:00
{
2010-08-09 17:50:26 +02:00
// make sure return signature is correct
if ( Token : : Match ( it - > tokenDef - > tokAt ( - 4 ) , " ;|}|{|public:|protected:|private: %type% & " ) & &
it - > tokenDef - > strAt ( - 3 ) = = info - > className )
2010-01-16 08:47:46 +01:00
{
2010-08-09 17:50:26 +02:00
// check for proper function parameter signature
if ( ( Token : : Match ( it - > tokenDef - > next ( ) , " ( const %var% & ) " ) | |
Token : : Match ( it - > tokenDef - > next ( ) , " ( const %var% & %var% ) " ) ) & &
it - > tokenDef - > strAt ( 3 ) = = info - > className )
2010-01-16 08:47:46 +01:00
{
2010-08-09 17:50:26 +02:00
// find the parameter name
const Token * rhs = it - > token ;
while ( rhs - > str ( ) ! = " & " )
rhs = rhs - > next ( ) ;
rhs = rhs - > next ( ) ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
// find the ')'
const Token * tok = it - > token - > next ( ) - > link ( ) ;
const Token * tok1 = tok ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
if ( tok1 & & tok1 - > tokAt ( 1 ) & & tok1 - > tokAt ( 1 ) - > str ( ) = = " { " & & tok1 - > tokAt ( 1 ) - > link ( ) )
2010-01-16 08:47:46 +01:00
{
2010-08-09 17:50:26 +02:00
const Token * first = tok1 - > tokAt ( 1 ) ;
const Token * last = first - > link ( ) ;
2010-01-16 08:47:46 +01:00
2010-08-09 17:50:26 +02:00
if ( ! hasAssignSelf ( first , last , rhs ) )
2010-01-16 08:47:46 +01:00
{
2010-08-09 17:50:26 +02:00
if ( hasDeallocation ( first , last ) )
operatorEqToSelfError ( tok ) ;
2010-01-16 08:47:46 +01:00
}
}
}
}
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// A destructor in a base class should be virtual
//---------------------------------------------------------------------------
void CheckClass : : virtualDestructor ( )
{
2010-05-29 11:19:28 +02:00
// This error should only be given if:
// * base class doesn't have virtual destructor
// * derived class has non-empty destructor
// * base class is deleted
if ( ! _settings - > inconclusive )
return ;
2010-08-13 18:34:02 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : const_iterator i ;
2010-01-16 08:47:46 +01:00
2010-11-02 18:28:55 +01:00
for ( i = spaceInfoList . begin ( ) ; i ! = spaceInfoList . end ( ) ; + + i )
2010-01-16 08:47:46 +01:00
{
2010-11-02 18:28:55 +01:00
const SpaceInfo * info = * i ;
2010-01-16 08:47:46 +01:00
2010-08-13 18:34:02 +02:00
// Skip base classes and namespaces
if ( info - > derivedFrom . empty ( ) )
continue ;
2010-01-16 08:47:46 +01:00
2010-08-13 18:34:02 +02:00
// Find the destructor
const Func * destructor = info - > getDestructor ( ) ;
// Check for destructor with implementation
if ( ! destructor | | ! destructor - > hasBody )
continue ;
// Empty destructor
2010-09-10 07:02:49 +02:00
if ( destructor - > token - > tokAt ( 3 ) - > link ( ) = = destructor - > token - > tokAt ( 4 ) )
2010-08-13 18:34:02 +02:00
continue ;
2010-01-16 08:47:46 +01:00
2010-08-13 18:34:02 +02:00
const Token * derived = info - > classDef ;
2010-01-16 08:47:46 +01:00
const Token * derivedClass = derived - > tokAt ( 1 ) ;
// Iterate through each base class...
2010-08-13 18:34:02 +02:00
for ( unsigned int j = 0 ; j < info - > derivedFrom . size ( ) ; + + j )
2010-01-16 08:47:46 +01:00
{
2010-08-13 18:34:02 +02:00
// Check if base class is public and exists in database
2010-08-13 23:57:53 +02:00
if ( info - > derivedFrom [ j ] . access = = Public & & info - > derivedFrom [ j ] . spaceInfo )
2010-01-16 08:47:46 +01:00
{
2010-08-13 23:57:53 +02:00
const SpaceInfo * spaceInfo = info - > derivedFrom [ j ] . spaceInfo ;
2010-01-16 08:47:46 +01:00
2010-08-13 23:57:53 +02:00
// Name of base class..
const std : : string baseName = spaceInfo - > className ;
2010-01-16 08:47:46 +01:00
2010-08-13 23:57:53 +02:00
// Find the destructor declaration for the base class.
const Func * base_destructor = spaceInfo - > getDestructor ( ) ;
const Token * base = 0 ;
if ( base_destructor )
base = base_destructor - > token ;
2010-01-16 08:47:46 +01:00
2010-08-13 23:57:53 +02:00
// Check that there is a destructor..
if ( ! base_destructor )
{
if ( spaceInfo - > derivedFrom . empty ( ) )
virtualDestructorError ( spaceInfo - > classDef , baseName , derivedClass - > str ( ) ) ;
}
else if ( ! base_destructor - > isVirtual )
{
// 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 ( spaceInfo - > derivedFrom . empty ( ) )
{
// 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.)
if ( base_destructor - > access = = Public )
virtualDestructorError ( base , baseName , derivedClass - > str ( ) ) ;
}
}
}
2010-01-16 08:47:46 +01:00
}
}
}
//---------------------------------------------------------------------------
void CheckClass : : thisSubtractionError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " thisSubtraction " , " Suspicious pointer subtraction " ) ;
2010-01-16 08:47:46 +01:00
}
void CheckClass : : thisSubtraction ( )
{
2010-05-01 21:43:47 +02:00
if ( ! _settings - > _checkCodingStyle )
2010-04-21 08:38:25 +02:00
return ;
2010-01-16 08:47:46 +01:00
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-07-18 10:18:41 +02:00
// check if this function is defined virtual in the base classes
2010-08-10 18:01:33 +02:00
bool CheckClass : : isVirtual ( const SpaceInfo * info , const Token * functionToken ) const
2010-07-18 10:18:41 +02:00
{
// check each base class
2010-08-10 18:01:33 +02:00
for ( unsigned int i = 0 ; i < info - > derivedFrom . size ( ) ; + + i )
2010-07-18 10:18:41 +02:00
{
2010-08-10 18:01:33 +02:00
// check if base class exists in database
if ( info - > derivedFrom [ i ] . spaceInfo )
2010-07-18 10:18:41 +02:00
{
2010-11-02 18:28:55 +01:00
const SpaceInfo * derivedFrom = info - > derivedFrom [ i ] . spaceInfo ;
2010-07-18 10:18:41 +02:00
2010-11-02 18:28:55 +01:00
std : : list < Func > : : const_iterator func ;
2010-07-18 10:18:41 +02:00
2010-08-10 18:01:33 +02:00
// check if function defined in base class
2010-11-02 18:28:55 +01:00
for ( func = derivedFrom - > functionList . begin ( ) ; func ! = derivedFrom - > functionList . end ( ) ; + + func )
2010-07-18 10:18:41 +02:00
{
2010-11-02 18:28:55 +01:00
if ( func - > isVirtual )
2010-07-18 10:18:41 +02:00
{
2010-11-02 18:28:55 +01:00
const Token * tok = func - > tokenDef ;
2010-07-18 10:18:41 +02:00
if ( tok - > str ( ) = = functionToken - > str ( ) )
{
const Token * temp1 = tok - > previous ( ) ;
const Token * temp2 = functionToken - > previous ( ) ;
bool returnMatch = true ;
// check for matching return parameters
while ( temp1 - > str ( ) ! = " virtual " )
{
if ( temp1 - > str ( ) ! = temp2 - > str ( ) )
{
returnMatch = false ;
break ;
}
temp1 = temp1 - > previous ( ) ;
temp2 = temp2 - > previous ( ) ;
}
// check for matching function parameters
2010-07-18 20:43:51 +02:00
if ( returnMatch & & argsMatch ( tok - > tokAt ( 2 ) , functionToken - > tokAt ( 2 ) , std : : string ( " " ) , 0 ) )
2010-07-18 10:18:41 +02:00
{
return true ;
}
}
}
}
2010-11-02 18:28:55 +01:00
if ( ! derivedFrom - > derivedFrom . empty ( ) )
2010-07-18 10:18:41 +02:00
{
2010-11-02 18:28:55 +01:00
if ( isVirtual ( derivedFrom , functionToken ) )
2010-07-18 10:18:41 +02:00
return true ;
}
}
2010-08-20 07:28:31 +02:00
else
{
// unable to find base class so assume it has a virtual function
return true ;
}
2010-07-18 10:18:41 +02:00
}
return false ;
}
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-08-07 13:08:36 +02:00
if ( ! _settings - > _checkCodingStyle | | _settings - > ifcfg )
2010-01-23 09:38:35 +01:00
return ;
2010-10-20 22:15:35 +02:00
// Don't check C# and JAVA classes
2010-10-28 18:51:55 +02:00
if ( _tokenizer - > isJavaOrCSharp ( ) )
2010-10-20 22:15:35 +02:00
{
return ;
}
2010-08-07 12:41:11 +02:00
createSymbolDatabase ( ) ;
2010-11-02 18:28:55 +01:00
std : : list < SpaceInfo * > : : iterator it ;
2010-01-23 09:19:22 +01:00
2010-11-02 18:28:55 +01:00
for ( it = spaceInfoList . begin ( ) ; it ! = spaceInfoList . end ( ) ; + + it )
2010-07-26 16:46:37 +02:00
{
2010-11-02 18:28:55 +01:00
SpaceInfo * info = * it ;
2010-01-23 09:19:22 +01:00
2010-11-02 18:28:55 +01:00
std : : list < Func > : : const_iterator func ;
2010-03-05 17:06:25 +01:00
2010-11-02 18:28:55 +01:00
for ( func = info - > functionList . begin ( ) ; func ! = info - > functionList . end ( ) ; + + func )
2010-07-26 16:46:37 +02:00
{
// does the function have a body?
2010-11-02 18:28:55 +01:00
if ( func - > type = = Func : : Function & & func - > hasBody & & ! func - > isFriend & & ! func - > isStatic & & ! func - > isConst & & ! func - > isVirtual )
2010-03-12 18:30:20 +01:00
{
2010-07-26 16:46:37 +02:00
// get last token of return type
2010-11-02 18:28:55 +01:00
const Token * previous = func - > tokenDef - > isName ( ) ? func - > token - > previous ( ) : func - > token - > tokAt ( - 2 ) ;
2010-07-26 16:46:37 +02:00
while ( previous - > str ( ) = = " :: " )
previous = previous - > tokAt ( - 2 ) ;
2010-03-12 18:30:20 +01:00
2010-07-26 16:46:37 +02:00
// does the function return a pointer or reference?
if ( Token : : Match ( previous , " *|& " ) )
{
2010-11-02 18:28:55 +01:00
const Token * temp = func - > token - > previous ( ) ;
2010-01-23 09:19:22 +01:00
2010-07-26 16:46:37 +02:00
while ( ! Token : : Match ( temp - > previous ( ) , " ;|}|{|public:|protected:|private: " ) )
temp = temp - > previous ( ) ;
2010-01-24 13:45:56 +01:00
2010-07-26 16:46:37 +02:00
if ( temp - > str ( ) ! = " const " )
2010-03-19 17:40:23 +01:00
continue ;
}
2010-07-26 16:46:37 +02:00
else if ( Token : : Match ( previous - > previous ( ) , " *|& > " ) )
2010-04-09 19:15:39 +02:00
{
2010-11-02 18:28:55 +01:00
const Token * temp = func - > token - > previous ( ) ;
2010-07-26 16:46:37 +02:00
while ( ! Token : : Match ( temp - > previous ( ) , " ;|}|{|public:|protected:|private: " ) )
2010-04-09 19:15:39 +02:00
{
2010-07-26 16:46:37 +02:00
temp = temp - > previous ( ) ;
if ( temp - > str ( ) = = " const " )
2010-04-09 19:15:39 +02:00
break ;
}
2010-07-26 16:46:37 +02:00
if ( temp - > str ( ) ! = " const " )
2010-04-09 19:15:39 +02:00
continue ;
}
2010-07-26 16:46:37 +02:00
else
2010-01-23 09:19:22 +01:00
{
2010-07-26 16:46:37 +02:00
// don't warn for unknown types..
// LPVOID, HDC, etc
if ( previous - > isName ( ) )
2010-03-05 17:06:25 +01:00
{
2010-07-26 16:46:37 +02:00
bool allupper = true ;
const std : : string s ( previous - > str ( ) ) ;
for ( std : : string : : size_type pos = 0 ; pos < s . size ( ) ; + + pos )
2010-07-18 10:18:41 +02:00
{
2010-08-06 21:02:43 +02:00
const char ch = s [ pos ] ;
2010-07-26 16:46:37 +02:00
if ( ! ( ch = = ' _ ' | | ( ch > = ' A ' & & ch < = ' Z ' ) ) )
2010-01-23 09:19:22 +01:00
{
2010-07-26 16:46:37 +02:00
allupper = false ;
break ;
2010-01-23 20:59:20 +01:00
}
2010-03-05 17:06:25 +01:00
}
2010-07-26 16:46:37 +02:00
2010-09-06 19:04:14 +02:00
if ( allupper & & previous - > str ( ) . size ( ) > 2 )
2010-07-26 16:46:37 +02:00
continue ;
2010-03-05 17:06:25 +01:00
}
}
2010-01-23 20:59:20 +01:00
2010-11-02 18:28:55 +01:00
const Token * paramEnd = func - > token - > next ( ) - > link ( ) ;
2010-03-05 17:06:25 +01:00
2010-07-26 16:46:37 +02:00
// check if base class function is virtual
if ( ! info - > derivedFrom . empty ( ) )
2010-03-05 17:06:25 +01:00
{
2010-11-02 18:28:55 +01:00
if ( isVirtual ( info , func - > tokenDef ) )
2010-07-26 16:46:37 +02:00
continue ;
2010-01-23 09:19:22 +01:00
}
2010-03-05 17:06:25 +01:00
2010-07-26 16:46:37 +02:00
// if nothing non-const was found. write error..
2010-08-10 18:01:33 +02:00
if ( checkConstFunc ( info , paramEnd ) )
2010-03-28 11:46:42 +02:00
{
2010-07-26 16:46:37 +02:00
std : : string classname = info - > className ;
2010-08-28 11:23:23 +02:00
SpaceInfo * nest = info - > nestedIn ;
2010-07-26 16:46:37 +02:00
while ( nest )
2010-03-28 11:46:42 +02:00
{
2010-07-26 16:46:37 +02:00
classname = std : : string ( nest - > className + " :: " + classname ) ;
2010-08-28 11:23:23 +02:00
nest = nest - > nestedIn ;
2010-03-28 11:46:42 +02:00
}
2010-04-18 15:40:31 +02:00
2010-09-01 06:32:46 +02:00
// get function name
2010-11-02 18:28:55 +01:00
std : : string functionName ( ( func - > tokenDef - > isName ( ) ? " " : " operator " ) + func - > tokenDef - > str ( ) ) ;
2010-09-01 06:32:46 +02:00
2010-11-02 18:28:55 +01:00
if ( func - > tokenDef - > str ( ) = = " ( " )
2010-09-01 06:32:46 +02:00
functionName + = " ) " ;
2010-11-02 18:28:55 +01:00
else if ( func - > tokenDef - > str ( ) = = " [ " )
2010-09-01 06:32:46 +02:00
functionName + = " ] " ;
2010-11-02 18:28:55 +01:00
if ( func - > isInline )
checkConstError ( func - > token , classname , functionName ) ;
2010-07-26 16:46:37 +02:00
else // not inline
2010-11-02 18:28:55 +01:00
checkConstError2 ( func - > token , func - > tokenDef , classname , functionName ) ;
2010-04-18 15:40:31 +02:00
}
2010-03-28 11:46:42 +02:00
}
}
}
}
2010-08-10 18:01:33 +02:00
bool CheckClass : : isMemberVar ( const SpaceInfo * info , const Token * tok )
2010-03-12 18:30:20 +01:00
{
2010-10-27 19:25:34 +02:00
const Token * tok1 = tok ;
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-10-27 19:25:34 +02:00
if ( Token : : Match ( tok , " ( * %var% ) [ " ) | | ( Token : : Match ( tok , " ( * %var% ) << " ) & & tok1 - > next ( ) - > str ( ) = = " << " ) )
2010-05-25 06:55:49 +02:00
tok = tok - > tokAt ( 2 ) ;
2010-04-01 16:59:35 +02:00
// ignore class namespace
2010-08-10 18:01:33 +02:00
if ( tok - > str ( ) = = info - > className & & tok - > next ( ) - > str ( ) = = " :: " )
2010-04-01 16:59:35 +02:00
tok = tok - > tokAt ( 2 ) ;
2010-08-11 22:36:04 +02:00
std : : list < Var > : : const_iterator var ;
for ( var = info - > varlist . begin ( ) ; var ! = info - > varlist . end ( ) ; + + var )
2010-03-12 18:30:20 +01:00
{
2010-08-13 07:34:34 +02:00
if ( var - > token - > str ( ) = = tok - > str ( ) )
2010-03-26 19:06:00 +01:00
{
return ! var - > isMutable ;
}
2010-03-12 18:30:20 +01:00
}
2010-07-19 13:16:11 +02:00
// not found in this class
2010-08-10 18:01:33 +02:00
if ( ! info - > derivedFrom . empty ( ) )
2010-07-19 13:16:11 +02:00
{
// check each base class
2010-08-10 18:01:33 +02:00
for ( unsigned int i = 0 ; i < info - > derivedFrom . size ( ) ; + + i )
2010-07-19 13:16:11 +02:00
{
// find the base class
2010-08-28 11:23:23 +02:00
const SpaceInfo * spaceInfo = info - > derivedFrom [ i ] . spaceInfo ;
2010-07-19 13:16:11 +02:00
// find the function in the base class
2010-08-10 18:01:33 +02:00
if ( spaceInfo )
2010-07-19 13:16:11 +02:00
{
2010-08-10 18:01:33 +02:00
if ( isMemberVar ( spaceInfo , tok ) )
2010-07-19 13:16:11 +02:00
return true ;
}
}
}
2010-03-12 18:30:20 +01:00
return false ;
}
2010-10-13 07:26:41 +02:00
bool CheckClass : : isConstMemberFunc ( const SpaceInfo * info , const Token * tok )
{
std : : list < Func > : : const_iterator func ;
for ( func = info - > functionList . begin ( ) ; func ! = info - > functionList . end ( ) ; + + func )
{
if ( func - > tokenDef - > str ( ) = = tok - > str ( ) & & func - > isConst )
return true ;
}
// not found in this class
if ( ! info - > derivedFrom . empty ( ) )
{
// check each base class
for ( unsigned int i = 0 ; i < info - > derivedFrom . size ( ) ; + + i )
{
// find the base class
const SpaceInfo * spaceInfo = info - > derivedFrom [ i ] . spaceInfo ;
// find the function in the base class
if ( spaceInfo )
{
if ( isConstMemberFunc ( spaceInfo , tok ) )
return true ;
}
}
}
return false ;
}
2010-08-10 18:01:33 +02:00
bool CheckClass : : checkConstFunc ( const SpaceInfo * info , 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-08-10 18:01:33 +02:00
if ( tok1 - > previous ( ) - > varId ( ) = = 0 & & ! info - > derivedFrom . empty ( ) )
2010-07-20 09:43:27 +02:00
{
isconst = false ;
break ;
}
2010-08-10 18:01:33 +02:00
else if ( isMemberVar ( info , 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-08-15 08:30:21 +02:00
else if ( tok1 - > previous ( ) - > str ( ) = = " ] " )
{
// TODO: I assume that the assigned variable is a member variable
// don't assume it
isconst = false ;
break ;
}
2010-08-20 19:47:41 +02:00
else if ( tok1 - > next ( ) - > str ( ) = = " this " )
{
isconst = false ;
break ;
}
2010-10-24 16:43:10 +02:00
// FIXME: I assume that a member union/struct variable is assigned.
else if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " . %var% " ) )
{
isconst = false ;
break ;
}
2010-03-05 17:06:25 +01:00
}
2010-04-02 22:03:07 +02:00
// streaming: <<
2010-08-10 18:01:33 +02:00
else if ( tok1 - > str ( ) = = " << " & & isMemberVar ( info , tok1 - > previous ( ) ) )
2010-04-02 22:03:07 +02:00
{
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-10-13 07:26:41 +02:00
else if ( Token : : Match ( tok1 , " %var% ( " ) & &
! ( Token : : Match ( tok1 , " return|c_str|if|string " ) | | tok1 - > isStandardType ( ) ) )
{
if ( ! isConstMemberFunc ( info , tok1 ) )
{
isconst = false ;
break ;
}
}
else if ( Token : : Match ( tok1 , " %var% < %any% > ( " ) )
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 )
{
2010-10-17 14:41:00 +02:00
// For performance reasons the constructor might be intentionally missing. Therefore this is not a "warning"
2010-01-16 08:47:46 +01:00
reportError ( tok , Severity : : style , " noConstructor " , " The " + std : : string ( isStruct ? " struct " : " class " ) + " ' " + classname + " ' has no constructor. Member variables not initialized. " ) ;
}
2010-05-16 14:43:42 +02:00
void CheckClass : : uninitVarError ( const Token * tok , const std : : string & classname , const std : : string & varname )
2010-01-16 08:47:46 +01:00
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " uninitVar " , " Member variable not initialized in the constructor ' " + classname + " :: " + varname + " ' " ) ;
2010-01-16 08:47:46 +01:00
}
void CheckClass : : operatorEqVarError ( const Token * tok , const std : : string & classname , const std : : string & varname )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " operatorEqVarError " , " Member variable ' " + classname + " :: " + varname + " ' is not assigned a value in ' " + classname + " ::operator= " + " ' " ) ;
2010-01-16 08:47:46 +01:00
}
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 )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " operatorEqToSelf " , " 'operator=' should check for assignment to self " ) ;
2010-01-16 08:47:46 +01:00
}