2009-01-26 20:14: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 .
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
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-26 20:14:46 +01:00
*/
//---------------------------------------------------------------------------
# include "checkother.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-12-14 20:30:31 +01:00
# include "executionpath.h"
2009-03-20 18:16:21 +01:00
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-12-06 18:41:28 +01:00
# include <memory>
2010-04-02 20:23:37 +02:00
# include <cmath> // fabs()
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
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
{
2010-04-25 14:56:04 +02:00
if ( ! _settings - > _checkCodingStyle | |
( _tokenizer - > tokens ( ) & & _tokenizer - > fileLine ( _tokenizer - > tokens ( ) ) . find ( " .cpp " ) = = std : : string : : npos ) )
2010-04-21 08:38:25 +02:00
return ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
// Old style pointer casting..
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " ( const| %type% * ) %var% " ) & &
! Token : : Match ( tok , " ( const| %type% * ) (| new " ) )
2009-01-26 20:14:46 +01:00
continue ;
2009-07-20 21:52:27 +02:00
int addToIndex = 0 ;
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 1 ) - > str ( ) = = " const " )
2009-07-20 21:52:27 +02:00
addToIndex = 1 ;
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 4 + addToIndex ) - > str ( ) = = " const " )
2009-06-18 22:26:21 +02:00
continue ;
2009-01-26 20:14:46 +01:00
// Is "type" a class?
2009-07-20 21:52:27 +02:00
const std : : string pattern ( " class " + tok - > tokAt ( 1 + addToIndex ) - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
2009-01-26 20:14:46 +01:00
continue ;
2009-03-21 17:58:13 +01:00
cstyleCastError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
}
//---------------------------------------------------------------------------
2010-04-13 19:30:25 +02:00
// "if (strlen(s))" can be rewritten as "if (*s != '\0')"
//---------------------------------------------------------------------------
void CheckOther : : checkEmptyStringTest ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-04-13 19:30:25 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Non-empty string tests
if ( Token : : Match ( tok , " if ( strlen ( %any% ) ) " ) )
{
emptyStringTestError ( tok , tok - > strAt ( 4 ) , false ) ;
}
else if ( Token : : Match ( tok , " strlen ( %any% ) !=|> 0 " ) )
{
emptyStringTestError ( tok , tok - > strAt ( 2 ) , false ) ;
}
else if ( Token : : Match ( tok , " 0 < strlen ( %any% ) " ) )
{
emptyStringTestError ( tok , tok - > strAt ( 4 ) , false ) ;
}
2009-01-26 20:14:46 +01:00
2010-04-13 19:30:25 +02:00
// Empty string tests
else if ( Token : : Match ( tok , " ! strlen ( %any% ) " ) )
{
emptyStringTestError ( tok , tok - > strAt ( 3 ) , true ) ;
}
else if ( Token : : Match ( tok , " strlen ( %any% ) == 0 " ) )
{
emptyStringTestError ( tok , tok - > strAt ( 2 ) , true ) ;
}
}
}
2010-05-04 08:14:45 +02:00
//---------------------------------------------------------------------------
// fflush(stdin) <- fflush only applies to output streams in ANSI C
//---------------------------------------------------------------------------
void CheckOther : : checkFflushOnInputStream ( )
{
2010-05-07 08:08:10 +02:00
const Token * tok = _tokenizer - > tokens ( ) ;
2010-05-18 19:19:15 +02:00
while ( tok & & ( ( tok = Token : : findmatch ( tok , " fflush ( stdin ) " ) ) ! = NULL ) )
2010-05-04 08:14:45 +02:00
{
2010-05-07 08:08:10 +02:00
fflushOnInputStreamError ( tok , tok - > strAt ( 2 ) ) ;
tok = tok - > tokAt ( 4 ) ;
2010-05-04 08:14:45 +02:00
}
}
2009-01-26 20:14:46 +01:00
2010-06-30 09:10:30 +02:00
//---------------------------------------------------------------------------
// switch (x)
// {
// case 2:
// y = a; // <- this assignment is redundant
// case 3:
// y = b; // <- case 2 falls through and sets y twice
// }
//---------------------------------------------------------------------------
void CheckOther : : checkRedundantAssignmentInSwitch ( )
{
const char switchPattern [ ] = " switch ( %any% ) { case " ;
2010-09-04 14:24:45 +02:00
const char breakPattern [ ] = " break|continue|return|exit|goto " ;
2010-06-30 09:10:30 +02:00
const char functionPattern [ ] = " %var% ( " ;
// Find the beginning of a switch. E.g.:
// switch (var) { ...
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , switchPattern ) ;
while ( tok )
{
// Check the contents of the switch statement
std : : map < unsigned int , const Token * > varsAssigned ;
int indentLevel = 0 ;
for ( const Token * tok2 = tok - > tokAt ( 5 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
{
// Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
// case 3: b = 1;
// case 4: if (a) { b = 2; } // Doesn't make the b=1 redundant because it's conditional
if ( Token : : Match ( tok2 - > previous ( ) , " )|else { " ) & & tok2 - > link ( ) )
{
const Token * endOfConditional = tok2 - > link ( ) ;
for ( const Token * tok3 = tok2 ; tok3 ! = endOfConditional ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > varId ( ) ! = 0 )
varsAssigned . erase ( tok3 - > varId ( ) ) ;
else if ( Token : : Match ( tok3 , functionPattern ) | | Token : : Match ( tok3 , breakPattern ) )
varsAssigned . clear ( ) ;
}
tok2 = endOfConditional ;
}
else
+ + indentLevel ;
}
else if ( tok2 - > str ( ) = = " } " )
{
- - indentLevel ;
// End of the switch block
if ( indentLevel < 0 )
break ;
}
// Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
// case 3: b = 1; // <== redundant
// case 4: b = 2;
if ( Token : : Match ( tok2 - > previous ( ) , " ;|{|}|: %var% = %any% ; " ) & & tok2 - > varId ( ) ! = 0 )
{
std : : map < unsigned int , const Token * > : : iterator i = varsAssigned . find ( tok2 - > varId ( ) ) ;
if ( i = = varsAssigned . end ( ) )
varsAssigned [ tok2 - > varId ( ) ] = tok2 ;
else
redundantAssignmentInSwitchError ( i - > second , i - > second - > str ( ) ) ;
}
// Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
// case 3: b = 1;
// case 4: b++;
else if ( tok2 - > varId ( ) ! = 0 )
varsAssigned . erase ( tok2 - > varId ( ) ) ;
// Reset our record of assignments if there is a break or function call. E.g.:
// case 3: b = 1; break;
if ( Token : : Match ( tok2 , functionPattern ) | | Token : : Match ( tok2 , breakPattern ) )
varsAssigned . clear ( ) ;
}
tok = Token : : findmatch ( tok - > next ( ) , switchPattern ) ;
}
}
2010-08-15 06:28:22 +02:00
//---------------------------------------------------------------------------
// int x = 1;
// x = x; // <- redundant assignment to self
//
// int y = y; // <- redundant initialization to self
//---------------------------------------------------------------------------
void CheckOther : : checkSelfAssignment ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
const char selfAssignmentPattern [ ] = " %var% = %var% ;|=|) " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , selfAssignmentPattern ) ;
while ( tok )
{
if ( tok - > varId ( ) & & tok - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) )
{
selfAssignmentError ( tok , tok - > str ( ) ) ;
}
tok = Token : : findmatch ( tok - > next ( ) , selfAssignmentPattern ) ;
}
}
2010-10-10 22:05:06 +02:00
//---------------------------------------------------------------------------
// int a = 1;
// assert(a = 2); // <- assert should not have a side-effect
//---------------------------------------------------------------------------
void CheckOther : : checkAssignmentInAssert ( )
{
2010-10-11 17:59:08 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-10-10 22:05:06 +02:00
const char assertPattern [ ] = " assert ( %any% " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , assertPattern ) ;
const Token * endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
while ( tok & & endTok )
{
const Token * varTok = Token : : findmatch ( tok - > tokAt ( 2 ) , " %var% --|++|+=|-=|*=|/=|&=|^=|= " , endTok ) ;
if ( varTok )
{
assignmentInAssertError ( tok , varTok - > str ( ) ) ;
}
2010-10-24 11:52:28 +02:00
else if ( NULL ! = ( varTok = Token : : findmatch ( tok - > tokAt ( 2 ) , " --|++ %var% " , endTok ) ) )
2010-10-10 22:05:06 +02:00
{
assignmentInAssertError ( tok , varTok - > strAt ( 1 ) ) ;
}
tok = Token : : findmatch ( endTok - > next ( ) , assertPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
}
}
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..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ( tok - > str ( ) ! = " strtol " ) & & ( tok - > str ( ) ! = " strtoul " ) )
2009-01-26 20:14:46 +01:00
continue ;
// Locate the third parameter of the function call..
int parlevel = 0 ;
int param = 1 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-01-26 20:14:46 +01:00
- - parlevel ;
2010-04-02 07:30:58 +02:00
else if ( parlevel = = 1 & & tok2 - > str ( ) = = " , " )
2009-01-26 20:14:46 +01:00
{
+ + param ;
2010-04-02 07:30:58 +02:00
if ( param = = 3 )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " , %num% ) " ) )
2009-01-26 20:14:46 +01:00
{
2009-05-02 10:45:15 +02:00
int radix = MathLib : : toLongNumber ( tok2 - > next ( ) - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! ( radix = = 0 | | ( radix > = 2 & & radix < = 36 ) ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
dangerousUsageStrtolError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
}
}
break ;
}
}
}
}
// sprintf|snprintf overlapping data
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
// Get variable id of target buffer..
unsigned int varid = 0 ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " sprintf|snprintf ( %var% , " ) )
2009-01-26 20:14:46 +01:00
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " sprintf|snprintf ( %var% . %var% , " ) )
2009-01-26 20:14:46 +01:00
varid = tok - > tokAt ( 4 ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-01-26 20:14:46 +01:00
continue ;
// goto ","
const Token * tok2 = tok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " , " )
2009-01-26 20:14:46 +01:00
tok2 = tok2 - > next ( ) ;
// is any source buffer overlapping the target buffer?
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
while ( ( tok2 = tok2 - > next ( ) ) ! = NULL )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-01-26 20:14:46 +01:00
{
- - parlevel ;
2010-04-02 07:30:58 +02:00
if ( parlevel < 0 )
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30:58 +02: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 ;
}
}
}
}
//---------------------------------------------------------------------------
2010-08-14 15:15:12 +02:00
void CheckOther : : invalidScanf ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
const Token * formatToken = 0 ;
if ( Token : : Match ( tok , " scanf|vscanf ( %str% , " ) )
formatToken = tok - > tokAt ( 2 ) ;
else if ( Token : : Match ( tok , " fscanf|vfscanf ( %var% , %str% , " ) )
formatToken = tok - > tokAt ( 4 ) ;
else
continue ;
bool format = false ;
// scan the string backwards, so we dont need to keep states
const std : : string & formatstr ( formatToken - > str ( ) ) ;
for ( unsigned int i = 1 ; i < formatstr . length ( ) ; i + + )
{
if ( formatstr [ i ] = = ' % ' )
format = ! format ;
else if ( ! format )
continue ;
else if ( std : : isdigit ( formatstr [ i ] ) )
{
format = false ;
}
else if ( std : : isalpha ( formatstr [ i ] ) )
{
invalidScanfError ( tok ) ;
format = false ;
}
}
}
}
void CheckOther : : invalidScanfError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-08-14 18:35:48 +02:00
" invalidscanf " , " scanf without field width limits can crash with huge input data \n "
" To fix this error message add a field width specifier: \n "
" %s => %20s \n "
" %i => %3i \n "
" \n "
" Sample program that can crash: \n "
" \n "
" #include <stdio.h> \n "
" int main() \n "
" { \n "
" int a; \n "
" scanf( \" %i \" , &a); \n "
" return 0; \n "
" } \n "
" \n "
" To make it crash: \n "
" perl -e 'print \" 5 \" x2100000' | ./a.out " ) ;
2010-08-14 15:15:12 +02:00
}
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
// Check for unsigned divisions
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkUnsignedDivision ( )
2009-01-26 20:14:46 +01:00
{
2010-05-16 14:43:42 +02:00
if ( ! _settings - > _checkCodingStyle )
2009-09-15 20:46:47 +02:00
return ;
2009-01-26 20:14:46 +01:00
// Check for "ivar / uvar" and "uvar / ivar"
2009-10-11 16:52:35 +02:00
std : : map < unsigned int , char > varsign ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [{};(,] %type% %var% [;=,)] " ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 1 ) - > isUnsigned ( ) )
2010-03-28 15:56:13 +02:00
varsign [ tok - > tokAt ( 2 ) - > varId ( ) ] = ' u ' ;
else
2009-10-11 16:52:35 +02:00
varsign [ tok - > tokAt ( 2 ) - > varId ( ) ] = ' s ' ;
2009-01-26 20:14:46 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( ! Token : : Match ( tok , " [).] " ) & & Token : : Match ( tok - > next ( ) , " %var% / %num% " ) )
2009-01-26 20:14:46 +01:00
{
2010-05-16 14:43:42 +02:00
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' )
2009-01-26 20:14:46 +01:00
{
2009-10-11 16:52:35 +02:00
char sign1 = varsign [ tok - > tokAt ( 1 ) - > varId ( ) ] ;
2010-04-02 07:30:58 +02:00
if ( sign1 = = ' u ' )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [([=*/+-,] %num% / %var% " ) )
2009-01-26 20:14:46 +01:00
{
2010-05-16 14:43:42 +02:00
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' )
2009-01-26 20:14:46 +01:00
{
2009-10-11 16:52:35 +02:00
char sign2 = varsign [ tok - > tokAt ( 3 ) - > varId ( ) ] ;
2010-04-02 07:30:58 +02:00
if ( sign2 = = ' u ' )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
}
//---------------------------------------------------------------------------
2010-02-18 18:45:13 +01:00
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
static bool isOp ( const Token * tok )
{
return bool ( tok & &
( tok - > str ( ) = = " && " | |
tok - > str ( ) = = " || " | |
tok - > str ( ) = = " == " | |
tok - > str ( ) = = " != " | |
tok - > str ( ) = = " < " | |
tok - > str ( ) = = " <= " | |
tok - > str ( ) = = " > " | |
tok - > str ( ) = = " >= " | |
tok - > str ( ) = = " << " | |
Token : : Match ( tok , " [+-*/%&!~|^,[])?:] " ) ) ) ;
}
2010-07-12 09:50:18 +02:00
/**
* @ brief This class is used to capture the control flow within a function .
*/
class Scope
{
public :
Scope ( ) : _token ( NULL ) , _parent ( NULL ) { }
Scope ( const Token * token , Scope * parent_ ) : _token ( token ) , _parent ( parent_ ) { }
~ Scope ( ) ;
Scope * parent ( )
{
return _parent ;
}
Scope * addChild ( const Token * token ) ;
void remove ( Scope * scope ) ;
private :
const Token * _token ;
Scope * _parent ;
std : : list < Scope * > _children ;
} ;
Scope : : ~ Scope ( )
{
while ( ! _children . empty ( ) )
{
delete * _children . begin ( ) ;
_children . pop_front ( ) ;
}
}
Scope * Scope : : addChild ( const Token * token )
{
Scope * temp = new Scope ( token , this ) ;
_children . push_back ( temp ) ;
return temp ;
}
void Scope : : remove ( Scope * scope )
{
std : : list < Scope * > : : iterator it ;
for ( it = _children . begin ( ) ; it ! = _children . end ( ) ; + + it )
{
if ( * it = = scope )
{
delete * it ;
_children . erase ( it ) ;
break ;
}
}
}
/**
* @ brief This class is used create a list of variables within a function .
*/
2010-04-27 05:05:32 +02:00
class Variables
2010-02-21 07:05:44 +01:00
{
public :
2010-06-23 06:54:14 +02:00
enum VariableType { standard , array , pointer , reference , pointerArray , referenceArray , pointerPointer } ;
2010-04-29 07:10:50 +02:00
2010-04-27 05:05:32 +02:00
/** Store information about variable usage */
2010-04-24 09:45:03 +02:00
class VariableUsage
2010-02-21 07:05:44 +01:00
{
2010-04-24 09:45:03 +02:00
public :
VariableUsage ( const Token * name = 0 ,
2010-04-29 07:10:50 +02:00
VariableType type = standard ,
2010-07-12 09:50:18 +02:00
Scope * scope = NULL ,
2010-04-24 09:45:03 +02:00
bool read = false ,
bool write = false ,
2010-05-01 09:26:47 +02:00
bool modified = false ) :
2010-04-24 09:45:03 +02:00
_name ( name ) ,
_type ( type ) ,
2010-07-12 09:50:18 +02:00
_scope ( scope ) ,
2010-04-24 09:45:03 +02:00
_read ( read ) ,
_write ( write ) ,
2010-06-16 17:57:56 +02:00
_modified ( modified )
2010-04-24 09:45:03 +02:00
{
}
/** variable is used.. set both read+write */
void use ( )
{
_read = true ;
_write = true ;
}
/** is variable unused? */
bool unused ( ) const
{
return ( _read = = false & & _write = = false ) ;
}
const Token * _name ;
2010-04-29 07:10:50 +02:00
VariableType _type ;
2010-07-12 09:50:18 +02:00
Scope * _scope ;
2010-04-24 09:45:03 +02:00
bool _read ;
bool _write ;
bool _modified ; // read/modify/write
2010-04-29 07:10:50 +02:00
std : : set < unsigned int > _aliases ;
2010-07-12 09:50:18 +02:00
std : : set < Scope * > _assignments ;
2010-04-24 09:45:03 +02:00
} ;
2010-04-27 05:05:32 +02:00
typedef std : : map < unsigned int , VariableUsage > VariableMap ;
2010-04-24 09:45:03 +02:00
void clear ( )
{
_varUsage . clear ( ) ;
}
2010-04-29 07:10:50 +02:00
VariableMap & varUsage ( )
2010-04-24 09:45:03 +02:00
{
return _varUsage ;
2010-02-21 07:05:44 +01:00
}
2010-07-12 09:50:18 +02:00
void addVar ( const Token * name , VariableType type , Scope * scope , bool write_ ) ;
2010-04-27 05:05:32 +02:00
void read ( unsigned int varid ) ;
2010-04-29 07:10:50 +02:00
void readAliases ( unsigned int varid ) ;
void readAll ( unsigned int varid ) ;
2010-04-27 05:05:32 +02:00
void write ( unsigned int varid ) ;
2010-04-29 07:10:50 +02:00
void writeAliases ( unsigned int varid ) ;
void writeAll ( unsigned int varid ) ;
2010-04-27 05:05:32 +02:00
void use ( unsigned int varid ) ;
void modified ( unsigned int varid ) ;
VariableUsage * find ( unsigned int varid ) ;
2010-07-08 07:59:47 +02:00
void alias ( unsigned int varid1 , unsigned int varid2 , bool replace ) ;
2010-04-29 07:10:50 +02:00
void erase ( unsigned int varid )
{
_varUsage . erase ( varid ) ;
}
2010-05-04 17:26:09 +02:00
void eraseAliases ( unsigned int varid ) ;
void eraseAll ( unsigned int varid ) ;
2010-06-16 17:57:56 +02:00
void clearAliases ( unsigned int varid ) ;
2010-05-04 17:28:03 +02:00
2010-04-27 05:05:32 +02:00
private :
VariableMap _varUsage ;
2010-04-24 09:45:03 +02:00
} ;
2010-07-08 07:59:47 +02:00
/**
* Alias the 2 given variables . Either replace the existing aliases if
* they exist or merge them . You would replace an existing alias when this
* assignment is in the same scope as the previous assignment . You might
* merge the aliases when this assignment is in a different scope from the
* previous assignment depending on the relationship of the 2 scopes .
*/
void Variables : : alias ( unsigned int varid1 , unsigned int varid2 , bool replace )
2010-04-29 07:10:50 +02:00
{
2010-07-08 07:59:47 +02:00
VariableUsage * var1 = find ( varid1 ) ;
VariableUsage * var2 = find ( varid2 ) ;
2010-04-30 21:36:48 +02:00
// alias to self
if ( varid1 = = varid2 )
{
2010-07-08 07:59:47 +02:00
if ( var1 )
var1 - > use ( ) ;
2010-04-30 21:36:48 +02:00
return ;
}
2010-04-29 07:10:50 +02:00
std : : set < unsigned int > : : iterator i ;
2010-07-08 07:59:47 +02:00
if ( replace )
2010-04-29 07:10:50 +02:00
{
2010-07-08 07:59:47 +02:00
// remove var1 from all aliases
for ( i = var1 - > _aliases . begin ( ) ; i ! = var1 - > _aliases . end ( ) ; + + i )
{
VariableUsage * temp = find ( * i ) ;
2010-04-29 07:10:50 +02:00
2010-07-08 07:59:47 +02:00
if ( temp )
temp - > _aliases . erase ( var1 - > _name - > varId ( ) ) ;
}
2010-04-29 07:10:50 +02:00
2010-07-08 07:59:47 +02:00
// remove all aliases from var1
var1 - > _aliases . clear ( ) ;
}
2010-04-29 07:10:50 +02:00
// var1 gets all var2s aliases
for ( i = var2 - > _aliases . begin ( ) ; i ! = var2 - > _aliases . end ( ) ; + + i )
{
if ( * i ! = varid1 )
var1 - > _aliases . insert ( * i ) ;
}
// var2 is an alias of var1
var2 - > _aliases . insert ( varid1 ) ;
var1 - > _aliases . insert ( varid2 ) ;
if ( var2 - > _type = = Variables : : pointer )
var2 - > _read = true ;
}
2010-06-16 17:57:56 +02:00
void Variables : : clearAliases ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
if ( usage )
{
// remove usage from all aliases
std : : set < unsigned int > : : iterator i ;
for ( i = usage - > _aliases . begin ( ) ; i ! = usage - > _aliases . end ( ) ; + + i )
{
VariableUsage * temp = find ( * i ) ;
if ( temp )
temp - > _aliases . erase ( usage - > _name - > varId ( ) ) ;
}
// remove all aliases from usage
usage - > _aliases . clear ( ) ;
}
}
2010-05-04 17:26:09 +02:00
void Variables : : eraseAliases ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
if ( usage )
{
std : : set < unsigned int > : : iterator aliases ;
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
erase ( * aliases ) ;
}
}
void Variables : : eraseAll ( unsigned int varid )
{
eraseAliases ( varid ) ;
erase ( varid ) ;
}
2010-04-29 07:10:50 +02:00
void Variables : : addVar ( const Token * name ,
VariableType type ,
2010-07-12 09:50:18 +02:00
Scope * scope ,
2010-05-01 09:26:47 +02:00
bool write_ )
2010-04-29 07:10:50 +02:00
{
2010-07-07 08:50:34 +02:00
if ( name - > varId ( ) > 0 )
2010-07-12 09:50:18 +02:00
_varUsage . insert ( std : : make_pair ( name - > varId ( ) , VariableUsage ( name , type , scope , false , write_ , false ) ) ) ;
2010-04-29 07:10:50 +02:00
}
2010-04-27 05:05:32 +02:00
void Variables : : read ( unsigned int varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
VariableUsage * usage = find ( varid ) ;
2010-02-21 07:05:44 +01:00
2010-04-29 07:10:50 +02:00
if ( usage )
usage - > _read = true ;
}
void Variables : : readAliases ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
if ( usage )
{
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > _read = true ;
2010-04-29 07:10:50 +02:00
}
}
}
void Variables : : readAll ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
2010-04-27 05:05:32 +02:00
if ( usage )
2010-02-21 07:05:44 +01:00
{
2010-04-27 05:05:32 +02:00
usage - > _read = true ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > _read = true ;
2010-04-29 07:10:50 +02:00
}
2010-02-21 07:05:44 +01:00
}
2010-04-24 09:45:03 +02:00
}
2010-04-27 05:05:32 +02:00
void Variables : : write ( unsigned int varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
VariableUsage * usage = find ( varid ) ;
2010-02-21 07:05:44 +01:00
2010-04-29 07:10:50 +02:00
if ( usage )
usage - > _write = true ;
}
void Variables : : writeAliases ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
if ( usage )
{
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > _write = true ;
2010-04-29 07:10:50 +02:00
}
}
}
void Variables : : writeAll ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
2010-04-27 05:05:32 +02:00
if ( usage )
2010-02-21 07:05:44 +01:00
{
2010-04-27 05:05:32 +02:00
usage - > _write = true ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > _write = true ;
2010-04-29 07:10:50 +02:00
}
2010-02-21 07:05:44 +01:00
}
2010-04-24 09:45:03 +02:00
}
2010-04-27 05:05:32 +02:00
void Variables : : use ( unsigned int varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
VariableUsage * usage = find ( varid ) ;
2010-02-21 07:05:44 +01:00
2010-04-27 05:05:32 +02:00
if ( usage )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
usage - > use ( ) ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > use ( ) ;
2010-04-29 07:10:50 +02:00
}
2010-04-24 09:45:03 +02:00
}
}
2010-04-29 07:10:50 +02:00
2010-04-27 05:05:32 +02:00
void Variables : : modified ( unsigned int varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
VariableUsage * usage = find ( varid ) ;
2010-04-24 09:45:03 +02:00
2010-04-27 05:05:32 +02:00
if ( usage )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
usage - > _modified = true ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
std : : set < unsigned int > : : iterator aliases ;
2010-05-04 17:28:03 +02:00
2010-06-16 17:57:56 +02:00
for ( aliases = usage - > _aliases . begin ( ) ; aliases ! = usage - > _aliases . end ( ) ; + + aliases )
{
VariableUsage * aliased = find ( * aliases ) ;
2010-04-29 07:10:50 +02:00
2010-06-16 17:57:56 +02:00
if ( aliased )
aliased - > _modified = true ;
2010-04-29 07:10:50 +02:00
}
2010-04-24 09:45:03 +02:00
}
}
2010-04-27 05:05:32 +02:00
Variables : : VariableUsage * Variables : : find ( unsigned int varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
if ( varid )
2010-04-24 09:45:03 +02:00
{
2010-04-27 05:05:32 +02:00
VariableMap : : iterator i = _varUsage . find ( varid ) ;
if ( i ! = _varUsage . end ( ) )
return & i - > second ;
2010-04-24 09:45:03 +02:00
}
2010-04-27 05:05:32 +02:00
return 0 ;
2010-04-24 09:45:03 +02:00
}
2010-02-21 07:05:44 +01:00
2010-07-12 09:50:18 +02:00
static int doAssignment ( Variables & variables , const Token * tok , bool dereference , Scope * scope )
2010-04-29 07:10:50 +02:00
{
int next = 0 ;
// check for aliased variable
unsigned int varid1 = tok - > varId ( ) ;
Variables : : VariableUsage * var1 = variables . find ( varid1 ) ;
if ( var1 )
{
Variables : : VariableUsage * var2 = 0 ;
2010-06-23 06:54:14 +02:00
int start = 1 ;
2010-04-29 07:10:50 +02:00
2010-06-23 06:54:14 +02:00
// search for '='
while ( tok - > tokAt ( start ) - > str ( ) ! = " = " )
2010-05-05 17:31:07 +02:00
start + + ;
2010-06-23 06:54:14 +02:00
start + + ;
2010-05-26 19:22:35 +02:00
2010-05-05 17:31:07 +02:00
if ( Token : : Match ( tok - > tokAt ( start ) , " &| %var% " ) | |
2010-05-09 07:15:40 +02:00
Token : : Match ( tok - > tokAt ( start ) , " ( const| struct|union| %type% *| ) &| %var% " ) | |
Token : : Match ( tok - > tokAt ( start ) , " ( const| struct|union| %type% *| ) ( &| %var% " ) | |
Token : : Match ( tok - > tokAt ( start ) , " %any% < const| struct|union| %type% *| > ( &| %var% " ) )
2010-04-29 07:10:50 +02:00
{
2010-08-06 19:40:54 +02:00
unsigned char offset = 0 ;
2010-04-29 07:10:50 +02:00
unsigned int varid2 ;
bool addressOf = false ;
2010-08-07 15:53:51 +02:00
if ( Token : : Match ( tok - > tokAt ( start ) , " %var% . " ) )
variables . use ( tok - > tokAt ( start ) - > varId ( ) ) ; // use = read + write
2010-04-29 07:10:50 +02:00
// check for C style cast
2010-05-05 17:31:07 +02:00
if ( tok - > tokAt ( start ) - > str ( ) = = " ( " )
2010-04-29 07:10:50 +02:00
{
2010-05-05 17:31:07 +02:00
if ( tok - > tokAt ( start + 1 ) - > str ( ) = = " const " )
2010-04-30 18:11:51 +02:00
offset + + ;
2010-05-05 17:31:07 +02:00
if ( Token : : Match ( tok - > tokAt ( start + 1 + offset ) , " struct|union " ) )
2010-04-30 18:11:51 +02:00
offset + + ;
2010-05-09 07:15:40 +02:00
if ( tok - > tokAt ( start + 2 + offset ) - > str ( ) = = " * " )
offset + + ;
if ( tok - > tokAt ( start + 3 + offset ) - > str ( ) = = " & " )
2010-04-29 07:10:50 +02:00
{
addressOf = true ;
2010-05-09 07:15:40 +02:00
next = start + 4 + offset ;
2010-04-29 07:10:50 +02:00
}
2010-05-09 07:15:40 +02:00
else if ( tok - > tokAt ( start + 3 + offset ) - > str ( ) = = " ( " )
2010-04-29 07:10:50 +02:00
{
2010-05-09 07:15:40 +02:00
if ( tok - > tokAt ( start + 4 + offset ) - > str ( ) = = " & " )
2010-04-29 07:10:50 +02:00
{
addressOf = true ;
2010-05-09 07:15:40 +02:00
next = start + 5 + offset ;
2010-04-29 07:10:50 +02:00
}
else
2010-05-09 07:15:40 +02:00
next = start + 4 + offset ;
2010-04-29 07:10:50 +02:00
}
else
2010-05-09 07:15:40 +02:00
next = start + 3 + offset ;
2010-04-29 07:10:50 +02:00
}
2010-04-30 18:11:51 +02:00
2010-04-29 07:10:50 +02:00
// check for C++ style cast
2010-05-09 07:15:40 +02:00
else if ( tok - > tokAt ( start ) - > str ( ) . find ( " cast " ) ! = std : : string : : npos & &
tok - > tokAt ( start + 1 ) - > str ( ) = = " < " )
2010-04-29 07:10:50 +02:00
{
2010-05-05 17:31:07 +02:00
if ( tok - > tokAt ( start + 2 ) - > str ( ) = = " const " )
2010-04-30 18:11:51 +02:00
offset + + ;
2010-05-05 17:31:07 +02:00
if ( Token : : Match ( tok - > tokAt ( start + 2 + offset ) , " struct|union " ) )
2010-04-30 18:11:51 +02:00
offset + + ;
2010-05-09 07:15:40 +02:00
if ( tok - > tokAt ( start + 3 + offset ) - > str ( ) = = " * " )
offset + + ;
if ( tok - > tokAt ( start + 5 + offset ) - > str ( ) = = " & " )
2010-04-29 07:10:50 +02:00
{
addressOf = true ;
2010-05-09 07:15:40 +02:00
next = start + 6 + offset ;
2010-04-29 07:10:50 +02:00
}
else
2010-05-09 07:15:40 +02:00
next = start + 5 + offset ;
2010-04-29 07:10:50 +02:00
}
2010-07-08 08:42:34 +02:00
// check for var ? ...
else if ( Token : : Match ( tok - > tokAt ( start ) , " %var% ? " ) )
{
next = start ;
}
2010-04-29 07:10:50 +02:00
// no cast
else
{
2010-05-05 17:31:07 +02:00
if ( tok - > tokAt ( start ) - > str ( ) = = " & " )
2010-04-29 07:10:50 +02:00
{
addressOf = true ;
2010-05-05 17:31:07 +02:00
next = start + 1 ;
2010-04-29 07:10:50 +02:00
}
2010-06-03 07:05:57 +02:00
else if ( tok - > tokAt ( start ) - > str ( ) = = " new " )
return 0 ;
2010-04-29 07:10:50 +02:00
else
2010-05-05 17:31:07 +02:00
next = start ;
2010-04-29 07:10:50 +02:00
}
// check if variable is local
varid2 = tok - > tokAt ( next ) - > varId ( ) ;
var2 = variables . find ( varid2 ) ;
2010-06-23 06:54:14 +02:00
if ( var2 ) // local variable (alias or read it)
2010-04-29 07:10:50 +02:00
{
2010-06-23 06:54:14 +02:00
if ( var1 - > _type = = Variables : : pointer )
2010-04-29 07:10:50 +02:00
{
2010-06-23 06:54:14 +02:00
if ( dereference )
2010-04-29 07:10:50 +02:00
variables . read ( varid2 ) ;
2010-06-23 06:54:14 +02:00
else
2010-04-29 07:10:50 +02:00
{
2010-06-23 06:54:14 +02:00
if ( addressOf | |
var2 - > _type = = Variables : : array | |
var2 - > _type = = Variables : : pointer )
{
2010-07-08 07:59:47 +02:00
bool replace = true ;
2010-07-12 09:50:18 +02:00
// check if variable declared in same scope
if ( scope = = var1 - > _scope )
replace = true ;
// not in same scope as decelaration
else
{
std : : set < Scope * > : : iterator assignment ;
// check for an assignment in this scope
assignment = var1 - > _assignments . find ( scope ) ;
// no other assignment in this scope
if ( assignment = = var1 - > _assignments . end ( ) )
{
// nothing to replace
if ( var1 - > _assignments . empty ( ) )
replace = false ;
// this variable has previous assignments
else
{
/**
* @ todo determine if existing aliases should be replaced or merged
*/
replace = false ;
}
}
// assignment in this scope
else
{
// replace when only one other assingnment
if ( var1 - > _assignments . size ( ) = = 1 )
replace = true ;
// otherwise, merge them
else
replace = false ;
}
}
2010-07-08 07:59:47 +02:00
variables . alias ( varid1 , varid2 , replace ) ;
2010-06-23 06:54:14 +02:00
}
2010-07-08 08:42:34 +02:00
else if ( tok - > tokAt ( next + 1 ) - > str ( ) = = " ? " )
{
if ( var2 - > _type = = Variables : : reference )
variables . readAliases ( varid2 ) ;
else
variables . read ( varid2 ) ;
}
2010-04-29 07:10:50 +02:00
}
}
else if ( var1 - > _type = = Variables : : reference )
{
2010-07-08 07:59:47 +02:00
variables . alias ( varid1 , varid2 , true ) ;
2010-04-29 07:10:50 +02:00
}
2010-05-04 17:28:03 +02:00
else
2010-06-23 06:54:14 +02:00
{
if ( var2 - > _type = = Variables : : pointer & & tok - > tokAt ( next + 1 ) - > str ( ) = = " [ " )
variables . readAliases ( varid2 ) ;
2010-05-04 17:28:03 +02:00
variables . read ( varid2 ) ;
2010-06-23 06:54:14 +02:00
}
2010-04-29 07:10:50 +02:00
}
2010-05-04 17:28:03 +02:00
else // not a local variable (or an unsupported local variable)
2010-04-29 07:10:50 +02:00
{
2010-06-23 06:54:14 +02:00
if ( var1 - > _type = = Variables : : pointer & & ! dereference )
2010-05-01 21:15:14 +02:00
{
2010-07-12 09:50:18 +02:00
// check if variable decelaration is in this scope
if ( var1 - > _scope = = scope )
variables . clearAliases ( varid1 ) ;
else
{
std : : set < Scope * > : : iterator assignment ;
// check for an assignment in this scope
assignment = var1 - > _assignments . find ( scope ) ;
// no other assignment in this scope
if ( assignment = = var1 - > _assignments . end ( ) )
{
/**
* @ todo determine if existing aliases should be discarded
*/
}
// this assignment replaces the last assignment in this scope
else
{
// aliased variables in a larger scope are not supported
// remove all aliases
variables . clearAliases ( varid1 ) ;
}
}
2010-05-01 21:15:14 +02:00
}
2010-04-29 07:10:50 +02:00
}
}
2010-07-12 09:50:18 +02:00
var1 - > _assignments . insert ( scope ) ;
2010-04-29 07:10:50 +02:00
}
2010-05-04 17:26:09 +02:00
// check for alias to struct member
// char c[10]; a.b = c;
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %var% . " ) )
{
if ( Token : : Match ( tok - > tokAt ( 2 ) , " %var% " ) )
{
unsigned int varid2 = tok - > tokAt ( 2 ) - > varId ( ) ;
Variables : : VariableUsage * var2 = variables . find ( varid2 ) ;
// struct member aliased to local variable
if ( var2 & & ( var2 - > _type = = Variables : : array | |
var2 - > _type = = Variables : : pointer ) )
{
// erase aliased variable and all variables that alias it
// to prevent false positives
variables . eraseAll ( varid2 ) ;
}
}
}
2010-04-29 07:10:50 +02:00
return next ;
}
2010-06-24 17:00:32 +02:00
static bool nextIsStandardType ( const Token * tok )
{
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
return tok - > isStandardType ( ) ;
}
static bool nextIsStandardTypeOrVoid ( const Token * tok )
{
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
return tok - > isStandardType ( ) | | tok - > str ( ) = = " void " ;
}
2010-02-18 18:45:13 +01:00
void CheckOther : : functionVariableUsage ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-02-18 18:45:13 +01:00
// Parse all executing scopes..
2010-04-02 07:30:58 +02:00
for ( const Token * token = Token : : findmatch ( _tokenizer - > tokens ( ) , " ) const| { " ) ; token ; )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
// goto "{"
2010-04-02 07:30:58 +02:00
while ( token - > str ( ) ! = " { " )
2010-02-21 08:02:44 +01:00
token = token - > next ( ) ;
// First token for the current scope..
2010-04-29 07:10:50 +02:00
const Token * const tok1 = token ;
2010-02-21 08:02:44 +01:00
// Find next scope that will be checked next time..
token = Token : : findmatch ( token - > link ( ) , " ) const| { " ) ;
2010-04-27 05:05:32 +02:00
// varId, usage {read, write, modified}
2010-04-29 07:10:50 +02:00
Variables variables ;
2010-02-18 18:45:13 +01:00
2010-07-12 09:50:18 +02:00
// scopes
Scope scopes ;
Scope * scope = & scopes ;
2010-04-27 05:05:32 +02:00
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2010-02-18 18:45:13 +01:00
{
2010-04-27 05:05:32 +02:00
if ( tok - > str ( ) = = " { " )
2010-07-12 09:50:18 +02:00
{
// replace the head node when found
if ( indentlevel = = 0 )
scopes = Scope ( tok , NULL ) ;
// add the new scope
else
scope = scope - > addChild ( tok ) ;
2010-02-18 18:45:13 +01:00
+ + indentlevel ;
2010-07-12 09:50:18 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
- - indentlevel ;
2010-07-12 09:50:18 +02:00
scope = scope - > parent ( ) ;
2010-04-24 09:45:03 +02:00
if ( indentlevel = = 0 )
break ;
2010-02-18 18:45:13 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " struct|union|class { " ) | |
2010-06-10 07:21:47 +02:00
Token : : Match ( tok , " struct|union|class %type% {|: " ) )
2010-02-18 18:45:13 +01:00
{
2010-04-02 07:30:58 +02:00
while ( tok - > str ( ) ! = " { " )
2010-02-18 18:45:13 +01:00
tok = tok - > next ( ) ;
2010-02-21 08:02:44 +01:00
tok = tok - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2010-02-18 18:45:13 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [;{}] asm ( ) ; " ) )
2010-03-31 20:20:51 +02:00
{
2010-04-27 05:05:32 +02:00
variables . clear ( ) ;
2010-03-31 20:20:51 +02:00
break ;
}
2010-04-27 05:05:32 +02:00
// standard type declaration with possible initialization
2010-06-24 17:00:32 +02:00
// int i; int j = 0; static int k;
if ( Token : : Match ( tok , " [;{}] static| %type% %var% ;|= " ) & &
nextIsStandardType ( tok ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > next ( ) , Variables : : standard , scope ,
2010-06-24 17:00:32 +02:00
tok - > tokAt ( 2 ) - > str ( ) = = " = " | |
tok - > previous ( ) - > str ( ) = = " static " ) ;
tok = tok - > next ( ) ;
2010-04-15 18:44:52 +02:00
}
2010-04-27 05:05:32 +02:00
// standard type declaration and initialization using constructor
2010-06-24 17:00:32 +02:00
// int i(0); static int j(0);
else if ( Token : : Match ( tok , " [;{}] static| %type% %var% ( %any% ) ; " ) & &
nextIsStandardType ( tok ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > next ( ) , Variables : : standard , scope , true ) ;
2010-04-24 09:45:03 +02:00
// check if a local variable is used to initialize this variable
2010-06-24 17:00:32 +02:00
if ( tok - > tokAt ( 3 ) - > varId ( ) > 0 )
variables . readAll ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
tok = tok - > tokAt ( 4 ) ;
2010-04-15 18:44:52 +02:00
}
2010-04-30 18:11:51 +02:00
// standard type declaration of array of with possible initialization
2010-06-24 17:00:32 +02:00
// int i[10]; int j[2] = { 0, 1 }; static int k[2] = { 2, 3 };
else if ( Token : : Match ( tok , " [;{}] static| %type% %var% [ %any% ] ;|= " ) & &
nextIsStandardType ( tok ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > tokAt ( 1 ) , Variables : : array , scope ,
2010-06-24 17:00:32 +02:00
tok - > tokAt ( 5 ) - > str ( ) = = " = " | | tok - > str ( ) = = " static " ) ;
2010-05-23 10:41:05 +02:00
// check for reading array size from local variable
2010-06-24 17:00:32 +02:00
if ( tok - > tokAt ( 3 ) - > varId ( ) ! = 0 )
variables . read ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2010-05-23 10:41:05 +02:00
2010-06-21 18:12:01 +02:00
// look at initializers
2010-06-24 17:00:32 +02:00
if ( Token : : Match ( tok - > tokAt ( 5 ) , " = { " ) )
2010-06-21 18:12:01 +02:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 7 ) ;
while ( tok - > str ( ) ! = " } " )
2010-06-21 18:12:01 +02:00
{
if ( Token : : Match ( tok , " %var% " ) )
variables . read ( tok - > varId ( ) ) ;
tok = tok - > next ( ) ;
}
}
else
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 4 ) ;
2010-04-15 18:44:52 +02:00
}
2010-04-27 05:05:32 +02:00
// pointer or reference declaration with possible initialization
2010-06-24 17:00:32 +02:00
// int * i; int * j = 0; static int * k = 0;
else if ( Token : : Match ( tok , " [;{}] static| const| %type% *|& %var% ;|= " ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
bool isStatic = false ;
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
{
tok = tok - > next ( ) ;
isStatic = true ;
}
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2010-07-07 08:39:18 +02:00
if ( tok - > str ( ) ! = " return " & & tok - > str ( ) ! = " throw " )
2010-04-15 18:44:52 +02:00
{
2010-04-29 07:10:50 +02:00
Variables : : VariableType type ;
2010-06-24 17:00:32 +02:00
if ( tok - > next ( ) - > str ( ) = = " * " )
2010-04-29 07:10:50 +02:00
type = Variables : : pointer ;
else
type = Variables : : reference ;
2010-06-24 17:00:32 +02:00
bool written = tok - > tokAt ( 3 ) - > str ( ) = = " = " ;
2010-04-29 07:10:50 +02:00
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > tokAt ( 2 ) , type , scope , written | | isStatic ) ;
2010-04-29 07:10:50 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2010-07-12 09:50:18 +02:00
offset = doAssignment ( variables , tok - > tokAt ( 2 ) , false , scope ) ;
2010-04-29 07:10:50 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 2 + offset ) ;
2010-04-15 18:44:52 +02:00
}
}
2010-06-24 17:00:32 +02:00
// pointer to pointer declaration with possible initialization
// int ** i; int ** j = 0; static int ** k = 0;
else if ( Token : : Match ( tok , " [;{}] static| const| %type% * * %var% ;|= " ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
bool isStatic = false ;
2010-04-29 07:10:50 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
2010-04-29 07:10:50 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " static " )
{
tok = tok - > next ( ) ;
isStatic = true ;
}
2010-04-29 07:10:50 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2010-04-15 18:44:52 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) ! = " return " )
2010-06-23 06:54:14 +02:00
{
2010-06-24 17:00:32 +02:00
bool written = tok - > tokAt ( 4 ) - > str ( ) = = " = " ;
2010-06-23 06:54:14 +02:00
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > tokAt ( 3 ) , Variables : : pointerPointer , scope , written | | isStatic ) ;
2010-06-23 06:54:14 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2010-07-12 09:50:18 +02:00
offset = doAssignment ( variables , tok - > tokAt ( 3 ) , false , scope ) ;
2010-06-23 06:54:14 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 3 + offset ) ;
2010-06-23 06:54:14 +02:00
}
}
2010-04-27 05:05:32 +02:00
// pointer or reference of struct or union declaration with possible initialization
2010-06-24 17:00:32 +02:00
// struct s * i; struct s * j = 0; static struct s * k = 0;
else if ( Token : : Match ( tok , " [;{}] static| const| struct|union %type% *|& %var% ;|= " ) )
2010-04-15 18:44:52 +02:00
{
2010-04-29 07:10:50 +02:00
Variables : : VariableType type ;
2010-06-24 17:00:32 +02:00
bool isStatic = false ;
2010-04-29 07:10:50 +02:00
2010-06-20 19:03:59 +02:00
tok = tok - > next ( ) ;
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " static " )
{
tok = tok - > next ( ) ;
isStatic = true ;
}
2010-06-20 19:03:59 +02:00
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2010-04-29 07:10:50 +02:00
2010-06-20 19:03:59 +02:00
if ( tok - > strAt ( 2 ) = = " * " )
2010-04-29 07:10:50 +02:00
type = Variables : : pointer ;
else
type = Variables : : reference ;
2010-06-20 19:03:59 +02:00
const bool written = tok - > strAt ( 4 ) = = " = " ;
2010-04-29 07:10:50 +02:00
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > tokAt ( 3 ) , type , scope , written | | isStatic ) ;
2010-04-29 07:10:50 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2010-07-12 09:50:18 +02:00
offset = doAssignment ( variables , tok - > tokAt ( 3 ) , false , scope ) ;
2010-04-29 07:10:50 +02:00
2010-06-20 19:03:59 +02:00
tok = tok - > tokAt ( 3 + offset ) ;
2010-04-15 18:44:52 +02:00
}
2010-04-27 05:05:32 +02:00
// pointer or reference declaration with initialization using constructor
2010-06-24 17:00:32 +02:00
// int * i(j); int * k(i); static int * l(i);
else if ( Token : : Match ( tok , " [;{}] static| const| %type% &|* %var% ( %any% ) ; " ) & &
nextIsStandardTypeOrVoid ( tok ) )
2010-04-15 18:44:52 +02:00
{
2010-04-29 07:10:50 +02:00
Variables : : VariableType type ;
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
if ( tok - > next ( ) - > str ( ) = = " * " )
2010-04-29 07:10:50 +02:00
type = Variables : : pointer ;
else
type = Variables : : reference ;
unsigned int varid = 0 ;
// check for aliased variable
2010-06-24 17:00:32 +02:00
if ( Token : : Match ( tok - > tokAt ( 4 ) , " %var% " ) )
varid = tok - > tokAt ( 4 ) - > varId ( ) ;
2010-04-29 07:10:50 +02:00
2010-07-12 09:50:18 +02:00
variables . addVar ( tok - > tokAt ( 2 ) , type , scope , true ) ;
2010-04-24 09:45:03 +02:00
// check if a local variable is used to initialize this variable
2010-04-29 07:10:50 +02:00
if ( varid > 0 )
2010-04-15 18:44:52 +02:00
{
2010-04-29 07:10:50 +02:00
Variables : : VariableUsage * var = variables . find ( varid ) ;
if ( type = = Variables : : pointer )
{
2010-06-24 17:00:32 +02:00
variables . use ( tok - > tokAt ( 4 ) - > varId ( ) ) ;
2010-04-29 07:10:50 +02:00
if ( var & & ( var - > _type = = Variables : : array | |
var - > _type = = Variables : : pointer ) )
var - > _aliases . insert ( tok - > varId ( ) ) ;
}
else
{
2010-06-24 17:00:32 +02:00
variables . readAll ( tok - > tokAt ( 4 ) - > varId ( ) ) ;
2010-04-29 07:10:50 +02:00
if ( var )
var - > _aliases . insert ( tok - > varId ( ) ) ;
}
2010-04-15 18:44:52 +02:00
}
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 5 ) ;
2010-04-15 18:44:52 +02:00
}
2010-06-24 17:00:32 +02:00
// array of pointer or reference declaration with possible initialization
// int * p[10]; int * q[10] = { 0 }; static int * * r[10] = { 0 };
else if ( Token : : Match ( tok , " [;{}] static| const| %type% *|& %var% [ %any% ] ;|= " ) )
2010-05-01 09:26:47 +02:00
{
2010-06-24 17:00:32 +02:00
bool isStatic = false ;
2010-05-01 09:26:47 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
2010-05-01 09:26:47 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " static " )
2010-05-01 09:26:47 +02:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
isStatic = true ;
2010-05-01 09:26:47 +02:00
}
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
if ( tok - > str ( ) ! = " return " )
2010-04-29 07:10:50 +02:00
{
2010-06-24 17:00:32 +02:00
variables . addVar ( tok - > tokAt ( 2 ) ,
2010-07-12 09:50:18 +02:00
tok - > next ( ) - > str ( ) = = " * " ? Variables : : pointerArray : Variables : : referenceArray , scope ,
2010-06-24 17:00:32 +02:00
tok - > tokAt ( 6 ) - > str ( ) = = " = " | | isStatic ) ;
2010-05-23 10:41:05 +02:00
// check for reading array size from local variable
2010-06-24 17:00:32 +02:00
if ( tok - > tokAt ( 4 ) - > varId ( ) ! = 0 )
variables . read ( tok - > tokAt ( 4 ) - > varId ( ) ) ;
2010-05-23 10:41:05 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 5 ) ;
2010-04-29 07:10:50 +02:00
}
}
2010-06-24 17:00:32 +02:00
// array of pointer or reference of struct or union declaration with possible initialization
// struct S * p[10]; struct T * q[10] = { 0 }; static struct S * r[10] = { 0 };
else if ( Token : : Match ( tok , " [;{}] static| const| struct|union %type% *|& %var% [ %any% ] ;|= " ) )
2010-04-15 18:44:52 +02:00
{
2010-06-24 17:00:32 +02:00
bool isStatic = false ;
2010-05-23 10:41:05 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
2010-05-23 10:41:05 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " static " )
{
tok = tok - > next ( ) ;
isStatic = true ;
}
2010-04-29 07:10:50 +02:00
2010-06-24 17:00:32 +02:00
if ( tok - > str ( ) = = " const " )
2010-06-23 06:54:14 +02:00
tok = tok - > next ( ) ;
2010-06-24 17:00:32 +02:00
variables . addVar ( tok - > tokAt ( 3 ) ,
2010-07-12 09:50:18 +02:00
tok - > tokAt ( 2 ) - > str ( ) = = " * " ? Variables : : pointerArray : Variables : : referenceArray , scope ,
2010-06-24 17:00:32 +02:00
tok - > tokAt ( 7 ) - > str ( ) = = " = " | | isStatic ) ;
2010-05-23 10:41:05 +02:00
// check for reading array size from local variable
2010-06-24 17:00:32 +02:00
if ( tok - > tokAt ( 5 ) - > varId ( ) ! = 0 )
variables . read ( tok - > tokAt ( 5 ) - > varId ( ) ) ;
2010-05-23 10:41:05 +02:00
2010-06-24 17:00:32 +02:00
tok = tok - > tokAt ( 6 ) ;
2010-04-15 18:44:52 +02:00
}
2010-06-03 07:05:57 +02:00
else if ( Token : : Match ( tok , " delete|return|throw %var% " ) )
2010-04-29 07:10:50 +02:00
variables . readAll ( tok - > next ( ) - > varId ( ) ) ;
2010-02-18 18:45:13 +01:00
2010-04-29 07:10:50 +02:00
// assignment
2010-05-26 19:22:35 +02:00
else if ( Token : : Match ( tok , " *| (| ++|--| %var% ++|--| )| = " ) )
2010-04-29 07:10:50 +02:00
{
2010-06-23 06:54:14 +02:00
bool dereference = false ;
2010-05-05 17:31:07 +02:00
bool pre = false ;
bool post = false ;
2010-04-29 07:10:50 +02:00
if ( tok - > str ( ) = = " * " )
{
2010-06-23 06:54:14 +02:00
dereference = true ;
2010-04-29 07:10:50 +02:00
tok = tok - > next ( ) ;
}
2010-05-26 19:22:35 +02:00
if ( tok - > str ( ) = = " ( " )
tok = tok - > next ( ) ;
2010-05-05 17:31:07 +02:00
if ( Token : : Match ( tok , " ++|-- " ) )
{
pre = true ;
tok = tok - > next ( ) ;
}
if ( Token : : Match ( tok - > next ( ) , " ++|-- " ) )
post = true ;
2010-04-29 07:10:50 +02:00
unsigned int varid1 = tok - > varId ( ) ;
const Token * start = tok ;
2010-07-12 09:50:18 +02:00
tok = tok - > tokAt ( doAssignment ( variables , tok , dereference , scope ) ) ;
2010-05-05 17:31:07 +02:00
if ( pre | | post )
variables . use ( varid1 ) ;
2010-04-29 07:10:50 +02:00
2010-06-23 06:54:14 +02:00
if ( dereference )
2010-04-29 07:10:50 +02:00
{
variables . writeAliases ( varid1 ) ;
variables . read ( varid1 ) ;
}
else
{
Variables : : VariableUsage * var = variables . find ( varid1 ) ;
if ( var & & var - > _type = = Variables : : reference )
{
variables . writeAliases ( varid1 ) ;
variables . read ( varid1 ) ;
}
else
variables . write ( varid1 ) ;
2010-08-31 20:58:37 +02:00
Variables : : VariableUsage * var2 = variables . find ( tok - > varId ( ) ) ;
if ( var2 & & var2 - > _type = = Variables : : reference )
{
variables . writeAliases ( tok - > varId ( ) ) ;
variables . read ( tok - > varId ( ) ) ;
}
2010-04-29 07:10:50 +02:00
}
2010-06-29 08:38:24 +02:00
const Token * equal = tok - > next ( ) ;
if ( Token : : Match ( tok - > next ( ) , " [ %any% ] " ) )
equal = tok - > tokAt ( 4 ) ;
2010-04-29 07:10:50 +02:00
// checked for chained assignments
2010-06-29 08:38:24 +02:00
if ( tok ! = start & & equal - > str ( ) = = " = " )
2010-04-29 07:10:50 +02:00
{
Variables : : VariableUsage * var = variables . find ( tok - > varId ( ) ) ;
if ( var & & var - > _type ! = Variables : : reference )
var - > _read = true ;
tok = tok - > previous ( ) ;
}
}
2010-02-18 18:45:13 +01:00
2010-04-30 18:11:51 +02:00
// assignment
2010-04-16 16:25:57 +02:00
else if ( Token : : Match ( tok , " %var% [ " ) & & Token : : Match ( tok - > next ( ) - > link ( ) , " ] = " ) )
2010-04-29 07:10:50 +02:00
{
unsigned int varid = tok - > varId ( ) ;
2010-08-31 20:33:28 +02:00
const Variables : : VariableUsage * var = variables . find ( varid ) ;
2010-04-15 18:44:52 +02:00
2010-04-29 07:10:50 +02:00
if ( var )
{
2010-08-31 20:33:28 +02:00
if ( var - > _type = = Variables : : pointer | | var - > _type = = Variables : : reference )
2010-04-29 07:10:50 +02:00
{
variables . read ( varid ) ;
variables . writeAliases ( varid ) ;
}
else
variables . writeAll ( varid ) ;
}
}
2010-02-18 18:45:13 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " >>|& %var% " ) )
2010-04-27 05:05:32 +02:00
variables . use ( tok - > next ( ) - > varId ( ) ) ; // use = read + write
2010-02-18 18:45:13 +01:00
2010-04-30 18:11:51 +02:00
// function parameter
else if ( Token : : Match ( tok , " [(,] %var% [ " ) )
variables . use ( tok - > next ( ) - > varId ( ) ) ; // use = read + write
2010-06-08 18:24:42 +02:00
else if ( Token : : Match ( tok , " [(,] %var% [,)] " ) & & tok - > previous ( ) - > str ( ) ! = " * " )
2010-04-27 05:05:32 +02:00
variables . use ( tok - > next ( ) - > varId ( ) ) ; // use = read + write
2010-06-22 17:04:11 +02:00
else if ( Token : : Match ( tok , " [(,] ( " ) & &
Token : : Match ( tok - > next ( ) - > link ( ) , " ) %var% [,)] " ) )
variables . use ( tok - > next ( ) - > link ( ) - > next ( ) - > varId ( ) ) ; // use = read + write
2010-02-21 08:02:44 +01:00
2010-06-21 18:12:01 +02:00
// function
else if ( Token : : Match ( tok , " %var% ( " ) )
variables . read ( tok - > varId ( ) ) ;
2010-04-15 18:44:52 +02:00
else if ( Token : : Match ( tok , " %var% . " ) )
2010-04-27 05:05:32 +02:00
variables . use ( tok - > varId ( ) ) ; // use = read + write
2010-04-15 18:44:52 +02:00
else if ( ( Token : : Match ( tok , " [(=&!] " ) | | isOp ( tok ) ) & &
2010-06-03 07:05:57 +02:00
( Token : : Match ( tok - > next ( ) , " %var% " ) & & ! Token : : Match ( tok - > next ( ) , " true|false|new " ) ) )
2010-04-29 07:10:50 +02:00
variables . readAll ( tok - > next ( ) - > varId ( ) ) ;
2010-02-18 18:45:13 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " -=|+=|*=|/=|&=|^= %var% " ) | | Token : : Match ( tok , " |= %var% " ) )
2010-04-27 05:05:32 +02:00
variables . modified ( tok - > next ( ) - > varId ( ) ) ;
2010-02-18 18:45:13 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " %var% " ) & & ( tok - > next ( ) - > str ( ) = = " ) " | | isOp ( tok - > next ( ) ) ) )
2010-04-29 07:10:50 +02:00
variables . readAll ( tok - > varId ( ) ) ;
2010-02-18 18:45:13 +01:00
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " ; %var% ; " ) )
2010-04-29 07:10:50 +02:00
variables . readAll ( tok - > next ( ) - > varId ( ) ) ;
2010-03-16 19:25:10 +01:00
2010-04-15 18:44:52 +02:00
else if ( Token : : Match ( tok , " ++|-- %var% " ) )
2010-04-27 05:05:32 +02:00
variables . modified ( tok - > next ( ) - > varId ( ) ) ;
2010-04-15 18:44:52 +02:00
else if ( Token : : Match ( tok , " %var% ++|-- " ) )
2010-04-27 05:05:32 +02:00
variables . modified ( tok - > varId ( ) ) ;
2010-02-18 18:45:13 +01:00
}
// Check usage of all variables in the current scope..
2010-04-27 05:05:32 +02:00
Variables : : VariableMap : : const_iterator it ;
for ( it = variables . varUsage ( ) . begin ( ) ; it ! = variables . varUsage ( ) . end ( ) ; + + it )
{
const Variables : : VariableUsage & usage = it - > second ;
const std : : string & varname = usage . _name - > str ( ) ;
2010-06-23 06:54:14 +02:00
// variable has been marked as unused so ignore it
2010-06-14 15:46:57 +02:00
if ( usage . _name - > isUnused ( ) )
continue ;
2010-06-23 06:54:14 +02:00
// skip things that are only partially implemented to prevent false positives
if ( usage . _type = = Variables : : pointerPointer | |
usage . _type = = Variables : : pointerArray | |
usage . _type = = Variables : : referenceArray )
continue ;
// variable has not been written, read, or modified
2010-04-27 05:05:32 +02:00
if ( usage . unused ( ) & & ! usage . _modified )
unusedVariableError ( usage . _name , varname ) ;
2010-06-23 06:54:14 +02:00
// variable has not been written but has been modified
2010-04-27 05:05:32 +02:00
else if ( usage . _modified & ! usage . _write )
unassignedVariableError ( usage . _name , varname ) ;
2010-06-23 06:54:14 +02:00
// variable has been written but not read
2010-04-29 07:10:50 +02:00
else if ( ! usage . _read & & ! usage . _modified )
2010-04-27 05:05:32 +02:00
unreadVariableError ( usage . _name , varname ) ;
2010-06-23 06:54:14 +02:00
// variable has been read but not written
2010-04-27 05:05:32 +02:00
else if ( ! usage . _write )
unassignedVariableError ( usage . _name , varname ) ;
}
2010-02-18 18:45:13 +01:00
}
}
void CheckOther : : unusedVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unusedVariable " , " Unused variable: " + varname ) ;
}
void CheckOther : : unreadVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unreadVariable " , " Variable ' " + varname + " ' is assigned a value that is never used " ) ;
}
void CheckOther : : unassignedVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unassignedVariable " , " Variable ' " + varname + " ' is not assigned a value " ) ;
}
//---------------------------------------------------------------------------
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
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2009-01-26 20:14:46 +01:00
// Walk through all tokens..
bool func = false ;
int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
// Skip class and struct declarations..
2010-04-02 07:30:58 +02:00
if ( ( tok - > str ( ) = = " class " ) | | ( tok - > str ( ) = = " struct " ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
{
2009-10-06 17:45:28 +02:00
tok = tok2 - > link ( ) ;
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " [,);] " ) )
2009-01-26 20:14:46 +01:00
{
break ;
}
}
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
{
+ + indentlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-26 20:14:46 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2009-01-26 20:14:46 +01:00
func = false ;
}
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 & & Token : : simpleMatch ( tok , " ) { " ) )
2009-01-26 20:14:46 +01:00
{
func = true ;
}
2010-04-02 07:30:58 +02:00
if ( indentlevel > 0 & & func & & Token : : Match ( tok , " [{};] " ) )
2009-01-26 20:14:46 +01:00
{
// First token of statement..
const Token * tok1 = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok1 )
2009-01-26 20:14:46 +01:00
continue ;
2010-04-02 07:30:58 +02:00
if ( ( tok1 - > str ( ) = = " return " ) | |
( tok1 - > str ( ) = = " throw " ) | |
( tok1 - > str ( ) = = " delete " ) | |
( tok1 - > str ( ) = = " goto " ) | |
( tok1 - > str ( ) = = " else " ) )
2009-01-26 20:14:46 +01:00
continue ;
// Variable declaration?
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " %type% %var% ; %var% = %num% ; " ) )
2009-08-16 21:12:57 +02:00
{
// Tokenizer modify "int i = 0;" to "int i; i = 0;",
// so to handle this situation we just skip
// initialization (see ticket #272).
const unsigned int firstVarId = tok1 - > next ( ) - > varId ( ) ;
const unsigned int secondVarId = tok1 - > tokAt ( 3 ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( firstVarId > 0 & & firstVarId = = secondVarId )
2009-08-16 21:12:57 +02:00
{
lookupVar ( tok1 - > tokAt ( 6 ) , tok1 - > strAt ( 1 ) ) ;
}
}
2010-04-09 16:53:27 +02:00
else if ( tok1 - > isStandardType ( ) & & 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
}
}
}
}
//---------------------------------------------------------------------------
2010-02-14 19:58:17 +01:00
void CheckOther : : lookupVar ( const Token * tok1 , const std : : string & varname )
2009-01-26 20:14:46 +01:00
{
const Token * tok = tok1 ;
// Skip the variable declaration..
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
2009-01-26 20:14:46 +01:00
tok = tok - > next ( ) ;
// Check if the variable is used in this indentlevel..
2010-01-21 18:50:56 +01:00
bool used1 = false ; // used in one sub-scope -> reducable
bool used2 = false ; // used in more sub-scopes -> not reducable
2009-01-26 20:14:46 +01:00
int indentlevel = 0 ;
int parlevel = 0 ;
2010-01-21 18:50:56 +01:00
bool for_or_while = false ; // is sub-scope a "for/while/etc". anything that is not "if"
2010-04-02 07:30:58 +02:00
while ( tok )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
{
+ + indentlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2009-06-12 16:17:51 +02:00
break ;
2009-01-26 20:14:46 +01:00
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( for_or_while & & used2 )
2009-01-26 20:14:46 +01:00
return ;
2010-01-21 18:50:56 +01:00
used2 | = used1 ;
used1 = false ;
2009-01-26 20:14:46 +01:00
}
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
{
+ + parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-01-26 20:14:46 +01:00
{
- - parlevel ;
}
2009-05-27 19:38:26 +02:00
// Bail out if references are used
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok , ( std : : string ( " & " ) + varname ) . c_str ( ) ) )
2009-05-27 19:38:26 +02:00
{
return ;
}
2009-01-26 20:14:46 +01:00
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = varname )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2010-01-21 18:50:56 +01:00
return ;
used1 = true ;
2010-04-02 07:30:58 +02:00
if ( for_or_while & & ! Token : : simpleMatch ( tok - > next ( ) , " = " ) )
2010-01-21 18:50:56 +01:00
used2 = true ;
2010-04-02 07:30:58 +02:00
if ( used1 & & used2 )
2009-01-26 20:14:46 +01:00
return ;
}
2010-04-02 07:30:58 +02:00
else if ( indentlevel = = 0 )
2009-01-26 20:14:46 +01:00
{
2009-09-29 23:56:43 +02:00
// %unknown% ( %any% ) {
// If %unknown% is anything except if, we assume
// that it is a for or while loop or a macro hiding either one
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > next ( ) , " ( " ) & &
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) )
2009-09-29 23:56:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) ! = " if " )
2009-09-29 23:56:43 +02:00
for_or_while = true ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " do { " ) )
2009-01-26 20:14:46 +01:00
for_or_while = true ;
2009-09-29 23:56:43 +02:00
2010-08-26 21:57:48 +02:00
// possible unexpanded macro hiding for/while..
if ( Token : : Match ( tok - > previous ( ) , " [;{}] %type% { " ) )
{
bool upper = true ;
for ( unsigned int i = 0 ; i < tok - > str ( ) . length ( ) ; + + i )
{
if ( ! std : : isupper ( tok - > str ( ) [ i ] ) )
upper = false ;
}
for_or_while | = upper ;
}
2010-04-02 07:30:58 +02:00
if ( parlevel = = 0 & & ( tok - > str ( ) = = " ; " ) )
2009-01-26 20:14:46 +01:00
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
2010-04-02 07:30:58 +02:00
if ( used1 | | used2 )
2009-06-12 16:17:51 +02:00
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
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [,(] const std :: %type% %var% [,)] " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 5 ) ) ;
2009-01-26 20:14:46 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% > %var% [,)] " ) )
2009-10-05 10:59:28 +02:00
{
passedByValueError ( tok , tok - > strAt ( 8 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% > %var% [,)] " ) )
2009-10-05 10:59:28 +02:00
{
passedByValueError ( tok , tok - > strAt ( 10 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% , std :: %type% > %var% [,)] " ) )
2009-10-06 23:04:54 +02:00
{
passedByValueError ( tok , tok - > strAt ( 14 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% , std :: %type% > %var% [,)] " ) )
2009-10-06 23:04:54 +02:00
{
passedByValueError ( tok , tok - > strAt ( 12 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% , %type% > %var% [,)] " ) )
2009-10-06 23:04:54 +02:00
{
passedByValueError ( tok , tok - > strAt ( 12 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% , %type% > %var% [,)] " ) )
2009-10-06 23:04:54 +02:00
{
passedByValueError ( tok , tok - > strAt ( 10 ) ) ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [,(] const %type% %var% [,)] " ) )
2009-01-26 20:14:46 +01:00
{
// Check if type is a struct or class.
const std : : string pattern ( std : : string ( " class|struct " ) + tok - > strAt ( 2 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
2009-01-26 20:14:46 +01:00
{
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
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-02-14 19:58:17 +01:00
std : : string structname ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > fileIndex ( ) ! = 0 )
2009-01-26 20:14:46 +01:00
continue ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " struct|union %type% { " ) )
2009-01-26 20:14:46 +01:00
{
2010-04-17 11:16:05 +02:00
structname . clear ( ) ;
if ( Token : : simpleMatch ( tok - > previous ( ) , " extern " ) )
continue ;
if ( ( ! tok - > previous ( ) | | Token : : simpleMatch ( tok - > previous ( ) , " ; " ) ) & & Token : : Match ( tok - > tokAt ( 2 ) - > link ( ) , ( " } ; " + tok - > strAt ( 1 ) + " %var% ; " ) . c_str ( ) ) )
continue ;
2009-01-26 20:14:46 +01:00
structname = tok - > strAt ( 1 ) ;
// Bail out if struct/union contain any functions
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
{
2010-09-04 11:21:34 +02:00
structname . clear ( ) ;
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2009-01-26 20:14:46 +01:00
break ;
}
2009-10-17 17:36:55 +02:00
2010-09-04 11:21:34 +02:00
// bail out if struct is inherited
if ( ! structname . empty ( ) & & Token : : findmatch ( tok , ( " ,|private|protected|public " + structname ) . c_str ( ) ) )
structname . clear ( ) ;
2009-10-17 17:36:55 +02:00
// Bail out if some data is casted to struct..
2009-10-17 19:31:14 +02:00
const std : : string s ( " ( struct| " + tok - > next ( ) - > str ( ) + " * ) & %var% [ " ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : findmatch ( tok , s . c_str ( ) ) )
2010-09-04 11:21:34 +02:00
structname . clear ( ) ;
2010-04-09 19:55:41 +02:00
// Try to prevent false positives when struct members are not used directly.
if ( Token : : findmatch ( tok , ( structname + " * " ) . c_str ( ) ) )
2010-09-04 11:21:34 +02:00
structname . clear ( ) ;
2010-04-09 19:55:41 +02:00
else if ( Token : : findmatch ( tok , ( structname + " %type% * " ) . c_str ( ) ) )
structname = " " ;
2009-01-26 20:14:46 +01:00
}
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " } " )
2010-09-04 11:21:34 +02:00
structname . clear ( ) ;
2009-01-26 20:14:46 +01:00
2010-04-02 07:30:58 +02:00
if ( ! structname . empty ( ) & & Token : : Match ( tok , " [{;] " ) )
2009-01-26 20:14:46 +01:00
{
2010-04-09 19:55:41 +02:00
// Declaring struct variable..
2010-02-14 19:58:17 +01:00
std : : string varname ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > next ( ) , " %type% %var% [;[] " ) )
2009-01-26 20:14:46 +01:00
varname = tok - > strAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% %var% [ ; [ ] " ))
2009-01-26 20:14:46 +01:00
varname = tok - > strAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok - > next ( ) , " %type% * %var% [ ; [ ] " ))
2009-01-26 20:14:46 +01:00
varname = tok - > strAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% * %var% [ ; [ ] " ))
2009-01-26 20:14:46 +01:00
varname = tok - > strAt ( 4 ) ;
else
continue ;
2010-09-04 11:21:34 +02:00
// Check if the struct variable is used anywhere in the file
2010-02-14 19:58:17 +01:00
const std : : string usagePattern ( " . " + varname ) ;
2009-01-26 20:14:46 +01:00
bool used = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = _tokenizer - > tokens ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 , usagePattern . c_str ( ) ) )
2009-01-26 20:14:46 +01:00
{
used = true ;
break ;
}
}
2010-04-02 07:30:58 +02:00
if ( ! used )
2009-01-26 20:14:46 +01:00
{
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
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
// Declaring the variable..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " [{};(,] char %var% [;=,)] " ) )
2009-01-26 20:14:46 +01:00
{
2010-03-28 15:56:13 +02:00
// Check for unsigned char
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 1 ) - > isUnsigned ( ) )
2010-03-28 15:56:13 +02:00
continue ;
2009-01-26 20:14:46 +01:00
// Set tok to point to the variable name
tok = tok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " char " )
2009-02-04 18:12:53 +01:00
tok = tok - > next ( ) ;
2009-01-26 20:14:46 +01:00
// Check usage of char variable..
int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-01-26 20:14:46 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 0 )
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " return " )
2009-03-23 19:04:51 +01:00
continue ;
2009-01-26 20:14:46 +01:00
std : : string temp = " %var% [ " + tok - > str ( ) + " ] " ;
2010-04-02 07:30:58 +02:00
if ( ( tok2 - > str ( ) ! = " . " ) & & Token : : Match ( tok2 - > next ( ) , temp . c_str ( ) ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
charArrayIndexError ( tok2 - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
break ;
}
2010-04-02 07:30: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?
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 3 ) - > varId ( ) ! = tok - > varId ( ) & & tok2 - > tokAt ( 5 ) - > varId ( ) ! = tok - > varId ( ) )
2009-06-20 19:24:58 +02:00
continue ;
// it's ok with a bitwise and where the other operand is 0xff or less..
2010-04-02 07:30:58 +02:00
if ( std : : string ( tok2 - > strAt ( 4 ) ) = = " & " )
2009-06-20 19:24:58 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 3 ) ) )
2009-06-20 19:24:58 +02:00
continue ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > tokAt ( 5 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 5 ) ) )
2009-06-20 19:24:58 +02:00
continue ;
}
// is the result stored in a short|int|long?
2010-04-02 07:30:58 +02:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , " short|int|long %varid% " , tok2 - > next ( ) - > varId ( ) ) )
2009-06-20 19:24:58 +02:00
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
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle )
return ;
2009-01-26 20:14:46 +01:00
int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-01-26 20:14:46 +01:00
- - parlevel ;
2010-04-02 07:30:58 +02:00
if ( parlevel ! = 0 )
2009-01-26 20:14:46 +01:00
continue ;
2010-04-02 07:30:58 +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 " ; " */
2010-04-02 07:30:58 +02:00
while ( tok - > str ( ) ! = " ; " )
2009-02-12 13:59:43 +01:00
{
int level = 0 ;
do
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " | | tok - > str ( ) = = " { " )
2009-02-12 13:59:43 +01:00
+ + level ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " | | tok - > str ( ) = = " } " )
2009-02-12 13:59:43 +01:00
- - level ;
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( tok = = NULL )
2009-02-12 13:59:43 +01:00
return ;
}
2010-04-02 07:30:58 +02:00
while ( level > 0 ) ;
2009-02-12 13:59:43 +01:00
}
2009-02-11 16:17:13 +01:00
continue ;
}
2010-04-02 07:30:58 +02: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
}
2010-04-02 07:30:58 +02: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 ( )
{
2010-10-19 21:54:15 +02:00
// Don't use this check for Java and C# programs..
if ( _tokenizer - > getFiles ( ) - > at ( 0 ) . find ( " .java " ) ! = std : : string : : npos | |
_tokenizer - > getFiles ( ) - > at ( 0 ) . find ( " .cs " ) ! = std : : string : : npos )
{
return ;
}
2010-02-01 19:46:51 +01:00
bool charVars [ 10000 ] = { 0 } ;
2009-01-26 20:14:46 +01:00
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-02-01 19:46:51 +01:00
// Declaring char variable..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " char|int|short %var% [;=] " ) )
2009-01-26 20:14:46 +01:00
{
unsigned int varid = tok - > next ( ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & varid < 10000 )
2010-02-01 19:46:51 +01:00
charVars [ varid ] = true ;
2009-01-26 20:14:46 +01:00
}
2010-02-01 19:46:51 +01:00
//
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " [=(] %str% + %any% " ) )
2009-01-26 20:14:46 +01:00
{
// char constant..
2010-02-14 19:58:17 +01:00
const std : : string s = tok - > strAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
if ( s [ 0 ] = = ' \' ' )
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 ( ) ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 & & varid < 10000 & & charVars [ varid ] )
2010-02-01 19:46:51 +01:00
strPlusChar ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-02-04 19:49:19 +01:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointerAfterLoop ( )
2009-03-27 17:19:34 +01:00
{
// Locate insufficient null-pointer handling after loop
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-03-27 17:19:34 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " while ( %var% ) " ) )
2009-03-27 17:19:34 +01:00
continue ;
const unsigned int varid ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-03-27 17:19:34 +01:00
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok - > strAt ( 2 ) ) ;
2009-03-27 17:19:34 +01:00
// Locate the end of the while loop..
const Token * tok2 = tok - > tokAt ( 4 ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > link ( ) ;
else
2009-03-27 17:19:34 +01:00
{
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > next ( ) ;
2009-03-27 17:19:34 +01:00
}
// Goto next token
2010-04-02 07:30:58 +02:00
if ( tok2 )
2009-08-17 22:23:37 +02:00
tok2 = tok2 - > next ( ) ;
2009-03-27 17:19:34 +01:00
// Check if the variable is dereferenced..
2010-04-02 07:30:58 +02:00
while ( tok2 )
2009-03-27 17:19:34 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " break " )
2009-03-27 17:19:34 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) = = varid )
2009-03-27 17:19:34 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > next ( ) - > str ( ) = = " . " | | Token : : Match ( tok2 - > next ( ) , " = %varid% . " , varid ) )
2009-05-10 08:43:16 +02:00
{
// Is this variable a pointer?
2009-10-08 10:55:37 +02:00
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok3 )
2009-05-10 08:43:16 +02:00
break ;
2010-04-02 07:30:58 +02:00
if ( ! tok3 - > previous ( ) | |
Token : : Match ( tok3 - > previous ( ) , " [({};] " ) | |
tok3 - > previous ( ) - > isName ( ) )
2009-05-10 08:43:16 +02:00
{
2009-08-11 17:18:01 +02:00
nullPointerError ( tok2 , varname ) ;
2009-05-10 08:43:16 +02:00
}
}
2009-03-27 17:19:34 +01:00
break ;
}
tok2 = tok2 - > next ( ) ;
}
}
2009-10-11 17:10:20 +02:00
}
2009-07-20 18:53:41 +02:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointerLinkedList ( )
{
2009-07-31 10:49:43 +02:00
// looping through items in a linked list in a inner loop..
2010-04-02 07:30:58 +02:00
for ( const Token * tok1 = _tokenizer - > tokens ( ) ; tok1 ; tok1 = tok1 - > next ( ) )
2009-07-31 10:49:43 +02:00
{
// search for a "for" token..
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok1 , " for ( " ) )
2009-07-31 10:49:43 +02:00
continue ;
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok1 - > next ( ) - > link ( ) , " ) { " ) )
2009-07-31 10:49:43 +02:00
continue ;
// is there any dereferencing occuring in the for statement..
unsigned int parlevel2 = 1 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok1 - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-07-31 10:49:43 +02:00
{
// Parantheses..
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-07-31 10:49:43 +02:00
+ + parlevel2 ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-07-31 10:49:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel2 < = 1 )
2009-07-31 10:49:43 +02:00
break ;
- - parlevel2 ;
}
// Dereferencing a variable inside the "for" parantheses..
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %var% . %var% " ) )
2009-07-31 10:49:43 +02:00
{
const unsigned int varid ( tok2 - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-07-31 10:49:43 +02:00
continue ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " %varid% ? " , varid ) )
2009-08-01 11:30:37 +02:00
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok2 - > str ( ) ) ;
2009-07-31 10:49:43 +02:00
// Check usage of dereferenced variable in the loop..
unsigned int indentlevel3 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok1 - > next ( ) - > link ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-07-31 10:49:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2009-07-31 10:49:43 +02:00
+ + indentlevel3 ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2009-07-31 10:49:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel3 < = 1 )
2009-07-31 10:49:43 +02:00
break ;
- - indentlevel3 ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " while ( %varid% &&|) " , varid ) )
2009-07-31 10:49:43 +02:00
{
// Make sure there is a "break" to prevent segmentation faults..
unsigned int indentlevel4 = indentlevel3 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok4 = tok3 - > next ( ) - > link ( ) ; tok4 ; tok4 = tok4 - > next ( ) )
2009-07-31 10:49:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok4 - > str ( ) = = " { " )
2009-07-31 10:49:43 +02:00
+ + indentlevel4 ;
2010-04-02 07:30:58 +02:00
else if ( tok4 - > str ( ) = = " } " )
2009-07-31 10:49:43 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel4 < = 1 )
2009-07-31 10:49:43 +02:00
{
2009-10-08 10:55:37 +02:00
// Is this variable a pointer?
const Token * tempTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid ) ;
2010-04-02 07:30:58 +02:00
if ( tempTok )
2010-02-28 07:26:50 +01:00
nullPointerError ( tok1 , varname , tok3 - > linenr ( ) ) ;
2009-10-08 10:55:37 +02:00
2009-07-31 10:49:43 +02:00
break ;
}
- - indentlevel4 ;
}
2010-09-02 21:08:58 +02:00
else if ( tok4 - > str ( ) = = " break " | | tok4 - > str ( ) = = " return " )
2009-07-31 10:49:43 +02:00
break ;
}
}
}
}
}
}
2009-10-11 17:10:20 +02:00
}
void CheckOther : : nullPointerStructByDeRefAndChec ( )
{
2010-08-07 21:00:17 +02:00
// don't check vars that has been tested against null already
std : : set < unsigned int > skipvar ;
skipvar . insert ( 0 ) ;
2009-07-23 14:13:46 +02:00
// Dereferencing a struct pointer and then checking if it's NULL..
2010-04-02 07:30:58 +02:00
for ( const Token * tok1 = _tokenizer - > tokens ( ) ; tok1 ; tok1 = tok1 - > next ( ) )
2009-07-20 18:53:41 +02:00
{
2010-08-07 21:00:17 +02:00
if ( Token : : Match ( tok1 , " if|while ( !| %var% ) " ) )
{
tok1 = tok1 - > tokAt ( 2 ) ;
if ( tok1 - > str ( ) = = " ! " )
tok1 = tok1 - > next ( ) ;
skipvar . insert ( tok1 - > varId ( ) ) ;
continue ;
}
2010-08-05 08:06:19 +02:00
// dereference in assignment
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 , " [{};] %var% = %var% . %var% " ) )
2009-07-20 18:53:41 +02:00
{
2010-04-02 07:30:58 +02:00
if ( std : : string ( tok1 - > strAt ( 1 ) ) = = tok1 - > strAt ( 3 ) )
2009-07-20 19:30:33 +02:00
continue ;
tok1 = tok1 - > tokAt ( 3 ) ;
2010-08-05 08:06:19 +02:00
}
2009-07-20 19:10:33 +02:00
2010-08-05 08:06:19 +02:00
// dereference in function call
else if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " %var% ( %var% . %var% " ) | |
Token : : Match ( tok1 - > previous ( ) , " , %var% . %var% " ) )
{
2009-08-11 17:18:01 +02:00
2010-08-05 08:06:19 +02:00
}
2009-07-23 19:59:29 +02:00
2010-08-05 08:06:19 +02:00
// Goto next token
else
{
continue ;
}
2009-07-20 19:30:33 +02:00
2010-08-05 08:06:19 +02:00
// struct dereference was found - investigate if it is later
// checked that it is not NULL
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
2010-08-07 21:00:17 +02:00
if ( skipvar . find ( varid1 ) ! = skipvar . end ( ) )
2010-08-05 08:06:19 +02:00
continue ;
const std : : string varname ( tok1 - > str ( ) ) ;
2009-07-20 19:30:33 +02:00
2010-08-05 08:06:19 +02:00
unsigned int indentlevel2 = 0 ;
for ( const Token * tok2 = tok1 - > tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
2009-07-21 12:09:58 +02:00
2010-08-05 08:06:19 +02:00
else if ( tok2 - > str ( ) = = " } " )
{
2010-08-07 19:59:56 +02:00
if ( indentlevel2 < = 1 )
2009-07-29 11:17:22 +02:00
break ;
2010-08-05 08:06:19 +02:00
- - indentlevel2 ;
}
2009-07-29 11:17:22 +02:00
2010-08-05 08:06:19 +02:00
// goto destination..
else if ( tok2 - > isName ( ) & & Token : : simpleMatch ( tok2 - > next ( ) , " : " ) )
break ;
2009-07-20 19:59:55 +02:00
2010-08-05 08:06:19 +02:00
// Reassignment of the struct
else if ( tok2 - > varId ( ) = = varid1 )
{
if ( tok2 - > next ( ) - > str ( ) = = " = " )
2009-07-21 17:00:11 +02:00
break ;
2010-08-05 08:06:19 +02:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [,(] & " ) )
break ;
}
// Loop..
/** @todo don't bail out if the variable is not used in the loop */
else if ( tok2 - > str ( ) = = " do " )
break ;
// return at base level => stop checking
else if ( indentlevel2 = = 0 & & tok2 - > str ( ) = = " return " )
break ;
else if ( Token : : Match ( tok2 , " if ( !| %varid% ) " , varid1 ) )
{
// Is this variable a pointer?
const Token * tempTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid1 ) ;
if ( tempTok )
nullPointerError ( tok1 , varname , tok2 - > linenr ( ) ) ;
break ;
2009-07-20 18:53:41 +02:00
}
}
}
2009-10-11 17:10:20 +02:00
}
void CheckOther : : nullPointerByDeRefAndChec ( )
{
2009-07-23 14:13:46 +02:00
// Dereferencing a pointer and then checking if it's NULL..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-07-23 14:13:46 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " if " & & Token : : Match ( tok - > previous ( ) , " ; if ( ! %var% ) " ) )
2009-07-23 14:13:46 +02:00
{
const unsigned int varid ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2009-07-23 14:13:46 +02:00
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok - > strAt ( 3 ) ) ;
2010-08-05 08:06:19 +02:00
// Check that variable is a pointer..
2009-07-25 20:36:02 +02:00
const Token * decltok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) ;
2010-08-05 08:06:19 +02:00
if ( ! Token : : Match ( decltok - > tokAt ( - 3 ) , " [;,(] %type% * " ) )
2009-07-25 20:36:02 +02:00
continue ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok1 = tok - > previous ( ) ; tok1 & & tok1 ! = decltok ; tok1 = tok1 - > previous ( ) )
2009-07-23 14:13:46 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok1 - > varId ( ) = = varid )
2009-07-23 14:13:46 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " [=;{}] * " ) )
2009-07-23 14:13:46 +02:00
{
2010-08-05 08:19:36 +02:00
nullPointerError ( tok1 , varname , tok - > linenr ( ) ) ;
2009-07-23 14:13:46 +02:00
break ;
}
2010-08-05 08:19:36 +02:00
else if ( Token : : simpleMatch ( tok1 - > previous ( ) , " & " ) )
2009-07-23 19:02:14 +02:00
{
break ;
}
2010-08-05 08:19:36 +02:00
else if ( Token : : simpleMatch ( tok1 - > next ( ) , " = " ) )
2009-07-23 14:13:46 +02:00
{
break ;
}
2010-08-05 08:19:36 +02:00
// dereference in function call
else if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " [(,] * " ) )
{
nullPointerError ( tok1 , varname , tok - > linenr ( ) ) ;
}
2009-07-23 14:13:46 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok1 - > str ( ) = = " { " ||
tok1 - > str ( ) = = " } " )
2009-07-23 14:13:46 +02:00
break ;
2009-08-12 18:54:52 +02:00
2010-08-05 08:06:19 +02:00
// label..
else if ( Token : : Match ( tok1 , " %type% : " ) )
2009-08-12 18:54:52 +02:00
break ;
2009-07-23 14:13:46 +02:00
}
}
}
2009-03-27 17:19:34 +01:00
}
2009-10-19 17:32:43 +02:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointer ( )
{
nullPointerAfterLoop ( ) ;
nullPointerLinkedList ( ) ;
nullPointerStructByDeRefAndChec ( ) ;
nullPointerByDeRefAndChec ( ) ;
}
2009-03-27 17:19:34 +01:00
2010-05-26 19:16:42 +02:00
/** Derefencing null constant (simplified token list) */
void CheckOther : : nullConstantDereference ( )
{
2010-06-02 17:53:45 +02:00
// this is kept at 0 for all scopes that are not executing
unsigned int indentlevel = 0 ;
2010-05-26 19:16:42 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2010-06-02 17:53:45 +02:00
// start of executable scope..
if ( indentlevel = = 0 & & Token : : Match ( tok , " ) const| { " ) )
indentlevel = 1 ;
2009-12-06 18:41:28 +01:00
2010-06-02 17:53:45 +02:00
else if ( indentlevel > = 1 )
2010-05-26 19:16:42 +02:00
{
2010-06-02 17:53:45 +02:00
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
2010-05-26 19:16:42 +02:00
{
2010-06-02 17:53:45 +02:00
if ( indentlevel < = 2 )
indentlevel = 0 ;
else
- - indentlevel ;
2010-05-26 19:16:42 +02:00
}
2010-06-02 17:53:45 +02:00
if ( tok - > str ( ) = = " ( " & & Token : : simpleMatch ( tok - > previous ( ) , " sizeof " ) )
tok = tok - > link ( ) ;
else if ( Token : : simpleMatch ( tok , " exit ( ) " ) )
{
// Goto end of scope
while ( tok & & tok - > str ( ) ! = " } " )
{
if ( tok - > str ( ) = = " { " )
tok = tok - > link ( ) ;
tok = tok - > next ( ) ;
}
2010-06-02 18:06:37 +02:00
if ( ! tok )
break ;
2010-06-02 17:53:45 +02:00
}
else if ( Token : : simpleMatch ( tok , " * 0 " ) )
2010-05-26 19:16:42 +02:00
{
2010-06-19 14:00:45 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [<>;{}=+-*/(,] " ) | |
2010-06-02 17:53:45 +02:00
Token : : Match ( tok - > previous ( ) , " return|<< " ) )
{
nullPointerError ( tok ) ;
}
2010-05-26 19:16:42 +02:00
}
}
}
}
2010-01-11 22:28:07 +01:00
2009-12-23 19:51:32 +01:00
/**
* \ brief parse a function call and extract information about variable usage
* \ param tok first token
* \ param var variables that the function read / write .
* \ param value 0 = > invalid with null pointers as parameter .
* 1 - . . = > invalid with uninitialized data .
*/
static void parseFunctionCall ( const Token & tok , std : : list < const Token * > & var , unsigned char value )
{
// standard functions that dereference first parameter..
// both uninitialized data and null pointers are invalid.
static std : : set < std : : string > functionNames1 ;
2010-04-02 07:30:58 +02:00
if ( functionNames1 . empty ( ) )
2009-12-23 19:51:32 +01:00
{
functionNames1 . insert ( " memchr " ) ;
functionNames1 . insert ( " memcmp " ) ;
functionNames1 . insert ( " strcat " ) ;
functionNames1 . insert ( " strncat " ) ;
functionNames1 . insert ( " strchr " ) ;
functionNames1 . insert ( " strrchr " ) ;
functionNames1 . insert ( " strcmp " ) ;
functionNames1 . insert ( " strncmp " ) ;
functionNames1 . insert ( " strdup " ) ;
2010-03-26 16:44:46 +01:00
functionNames1 . insert ( " strndup " ) ;
2009-12-23 19:51:32 +01:00
functionNames1 . insert ( " strlen " ) ;
functionNames1 . insert ( " strstr " ) ;
}
// standard functions that dereference second parameter..
// both uninitialized data and null pointers are invalid.
static std : : set < std : : string > functionNames2 ;
2010-04-02 07:30:58 +02:00
if ( functionNames2 . empty ( ) )
2009-12-23 19:51:32 +01:00
{
functionNames2 . insert ( " memcmp " ) ;
functionNames2 . insert ( " memcpy " ) ;
functionNames2 . insert ( " memmove " ) ;
functionNames2 . insert ( " strcat " ) ;
functionNames2 . insert ( " strncat " ) ;
functionNames2 . insert ( " strcmp " ) ;
functionNames2 . insert ( " strncmp " ) ;
functionNames2 . insert ( " strcpy " ) ;
functionNames2 . insert ( " strncpy " ) ;
functionNames2 . insert ( " strstr " ) ;
}
// 1st parameter..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " %var% ( %var% ,|) " ) & & tok . tokAt ( 2 ) - > varId ( ) > 0 )
2009-12-23 19:51:32 +01:00
{
2010-04-02 07:30:58 +02:00
if ( functionNames1 . find ( tok . str ( ) ) ! = functionNames1 . end ( ) )
2009-12-23 19:51:32 +01:00
var . push_back ( tok . tokAt ( 2 ) ) ;
2010-04-02 07:30:58 +02:00
else if ( value = = 0 & & Token : : Match ( & tok , " memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf " ) )
2009-12-23 19:51:32 +01:00
var . push_back ( tok . tokAt ( 2 ) ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( & tok , " fflush " ) )
2009-12-23 19:51:32 +01:00
var . push_back ( tok . tokAt ( 2 ) ) ;
}
// 2nd parameter..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " %var% ( %any% , %var% ,|) " ) & & tok . tokAt ( 4 ) - > varId ( ) > 0 )
2009-12-23 19:51:32 +01:00
{
2010-04-02 07:30:58 +02:00
if ( functionNames2 . find ( tok . str ( ) ) ! = functionNames2 . end ( ) )
2009-12-23 19:51:32 +01:00
var . push_back ( tok . tokAt ( 4 ) ) ;
}
}
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/// @addtogroup Checks
/// @{
/**
* @ brief % Check for null pointer usage ( using ExecutionPath )
*/
2009-12-06 18:41:28 +01:00
class CheckNullpointer : public ExecutionPath
{
public :
2010-03-13 21:42:59 +01:00
/** Startup constructor */
2009-12-21 18:17:35 +01:00
CheckNullpointer ( Check * c ) : ExecutionPath ( c , 0 ) , null ( false )
2009-12-06 18:41:28 +01:00
{
}
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
private :
2010-03-13 21:42:59 +01:00
/** Create checking of specific variable: */
2009-12-21 18:17:35 +01:00
CheckNullpointer ( Check * c , const unsigned int id , const std : : string & name )
2010-04-15 20:08:51 +02:00
: ExecutionPath ( c , id ) ,
varname ( name ) ,
null ( false )
2009-12-20 19:44:32 +01:00
{
}
2010-03-13 21:42:59 +01:00
/** Copy this check */
2009-12-06 18:41:28 +01:00
ExecutionPath * copy ( )
{
return new CheckNullpointer ( * this ) ;
}
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/** no implementation => compiler error if used by accident */
2009-12-06 20:34:02 +01:00
void operator = ( const CheckNullpointer & ) ;
2010-04-25 11:55:57 +02:00
/** is other execution path equal? */
bool is_equal ( const ExecutionPath * e ) const
{
const CheckNullpointer * c = static_cast < const CheckNullpointer * > ( e ) ;
return ( varname = = c - > varname & & null = = c - > null ) ;
}
2010-03-13 21:42:59 +01:00
/** variable name for this check (empty => dummy check) */
2009-12-20 19:44:32 +01:00
const std : : string varname ;
2010-03-13 21:42:59 +01:00
/** is this variable null? */
2009-12-06 18:41:28 +01:00
bool null ;
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/** variable is set to null */
2009-12-20 19:44:32 +01:00
static void setnull ( std : : list < ExecutionPath * > & checks , const unsigned int varid )
2009-12-06 18:41:28 +01:00
{
std : : list < ExecutionPath * > : : iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-20 19:44:32 +01:00
{
CheckNullpointer * c = dynamic_cast < CheckNullpointer * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2009-12-20 19:44:32 +01:00
c - > null = true ;
}
2009-12-06 18:41:28 +01:00
}
2009-10-29 21:34:43 +01:00
2010-04-04 11:24:52 +02:00
/**
* Dereferencing variable . Check if it is safe ( if the variable is null there ' s an error )
* @ param checks Checks
* @ param tok token where dereferencing happens
*/
static void dereference ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-06 18:41:28 +01:00
{
2009-12-20 19:44:32 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
2009-12-06 18:41:28 +01:00
std : : list < ExecutionPath * > : : iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-06 18:41:28 +01:00
{
2009-12-20 19:44:32 +01:00
CheckNullpointer * c = dynamic_cast < CheckNullpointer * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid & & c - > null )
2009-12-06 18:41:28 +01:00
{
2009-12-21 18:17:35 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
2010-04-02 07:30:58 +02:00
if ( checkOther )
2009-12-21 18:17:35 +01:00
{
checkOther - > nullPointerError ( tok , c - > varname ) ;
2010-04-04 11:24:52 +02:00
return ;
2009-12-21 18:17:35 +01:00
}
2009-12-20 19:44:32 +01:00
}
}
}
2010-03-13 21:42:59 +01:00
/** parse tokens */
2010-04-04 11:24:52 +02:00
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const
2009-12-06 18:41:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] const| %type% * %var% ; " ) )
2009-12-20 19:44:32 +01:00
{
const Token * vartok = tok . tokAt ( 2 ) ;
2010-03-26 16:44:46 +01:00
2010-04-02 07:30:58 +02:00
if ( tok . str ( ) = = " const " )
2010-03-26 16:44:46 +01:00
vartok = vartok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( vartok - > varId ( ) ! = 0 )
2009-12-21 18:17:35 +01:00
checks . push_back ( new CheckNullpointer ( owner , vartok - > varId ( ) , vartok - > str ( ) ) ) ;
2009-12-20 19:44:32 +01:00
return vartok - > next ( ) ;
}
2010-01-03 13:30:20 +01:00
// Template pointer variable..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% ::|< " ) )
2010-01-03 13:30:20 +01:00
{
const Token * vartok = & tok ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( vartok , " %type% :: " ) )
2010-01-03 13:30:20 +01:00
vartok = vartok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( vartok , " %type% < %type% " ) )
2010-01-03 13:30:20 +01:00
{
vartok = vartok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( vartok & & ( vartok - > str ( ) = = " * " | | vartok - > isName ( ) ) )
2010-01-03 13:30:20 +01:00
vartok = vartok - > next ( ) ;
2010-10-09 07:57:34 +02:00
}
if ( vartok
& & ( vartok - > str ( ) = = " > " | | vartok - > isName ( ) )
& & Token : : Match ( vartok - > next ( ) , " * %var% ;|= " ) )
{
vartok = vartok - > tokAt ( 2 ) ;
checks . push_back ( new CheckNullpointer ( owner , vartok - > varId ( ) , vartok - > str ( ) ) ) ;
if ( Token : : simpleMatch ( vartok - > next ( ) , " = 0 ; " ) )
setnull ( checks , vartok - > varId ( ) ) ;
return vartok - > next ( ) ;
2010-01-03 13:30:20 +01:00
}
}
2010-07-24 14:27:18 +02:00
if ( Token : : simpleMatch ( & tok , " try { " ) )
{
// Bail out all used variables
unsigned int indentlevel = 0 ;
for ( const Token * tok2 = & tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel = = 0 )
break ;
if ( indentlevel = = 1 & & ! Token : : simpleMatch ( tok2 , " } catch ( " ) )
return tok2 ;
- - indentlevel ;
}
else if ( tok2 - > varId ( ) )
bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
}
2010-01-03 13:30:20 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " %var% ( " ) )
2009-12-23 19:51:32 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok . str ( ) = = " sizeof " )
2010-01-14 20:02:38 +01:00
return tok . next ( ) - > link ( ) ;
2009-12-23 19:51:32 +01:00
// parse usage..
std : : list < const Token * > var ;
parseFunctionCall ( tok , var , 0 ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
2010-04-04 11:24:52 +02:00
dereference ( checks , * it ) ;
2009-12-23 19:51:32 +01:00
}
2010-04-02 07:30:58 +02:00
if ( tok . varId ( ) ! = 0 )
2009-12-06 18:41:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}=] %var% = 0 ; " ) )
2009-12-20 19:44:32 +01:00
setnull ( checks , tok . varId ( ) ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok . tokAt ( - 2 ) , " [ ; { } = + - / ( , ] * % var % " ))
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok . tokAt ( - 2 ) , " return * %var% " ) )
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( ! Token : : simpleMatch ( tok . tokAt ( - 2 ) , " & ( " ) & & Token : : Match ( tok . next ( ) , " . %var% " ) )
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok . previous ( ) , " [ ; { } = + - / ( , ] % var % [ % any % ] " ))
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok . previous ( ) , " return %var% [ %any% ] " ) )
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( & tok , " %var% ( " ) )
2010-04-04 11:24:52 +02:00
dereference ( checks , & tok ) ;
2009-12-06 18:41:28 +01:00
else
2009-12-20 19:44:32 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
}
2009-12-20 19:44:32 +01:00
2010-04-28 22:07:39 +02:00
else if ( tok . str ( ) = = " delete " )
{
const Token * ret = tok . next ( ) ;
if ( Token : : simpleMatch ( ret , " [ ] " ) )
ret = ret - > tokAt ( 2 ) ;
if ( Token : : Match ( ret , " %var% ; " ) )
return ret - > next ( ) ;
}
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-25 19:45:21 +01:00
2010-03-13 21:42:59 +01:00
/** parse condition. @sa ExecutionPath::parseCondition */
2009-12-25 20:50:23 +01:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks )
2009-12-25 19:45:21 +01:00
{
2010-06-06 12:15:31 +02:00
for ( const Token * tok2 = & tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " ) " )
break ;
if ( Token : : Match ( tok2 , " [<>=] * %var% " ) )
dereference ( checks , tok2 - > tokAt ( 2 ) ) ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " !| %var% ( " ) )
2009-12-25 19:45:21 +01:00
{
std : : list < const Token * > var ;
parseFunctionCall ( tok . str ( ) = = " ! " ? * tok . next ( ) : tok , var , 0 ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
2010-04-04 11:24:52 +02:00
dereference ( checks , * it ) ;
2009-12-25 19:45:21 +01:00
}
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2009-12-06 18:41:28 +01:00
} ;
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/**
* @ brief % Check that uninitialized variables aren ' t used ( using ExecutionPath )
* */
2009-12-06 18:41:28 +01:00
class CheckUninitVar : public ExecutionPath
{
public :
2010-03-13 21:42:59 +01:00
/** Startup constructor */
2009-12-21 18:17:35 +01:00
CheckUninitVar ( Check * c )
2010-04-15 20:08:51 +02:00
: ExecutionPath ( c , 0 ) , pointer ( false ) , array ( false ) , alloc ( false ) , strncpy_ ( false )
2009-12-06 18:41:28 +01:00
{
}
private :
2010-03-13 21:42:59 +01:00
/** Create a copy of this check */
2009-12-06 18:41:28 +01:00
ExecutionPath * copy ( )
{
return new CheckUninitVar ( * this ) ;
}
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/** no implementation => compiler error if used */
2009-12-06 20:34:02 +01:00
void operator = ( const CheckUninitVar & ) ;
2010-03-13 21:42:59 +01:00
/** internal constructor for creating extra checks */
2009-12-21 18:17:35 +01:00
CheckUninitVar ( Check * c , unsigned int v , const std : : string & name , bool p , bool a )
2010-04-15 20:08:51 +02:00
: ExecutionPath ( c , v ) , varname ( name ) , pointer ( p ) , array ( a ) , alloc ( false ) , strncpy_ ( false )
2009-12-21 18:17:35 +01:00
{
}
2010-04-25 11:55:57 +02:00
/** is other execution path equal? */
bool is_equal ( const ExecutionPath * e ) const
{
const CheckUninitVar * c = static_cast < const CheckUninitVar * > ( e ) ;
return ( varname = = c - > varname & & pointer = = c - > pointer & & array = = c - > array & & alloc = = c - > alloc & & strncpy_ = = c - > strncpy_ ) ;
}
2010-03-13 21:42:59 +01:00
/** variable name for this check */
2009-12-21 18:17:35 +01:00
const std : : string varname ;
2010-03-13 21:42:59 +01:00
/** is this variable a pointer? */
2009-12-06 18:41:28 +01:00
const bool pointer ;
2010-03-13 21:42:59 +01:00
/** is this variable an array? */
2009-12-06 18:41:28 +01:00
const bool array ;
2010-03-13 21:42:59 +01:00
/** is this variable allocated? */
2009-12-21 18:17:35 +01:00
bool alloc ;
2010-03-13 21:42:59 +01:00
/** is this variable initialized with strncpy (not always zero-terminated) */
2010-02-05 17:35:18 +01:00
bool strncpy_ ;
2009-12-21 18:17:35 +01:00
2010-03-13 21:42:59 +01:00
/** allocating pointer. For example : p = malloc(10); */
2009-12-21 18:17:35 +01:00
static void alloc_pointer ( std : : list < ExecutionPath * > & checks , unsigned int varid )
2009-12-06 18:41:28 +01:00
{
std : : list < ExecutionPath * > : : const_iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-06 18:41:28 +01:00
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2009-12-29 09:30:02 +01:00
c - > alloc = true ;
2009-10-29 21:34:43 +01:00
}
2009-12-06 18:41:28 +01:00
}
2009-10-29 21:34:43 +01:00
2010-03-13 21:42:59 +01:00
/** Initializing a pointer value. For example: *p = 0; */
2010-04-04 11:24:52 +02:00
static void init_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-26 09:30:02 +01:00
{
const unsigned int varid ( tok - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! varid )
2009-12-26 09:30:02 +01:00
return ;
std : : list < ExecutionPath * > : : iterator it = checks . begin ( ) ;
2010-04-02 07:30:58 +02:00
while ( it ! = checks . end ( ) )
2009-12-26 09:30:02 +01:00
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2009-12-26 09:30:02 +01:00
{
2010-04-02 07:30:58 +02:00
if ( c - > alloc | | c - > array )
2009-12-26 09:30:02 +01:00
{
2009-12-29 09:30:02 +01:00
delete c ;
checks . erase ( it + + ) ;
continue ;
}
else
{
2010-04-04 11:24:52 +02:00
use_pointer ( checks , tok ) ;
2009-12-26 09:30:02 +01:00
}
}
+ + it ;
}
}
2010-03-13 21:42:59 +01:00
/** Deallocate a pointer. For example: free(p); */
2010-04-04 11:24:52 +02:00
static void dealloc_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-21 18:17:35 +01:00
{
const unsigned int varid ( tok - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! varid )
2009-12-28 12:51:28 +01:00
return ;
2009-12-21 18:17:35 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2009-12-21 18:17:35 +01:00
{
2010-04-02 07:30:58 +02:00
if ( c - > pointer & & ! c - > alloc )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
2010-04-02 07:30:58 +02:00
if ( checkOther )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
checkOther - > uninitvarError ( tok , c - > varname ) ;
break ;
2009-12-21 18:17:35 +01:00
}
}
2009-12-29 09:30:02 +01:00
c - > alloc = false ;
2009-12-21 18:17:35 +01:00
}
}
}
2010-01-17 19:08:45 +01:00
/**
* Pointer assignment : p = x ;
* if p is a pointer and x is an array / pointer then bail out
* \ param checks all available checks
* \ param tok1 the " p " token
* \ param tok2 the " x " token
*/
static void pointer_assignment ( std : : list < ExecutionPath * > & checks , const Token * tok1 , const Token * tok2 )
{
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid1 = = 0 )
2010-01-17 19:08:45 +01:00
return ;
const unsigned int varid2 ( tok2 - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid2 = = 0 )
2010-01-17 19:08:45 +01:00
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
// bail out if first variable is a pointer
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2010-01-17 19:08:45 +01:00
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid1 & & c - > pointer )
2010-01-17 19:08:45 +01:00
{
bailOutVar ( checks , varid1 ) ;
break ;
}
}
// bail out if second variable is a array/pointer
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2010-01-17 19:08:45 +01:00
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid2 & & ( c - > pointer | | c - > array ) )
2010-01-17 19:08:45 +01:00
{
bailOutVar ( checks , varid2 ) ;
break ;
}
}
}
2010-03-17 22:16:18 +01:00
/** Initialize an array with strncpy. */
2010-02-05 17:35:18 +01:00
static void init_strncpy ( std : : list < ExecutionPath * > & checks , const Token * tok )
{
const unsigned int varid ( tok - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( ! varid )
2010-02-05 17:35:18 +01:00
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2010-02-05 17:35:18 +01:00
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2010-02-05 17:35:18 +01:00
{
c - > strncpy_ = true ;
}
}
}
2009-12-27 10:48:44 +01:00
/**
* use - called from the use * functions below .
* @ param checks all available checks
* @ param tok variable token
* @ param mode specific behaviour
2010-04-04 11:24:52 +02:00
* @ return if error is found , true is returned
2009-12-27 10:48:44 +01:00
*/
2010-04-04 11:24:52 +02:00
static bool use ( std : : list < ExecutionPath * > & checks , const Token * tok , const int mode )
2009-12-21 18:17:35 +01:00
{
const unsigned int varid ( tok - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( varid = = 0 )
2010-04-04 11:24:52 +02:00
return false ;
2009-12-21 18:17:35 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
2010-04-02 07:30:58 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varId = = varid )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
// mode 0 : the variable is used "directly"
// example: .. = var;
// it is ok to read the address of an uninitialized array.
// it is ok to read the address of an allocated pointer
2010-04-02 07:30:58 +02:00
if ( mode = = 0 & & ( c - > array | | ( c - > pointer & & c - > alloc ) ) )
2009-12-29 09:30:02 +01:00
continue ;
2009-12-27 10:48:44 +01:00
2009-12-29 09:30:02 +01:00
// mode 2 : bad usage of pointer. if it's not a pointer then the usage is ok.
// example: ptr->foo();
2010-04-02 07:30:58 +02:00
if ( mode = = 2 & & ! c - > pointer )
2009-12-29 09:30:02 +01:00
continue ;
2009-12-21 18:17:35 +01:00
2009-12-29 20:36:20 +01:00
// mode 3 : using dead pointer is invalid.
2010-04-02 07:30:58 +02:00
if ( mode = = 3 & & ( ! c - > pointer | | c - > alloc ) )
2009-12-29 20:36:20 +01:00
continue ;
2010-04-05 08:38:26 +02:00
// mode 4 : reading uninitialized array or pointer is invalid.
if ( mode = = 4 & & ( ! c - > array & & ! c - > pointer ) )
continue ;
2009-12-29 09:30:02 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
2010-04-02 07:30:58 +02:00
if ( checkOther )
2009-12-29 09:30:02 +01:00
{
2010-04-02 07:30:58 +02:00
if ( c - > strncpy_ )
2010-02-05 17:35:18 +01:00
checkOther - > uninitstringError ( tok , c - > varname ) ;
2010-04-02 07:30:58 +02:00
else if ( c - > pointer & & c - > alloc )
2009-12-29 09:30:02 +01:00
checkOther - > uninitdataError ( tok , c - > varname ) ;
else
checkOther - > uninitvarError ( tok , c - > varname ) ;
2010-04-04 11:24:52 +02:00
return true ;
2009-12-21 18:17:35 +01:00
}
}
}
2010-04-04 11:24:52 +02:00
// No error found
return false ;
2009-12-21 18:17:35 +01:00
}
2009-12-27 10:48:44 +01:00
/**
* Reading variable . Use this function in situations when it is
* invalid to read the data of the variable but not the address .
* @ param checks all available checks
* @ param tok variable token
2010-04-04 11:24:52 +02:00
* @ return if error is found , true is returned
2009-12-27 10:48:44 +01:00
*/
2010-04-04 11:24:52 +02:00
static bool use ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-21 18:17:35 +01:00
{
2010-04-04 11:24:52 +02:00
return use ( checks , tok , 0 ) ;
2009-12-21 18:17:35 +01:00
}
2009-12-27 10:48:44 +01:00
/**
* Reading array elements . If the variable is not an array then the usage is ok .
* @ param checks all available checks
* @ param tok variable token
*/
2010-04-04 11:24:52 +02:00
static void use_array ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-21 18:17:35 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , tok , 1 ) ;
2009-12-21 18:17:35 +01:00
}
2009-12-27 10:48:44 +01:00
/**
* Bad pointer usage . If the variable is not a pointer then the usage is ok .
* @ param checks all available checks
* @ param tok variable token
2010-05-08 19:23:46 +02:00
* @ return if error is found , true is returned
2009-12-27 10:48:44 +01:00
*/
2010-04-05 08:38:26 +02:00
static bool use_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-21 18:17:35 +01:00
{
2010-04-05 08:38:26 +02:00
return use ( checks , tok , 2 ) ;
2009-12-21 18:17:35 +01:00
}
2009-12-29 20:36:20 +01:00
/**
* Using variable . . if it ' s a dead pointer the usage is invalid .
* @ param checks all available checks
* @ param tok variable token
2010-05-08 19:23:46 +02:00
* @ return if error is found , true is returned
2009-12-29 20:36:20 +01:00
*/
2010-04-05 08:38:26 +02:00
static bool use_dead_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-29 20:36:20 +01:00
{
2010-04-05 08:38:26 +02:00
return use ( checks , tok , 3 ) ;
2009-12-29 20:36:20 +01:00
}
2010-04-05 08:38:26 +02:00
/**
* Using variable . . reading from uninitialized array or pointer data is invalid .
* Example : = x [ 0 ] ;
* @ param checks all available checks
* @ param tok variable token
2010-05-08 19:23:46 +02:00
* @ return if error is found , true is returned
2010-04-05 08:38:26 +02:00
*/
static bool use_array_or_pointer_data ( std : : list < ExecutionPath * > & checks , const Token * tok )
{
return use ( checks , tok , 4 ) ;
}
2010-03-13 21:42:59 +01:00
/** declaring a variable */
2010-01-01 19:43:02 +01:00
void declare ( std : : list < ExecutionPath * > & checks , const Token * vartok , const Token & tok , const bool p , const bool a ) const
{
2010-04-02 07:30:58 +02:00
if ( vartok - > varId ( ) = = 0 )
2010-01-01 19:43:02 +01:00
return ;
2010-01-10 20:36:15 +01:00
// Suppress warnings if variable in inner scope has same name as variable in outer scope
2010-09-24 20:56:21 +02:00
if ( ! tok . isStandardType ( ) )
2010-01-01 19:43:02 +01:00
{
2010-01-01 19:49:33 +01:00
std : : set < unsigned int > dup ;
2010-04-02 07:30:58 +02:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2010-01-01 19:43:02 +01:00
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-04-02 07:30:58 +02:00
if ( c & & c - > varname = = vartok - > str ( ) & & c - > varId ! = vartok - > varId ( ) )
2010-01-01 19:49:33 +01:00
dup . insert ( c - > varId ) ;
2010-01-01 19:43:02 +01:00
}
2010-04-02 07:30:58 +02:00
if ( ! dup . empty ( ) )
2010-01-01 19:49:33 +01:00
{
2010-04-02 07:30:58 +02:00
for ( std : : set < unsigned int > : : const_iterator it = dup . begin ( ) ; it ! = dup . end ( ) ; + + it )
2010-01-01 19:49:33 +01:00
bailOutVar ( checks , * it ) ;
2010-01-01 19:43:02 +01:00
return ;
2010-01-01 19:49:33 +01:00
}
2010-01-01 19:43:02 +01:00
}
2010-09-24 20:56:21 +02:00
if ( a | | p | | tok . isStandardType ( ) )
2010-01-01 19:43:02 +01:00
checks . push_back ( new CheckUninitVar ( owner , vartok - > varId ( ) , vartok - > str ( ) , p , a ) ) ;
}
2010-03-13 21:42:59 +01:00
/** parse tokens. @sa ExecutionPath::parse */
2010-04-04 11:24:52 +02:00
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const
2009-12-06 18:41:28 +01:00
{
2009-12-21 18:17:35 +01:00
// Variable declaration..
2010-05-30 08:02:39 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %var% " ) & & tok . str ( ) ! = " return " )
2009-10-29 21:34:43 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " enum %type% { " ) )
2010-01-10 20:36:15 +01:00
return tok . tokAt ( 2 ) - > link ( ) ;
2010-05-30 08:02:39 +02:00
const Token * vartok = & tok ;
while ( Token : : Match ( vartok , " const|struct " ) )
vartok = vartok - > next ( ) ;
2009-12-21 18:17:35 +01:00
2010-05-30 08:02:39 +02:00
if ( Token : : Match ( vartok , " %type% *| %var% ; " ) )
2010-05-30 07:55:11 +02:00
{
2010-05-30 08:02:39 +02:00
vartok = vartok - > next ( ) ;
2010-05-30 07:55:11 +02:00
const bool p ( vartok - > str ( ) = = " * " ) ;
if ( p )
vartok = vartok - > next ( ) ;
declare ( checks , vartok , tok , p , false ) ;
return vartok ;
}
2009-12-23 17:55:03 +01:00
// Variable declaration for array..
2010-05-30 08:02:39 +02:00
if ( Token : : Match ( vartok , " %type% %var% [ %num% ] ; " ) )
2009-12-23 17:55:03 +01:00
{
2010-05-30 08:02:39 +02:00
vartok = vartok - > next ( ) ;
2010-01-01 19:43:02 +01:00
declare ( checks , vartok , tok , false , true ) ;
2010-03-28 21:27:06 +02:00
return vartok - > next ( ) - > link ( ) ;
2009-12-23 17:55:03 +01:00
}
2010-01-03 13:30:20 +01:00
// Template pointer variable..
2010-05-30 08:02:39 +02:00
if ( Token : : Match ( vartok , " %type% ::|< " ) )
2010-01-03 13:30:20 +01:00
{
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( vartok , " %type% :: " ) )
2010-01-03 13:30:20 +01:00
vartok = vartok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( vartok , " %type% < %type% " ) )
2010-01-03 13:30:20 +01:00
{
vartok = vartok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( vartok & & ( vartok - > str ( ) = = " * " | | vartok - > isName ( ) ) )
2010-01-03 13:30:20 +01:00
vartok = vartok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( vartok , " > * %var% ; " ) )
2010-01-03 13:30:20 +01:00
{
declare ( checks , vartok - > tokAt ( 2 ) , tok , true , false ) ;
return vartok - > tokAt ( 2 ) ;
}
}
}
2009-12-21 18:17:35 +01:00
}
2010-04-02 07:30:58 +02:00
if ( tok . varId ( ) )
2009-12-21 18:17:35 +01:00
{
2010-01-09 22:26:05 +01:00
// Used..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " [[(,+-*/] %var% []),+-*/] " ) )
2010-01-09 22:26:05 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2010-01-09 22:26:05 +01:00
return & tok ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " ++|-- " ) | | Token : : Match ( tok . next ( ) , " ++|-- " ) )
2010-01-10 09:09:37 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2010-01-10 09:09:37 +01:00
return & tok ;
}
2010-09-23 21:40:08 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %var% [=[.] " ) )
2009-12-30 20:15:44 +01:00
{
2010-05-30 07:55:11 +02:00
if ( tok . next ( ) - > str ( ) = = " . " )
2009-12-30 20:15:44 +01:00
{
2010-05-30 07:55:11 +02:00
if ( use_dead_pointer ( checks , & tok ) )
2010-04-04 11:24:52 +02:00
{
2010-05-30 07:55:11 +02:00
return & tok ;
}
}
else
{
// check variable usages in rhs/index
for ( const Token * tok2 = tok . tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
2010-09-23 21:40:08 +02:00
if ( Token : : Match ( tok2 , " [;)=?] " ) )
2010-05-30 07:55:11 +02:00
break ;
if ( Token : : Match ( tok2 , " %var% ( " ) )
break ;
if ( tok2 - > varId ( ) & &
! Token : : Match ( tok2 - > previous ( ) , " &|:: " ) & &
! Token : : simpleMatch ( tok2 - > next ( ) , " = " ) )
2010-04-04 11:24:52 +02:00
{
2010-06-25 19:39:30 +02:00
// Multiple assignments..
if ( Token : : simpleMatch ( tok2 - > next ( ) , " [ " ) )
{
const Token * tok3 = tok2 ;
while ( Token : : simpleMatch ( tok3 - > next ( ) , " [ " ) )
tok3 = tok3 - > next ( ) - > link ( ) ;
if ( Token : : simpleMatch ( tok3 , " ] = " ) )
continue ;
}
2010-05-30 07:55:11 +02:00
bool foundError ;
2010-06-14 08:36:34 +02:00
if ( tok2 - > previous ( ) - > str ( ) = = " * " | | tok2 - > next ( ) - > str ( ) = = " [ " )
2010-05-30 07:55:11 +02:00
foundError = use_array_or_pointer_data ( checks , tok2 ) ;
else
foundError = use ( checks , tok2 ) ;
// prevent duplicate error messages
if ( foundError )
{
bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
2010-04-04 11:24:52 +02:00
}
}
2009-12-30 20:15:44 +01:00
}
2010-01-17 19:08:45 +01:00
// pointer aliasing?
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . tokAt ( 2 ) , " %var% ; " ) )
2010-01-17 19:08:45 +01:00
{
pointer_assignment ( checks , & tok , tok . tokAt ( 2 ) ) ;
}
2009-12-30 20:15:44 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " ( " ) )
2010-01-23 07:57:57 +01:00
{
2010-04-04 11:24:52 +02:00
use_pointer ( checks , & tok ) ;
2010-01-23 07:57:57 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [;{}] * " ) )
2009-12-06 18:41:28 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " = " ) )
2010-04-04 11:24:52 +02:00
init_pointer ( checks , & tok ) ;
2009-12-26 09:30:02 +01:00
else
2010-04-04 11:24:52 +02:00
use_pointer ( checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-15 20:26:07 +01:00
2010-01-03 18:49:13 +01:00
// += etc
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] " ) | | Token : : Match ( tok . tokAt ( - 2 ) , " [;{}] * " ) )
2010-01-03 18:49:13 +01:00
{
// goto the equal..
const Token * eq = tok . next ( ) ;
2010-04-02 07:30:58 +02:00
if ( eq & & eq - > str ( ) = = " [ " & & eq - > link ( ) & & eq - > link ( ) - > next ( ) )
2010-01-03 18:49:13 +01:00
eq = eq - > link ( ) - > next ( ) ;
// is it X=
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( eq , " +=|-=|*=|/=|&=|^= " ) | | eq - > str ( ) = = " |= " )
2010-01-03 18:49:13 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok . previous ( ) - > str ( ) = = " * " )
2010-04-04 11:24:52 +02:00
use_pointer ( checks , & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( tok . next ( ) - > str ( ) = = " [ " )
2010-04-04 11:24:52 +02:00
use_array ( checks , & tok ) ;
2010-01-03 18:49:13 +01:00
else
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2010-01-03 18:49:13 +01:00
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . next ( ) , " = malloc|kmalloc " ) | | Token : : simpleMatch ( tok . next ( ) , " = new char [ " ) )
2009-11-02 16:28:15 +01:00
{
2009-12-21 18:17:35 +01:00
alloc_pointer ( checks , tok . varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( tok . tokAt ( 3 ) - > str ( ) = = " ( " )
2010-05-30 10:30:51 +02:00
return tok . tokAt ( 3 ) ;
2009-12-21 18:17:35 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok . previous ( ) , " >> " ) | | Token : : simpleMatch ( tok . next ( ) , " = " ) )
2009-12-21 18:17:35 +01:00
{
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-02 16:28:15 +01:00
}
2009-11-03 21:02:16 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) )
2009-11-03 21:02:16 +01:00
{
2009-12-06 18:41:28 +01:00
const Token * tok2 = tok . next ( ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok2 ? tok2 - > next ( ) : 0 , " = " ) )
2009-11-03 21:02:16 +01:00
{
2010-01-09 22:26:05 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-03 21:02:16 +01:00
}
}
2009-11-15 20:01:57 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . previous ( ) , " delete " ) | |
Token : : simpleMatch ( tok . tokAt ( - 3 ) , " delete [ ] " ) )
2009-11-15 20:01:57 +01:00
{
2010-04-04 11:24:52 +02:00
dealloc_pointer ( checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-15 20:01:57 +01:00
}
2009-10-29 21:34:43 +01:00
}
2010-09-27 19:26:09 +02:00
if ( Token : : Match ( & tok , " %var% ( " ) & & uvarFunctions . find ( tok . str ( ) ) = = uvarFunctions . end ( ) )
2009-10-30 14:06:40 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( & tok , " sizeof ( " ) )
2009-12-30 11:32:46 +01:00
return tok . next ( ) - > link ( ) ;
2009-12-27 18:00:43 +01:00
// deallocate pointer
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " free|kfree|fclose ( %var% ) " ) )
2009-12-27 18:00:43 +01:00
{
2010-04-04 11:24:52 +02:00
dealloc_pointer ( checks , tok . tokAt ( 2 ) ) ;
2009-12-27 18:00:43 +01:00
return tok . tokAt ( 3 ) ;
}
2009-12-23 19:51:32 +01:00
// parse usage..
2009-11-03 17:03:53 +01:00
{
2009-12-23 19:51:32 +01:00
std : : list < const Token * > var ;
parseFunctionCall ( tok , var , 1 ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
2010-04-04 11:24:52 +02:00
use_array ( checks , * it ) ;
2010-05-08 19:23:46 +02:00
// Using uninitialized pointer is bad if using null pointer is bad
std : : list < const Token * > var2 ;
parseFunctionCall ( tok , var2 , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = var2 . begin ( ) ; it ! = var2 . end ( ) ; + + it )
{
if ( std : : find ( var . begin ( ) , var . end ( ) , * it ) = = var . end ( ) )
2010-05-09 07:48:52 +02:00
use_dead_pointer ( checks , * it ) ;
2010-05-08 19:23:46 +02:00
}
2009-12-06 18:41:28 +01:00
}
2009-12-21 18:17:35 +01:00
// strncpy doesn't 0-terminate first parameter
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " strncpy ( %var% , " ) )
2010-02-05 17:35:18 +01:00
{
2010-07-05 12:45:39 +02:00
if ( Token : : Match ( tok . tokAt ( 4 ) , " %str% , " ) )
{
if ( Token : : Match ( tok . tokAt ( 6 ) , " %num% ) " ) )
{
const unsigned int len = Token : : getStrLength ( tok . tokAt ( 4 ) ) ;
2010-08-06 22:37:48 +02:00
const long sz = MathLib : : toLongNumber ( tok . strAt ( 6 ) ) ;
if ( sz > = 0 & & len > = static_cast < unsigned long > ( sz ) )
2010-07-05 12:45:39 +02:00
{
init_strncpy ( checks , tok . tokAt ( 2 ) ) ;
return tok . next ( ) - > link ( ) ;
}
}
}
else
{
init_strncpy ( checks , tok . tokAt ( 2 ) ) ;
return tok . next ( ) - > link ( ) ;
}
2010-02-05 17:35:18 +01:00
}
2009-12-21 18:17:35 +01:00
2010-06-14 08:36:34 +02:00
if ( Token : : simpleMatch ( & tok , " asm ( ) " ) )
2009-12-06 18:41:28 +01:00
{
ExecutionPath : : bailOut ( checks ) ;
return & tok ;
2009-11-03 17:03:53 +01:00
}
2009-10-31 16:36:56 +01:00
2009-10-30 14:06:40 +01:00
// is the variable passed as a parameter to some function?
unsigned int parlevel = 0 ;
2010-01-03 13:30:20 +01:00
std : : set < unsigned int > bailouts ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok . next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-10-30 14:06:40 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-11-15 12:42:04 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-11-15 12:42:04 +01:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel < = 1 )
2009-11-15 12:42:04 +01:00
break ;
- - parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok2 , " sizeof ( " ) )
2009-12-31 09:10:20 +01:00
{
2010-01-02 18:16:44 +01:00
tok2 = tok2 - > next ( ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-12-31 09:10:20 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( tok2 - > varId ( ) )
2009-11-15 12:42:04 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [(,] * " ) | | Token : : Match ( tok2 - > next ( ) , " . %var% " ) )
2010-05-30 09:31:10 +02:00
{
if ( use_dead_pointer ( checks , tok2 ) )
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
2009-12-29 20:36:20 +01:00
2009-11-15 12:42:04 +01:00
// it is possible that the variable is initialized here
2010-05-30 09:31:10 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " [(,] %var% [,)] " ) )
bailouts . insert ( tok2 - > varId ( ) ) ;
2010-07-19 10:03:54 +02:00
// array initialization..
if ( Token : : Match ( tok2 - > previous ( ) , " [,(] %var% + " ) )
{
// if var is array, bailout
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
if ( ( * it ) - > varId = = tok2 - > varId ( ) )
{
const CheckUninitVar * c = dynamic_cast < const CheckUninitVar * > ( * it ) ;
if ( c & & c - > array )
bailouts . insert ( tok2 - > varId ( ) ) ;
break ;
}
}
}
2009-11-15 12:42:04 +01:00
}
}
2010-01-03 13:30:20 +01:00
2010-04-02 07:30:58 +02:00
for ( std : : set < unsigned int > : : const_iterator it = bailouts . begin ( ) ; it ! = bailouts . end ( ) ; + + it )
2010-01-03 13:30:20 +01:00
ExecutionPath : : bailOutVar ( checks , * it ) ;
2009-11-15 12:42:04 +01:00
}
// function call via function pointer
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " ( * %var% ) ( " ) )
2009-11-15 12:42:04 +01:00
{
// is the variable passed as a parameter to some function?
unsigned int parlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok . link ( ) - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-11-15 12:42:04 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-10-30 14:06:40 +01:00
+ + parlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-10-30 14:06:40 +01:00
{
2010-04-02 07:30:58 +02:00
if ( parlevel < = 1 )
2009-10-30 14:06:40 +01:00
break ;
- - parlevel ;
}
2010-04-02 07:30:58 +02:00
else if ( tok2 - > varId ( ) )
2009-10-30 14:06:40 +01:00
{
// it is possible that the variable is initialized here
2009-12-21 18:17:35 +01:00
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
2009-10-30 14:06:40 +01:00
}
}
}
2010-04-02 07:30:58 +02:00
if ( tok . str ( ) = = " return " )
2009-11-06 16:02:13 +01:00
{
2009-12-21 18:17:35 +01:00
// Todo: if (!array && ..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . next ( ) , " %var% ; " ) )
2009-11-06 16:02:13 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , tok . next ( ) ) ;
2009-11-06 16:02:13 +01:00
}
2010-08-04 21:13:40 +02:00
else if ( Token : : Match ( tok . next ( ) , " %var% [ " ) )
{
use_array_or_pointer_data ( checks , tok . next ( ) ) ;
}
2009-11-06 16:02:13 +01:00
}
2010-04-02 07:30:58 +02:00
if ( tok . varId ( ) )
2009-10-30 14:31:37 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . previous ( ) , " = " ) )
2009-11-03 17:03:53 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . tokAt ( - 3 ) , " & %var% = " ) )
2009-12-15 19:50:48 +01:00
{
2009-12-21 18:17:35 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-15 19:50:48 +01:00
return & tok ;
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " . %var% = " ) )
2009-11-03 17:03:53 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " [;{}] %var% = " ) )
2009-12-06 18:41:28 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-05 21:07:04 +01:00
2009-12-06 18:41:28 +01:00
const unsigned int varid2 = tok . tokAt ( - 2 ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( varid2 )
2009-11-05 21:07:04 +01:00
{
2009-12-06 18:41:28 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-05 21:07:04 +01:00
}
2009-11-03 17:03:53 +01:00
}
}
2009-11-02 19:58:49 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " . " ) )
2009-12-06 18:41:28 +01:00
{
2010-03-07 09:08:52 +01:00
const Token * tok2 = tok . next ( ) ;
2010-04-02 07:30:58 +02:00
while ( Token : : Match ( tok2 , " . %var% " ) )
2010-03-07 09:08:52 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( tok2 & & tok2 - > str ( ) ! = " = " )
2010-04-04 11:24:52 +02:00
use_pointer ( checks , & tok ) ;
2010-01-23 21:25:17 +01:00
else
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) )
2009-12-06 18:41:28 +01:00
{
2009-12-21 18:17:35 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-27 17:20:34 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [,(=] * " ) )
2009-12-27 17:20:34 +01:00
{
2010-04-04 11:24:52 +02:00
use_pointer ( checks , & tok ) ;
2009-12-27 17:20:34 +01:00
return & tok ;
}
2010-01-11 19:25:01 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok . previous ( ) , " & " ) )
2010-01-11 19:25:01 +01:00
{
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
}
2009-12-06 18:41:28 +01:00
}
2010-03-28 21:27:06 +02:00
// Parse "for"
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( & tok , " [;{}] for ( " ) )
2010-03-28 21:27:06 +02:00
{
// initialized variables
std : : set < unsigned int > varid1 ;
varid1 . insert ( 0 ) ;
// Parse token
const Token * tok2 ;
// parse setup
2010-04-02 07:30:58 +02:00
for ( tok2 = tok . tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2010-03-28 21:27:06 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ; " )
2010-03-28 21:27:06 +02:00
break ;
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) )
2010-03-28 21:27:06 +02:00
varid1 . insert ( tok2 - > varId ( ) ) ;
}
// parse condition
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; %var% <|<=|>=|> %num% ; " ) )
2010-03-28 21:27:06 +02:00
{
// If the variable hasn't been initialized then call "use"
2010-04-02 07:30:58 +02:00
if ( varid1 . find ( tok2 - > next ( ) - > varId ( ) ) = = varid1 . end ( ) )
2010-04-04 11:24:52 +02:00
use ( checks , tok2 - > next ( ) ) ;
2010-03-28 21:27:06 +02:00
}
// goto stepcode
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
2010-03-28 21:27:06 +02:00
tok2 = tok2 - > next ( ) ;
// parse the stepcode
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; ++|-- %var% ) { " ) | |
Token : : Match ( tok2 , " ; %var% ++|-- ) { " ) )
2010-03-28 21:27:06 +02:00
{
// get id of variable..
unsigned int varid = tok2 - > next ( ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! varid )
2010-03-28 21:27:06 +02:00
varid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
// Check that the variable hasn't been initialized and
// that it isn't initialized in the body..
2010-04-02 07:30:58 +02:00
if ( varid1 . find ( varid ) = = varid1 . end ( ) )
2010-03-28 21:27:06 +02:00
{
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok2 - > tokAt ( 5 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2010-03-28 21:27:06 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2010-03-28 21:27:06 +02:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2010-03-28 21:27:06 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2010-03-28 21:27:06 +02:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( tok3 - > varId ( ) = = varid )
2010-03-28 21:27:06 +02:00
{
2010-04-04 09:17:53 +02:00
varid = 0 ; // variable is used.. maybe it's initialized. clear the variable id.
2010-03-28 21:27:06 +02:00
break ;
}
}
// If the variable isn't initialized in the body call "use"
2010-04-02 07:30:58 +02:00
if ( varid ! = 0 )
2010-03-28 21:27:06 +02:00
{
// goto variable
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 - > varId ( ) )
2010-03-28 21:27:06 +02:00
tok2 = tok2 - > next ( ) ;
// call "use"
2010-04-04 11:24:52 +02:00
use ( checks , tok2 ) ;
2010-03-28 21:27:06 +02:00
}
}
}
}
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-25 19:45:21 +01:00
2009-12-25 20:50:23 +01:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks )
2009-12-25 19:45:21 +01:00
{
2010-08-04 21:13:40 +02:00
if ( tok . varId ( ) & & Token : : Match ( & tok , " %var% <|<=|==|!=|) " ) )
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2009-12-25 19:45:21 +01:00
2010-08-04 21:13:40 +02:00
else if ( Token : : Match ( & tok , " !| %var% [ " ) )
use_array_or_pointer_data ( checks , tok . str ( ) = = " ! " ? tok . next ( ) : & tok ) ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( & tok , " !| %var% ( " ) )
2009-12-25 19:45:21 +01:00
{
std : : list < const Token * > var ;
parseFunctionCall ( tok . str ( ) = = " ! " ? * tok . next ( ) : tok , var , 1 ) ;
2010-04-02 07:30:58 +02:00
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
2010-04-04 11:24:52 +02:00
use_array ( checks , * it ) ;
2009-12-25 19:45:21 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( & tok , " ! %var% ) " ) )
2009-12-30 20:37:11 +01:00
{
2010-04-04 11:24:52 +02:00
use ( checks , & tok ) ;
2009-12-30 20:37:11 +01:00
return false ;
}
2009-12-25 19:45:21 +01:00
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2010-01-11 22:28:07 +01:00
2010-10-24 18:12:48 +02:00
void parseLoopBody ( const Token * tok_ , std : : list < ExecutionPath * > & checks ) const
{
for ( ; tok_ ; tok_ = tok_ - > next ( ) )
{
if ( tok_ - > str ( ) = = " { " )
return ;
const Token & tok = * tok_ ;
if ( Token : : Match ( tok . previous ( ) , " [;{}] %var% [=[.] " ) )
{
if ( tok . next ( ) - > str ( ) = = " . " )
{
if ( use_dead_pointer ( checks , & tok ) )
{
return ;
}
}
else
{
// check variable usages in rhs/index
for ( const Token * tok2 = tok . tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( Token : : Match ( tok2 , " [;)=?] " ) )
break ;
if ( Token : : Match ( tok2 , " %var% ( " ) )
break ;
if ( tok2 - > varId ( ) & &
! Token : : Match ( tok2 - > previous ( ) , " &|:: " ) & &
! Token : : simpleMatch ( tok2 - > next ( ) , " = " ) )
{
// Multiple assignments..
if ( Token : : simpleMatch ( tok2 - > next ( ) , " [ " ) )
{
const Token * tok3 = tok2 ;
while ( Token : : simpleMatch ( tok3 - > next ( ) , " [ " ) )
tok3 = tok3 - > next ( ) - > link ( ) ;
if ( Token : : simpleMatch ( tok3 , " ] = " ) )
continue ;
}
bool foundError ;
if ( tok2 - > previous ( ) - > str ( ) = = " * " | | tok2 - > next ( ) - > str ( ) = = " [ " )
foundError = use_array_or_pointer_data ( checks , tok2 ) ;
else
foundError = use ( checks , tok2 ) ;
// prevent duplicate error messages
if ( foundError )
{
bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
}
}
}
// pointer aliasing?
if ( Token : : Match ( tok . tokAt ( 2 ) , " %var% ; " ) )
{
pointer_assignment ( checks , & tok , tok . tokAt ( 2 ) ) ;
}
}
}
}
2010-01-11 22:28:07 +01:00
public :
2010-03-13 21:42:59 +01:00
/** Functions that don't handle uninitialized variables well */
2010-01-11 22:28:07 +01:00
static std : : set < std : : string > uvarFunctions ;
2010-05-21 19:35:18 +02:00
static void analyseFunctions ( const Token * const tokens , std : : set < std : : string > & func )
2010-01-11 22:28:07 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = tokens ; tok ; tok = tok - > next ( ) )
2010-01-11 22:28:07 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2010-01-11 22:28:07 +01:00
{
tok = tok - > link ( ) ;
continue ;
}
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) ! = " :: " & & Token : : Match ( tok - > next ( ) , " %var% ( %type% " ) )
2010-01-11 22:28:07 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok - > tokAt ( 2 ) - > link ( ) , " ) { " ) )
2010-01-11 22:28:07 +01:00
continue ;
const Token * tok2 = tok - > tokAt ( 3 ) ;
2010-04-02 07:30:58 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ) " )
2010-01-11 22:28:07 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " , " )
2010-01-11 22:28:07 +01:00
tok2 = tok2 - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %type% %var% ,|) " ) & & tok2 - > isStandardType ( ) )
2010-01-11 22:28:07 +01:00
{
tok2 = tok2 - > tokAt ( 2 ) ;
continue ;
}
2010-04-04 09:17:53 +02:00
if ( tok2 - > isStandardType ( ) & & Token : : Match ( tok2 , " %type% & %var% ,|) " ) )
2010-01-11 22:28:07 +01:00
{
2010-04-04 09:17:53 +02:00
const unsigned int varid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
// flags for read/write
bool r = false , w = false ;
// check how the variable is used in the function
unsigned int indentlevel = 0 ;
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok3 - > str ( ) = = " } " )
{
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
}
else if ( indentlevel = = 0 & & tok3 - > str ( ) = = " ; " )
break ;
else if ( indentlevel > = 1 & & tok3 - > varId ( ) = = varid )
{
if ( Token : : Match ( tok3 - > previous ( ) , " ++|-- " ) | |
Token : : Match ( tok3 - > next ( ) , " ++|-- " ) )
{
r = true ;
}
else
{
w = true ;
break ;
}
}
}
if ( ! r | | w )
break ;
tok2 = tok2 - > tokAt ( 3 ) ;
continue ;
}
if ( Token : : Match ( tok2 , " const %type% &|*| const| %var% ,|) " ) & & tok2 - > next ( ) - > isStandardType ( ) )
{
tok2 = tok2 - > tokAt ( 3 ) ;
while ( tok2 - > isName ( ) )
tok2 = tok2 - > next ( ) ;
2010-01-11 22:28:07 +01:00
continue ;
}
break ;
}
// found simple function..
2010-04-02 07:30:58 +02:00
if ( tok2 - > link ( ) = = tok - > tokAt ( 2 ) )
2010-01-11 22:28:07 +01:00
func . insert ( tok - > next ( ) - > str ( ) ) ;
}
}
}
2009-12-06 18:41:28 +01:00
} ;
2010-03-13 21:42:59 +01:00
/** Functions that don't handle uninitialized variables well */
2010-01-11 22:28:07 +01:00
std : : set < std : : string > CheckUninitVar : : uvarFunctions ;
2010-03-13 21:42:59 +01:00
/// @}
2010-05-21 19:35:18 +02:00
void CheckOther : : analyse ( const Token * const tokens , std : : set < std : : string > & func ) const
2010-01-11 22:28:07 +01:00
{
2010-05-21 19:35:18 +02:00
CheckUninitVar : : analyseFunctions ( tokens , func ) ;
2010-01-11 22:28:07 +01:00
}
2010-05-21 19:35:18 +02:00
void CheckOther : : saveAnalysisData ( const std : : set < std : : string > & data ) const
{
CheckUninitVar : : uvarFunctions . insert ( data . begin ( ) , data . end ( ) ) ;
}
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
void CheckOther : : executionPaths ( )
2009-10-29 21:34:43 +01:00
{
2009-12-25 20:12:06 +01:00
// Check for null pointer errors..
2009-10-29 21:34:43 +01:00
{
2009-12-25 20:12:06 +01:00
CheckNullpointer c ( this ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
}
2009-12-21 18:17:35 +01:00
2009-12-25 20:12:06 +01:00
// check if variable is accessed uninitialized..
{
2010-01-12 22:33:47 +01:00
// no writing if multiple threads are used (TODO: thread safe analysis?)
2010-04-02 07:30:58 +02:00
if ( _settings - > _jobs = = 1 )
2010-05-21 19:35:18 +02:00
CheckUninitVar : : analyseFunctions ( _tokenizer - > tokens ( ) , CheckUninitVar : : uvarFunctions ) ;
2010-01-12 22:33:47 +01:00
2009-12-25 20:12:06 +01:00
CheckUninitVar c ( this ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
2009-10-29 21:34:43 +01:00
}
}
2009-07-05 22:16:43 +02:00
void CheckOther : : checkZeroDivision ( )
2009-03-28 07:49:47 +01:00
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-03-28 07:49:47 +01:00
{
2009-09-01 21:06:46 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " / %num% " ) & &
MathLib : : isInt ( tok - > next ( ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) = = 0L )
2009-08-23 05:34:19 +02:00
{
2009-03-29 18:47:05 +02:00
zerodivError ( tok ) ;
2009-08-23 05:34:19 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " div|ldiv|lldiv|imaxdiv ( %num% , %num% ) " ) & &
MathLib : : isInt ( tok - > tokAt ( 4 ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > tokAt ( 4 ) - > str ( ) ) = = 0L )
2009-08-23 05:34:19 +02:00
{
zerodivError ( tok ) ;
}
2009-03-28 07:49:47 +01:00
}
}
2010-04-02 02:19:38 +02:00
void CheckOther : : checkMathFunctions ( )
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2010-04-02 02:19:38 +02:00
{
2010-04-02 07:32:03 +02:00
// case log(-2)
2010-07-07 09:03:40 +02:00
if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " log|log10 ( %num% ) " ) & &
2010-04-02 07:30:58 +02:00
MathLib : : isNegative ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : isInt ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > tokAt ( 2 ) - > str ( ) ) < = 0 )
2010-04-02 02:19:38 +02:00
{
mathfunctionCallError ( tok ) ;
}
2010-04-02 07:32:03 +02:00
// case log(-2.0)
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " log|log10 ( %num% ) " ) & &
2010-04-02 07:32:03 +02:00
MathLib : : isNegative ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : isFloat ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : toDoubleNumber ( tok - > tokAt ( 2 ) - > str ( ) ) < = 0. )
{
mathfunctionCallError ( tok ) ;
}
// case log(0.0)
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " log|log10 ( %num% ) " ) & &
2010-04-02 07:32:03 +02:00
! MathLib : : isNegative ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : isFloat ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : toDoubleNumber ( tok - > tokAt ( 2 ) - > str ( ) ) < = 0. )
{
mathfunctionCallError ( tok ) ;
}
// case log(0)
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " log|log10 ( %num% ) " ) & &
2010-04-02 07:32:03 +02:00
! MathLib : : isNegative ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : isInt ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > tokAt ( 2 ) - > str ( ) ) < = 0 )
{
mathfunctionCallError ( tok ) ;
2010-04-02 20:23:37 +02:00
}
2010-04-02 21:17:09 +02:00
// acos( x ), asin( x ) where x is defined for intervall [-1,+1], but not beyound
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " acos|asin ( %num% ) " ) & &
2010-04-03 07:51:40 +02:00
std : : fabs ( MathLib : : toDoubleNumber ( tok - > tokAt ( 2 ) - > str ( ) ) ) > 1.0 )
2010-04-02 20:23:37 +02:00
{
mathfunctionCallError ( tok ) ;
2010-04-05 19:35:56 +02:00
}
2010-04-05 20:20:20 +02:00
// sqrt( x ): if x is negative the result is undefined
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " sqrt ( %num% ) " ) & &
2010-04-05 20:20:20 +02:00
MathLib : : isNegative ( tok - > tokAt ( 2 ) - > str ( ) ) )
{
mathfunctionCallError ( tok ) ;
}
2010-04-05 19:57:54 +02:00
// atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " atan2 ( %num% , %num% ) " ) & &
2010-04-05 19:35:56 +02:00
MathLib : : isNullValue ( tok - > tokAt ( 2 ) - > str ( ) ) & &
2010-04-05 19:57:54 +02:00
MathLib : : isNullValue ( tok - > tokAt ( 4 ) - > str ( ) ) )
2010-04-05 19:35:56 +02:00
{
2010-04-05 19:57:54 +02:00
mathfunctionCallError ( tok , 2 ) ;
2010-04-02 07:32:03 +02:00
}
2010-04-05 19:57:54 +02:00
// fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " fmod ( %num% , %num% ) " ) & &
2010-04-05 19:57:54 +02:00
MathLib : : isNullValue ( tok - > tokAt ( 4 ) - > str ( ) ) )
2010-04-05 19:45:33 +02:00
{
2010-04-05 19:57:54 +02:00
mathfunctionCallError ( tok , 2 ) ;
2010-04-05 20:07:53 +02:00
}
2010-04-05 20:12:43 +02:00
// pow ( x , y) If x is zero, and y is negative --> division by zero
2010-07-07 09:03:40 +02:00
else if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " pow ( %num% , %num% ) " ) & &
2010-04-05 20:12:43 +02:00
MathLib : : isNullValue ( tok - > tokAt ( 2 ) - > str ( ) ) & &
MathLib : : isNegative ( tok - > tokAt ( 4 ) - > str ( ) ) )
2010-04-05 20:07:53 +02:00
{
2010-04-05 20:12:43 +02:00
mathfunctionCallError ( tok , 2 ) ;
2010-04-05 19:45:33 +02:00
}
2010-04-02 02:19:38 +02:00
}
}
2010-10-01 17:23:22 +02:00
bool CheckOther : : isIdentifierObjectType ( const Token * const tok )
{
const std : : string identifier = tok - > tokAt ( 1 ) - > str ( ) ;
2010-10-02 10:43:12 +02:00
const std : : map < std : : string , bool > : : const_iterator found = isClassResults . find ( identifier ) ;
if ( found ! = isClassResults . end ( ) )
2010-10-01 17:23:22 +02:00
{
return found - > second ;
}
2010-10-13 11:31:41 +02:00
const std : : string classDefnOrDecl = std : : string ( " class|struct " ) + identifier + " [{:;] " ;
2010-10-13 12:19:18 +02:00
const bool result = Token : : findmatch ( _tokenizer - > tokens ( ) , classDefnOrDecl . c_str ( ) ) ! = NULL ;
2010-10-02 10:43:12 +02:00
isClassResults . insert ( std : : make_pair ( identifier , result ) ) ;
2010-10-01 17:23:22 +02:00
return result ;
}
void CheckOther : : checkMisusedScopedObject ( )
{
2010-10-02 12:12:52 +02:00
bool withinFunction = false ;
2010-10-01 17:23:22 +02:00
unsigned int depth = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2010-10-02 12:12:52 +02:00
withinFunction | = Token : : Match ( tok , " ) const| { " ) ;
if ( withinFunction )
2010-10-01 17:23:22 +02:00
{
if ( tok - > str ( ) = = " { " )
{
+ + depth ;
}
else if ( tok - > str ( ) = = " } " )
{
- - depth ;
2010-10-02 12:12:52 +02:00
withinFunction & = depth > 0 ;
2010-10-01 17:23:22 +02:00
}
2010-10-02 13:16:50 +02:00
if ( withinFunction
& & Token : : Match ( tok , " [;{}] %var% ( " )
2010-10-03 23:16:11 +02:00
& & Token : : Match ( tok - > tokAt ( 2 ) - > link ( ) , " ) ; " )
2010-10-02 12:26:29 +02:00
& & isIdentifierObjectType ( tok )
)
2010-10-01 17:23:22 +02:00
{
tok = tok - > next ( ) ;
misusedScopeObjectError ( tok , tok - > str ( ) ) ;
tok = tok - > next ( ) ;
}
}
}
}
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 : : 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 : : sprintfOverlappingDataError ( const Token * tok , const std : : string & varname )
{
2009-12-21 21:05:55 +01:00
reportError ( tok , Severity : : error , " sprintfOverlappingData " , " Undefined behaviour: " + varname + " is used wrong in call to sprintf or snprintf. Quote: If copying takes place between objects that overlap as a result of a call to sprintf() or snprintf(), the results are undefined. " ) ;
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 : : 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 )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : performance , " passedByValue " , " Function parameter ' " + parname + " ' is passed by value. It could be passed by reference instead, to make it faster. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : constStatementError ( const Token * tok , const std : : string & type )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " 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 )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " charArrayIndex " , " Warning - using char variable as array index " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : charBitOpError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " 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 )
{
2010-07-19 11:30:01 +02:00
reportError ( tok ,
Severity : : style ,
" variableScope " ,
" The scope of the variable " + varname + " can be reduced \n "
2010-07-23 12:29:21 +02:00
" Warning: It can be unsafe to fix this message. Be careful. Especially when there are inner loops. \n "
" Here is an example where cppcheck will write that the scope for 'i' can be reduced: \n "
" void f(int x) \n "
" { \n "
" int i = 0; \n "
" if (x) { \n "
" // it's safe to move 'int i = 0' here \n "
" for (int n = 0; n < 10; ++n) { \n "
" // it is possible but not safe to move 'int i = 0' here \n "
" do_something(&i); \n "
" } \n "
" } \n "
" } \n "
" \n "
" When you see this message it is always safe to reduce the variable scope 1 level. " ) ;
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-12-30 17:42:41 +01:00
void CheckOther : : nullPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " nullPointer " , " Null pointer dereference " ) ;
}
2009-08-11 17:18:01 +02:00
void CheckOther : : nullPointerError ( const Token * tok , const std : : string & varname )
2009-03-27 17:19:34 +01:00
{
2009-08-11 17:18:01 +02:00
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference: " + varname ) ;
2009-03-27 17:19:34 +01:00
}
2009-03-28 07:49:47 +01:00
2010-08-06 19:40:54 +02:00
void CheckOther : : nullPointerError ( const Token * tok , const std : : string & varname , const unsigned int line )
2009-08-21 12:42:40 +02:00
{
2010-08-06 22:37:48 +02:00
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference: " + varname + " - otherwise it is redundant to check if " + varname + " is null at line " + MathLib : : toString < unsigned int > ( line ) ) ;
2009-08-21 12:42:40 +02:00
}
2010-02-05 17:35:18 +01:00
void CheckOther : : uninitstringError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitstring " , " Dangerous usage of ' " + varname + " ' (strncpy doesn't always 0-terminate it) " ) ;
}
2009-11-07 09:10:15 +01:00
void CheckOther : : uninitdataError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitdata " , " Data is allocated but not initialized: " + varname ) ;
}
2009-10-29 21:34:43 +01:00
void CheckOther : : uninitvarError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitvar " , " Uninitialized variable: " + varname ) ;
}
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
}
2009-07-25 00:36:15 +02:00
2010-04-05 19:35:56 +02:00
void CheckOther : : mathfunctionCallError ( const Token * tok , const unsigned int numParam )
2010-04-02 02:19:38 +02:00
{
2010-04-03 21:53:06 +02:00
if ( tok )
2010-04-05 19:35:56 +02:00
{
2010-04-05 19:57:54 +02:00
if ( numParam = = 1 )
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " + tok - > tokAt ( 2 ) - > str ( ) + " to " + tok - > str ( ) + " () leads to undefined result " ) ;
else if ( numParam = = 2 )
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " + tok - > tokAt ( 2 ) - > str ( ) + " and " + tok - > tokAt ( 4 ) - > str ( ) + " to " + tok - > str ( ) + " () leads to undefined result " ) ;
}
2010-04-03 21:53:06 +02:00
else
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " " to " " () leads to undefined result " ) ;
2010-04-02 02:19:38 +02:00
}
2010-04-13 19:30:25 +02:00
void CheckOther : : emptyStringTestError ( const Token * tok , const std : : string & var_name , const bool isTestForEmpty )
{
if ( isTestForEmpty )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : performance ,
2010-04-13 19:30:51 +02:00
" emptyStringTest " , " Empty string test can be simplified to \" * " + var_name + " == ' \\ 0' \" " ) ;
2010-04-13 19:30:25 +02:00
}
else
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : performance ,
2010-04-13 19:30:51 +02:00
" emptyStringTest " , " Non-empty string test can be simplified to \" * " + var_name + " != ' \\ 0' \" " ) ;
2010-04-13 19:30:25 +02:00
}
}
2010-05-04 08:14:45 +02:00
void CheckOther : : fflushOnInputStreamError ( const Token * tok , const std : : string & varname )
{
2010-05-07 08:08:10 +02:00
reportError ( tok , Severity : : error ,
2010-05-04 20:02:47 +02:00
" fflushOnInputStream " , " fflush() called on input stream \" " + varname + " \" may result in undefined behaviour " ) ;
2010-05-04 08:14:45 +02:00
}
2010-05-15 14:06:45 +02:00
void CheckOther : : sizeofsizeof ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : simpleMatch ( tok , " sizeof sizeof " ) )
sizeofsizeofError ( tok ) ;
}
}
void CheckOther : : sizeofsizeofError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-06-11 18:20:21 +02:00
" sizeofsizeof " , " Suspicious code 'sizeof sizeof ..', most likely there should only be one sizeof. The current code is equivalent to 'sizeof(size_t)'. " ) ;
2010-05-15 14:06:45 +02:00
}
2010-06-30 09:10:30 +02:00
2010-08-06 22:57:10 +02:00
void CheckOther : : sizeofCalculation ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : simpleMatch ( tok , " sizeof ( " ) )
{
unsigned int parlevel = 0 ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
if ( parlevel < = 1 )
break ;
- - parlevel ;
}
else if ( Token : : Match ( tok2 , " +|/ " ) )
{
sizeofCalculationError ( tok2 ) ;
break ;
}
}
}
}
}
void CheckOther : : sizeofCalculationError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-08-06 22:57:10 +02:00
" sizeofCalculation " , " Found calculation inside sizeof() " ) ;
}
2010-06-30 09:10:30 +02:00
void CheckOther : : redundantAssignmentInSwitchError ( const Token * tok , const std : : string & varname )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-06-30 09:10:30 +02:00
" redundantAssignInSwitch " , " Redundant assignment of \" " + varname + " \" in switch " ) ;
}
2010-08-15 06:28:22 +02:00
void CheckOther : : selfAssignmentError ( const Token * tok , const std : : string & varname )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-08-15 06:28:22 +02:00
" selfAssignment " , " Redundant assignment of \" " + varname + " \" to itself " ) ;
2010-08-26 21:57:48 +02:00
}
2010-10-10 22:05:06 +02:00
void CheckOther : : assignmentInAssertError ( const Token * tok , const std : : string & varname )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-10-11 17:59:08 +02:00
" assignmentInAssert " , " Assert statement modifies ' " + varname + " '. If the modification is needed in release builds there is a bug. " ) ;
2010-10-10 22:05:06 +02:00
}
2010-10-01 17:23:22 +02:00
void CheckOther : : misusedScopeObjectError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error ,
" unusedScopedObject " , " instance of \" " + varname + " \" object destroyed immediately " ) ;
}