2009-01-26 20:14:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-01-26 20:14: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 "checkother.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-03-20 18:16:21 +01:00
# include "tokenize.h"
2009-02-04 19:49:19 +01:00
# include <algorithm>
2009-01-26 20:14:46 +01:00
# include <list>
# include <map>
# include <sstream>
# include <cstring>
# include <cctype>
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
// Register this check class (by creating a static instance of it)
namespace
2009-01-26 20:14:46 +01:00
{
2009-03-20 18:16:21 +01:00
CheckOther instance ;
2009-01-26 20:14:46 +01:00
}
2009-03-20 18:16:21 +01:00
//---------------------------------------------------------------------------
2009-01-26 20:14:46 +01:00
2009-07-05 22:16:43 +02:00
void CheckOther : : warningOldStylePointerCast ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Old style pointer casting..
if ( ! Token : : Match ( tok , " ( %type% * ) %var% " ) )
continue ;
2009-06-18 22:26:21 +02:00
if ( Token : : simpleMatch ( tok - > tokAt ( 4 ) , " const " ) )
continue ;
2009-01-26 20:14:46 +01:00
// Is "type" a class?
const std : : string pattern ( " class " + tok - > next ( ) - > str ( ) ) ;
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
continue ;
2009-03-21 17:58:13 +01:00
cstyleCastError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
}
//---------------------------------------------------------------------------
// Redundant code..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : warningRedundantCode ( )
2009-01-26 20:14:46 +01:00
{
// if (p) delete p
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) ! = " if " )
continue ;
const char * varname1 = NULL ;
const Token * tok2 = NULL ;
if ( Token : : Match ( tok , " if ( %var% ) " ) )
{
varname1 = tok - > strAt ( 2 ) ;
tok2 = tok - > tokAt ( 4 ) ;
}
2009-05-19 20:23:43 +02:00
else if ( Token : : Match ( tok , " if ( %var% != 0 ) " ) )
2009-01-26 20:14:46 +01:00
{
varname1 = tok - > strAt ( 2 ) ;
tok2 = tok - > tokAt ( 6 ) ;
}
if ( varname1 = = NULL | | tok2 = = NULL )
continue ;
bool err = false ;
if ( tok2 - > str ( ) = = " { " )
{
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " delete %var% ; } " ) )
{
err = ( strcmp ( tok2 - > strAt ( 1 ) , varname1 ) = = 0 ) ;
}
else if ( Token : : Match ( tok2 , " delete [ ] %var% ; } " ) )
{
2009-05-19 20:28:25 +02:00
err = ( strcmp ( tok2 - > strAt ( 3 ) , varname1 ) = = 0 ) ;
2009-01-26 20:14:46 +01:00
}
else if ( Token : : Match ( tok2 , " free ( %var% ) ; } " ))
{
err = ( strcmp ( tok2 - > strAt ( 2 ) , varname1 ) = = 0 ) ;
}
else if ( Token : : Match ( tok2 , " kfree ( %var% ) ; } " ))
{
err = ( strcmp ( tok2 - > strAt ( 2 ) , varname1 ) = = 0 ) ;
}
}
else
{
if ( Token : : Match ( tok2 , " delete %var% ; " ) )
{
err = ( strcmp ( tok2 - > strAt ( 1 ) , varname1 ) = = 0 ) ;
}
else if ( Token : : Match ( tok2 , " delete [ ] %var% ; " ) )
{
2009-05-19 20:28:25 +02:00
err = ( strcmp ( tok2 - > strAt ( 3 ) , varname1 ) = = 0 ) ;
2009-01-26 20:14:46 +01:00
}
else if ( Token : : Match ( tok2 , " free ( %var% ) ; " ))
{
err = ( strcmp ( tok2 - > strAt ( 2 ) , varname1 ) = = 0 ) ;
}
else if ( Token : : Match ( tok2 , " kfree ( %var% ) ; " ))
{
err = ( strcmp ( tok2 - > strAt ( 2 ) , varname1 ) = = 0 ) ;
}
}
if ( err )
{
2009-03-21 17:58:13 +01:00
redundantIfDelete0Error ( tok ) ;
2009-01-26 20:14:46 +01:00
}
}
// Redundant condition
// if (haystack.find(needle) != haystack.end())
// haystack.remove(needle);
redundantCondition2 ( ) ;
}
//---------------------------------------------------------------------------
void CheckOther : : redundantCondition2 ( )
{
const char pattern [ ] = " if ( %var% . find ( %any% ) != %var% . end ( ) ) "
" {|{| "
" %var% . remove ( %any% ) ; "
" }|}| " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ;
while ( tok )
{
2009-05-21 17:55:52 +02:00
bool b = Token : : simpleMatch ( tok - > tokAt ( 15 ) , " { " ) ;
2009-01-26 20:14:46 +01:00
// Get tokens for the fields %var% and %any%
const Token * var1 = tok - > tokAt ( 2 ) ;
const Token * any1 = tok - > tokAt ( 6 ) ;
const Token * var2 = tok - > tokAt ( 9 ) ;
const Token * var3 = tok - > tokAt ( b ? 16 : 15 ) ;
const Token * any2 = tok - > tokAt ( b ? 20 : 19 ) ;
// Check if all the "%var%" fields are the same and if all the "%any%" are the same..
if ( var1 - > str ( ) = = var2 - > str ( ) & &
var2 - > str ( ) = = var3 - > str ( ) & &
any1 - > str ( ) = = any2 - > str ( ) )
{
2009-03-21 17:58:13 +01:00
redundantIfRemoveError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
tok = Token : : findmatch ( tok - > next ( ) , pattern ) ;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// if (condition) ....
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : warningIf ( )
2009-01-26 20:14:46 +01:00
{
2009-03-20 18:16:21 +01:00
if ( ErrorLogger : : ifNoAction ( * _settings ) )
2009-01-26 20:14:46 +01:00
{
// Search for 'if (condition);'
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ! Token : : simpleMatch ( tok , " if ( " ) )
continue ;
// Search for the end paranthesis for the condition..
int parlevel = 0 ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
- - parlevel ;
if ( parlevel < = 0 )
{
if ( Token : : Match ( tok2 , " ) ; !!else " ) )
{
2009-03-21 17:58:13 +01:00
ifNoActionError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
break ;
}
}
}
}
}
2009-03-24 19:49:01 +01:00
if ( _settings - > _checkCodingStyle )
2009-01-26 20:14:46 +01:00
{
// Search for 'a=b; if (a==b)'
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Begin statement?
if ( ! Token : : Match ( tok , " [;{}] " ) )
continue ;
tok = tok - > next ( ) ;
if ( ! tok )
break ;
if ( ! Token : : Match ( tok , " %var% = %var% ; if ( %var% " ) )
continue ;
if ( strcmp ( tok - > strAt ( 9 ) , " ) " ) ! = 0 )
continue ;
// var1 = var2 ; if ( var3 cond var4 )
2009-03-24 19:49:01 +01:00
unsigned int var1 = tok - > tokAt ( 0 ) - > varId ( ) ;
unsigned int var2 = tok - > tokAt ( 2 ) - > varId ( ) ;
unsigned int var3 = tok - > tokAt ( 6 ) - > varId ( ) ;
2009-01-26 20:14:46 +01:00
const char * cond = tok - > strAt ( 7 ) ;
2009-03-24 19:49:01 +01:00
unsigned int var4 = tok - > tokAt ( 8 ) - > varId ( ) ;
if ( var1 = = 0 | | var2 = = 0 | | var3 = = 0 | | var4 = = 0 )
continue ;
if ( var1 = = var2 | | var3 = = var4 )
continue ;
2009-01-26 20:14:46 +01:00
// Check that var3 is equal with either var1 or var2
2009-03-24 19:49:01 +01:00
if ( var1 ! = var3 & & var2 ! = var3 )
2009-01-26 20:14:46 +01:00
continue ;
// Check that var4 is equal with either var1 or var2
2009-03-24 19:49:01 +01:00
if ( var1 ! = var4 & & var2 ! = var4 )
2009-01-26 20:14:46 +01:00
continue ;
// Check that there is a condition..
2009-05-22 16:20:32 +02:00
static const char * const p [ 6 ] = { " == " , " <= " , " >= " , " != " , " < " , " > " } ;
2009-01-26 20:14:46 +01:00
bool iscond = false ;
for ( int i = 0 ; i < 6 ; i + + )
{
if ( strcmp ( cond , p [ i ] ) = = 0 )
{
iscond = true ;
break ;
}
}
if ( ! iscond )
2009-03-24 19:49:01 +01:00
continue ;
// If there are casting involved it's hard to know if the
// condition is true or false
const Token * vardecl1 = Token : : findmatch ( _tokenizer - > tokens ( ) , " ; %type% %varid% ; " , var1 ) ;
if ( ! vardecl1 )
continue ;
const Token * vardecl2 = Token : : findmatch ( _tokenizer - > tokens ( ) , " ; %type% %varid% ; " , var2 ) ;
if ( ! vardecl2 )
continue ;
// variable 1 & 2 must be the same type..
if ( vardecl1 - > next ( ) - > str ( ) ! = vardecl2 - > next ( ) - > str ( ) )
continue ;
2009-01-26 20:14:46 +01:00
// we found the error. Report.
bool b = false ;
for ( int i = 0 ; i < 6 ; i + + )
{
if ( strcmp ( cond , p [ i ] ) = = 0 )
b = ( i < 3 ) ;
}
2009-03-21 17:58:13 +01:00
conditionAlwaysTrueFalse ( tok - > tokAt ( 4 ) , b ? " True " : " False " ) ;
2009-01-26 20:14:46 +01:00
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// strtol(str, 0, radix) <- radix must be 0 or 2-36
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : invalidFunctionUsage ( )
2009-01-26 20:14:46 +01:00
{
// strtol and strtoul..
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ( tok - > str ( ) ! = " strtol " ) & & ( tok - > str ( ) ! = " strtoul " ) )
continue ;
// Locate the third parameter of the function call..
int parlevel = 0 ;
int param = 1 ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
2009-05-21 17:55:52 +02:00
if ( Token : : simpleMatch ( tok2 , " ( " ) )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2009-05-21 17:55:52 +02:00
else if ( Token : : simpleMatch ( tok2 , " ) " ) )
2009-01-26 20:14:46 +01:00
- - parlevel ;
2009-05-21 17:55:52 +02:00
else if ( parlevel = = 1 & & Token : : simpleMatch ( tok2 , " , " ) )
2009-01-26 20:14:46 +01:00
{
+ + param ;
if ( param = = 3 )
{
if ( Token : : Match ( tok2 , " , %num% ) " ) )
{
2009-05-02 10:45:15 +02:00
int radix = MathLib : : toLongNumber ( tok2 - > next ( ) - > str ( ) ) ;
2009-01-26 20:14:46 +01:00
if ( ! ( radix = = 0 | | ( radix > = 2 & & radix < = 36 ) ) )
{
2009-03-21 17:58:13 +01:00
dangerousUsageStrtolError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
}
}
break ;
}
}
}
}
// sprintf|snprintf overlapping data
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Get variable id of target buffer..
unsigned int varid = 0 ;
if ( Token : : Match ( tok , " sprintf|snprintf ( %var% , " ) )
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
else if ( Token : : Match ( tok , " sprintf|snprintf ( %var% . %var% , " ) )
varid = tok - > tokAt ( 4 ) - > varId ( ) ;
if ( varid = = 0 )
continue ;
// goto ","
const Token * tok2 = tok - > tokAt ( 3 ) ;
while ( tok2 & & tok2 - > str ( ) ! = " , " )
tok2 = tok2 - > next ( ) ;
// is any source buffer overlapping the target buffer?
int parlevel = 0 ;
while ( ( tok2 = tok2 - > next ( ) ) ! = NULL )
{
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
- - parlevel ;
if ( parlevel < 0 )
break ;
}
2009-01-27 08:21:52 +01:00
else if ( parlevel = = 0 & & Token : : Match ( tok2 , " , %varid% [,)] " , varid ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
sprintfOverlappingDataError ( tok2 - > next ( ) , tok2 - > next ( ) - > str ( ) ) ;
2009-01-26 20:14:46 +01:00
break ;
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check for unsigned divisions
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkUnsignedDivision ( )
2009-01-26 20:14:46 +01:00
{
// Check for "ivar / uvar" and "uvar / ivar"
std : : map < std : : string , char > varsign ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " [{};(,] %type% %var% [;=,)] " ) )
{
const char * type = tok - > strAt ( 1 ) ;
if ( strcmp ( type , " char " ) = = 0 | | strcmp ( type , " short " ) = = 0 | | strcmp ( type , " int " ) = = 0 )
varsign [ tok - > strAt ( 2 ) ] = ' s ' ;
}
else if ( Token : : Match ( tok , " [{};(,] unsigned %type% %var% [;=,)] " ) )
varsign [ tok - > strAt ( 3 ) ] = ' u ' ;
else if ( ! Token : : Match ( tok , " [).] " ) & & Token : : Match ( tok - > next ( ) , " %var% / %var% " ) )
{
2009-03-20 18:16:21 +01:00
if ( ErrorLogger : : udivWarning ( * _settings ) )
2009-01-26 20:14:46 +01:00
{
const char * varname1 = tok - > strAt ( 1 ) ;
const char * varname2 = tok - > strAt ( 3 ) ;
char sign1 = varsign [ varname1 ] ;
char sign2 = varsign [ varname2 ] ;
if ( sign1 & & sign2 & & sign1 ! = sign2 )
{
// One of the operands are signed, the other is unsigned..
2009-03-21 17:58:13 +01:00
udivWarning ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-03-17 20:50:06 +01:00
else if ( ! Token : : Match ( tok , " [).] " ) & & Token : : Match ( tok - > next ( ) , " %var% / %num% " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-17 20:50:06 +01:00
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' & & ErrorLogger : : udivError ( ) )
2009-01-26 20:14:46 +01:00
{
const char * varname1 = tok - > strAt ( 1 ) ;
char sign1 = varsign [ varname1 ] ;
if ( sign1 = = ' u ' )
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-03-17 20:50:06 +01:00
else if ( Token : : Match ( tok , " [([=*/+-,] %num% / %var% " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-17 20:50:06 +01:00
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' & & ErrorLogger : : udivError ( ) )
2009-01-26 20:14:46 +01:00
{
2009-03-17 20:50:06 +01:00
const char * varname2 = tok - > strAt ( 3 ) ;
2009-01-26 20:14:46 +01:00
char sign2 = varsign [ varname2 ] ;
if ( sign2 = = ' u ' )
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check scope of variables..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkVariableScope ( )
2009-01-26 20:14:46 +01:00
{
// Walk through all tokens..
bool func = false ;
int indentlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Skip class and struct declarations..
if ( ( tok - > str ( ) = = " class " ) | | ( tok - > str ( ) = = " struct " ) )
{
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
{
int indentlevel2 = 0 ;
for ( tok = tok2 ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel2 ;
}
if ( tok - > str ( ) = = " } " )
{
- - indentlevel2 ;
if ( indentlevel2 < = 0 )
{
tok = tok - > next ( ) ;
break ;
}
}
}
break ;
}
if ( Token : : Match ( tok2 , " [,);] " ) )
{
break ;
}
}
if ( ! tok )
break ;
}
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel = = 0 )
func = false ;
}
2009-05-21 17:55:52 +02:00
if ( indentlevel = = 0 & & Token : : simpleMatch ( tok , " ) { " ) )
2009-01-26 20:14:46 +01:00
{
func = true ;
}
if ( indentlevel > 0 & & func & & Token : : Match ( tok , " [{};] " ) )
{
// First token of statement..
const Token * tok1 = tok - > next ( ) ;
if ( ! tok1 )
continue ;
if ( ( tok1 - > str ( ) = = " return " ) | |
2009-03-24 20:59:56 +01:00
( tok1 - > str ( ) = = " throw " ) | |
2009-01-26 20:14:46 +01:00
( tok1 - > str ( ) = = " delete " ) | |
( tok1 - > str ( ) = = " goto " ) | |
( tok1 - > str ( ) = = " else " ) )
continue ;
// Variable declaration?
2009-06-12 16:17:51 +02:00
if ( Token : : Match ( tok1 , " %type% %var% [;=] " ) )
2009-01-26 20:14:46 +01:00
{
2009-07-05 22:16:43 +02:00
lookupVar ( tok1 , tok1 - > strAt ( 1 ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : lookupVar ( const Token * tok1 , const char varname [ ] )
2009-01-26 20:14:46 +01:00
{
const Token * tok = tok1 ;
// Skip the variable declaration..
2009-05-21 17:55:52 +02:00
while ( tok & & ! Token : : simpleMatch ( tok , " ; " ) )
2009-01-26 20:14:46 +01:00
tok = tok - > next ( ) ;
// Check if the variable is used in this indentlevel..
bool used = false , used1 = false ;
int indentlevel = 0 ;
int parlevel = 0 ;
bool for_or_while = false ;
2009-06-12 16:17:51 +02:00
while ( tok )
2009-01-26 20:14:46 +01:00
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
2009-06-12 16:17:51 +02:00
if ( indentlevel = = 0 )
break ;
2009-01-26 20:14:46 +01:00
- - indentlevel ;
if ( indentlevel = = 0 )
{
if ( for_or_while & & used )
return ;
2009-03-24 20:28:44 +01:00
used1 | = used ;
2009-01-26 20:14:46 +01:00
used = false ;
}
}
else if ( tok - > str ( ) = = " ( " )
{
+ + parlevel ;
}
else if ( tok - > str ( ) = = " ) " )
{
- - parlevel ;
}
2009-05-27 19:38:26 +02:00
// Bail out if references are used
else if ( Token : : simpleMatch ( tok , ( std : : string ( " & " ) + varname ) . c_str ( ) ) )
{
return ;
}
2009-01-26 20:14:46 +01:00
else if ( tok - > str ( ) = = varname )
{
if ( indentlevel = = 0 | | used1 )
return ;
used = true ;
}
else if ( indentlevel = = 0 )
{
if ( ( tok - > str ( ) = = " for " ) | | ( tok - > str ( ) = = " while " ) )
for_or_while = true ;
if ( parlevel = = 0 & & ( tok - > str ( ) = = " ; " ) )
for_or_while = false ;
}
tok = tok - > next ( ) ;
}
2009-06-12 16:17:51 +02:00
// Warning if this variable:
// * not used in this indentlevel
// * used in lower indentlevel
if ( ! used & & used1 )
variableScopeError ( tok1 , varname ) ;
2009-01-26 20:14:46 +01:00
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check for constant function parameters
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkConstantFunctionParameter ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " [,(] const std :: %type% %var% [,)] " ) )
{
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 5 ) ) ;
2009-01-26 20:14:46 +01:00
}
else if ( Token : : Match ( tok , " [,(] const %type% %var% [,)] " ) )
{
// Check if type is a struct or class.
const std : : string pattern ( std : : string ( " class|struct " ) + tok - > strAt ( 2 ) ) ;
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
{
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 3 ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check that all struct members are used
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkStructMemberUsage ( )
2009-01-26 20:14:46 +01:00
{
const char * structname = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > fileIndex ( ) ! = 0 )
continue ;
if ( Token : : Match ( tok , " struct|union %type% { " ) )
{
structname = tok - > strAt ( 1 ) ;
// Bail out if struct/union contain any functions
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
{
structname = 0 ;
break ;
}
if ( tok2 - > str ( ) = = " } " )
break ;
}
}
if ( tok - > str ( ) = = " } " )
structname = 0 ;
if ( structname & & Token : : Match ( tok , " [{;] " ) )
{
const char * varname = 0 ;
if ( Token : : Match ( tok - > next ( ) , " %type% %var% [;[] " ) )
varname = tok - > strAt ( 2 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% %var% [ ; [ ] " ))
varname = tok - > strAt ( 3 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% * %var% [ ; [ ] " ))
varname = tok - > strAt ( 3 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% * %var% [ ; [ ] " ))
varname = tok - > strAt ( 4 ) ;
else
continue ;
const std : : string usagePattern ( " . " + std : : string ( varname ) ) ;
bool used = false ;
for ( const Token * tok2 = _tokenizer - > tokens ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( Token : : simpleMatch ( tok2 , usagePattern . c_str ( ) ) )
{
used = true ;
break ;
}
}
if ( ! used )
{
2009-03-21 17:58:13 +01:00
unusedStructMemberError ( tok - > next ( ) , structname , varname ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
// Check usage of char variables..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkCharVariable ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Declaring the variable..
2009-02-04 18:12:53 +01:00
if ( Token : : Match ( tok , " [{};(,] signed| char %var% [;=,)] " ) )
2009-01-26 20:14:46 +01:00
{
// Set tok to point to the variable name
tok = tok - > tokAt ( 2 ) ;
2009-02-04 18:12:53 +01:00
if ( tok - > str ( ) = = " char " )
tok = tok - > next ( ) ;
2009-01-26 20:14:46 +01:00
// Check usage of char variable..
int indentlevel = 0 ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < = 0 )
break ;
}
2009-03-23 19:04:51 +01:00
else if ( tok2 - > str ( ) = = " return " )
continue ;
2009-01-26 20:14:46 +01:00
std : : string temp = " %var% [ " + tok - > str ( ) + " ] " ;
if ( ( tok2 - > str ( ) ! = " . " ) & & Token : : Match ( tok2 - > next ( ) , temp . c_str ( ) ) )
{
2009-03-21 17:58:13 +01:00
charArrayIndexError ( tok2 - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
break ;
}
2009-06-20 19:24:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] %var% = %any% [&|] %any% ; " ) )
2009-01-26 20:14:46 +01:00
{
2009-06-20 19:24:58 +02:00
// is the char variable used in the calculation?
if ( tok2 - > tokAt ( 3 ) - > varId ( ) ! = tok - > varId ( ) & & tok2 - > tokAt ( 5 ) - > varId ( ) ! = tok - > varId ( ) )
continue ;
// it's ok with a bitwise and where the other operand is 0xff or less..
if ( std : : string ( tok2 - > strAt ( 4 ) ) = = " & " )
{
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 3 ) ) )
continue ;
if ( tok2 - > tokAt ( 5 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 5 ) ) )
continue ;
}
// is the result stored in a short|int|long?
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , " short|int|long %varid% " , tok2 - > next ( ) - > varId ( ) ) )
continue ;
// This is an error..
2009-03-21 17:58:13 +01:00
charBitOpError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
break ;
}
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Incomplete statement..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkIncompleteStatement ( )
2009-01-26 20:14:46 +01:00
{
int parlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok - > str ( ) = = " ) " )
- - parlevel ;
if ( parlevel ! = 0 )
continue ;
2009-05-21 17:55:52 +02:00
if ( Token : : simpleMatch ( tok , " = { " ) )
2009-02-11 16:17:13 +01:00
{
2009-02-12 13:59:43 +01:00
/* We are in an assignment, so it's not a statement.
* Skip until " ; " */
2009-05-21 17:55:52 +02:00
while ( ! Token : : simpleMatch ( tok , " ; " ) )
2009-02-12 13:59:43 +01:00
{
int level = 0 ;
do
{
if ( tok - > str ( ) = = " ( " | | tok - > str ( ) = = " { " )
+ + level ;
else if ( tok - > str ( ) = = " ) " | | tok - > str ( ) = = " } " )
- - level ;
tok = tok - > next ( ) ;
if ( tok = = NULL )
return ;
}
while ( level > 0 ) ;
}
2009-02-11 16:17:13 +01:00
continue ;
}
2009-02-05 19:57:53 +01:00
if ( Token : : Match ( tok , " [;{}] %str% " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) , " [,}] " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
constStatementError ( tok - > next ( ) , " string " ) ;
2009-01-26 20:14:46 +01:00
}
2009-02-05 19:57:53 +01:00
if ( Token : : Match ( tok , " [;{}] %num% " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) , " [,}] " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
constStatementError ( tok - > next ( ) , " numeric " ) ;
2009-01-26 20:14:46 +01:00
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// str plus char
//---------------------------------------------------------------------------
void CheckOther : : strPlusChar ( )
{
bool charVars [ 10000 ] = { 0 } ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Declaring char variable..
if ( Token : : Match ( tok , " char %var% [;=] " ) )
{
unsigned int varid = tok - > next ( ) - > varId ( ) ;
if ( varid > 0 & & varid < 10000 )
charVars [ varid ] = true ;
}
//
else if ( Token : : Match ( tok , " [=(] %str% + %any% " ) )
{
// char constant..
const char * s = tok - > strAt ( 3 ) ;
if ( * s = = ' \' ' )
2009-03-21 17:58:13 +01:00
strPlusChar ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
// char variable..
unsigned int varid = tok - > tokAt ( 3 ) - > varId ( ) ;
if ( varid > 0 & & varid < 10000 & & charVars [ varid ] )
2009-03-21 17:58:13 +01:00
strPlusChar ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-02-04 19:49:19 +01:00
2009-03-27 17:19:34 +01:00
void CheckOther : : nullPointer ( )
{
// Locate insufficient null-pointer handling after loop
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ! Token : : Match ( tok , " while ( %var% ) " ) )
continue ;
const unsigned int varid ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
// Locate the end of the while loop..
const Token * tok2 = tok - > tokAt ( 4 ) ;
int indentlevel = 0 ;
while ( tok2 )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
}
else if ( indentlevel = = 0 & & tok2 - > str ( ) = = " ; " )
break ;
tok2 = tok2 - > next ( ) ;
}
// Goto next token
tok2 = tok2 ? tok2 - > next ( ) : 0 ;
// Check if the variable is dereferenced..
while ( tok2 )
{
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " } " )
break ;
if ( tok2 - > varId ( ) = = varid )
{
if ( tok2 - > next ( ) - > str ( ) = = " . " | | Token : : Match ( tok2 - > next ( ) , " = %varid% . " , varid ) )
2009-05-10 08:43:16 +02:00
{
// Is this variable a pointer?
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)] " , varid ) ;
if ( ! tok3 )
break ;
if ( ! tok3 - > previous ( ) | |
Token : : Match ( tok3 - > previous ( ) , " [({};] " ) | |
tok3 - > previous ( ) - > isName ( ) )
{
nullPointerError ( tok2 ) ;
}
}
2009-03-27 17:19:34 +01:00
break ;
}
tok2 = tok2 - > next ( ) ;
}
}
}
2009-07-05 22:16:43 +02:00
void CheckOther : : checkZeroDivision ( )
2009-03-28 07:49:47 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : simpleMatch ( tok , " / 0 " ) )
2009-03-29 18:47:05 +02:00
zerodivError ( tok ) ;
2009-03-28 07:49:47 +01:00
}
}
2009-03-21 17:58:13 +01:00
void CheckOther : : cstyleCastError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " cstyleCast " , " C-style pointer casting " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : redundantIfDelete0Error ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " redundantIfDelete0 " , " Redundant condition. It is safe to deallocate a NULL pointer " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : redundantIfRemoveError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " redundantIfRemove " , " Redundant condition. The remove function in the STL will not do anything if element doesn't exist " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : dangerousUsageStrtolError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " dangerousUsageStrtol " , " Invalid radix in call to strtol or strtoul. Must be 0 or 2-36 " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : ifNoActionError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " ifNoAction " , " Found redundant if condition - 'if (condition);' " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : sprintfOverlappingDataError ( const Token * tok , const std : : string & varname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " sprintfOverlappingData " , " Overlapping data buffer " + varname + " \n When using sprintf the same buffer must not be used both for output and input. The behaviour is undefined when that happens. \n For example: 'sprintf(str, \" <%s> \" ,str);' " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : udivError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " udivError " , " Unsigned division. The result will be wrong. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : udivWarning ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : possibleStyle , " udivWarning " , " Warning: Division with signed and unsigned operators " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : unusedStructMemberError ( const Token * tok , const std : : string & structname , const std : : string & varname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " unusedStructMember " , " struct or union member ' " + structname + " :: " + varname + " ' is never used " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : passedByValueError ( const Token * tok , const std : : string & parname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " passedByValue " , " Function parameter ' " + parname + " ' is passed by value. It could be passed by reference instead. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : constStatementError ( const Token * tok , const std : : string & type )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " constStatement " , " Redundant code: Found a statement that begins with " + type + " constant " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : charArrayIndexError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " charArrayIndex " , " Warning - using char variable as array index " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : charBitOpError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " charBitOp " , " Warning - using char variable in bit operation " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : variableScopeError ( const Token * tok , const std : : string & varname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " variableScope " , " The scope of the variable " + varname + " can be limited " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : conditionAlwaysTrueFalse ( const Token * tok , const std : : string & truefalse )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " conditionAlwaysTrueFalse " , " Condition is always " + truefalse ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : strPlusChar ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " strPlusChar " , " Unusual pointer arithmetic " ) ;
2009-03-21 17:58:13 +01:00
}
2009-03-27 17:19:34 +01:00
void CheckOther : : nullPointerError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference " ) ;
2009-03-27 17:19:34 +01:00
}
2009-03-28 07:49:47 +01:00
2009-03-29 18:47:05 +02:00
void CheckOther : : zerodivError ( const Token * tok )
2009-03-28 07:49:47 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " zerodiv " , " Division by zero " ) ;
2009-03-28 07:49:47 +01:00
}