2009-01-26 20:14:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2011-01-09 20:33:36 +01:00
* Copyright ( C ) 2007 - 2011 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"
2010-12-16 19:04:47 +01:00
# include "symboldatabase.h"
2010-10-31 12:31:11 +01:00
2010-10-31 11:42:45 +01:00
# include <cctype> // std::isupper
2010-04-02 20:23:37 +02:00
# include <cmath> // fabs()
2011-02-19 20:02:28 +01:00
# include <stack>
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
//---------------------------------------------------------------------------
2011-02-11 23:38:23 +01:00
void CheckOther : : checkIncrementBoolean ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " %var% ++ " ) )
{
if ( tok - > varId ( ) )
{
const Token * declTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " bool %varid% " , tok - > varId ( ) ) ;
if ( declTok )
incrementBooleanError ( tok ) ;
}
}
}
}
void CheckOther : : incrementBooleanError ( const Token * tok )
{
reportError (
tok ,
Severity : : style ,
" incrementboolean " ,
" The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard. \n "
" The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true \n "
) ;
}
//---------------------------------------------------------------------------
2009-01-26 20:14:46 +01:00
2011-01-24 21:40:49 +01:00
void CheckOther : : clarifyCalculation ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-02-17 21:30:59 +01:00
if ( tok - > strAt ( 1 ) = = " ? " )
2011-01-24 21:40:49 +01:00
{
// condition
2011-02-17 21:30:59 +01:00
const Token * cond = tok ;
2011-01-24 21:40:49 +01:00
if ( cond - > isName ( ) | | cond - > isNumber ( ) )
cond = cond - > previous ( ) ;
else if ( cond - > str ( ) = = " ) " )
cond = cond - > link ( ) - > previous ( ) ;
else
continue ;
2011-04-02 11:43:20 +02:00
// calculation
2011-04-09 18:50:05 +02:00
if ( ! cond - > isArithmeticalOp ( ) )
2011-01-24 21:40:49 +01:00
continue ;
2011-04-03 22:12:22 +02:00
const std : : string & op = cond - > str ( ) ;
2011-04-02 11:43:20 +02:00
cond = cond - > previous ( ) ;
2011-01-24 21:40:49 +01:00
// skip previous multiplications..
while ( cond & & cond - > strAt ( - 1 ) = = " * " & & ( cond - > isName ( ) | | cond - > isNumber ( ) ) )
cond = cond - > tokAt ( - 2 ) ;
if ( ! cond )
continue ;
// first multiplication operand
if ( cond - > str ( ) = = " ) " )
{
2011-04-02 11:43:20 +02:00
clarifyCalculationError ( cond , op ) ;
2011-01-24 21:40:49 +01:00
}
else if ( cond - > isName ( ) | | cond - > isNumber ( ) )
{
2011-04-04 21:33:16 +02:00
if ( Token : : Match ( cond - > previous ( ) , ( " return|=|+|-|,|(| " + op ) . c_str ( ) ) )
2011-04-02 11:43:20 +02:00
clarifyCalculationError ( cond , op ) ;
2011-01-24 21:40:49 +01:00
}
}
}
}
2011-04-03 22:12:22 +02:00
void CheckOther : : clarifyCalculationError ( const Token * tok , const std : : string & op )
2011-01-24 21:40:49 +01:00
{
2011-04-02 11:43:20 +02:00
// suspicious calculation
2011-04-03 22:12:22 +02:00
const std : : string calc ( " 'a " + op + " b?c:d' " ) ;
2011-04-02 11:43:20 +02:00
// recommended calculation #1
2011-04-03 22:12:22 +02:00
const std : : string s1 ( " '(a " + op + " b)?c:d' " ) ;
2011-04-02 11:43:20 +02:00
// recommended calculation #2
2011-04-03 22:12:22 +02:00
const std : : string s2 ( " 'a " + op + " (b?c:d)' " ) ;
2011-04-02 11:43:20 +02:00
2011-01-24 21:40:49 +01:00
reportError ( tok ,
2011-03-09 22:20:14 +01:00
Severity : : style ,
2011-01-24 21:40:49 +01:00
" clarifyCalculation " ,
2011-04-03 22:12:22 +02:00
" Clarify calculation precedence for " + op + " and ? \n "
2011-04-02 11:43:20 +02:00
" Suspicious calculation. Please use parentheses to clarify the code. "
" The code " + calc + " should be written as either " + s1 + " or " + s2 + " . " ) ;
2011-01-24 21:40:49 +01:00
}
2009-01-26 20:14:46 +01:00
2011-03-09 22:20:14 +01:00
// Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
void CheckOther : : clarifyCondition ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " ( %var% = " ) )
{
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " [ " )
tok2 = tok2 - > link ( ) ;
2011-04-10 11:52:12 +02:00
else if ( Token : : Match ( tok2 , " &&|%oror%|?|) " ) )
2011-03-09 22:20:14 +01:00
break ;
else if ( Token : : Match ( tok2 , " <|<=|==|!=|>|>= %num% ) " ) )
{
clarifyConditionError ( tok ) ;
break ;
}
}
}
}
}
void CheckOther : : clarifyConditionError ( const Token * tok )
{
reportError ( tok ,
Severity : : style ,
" clarifyCondition " ,
2011-03-30 16:44:16 +02:00
" Suspicious condition (assignment+comparison), it can be clarified with parentheses " ) ;
2011-03-09 22:20:14 +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-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
2011-01-22 19:21:56 +01:00
void CheckOther : : checkSizeofForArrayParameter ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-02-02 16:41:43 +01:00
if ( Token : : Match ( tok , " sizeof ( %var% ) " ) | | Token : : Match ( tok , " sizeof %var% " ) )
2011-01-22 19:21:56 +01:00
{
int tokIdx = 1 ;
if ( tok - > tokAt ( tokIdx ) - > str ( ) = = " ( " )
{
+ + tokIdx ;
}
if ( tok - > tokAt ( tokIdx ) - > varId ( ) > 0 )
{
const Token * declTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok - > tokAt ( tokIdx ) - > varId ( ) ) ;
if ( declTok )
{
2011-01-25 09:57:58 +01:00
if ( Token : : simpleMatch ( declTok - > next ( ) , " [ " ) )
2011-01-22 19:21:56 +01:00
{
2011-01-25 09:57:58 +01:00
declTok = declTok - > next ( ) - > link ( ) ;
// multidimensional array
while ( Token : : simpleMatch ( declTok - > next ( ) , " [ " ) )
{
declTok = declTok - > next ( ) - > link ( ) ;
}
2011-01-26 20:10:56 +01:00
if ( ! ( Token : : Match ( declTok - > next ( ) , " = %str% " ) ) & & ! ( Token : : simpleMatch ( declTok - > next ( ) , " = { " ) ) & & ! ( Token : : simpleMatch ( declTok - > next ( ) , " ; " ) ) )
2011-01-26 20:08:06 +01:00
{
if ( Token : : simpleMatch ( declTok - > next ( ) , " , " ) )
{
declTok = declTok - > next ( ) ;
2011-01-26 20:10:56 +01:00
while ( ! Token : : simpleMatch ( declTok , " ; " ) )
2011-01-26 20:08:06 +01:00
{
if ( Token : : simpleMatch ( declTok , " ) " ) )
{
sizeofForArrayParameterError ( tok ) ;
break ;
}
if ( Token : : Match ( declTok , " (|[|{ " ) )
{
declTok = declTok - > link ( ) ;
}
declTok = declTok - > next ( ) ;
}
}
}
if ( Token : : simpleMatch ( declTok - > next ( ) , " ) " ) )
2011-01-25 09:57:58 +01:00
{
sizeofForArrayParameterError ( tok ) ;
}
2011-01-22 19:21:56 +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 " ;
2011-03-11 19:27:31 +01:00
const char breakPattern [ ] = " break|continue|return|exit|goto|throw " ;
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
2011-02-19 09:33:29 +01:00
void CheckOther : : checkSwitchCaseFallThrough ( )
{
2011-04-10 15:55:08 +02:00
if ( ! ( _settings - > _checkCodingStyle & & _settings - > experimental ) )
2011-03-05 21:42:15 +01:00
return ;
2011-02-19 20:02:28 +01:00
const char switchPattern [ ] = " switch ( " ;
2011-03-11 19:27:31 +01:00
const char breakPattern [ ] = " break|continue|return|exit|goto|throw " ;
2011-02-19 09:33:29 +01:00
// 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
2011-02-19 20:02:28 +01:00
std : : stack < std : : pair < Token * , bool > > ifnest ;
std : : stack < Token * > loopnest ;
std : : stack < Token * > scopenest ;
bool justbreak = true ;
2011-02-23 10:45:21 +01:00
bool firstcase = true ;
2011-02-19 20:02:28 +01:00
for ( const Token * tok2 = tok - > tokAt ( 1 ) - > link ( ) - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2011-02-19 09:33:29 +01:00
{
2011-02-19 20:02:28 +01:00
if ( Token : : Match ( tok2 , " if ( " ) )
2011-02-19 09:33:29 +01:00
{
2011-02-19 20:02:28 +01:00
tok2 = tok2 - > tokAt ( 1 ) - > link ( ) - > next ( ) ;
2011-02-19 21:43:24 +01:00
if ( tok2 - > link ( ) = = NULL )
{
std : : ostringstream errmsg ;
errmsg < < " unmatched if in switch: " < < tok2 - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
break ;
}
2011-02-19 20:02:28 +01:00
ifnest . push ( std : : make_pair ( tok2 - > link ( ) , false ) ) ;
justbreak = false ;
2011-02-19 09:33:29 +01:00
}
2011-02-19 20:02:28 +01:00
else if ( Token : : Match ( tok2 , " while ( " ) )
2011-02-19 09:33:29 +01:00
{
2011-02-19 20:02:28 +01:00
tok2 = tok2 - > tokAt ( 1 ) - > link ( ) - > next ( ) ;
2011-02-19 21:43:24 +01:00
// skip over "do { } while ( ) ;" case
if ( tok2 - > str ( ) = = " { " )
{
if ( tok2 - > link ( ) = = NULL )
{
std : : ostringstream errmsg ;
errmsg < < " unmatched while in switch: " < < tok2 - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
break ;
}
loopnest . push ( tok2 - > link ( ) ) ;
}
2011-02-19 20:02:28 +01:00
justbreak = false ;
}
else if ( Token : : Match ( tok2 , " do { " ) )
{
tok2 = tok2 - > tokAt ( 1 ) ;
2011-02-19 21:43:24 +01:00
if ( tok2 - > link ( ) = = NULL )
{
std : : ostringstream errmsg ;
errmsg < < " unmatched do in switch: " < < tok2 - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
break ;
}
2011-02-19 20:02:28 +01:00
loopnest . push ( tok2 - > link ( ) ) ;
justbreak = false ;
}
else if ( Token : : Match ( tok2 , " for ( " ) )
{
tok2 = tok2 - > tokAt ( 1 ) - > link ( ) - > next ( ) ;
2011-02-19 21:43:24 +01:00
if ( tok2 - > link ( ) = = NULL )
{
std : : ostringstream errmsg ;
errmsg < < " unmatched for in switch: " < < tok2 - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
break ;
}
2011-02-19 20:02:28 +01:00
loopnest . push ( tok2 - > link ( ) ) ;
justbreak = false ;
}
else if ( Token : : Match ( tok2 , switchPattern ) )
{
// skip over nested switch, we'll come to that soon
tok2 = tok2 - > tokAt ( 1 ) - > link ( ) - > next ( ) - > link ( ) ;
}
else if ( Token : : Match ( tok2 , breakPattern ) )
{
if ( loopnest . empty ( ) )
{
justbreak = true ;
}
tok2 = Token : : findmatch ( tok2 , " ; " ) ;
}
else if ( Token : : Match ( tok2 , " case|default " ) )
{
2011-02-23 10:45:21 +01:00
if ( ! justbreak & & ! firstcase )
2011-02-19 09:33:29 +01:00
{
switchCaseFallThrough ( tok2 ) ;
}
2011-02-19 20:02:28 +01:00
tok2 = Token : : findmatch ( tok2 , " : " ) ;
justbreak = true ;
2011-02-23 10:45:21 +01:00
firstcase = false ;
2011-02-19 20:02:28 +01:00
}
else if ( tok2 - > str ( ) = = " { " )
{
scopenest . push ( tok2 - > link ( ) ) ;
2011-02-19 09:33:29 +01:00
}
else if ( tok2 - > str ( ) = = " } " )
{
2011-02-19 20:02:28 +01:00
if ( ! ifnest . empty ( ) & & tok2 = = ifnest . top ( ) . first )
{
if ( tok2 - > next ( ) - > str ( ) = = " else " )
{
tok2 = tok2 - > tokAt ( 2 ) ;
ifnest . pop ( ) ;
2011-02-20 11:44:18 +01:00
if ( tok2 - > link ( ) = = NULL )
{
std : : ostringstream errmsg ;
errmsg < < " unmatched if in switch: " < < tok2 - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
break ;
}
2011-02-19 20:02:28 +01:00
ifnest . push ( std : : make_pair ( tok2 - > link ( ) , justbreak ) ) ;
justbreak = false ;
}
else
{
justbreak & = ifnest . top ( ) . second ;
ifnest . pop ( ) ;
}
}
else if ( ! loopnest . empty ( ) & & tok2 = = loopnest . top ( ) )
{
loopnest . pop ( ) ;
}
else if ( ! scopenest . empty ( ) & & tok2 = = scopenest . top ( ) )
{
scopenest . pop ( ) ;
}
else
{
2011-02-19 21:43:24 +01:00
if ( ! ifnest . empty ( ) | | ! loopnest . empty ( ) | | ! scopenest . empty ( ) )
{
std : : ostringstream errmsg ;
errmsg < < " unexpected end of switch: " ;
errmsg < < " ifnest= " < < ifnest . size ( ) ;
if ( ! ifnest . empty ( ) )
errmsg < < " , " < < ifnest . top ( ) . first - > linenr ( ) ;
errmsg < < " , loopnest= " < < loopnest . size ( ) ;
if ( ! loopnest . empty ( ) )
errmsg < < " , " < < loopnest . top ( ) - > linenr ( ) ;
errmsg < < " , scopenest= " < < scopenest . size ( ) ;
if ( ! scopenest . empty ( ) )
errmsg < < " , " < < scopenest . top ( ) - > linenr ( ) ;
reportError ( _tokenizer - > tokens ( ) , Severity : : debug , " debug " , errmsg . str ( ) ) ;
}
2011-02-19 20:02:28 +01:00
// end of switch block
break ;
}
}
else if ( tok2 - > str ( ) ! = " ; " )
{
justbreak = false ;
2011-02-19 09:33:29 +01:00
}
}
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 ;
2011-02-12 14:27:07 +01:00
// POD variables..
std : : set < unsigned int > pod ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-02-19 09:56:17 +01:00
if ( tok - > isStandardType ( ) & & Token : : Match ( tok - > tokAt ( 2 ) , " [,);] " ) & & tok - > next ( ) - > varId ( ) )
2011-02-12 14:27:07 +01:00
pod . insert ( tok - > next ( ) - > varId ( ) ) ;
}
2010-08-15 06:28:22 +02:00
const char selfAssignmentPattern [ ] = " %var% = %var% ;|=|) " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , selfAssignmentPattern ) ;
while ( tok )
{
2011-02-04 21:08:42 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [;{}] " ) & &
2011-02-12 14:27:07 +01:00
tok - > varId ( ) & & tok - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) & &
pod . find ( tok - > varId ( ) ) ! = pod . end ( ) )
2010-08-15 06:28:22 +02:00
{
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 ;
}
}
2010-10-25 03:14:21 +02:00
//---------------------------------------------------------------------------
// if ((x != 1) || (x != 3)) // <- always true
//---------------------------------------------------------------------------
void CheckOther : : checkIncorrectLogicOperator ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
const char conditionPattern [ ] = " if|while ( " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , conditionPattern ) ;
const Token * endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
while ( tok & & endTok )
{
// Find a pair of OR'd terms, with or without parenthesis
2010-11-21 09:06:43 +01:00
// e.g. if (x != 3 || x != 4)
2010-10-25 03:14:21 +02:00
const Token * logicTok = NULL , * term1Tok = NULL , * term2Tok = NULL ;
2010-11-08 17:29:08 +01:00
if ( NULL ! = ( logicTok = Token : : findmatch ( tok , " ( %any% != %any% ) %oror% ( %any% != %any% ) !!&& " , endTok ) ) )
2010-10-25 03:14:21 +02:00
{
term1Tok = logicTok - > next ( ) ;
term2Tok = logicTok - > tokAt ( 7 ) ;
}
2010-11-08 17:29:08 +01:00
else if ( NULL ! = ( logicTok = Token : : findmatch ( tok , " %any% != %any% %oror% %any% != %any% !!&& " , endTok ) ) )
2010-10-25 03:14:21 +02:00
{
term1Tok = logicTok ;
term2Tok = logicTok - > tokAt ( 4 ) ;
}
2010-11-21 09:06:43 +01:00
// The terms must not be AND'd with anything, to prevent false positives
2010-10-25 03:14:21 +02:00
if ( logicTok & & ( logicTok - > strAt ( - 1 ) ! = " && " ) )
{
2010-11-21 09:06:43 +01:00
// Find the common variable and the two different-valued constants
unsigned int variableTested = 0 ;
std : : string firstConstant , secondConstant ;
if ( Token : : Match ( term1Tok , " %var% != %num% " ) )
{
const unsigned int varId = term1Tok - > varId ( ) ;
2010-12-29 10:07:28 +01:00
if ( ! varId )
2011-01-16 22:57:29 +01:00
{
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
2010-12-29 10:07:28 +01:00
continue ;
2011-01-16 22:57:29 +01:00
}
2010-11-21 09:06:43 +01:00
firstConstant = term1Tok - > tokAt ( 2 ) - > str ( ) ;
2010-11-04 08:10:25 +01:00
2010-11-21 09:06:43 +01:00
if ( Token : : Match ( term2Tok , " %varid% != %num% " , varId ) )
{
variableTested = varId ;
secondConstant = term2Tok - > tokAt ( 2 ) - > str ( ) ;
}
else if ( Token : : Match ( term2Tok , " %num% != %varid% " , varId ) )
{
variableTested = varId ;
secondConstant = term2Tok - > str ( ) ;
}
}
else if ( Token : : Match ( term1Tok , " %num% != %var% " ) )
2010-10-25 03:14:21 +02:00
{
2010-11-21 09:06:43 +01:00
const unsigned int varId = term1Tok - > tokAt ( 2 ) - > varId ( ) ;
firstConstant = term1Tok - > str ( ) ;
if ( Token : : Match ( term2Tok , " %varid% != %num% " , varId ) )
{
variableTested = varId ;
secondConstant = term2Tok - > tokAt ( 2 ) - > str ( ) ;
}
else if ( Token : : Match ( term2Tok , " %num% != %varid% " , varId ) )
{
variableTested = varId ;
secondConstant = term2Tok - > str ( ) ;
}
2010-10-25 03:14:21 +02:00
}
2010-11-21 09:06:43 +01:00
// If there is a common variable tested for inequality against
// either of two different-valued constants, then the expression
// will always evaluate to true and the || probably should be an &&
if ( variableTested ! = 0 & &
! firstConstant . empty ( ) & &
! secondConstant . empty ( ) & &
firstConstant ! = secondConstant )
2010-10-25 03:14:21 +02:00
{
2010-11-21 09:06:43 +01:00
incorrectLogicOperatorError ( term1Tok ) ;
2010-10-25 03:14:21 +02:00
}
}
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
}
}
2010-12-31 12:01:38 +01:00
//---------------------------------------------------------------------------
// try {} catch (std::exception err) {} <- Should be "std::exception& err"
//---------------------------------------------------------------------------
void CheckOther : : checkCatchExceptionByValue ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
const char catchPattern [ ] = " } catch ( " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , catchPattern ) ;
const Token * endTok = tok ? tok - > tokAt ( 2 ) - > link ( ) : NULL ;
while ( tok & & endTok )
{
// Find a pass-by-value declaration in the catch(), excluding basic types
// e.g. catch (std::exception err)
const Token * tokType = Token : : findmatch ( tok , " %type% %var% ) " , endTok ) ;
2010-12-31 21:48:24 +01:00
if ( tokType & & ! tokType - > isStandardType ( ) )
2010-12-31 12:01:38 +01:00
{
catchExceptionByValueError ( tokType ) ;
}
tok = Token : : findmatch ( endTok - > next ( ) , catchPattern ) ;
endTok = tok ? tok - > tokAt ( 2 ) - > 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
{
2011-01-08 09:23:51 +01:00
if ( ! Token : : Match ( tok , " strtol|strtoul ( " ) )
2009-01-26 20:14:46 +01:00
continue ;
// Locate the third parameter of the function call..
int param = 1 ;
2011-01-08 09:23:51 +01: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 ( ) = = " ( " )
2011-01-08 09:23:51 +01:00
tok2 = tok2 - > link ( ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2011-01-08 09:23:51 +01:00
break ;
else if ( 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
{
2010-11-20 11:28:47 +01:00
const MathLib : : bigint 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 ;
}
}
}
}
2011-02-27 21:30:22 +01:00
//---------------------------------------------------------------------------
// if (!x==3) <- Probably meant to be "x!=3"
//---------------------------------------------------------------------------
void CheckOther : : checkComparisonOfBoolWithInt ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " ( ! %var% ==|!= %num% ) " ) )
{
const Token * numTok = tok - > tokAt ( 4 ) ;
if ( numTok & & numTok - > str ( ) ! = " 0 " )
{
comparisonOfBoolWithIntError ( numTok , tok - > strAt ( 2 ) ) ;
}
}
else if ( Token : : Match ( tok , " ( %num% ==|!= ! %var% ) " ) )
{
const Token * numTok = tok - > tokAt ( 1 ) ;
if ( numTok & & numTok - > str ( ) ! = " 0 " )
{
comparisonOfBoolWithIntError ( numTok , tok - > strAt ( 4 ) ) ;
}
}
}
}
2011-01-22 19:21:56 +01:00
void CheckOther : : sizeofForArrayParameterError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
" sizeofwithsilentarraypointer " , " Using sizeof for array given as function argument "
" returns the size of pointer. \n "
" Giving array as function parameter and then using sizeof-operator for the array "
" argument. In this case the sizeof-operator returns the size of pointer (in the "
2011-01-26 09:35:11 +01:00
" system). It does not return the size of the whole array in bytes as might be "
2011-01-22 19:21:56 +01:00
" expected. For example, this code: \n "
" int f(char a[100]) { \n "
" return sizeof(a); \n "
" } \n "
" returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
" size of the array in bytes). "
) ;
}
2010-08-14 15:15:12 +02:00
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 "
2010-11-11 19:54:43 +01:00
" scanf without field width limits can crash with huge input data. To fix this error "
" message add a field width specifier: \n "
2010-08-14 18:35:48 +02:00
" %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
}
}
}
2011-04-10 11:31:04 +02:00
else if ( Token : : Match ( tok , " (|[|=|%op% %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
}
}
}
}
}
2011-01-06 11:31:58 +01:00
//---------------------------------------------------------------------------
// memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
//---------------------------------------------------------------------------
void CheckOther : : checkMemsetZeroBytes ( )
{
const Token * tok = _tokenizer - > tokens ( ) ;
while ( tok & & ( ( tok = Token : : findmatch ( tok , " memset ( %var% , %num% , 0 ) " ) ) ! = NULL ) )
{
memsetZeroBytesError ( tok , tok - > strAt ( 2 ) ) ;
tok = tok - > tokAt ( 8 ) ;
}
}
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
2010-02-18 18:45:13 +01:00
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
2010-07-12 09:50:18 +02:00
/**
* @ brief This class is used to capture the control flow within a function .
*/
2011-01-17 18:29:19 +01:00
class ScopeInfo
2010-07-12 09:50:18 +02:00
{
public :
2011-01-17 18:29:19 +01:00
ScopeInfo ( ) : _token ( NULL ) , _parent ( NULL ) { }
ScopeInfo ( const Token * token , ScopeInfo * parent_ ) : _token ( token ) , _parent ( parent_ ) { }
~ ScopeInfo ( ) ;
2010-07-12 09:50:18 +02:00
2011-01-17 18:29:19 +01:00
ScopeInfo * parent ( )
2010-07-12 09:50:18 +02:00
{
return _parent ;
}
2011-01-17 18:29:19 +01:00
ScopeInfo * addChild ( const Token * token ) ;
void remove ( ScopeInfo * scope ) ;
2010-07-12 09:50:18 +02:00
private :
const Token * _token ;
2011-01-17 18:29:19 +01:00
ScopeInfo * _parent ;
std : : list < ScopeInfo * > _children ;
2010-07-12 09:50:18 +02:00
} ;
2011-01-17 18:29:19 +01:00
ScopeInfo : : ~ ScopeInfo ( )
2010-07-12 09:50:18 +02:00
{
while ( ! _children . empty ( ) )
{
delete * _children . begin ( ) ;
_children . pop_front ( ) ;
}
}
2011-01-17 18:29:19 +01:00
ScopeInfo * ScopeInfo : : addChild ( const Token * token )
2010-07-12 09:50:18 +02:00
{
2011-01-17 18:29:19 +01:00
ScopeInfo * temp = new ScopeInfo ( token , this ) ;
2010-07-12 09:50:18 +02:00
_children . push_back ( temp ) ;
return temp ;
}
2011-01-17 18:29:19 +01:00
void ScopeInfo : : remove ( ScopeInfo * scope )
2010-07-12 09:50:18 +02:00
{
2011-01-17 18:29:19 +01:00
std : : list < ScopeInfo * > : : iterator it ;
2010-07-12 09:50:18 +02:00
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 ,
2011-01-17 18:29:19 +01:00
ScopeInfo * scope = NULL ,
2010-04-24 09:45:03 +02:00
bool read = false ,
bool write = false ,
2010-11-15 02:37:36 +01:00
bool modified = false ,
bool allocateMemory = 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-11-15 02:37:36 +01:00
_modified ( modified ) ,
_allocateMemory ( allocateMemory )
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 ;
2011-01-17 18:29:19 +01:00
ScopeInfo * _scope ;
2010-04-24 09:45:03 +02:00
bool _read ;
bool _write ;
bool _modified ; // read/modify/write
2010-11-15 02:37:36 +01:00
bool _allocateMemory ;
2010-04-29 07:10:50 +02:00
std : : set < unsigned int > _aliases ;
2011-01-17 18:29:19 +01:00
std : : set < ScopeInfo * > _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
}
2011-01-17 18:29:19 +01:00
void addVar ( const Token * name , VariableType type , ScopeInfo * scope , bool write_ ) ;
2010-11-15 02:37:36 +01:00
void allocateMemory ( unsigned int varid ) ;
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 ,
2011-01-17 18:29:19 +01:00
ScopeInfo * 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-11-15 02:37:36 +01:00
void Variables : : allocateMemory ( unsigned int varid )
{
VariableUsage * usage = find ( varid ) ;
if ( usage )
usage - > _allocateMemory = true ;
}
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
2011-01-17 18:29:19 +01:00
static int doAssignment ( Variables & variables , const Token * tok , bool dereference , ScopeInfo * scope )
2010-04-29 07:10:50 +02:00
{
int next = 0 ;
2010-10-31 09:34:25 +01:00
// a = a + b;
if ( Token : : Match ( tok , " %var% = %var% !!; " ) & & tok - > str ( ) = = tok - > strAt ( 2 ) )
{
return 2 ;
}
2010-04-29 07:10:50 +02:00
// check for aliased variable
2010-10-31 09:34:25 +01:00
const unsigned int varid1 = tok - > varId ( ) ;
2010-04-29 07:10:50 +02:00
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 ;
2010-12-15 18:45:53 +01:00
// not in same scope as declaration
2010-07-12 09:50:18 +02:00
else
{
2011-01-17 18:29:19 +01:00
std : : set < ScopeInfo * > : : iterator assignment ;
2010-07-12 09:50:18 +02:00
// 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
{
2010-12-15 18:45:53 +01:00
// replace when only one other assignment
2010-07-12 09:50:18 +02:00
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-12-15 18:45:53 +01:00
// check if variable declaration is in this scope
2010-07-12 09:50:18 +02:00
if ( var1 - > _scope = = scope )
variables . clearAliases ( varid1 ) ;
else
{
2011-01-17 18:29:19 +01:00
std : : set < ScopeInfo * > : : iterator assignment ;
2010-07-12 09:50:18 +02:00
// 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..
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-12-16 19:04:47 +01:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-16 19:04:47 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2010-02-18 18:45:13 +01:00
{
2010-12-16 19:04:47 +01:00
// only check functions
2011-03-11 01:43:29 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-16 19:04:47 +01:00
continue ;
2010-02-21 08:02:44 +01:00
2010-12-16 19:04:47 +01:00
// First token for the current scope..
2011-03-11 01:43:29 +01:00
const Token * const tok1 = scope - > classStart ;
2010-02-21 08:02:44 +01:00
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
2011-01-17 18:29:19 +01:00
ScopeInfo scopes ;
2011-03-11 01:43:29 +01:00
ScopeInfo * info = & scopes ;
2010-07-12 09:50:18 +02:00
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 )
2011-01-17 18:29:19 +01:00
scopes = ScopeInfo ( tok , NULL ) ;
2010-07-12 09:50:18 +02:00
// add the new scope
else
2011-03-11 01:43:29 +01:00
info = info - > 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
2011-03-11 01:43:29 +01:00
info = info - > parent ( ) ;
2010-07-12 09:50:18 +02:00
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 ( ) ;
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > next ( ) , Variables : : standard , info ,
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 ( ) ;
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > next ( ) , Variables : : standard , info , 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 };
2010-11-15 17:53:55 +01:00
else if ( Token : : Match ( tok , " [;{}] static| const| %type% *| %var% [ %any% ] ;|= " ) & &
2010-06-24 17:00:32 +02:00
nextIsStandardType ( tok ) )
2010-04-15 18:44:52 +02:00
{
2010-11-15 17:53:55 +01:00
bool isStatic = false ;
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " static " )
2010-11-15 17:53:55 +01:00
{
2010-06-24 17:00:32 +02:00
tok = tok - > next ( ) ;
2010-11-15 17:53:55 +01:00
isStatic = true ;
}
2010-06-24 17:00:32 +02:00
2010-11-15 17:53:55 +01:00
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2010-05-23 10:41:05 +02:00
2010-11-15 17:53:55 +01:00
if ( tok - > str ( ) ! = " return " & & tok - > str ( ) ! = " throw " )
2010-06-21 18:12:01 +02:00
{
2010-11-15 17:53:55 +01:00
bool isPointer = bool ( tok - > strAt ( 1 ) = = " * " ) ;
const Token * const nametok = tok - > tokAt ( isPointer ? 2 : 1 ) ;
2011-03-11 01:43:29 +01:00
variables . addVar ( nametok , isPointer ? Variables : : pointerArray : Variables : : array , info ,
2010-11-15 17:53:55 +01:00
nametok - > tokAt ( 4 ) - > str ( ) = = " = " | | isStatic ) ;
// check for reading array size from local variable
if ( nametok - > tokAt ( 2 ) - > varId ( ) ! = 0 )
variables . read ( nametok - > tokAt ( 2 ) - > varId ( ) ) ;
// look at initializers
2011-02-02 16:48:00 +01:00
if ( Token : : simpleMatch ( nametok - > tokAt ( 4 ) , " = { " ) )
2010-06-21 18:12:01 +02:00
{
2010-11-15 17:53:55 +01:00
tok = nametok - > tokAt ( 6 ) ;
while ( tok - > str ( ) ! = " } " )
{
if ( Token : : Match ( tok , " %var% " ) )
variables . read ( tok - > varId ( ) ) ;
tok = tok - > next ( ) ;
}
2010-06-21 18:12:01 +02:00
}
2010-11-15 17:53:55 +01:00
else
tok = nametok - > tokAt ( 3 ) ;
2010-06-21 18:12:01 +02:00
}
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-11-15 02:37:36 +01:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok = tok - > tokAt ( 2 ) ;
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
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > tokAt ( 2 ) , type , info , written | | isStatic ) ;
2010-04-29 07:10:50 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2011-03-11 01:43:29 +01:00
offset = doAssignment ( variables , tok - > tokAt ( 2 ) , false , info ) ;
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
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > tokAt ( 3 ) , Variables : : pointerPointer , info , written | | isStatic ) ;
2010-06-23 06:54:14 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2011-03-11 01:43:29 +01:00
offset = doAssignment ( variables , tok - > tokAt ( 3 ) , false , info ) ;
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
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > tokAt ( 3 ) , type , info , written | | isStatic ) ;
2010-04-29 07:10:50 +02:00
int offset = 0 ;
// check for assignment
if ( written )
2011-03-11 01:43:29 +01:00
offset = doAssignment ( variables , tok - > tokAt ( 3 ) , false , info ) ;
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
2011-03-11 01:43:29 +01:00
variables . addVar ( tok - > tokAt ( 2 ) , type , info , 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 ) ,
2011-03-11 01:43:29 +01:00
tok - > next ( ) - > str ( ) = = " * " ? Variables : : pointerArray : Variables : : referenceArray , info ,
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 ) ,
2011-03-11 01:43:29 +01:00
tok - > tokAt ( 2 ) - > str ( ) = = " * " ? Variables : : pointerArray : Variables : : referenceArray , info ,
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-11-15 02:37:36 +01:00
// Freeing memory (not considered "using" the pointer if it was also allocated in this function)
else if ( Token : : Match ( tok , " free|g_free|kfree|vfree ( %var% ) " ) | |
Token : : Match ( tok , " delete %var% ; " ) | |
Token : : Match ( tok , " delete [ ] %var% ; " ) )
{
unsigned int varid = 0 ;
if ( tok - > str ( ) ! = " delete " )
{
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
tok = tok - > tokAt ( 3 ) ;
}
else if ( tok - > strAt ( 1 ) = = " [ " )
{
varid = tok - > tokAt ( 3 ) - > varId ( ) ;
tok = tok - > tokAt ( 4 ) ;
}
else
{
varid = tok - > next ( ) - > varId ( ) ;
tok = tok - > tokAt ( 2 ) ;
}
Variables : : VariableUsage * var = variables . find ( varid ) ;
if ( var & & ! var - > _allocateMemory )
{
variables . readAll ( varid ) ;
}
}
else if ( Token : : Match ( tok , " 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-11-15 17:30:07 +01:00
else if ( Token : : Match ( tok , " *| (| ++|--| %var% ++|--| )| = " ) | |
Token : : Match ( tok , " *| ( const| %type% *| ) %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-11-15 17:30:07 +01:00
if ( Token : : Match ( tok , " ( const| %type% *| ) %var% = " ) )
tok = tok - > link ( ) - > next ( ) ;
else if ( tok - > str ( ) = = " ( " )
2010-05-26 19:22:35 +02:00
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-12-19 18:27:31 +01:00
const unsigned int varid1 = tok - > varId ( ) ;
2010-04-29 07:10:50 +02:00
const Token * start = tok ;
2011-03-11 01:43:29 +01:00
tok = tok - > tokAt ( doAssignment ( variables , tok , dereference , info ) ) ;
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 ) ;
}
2010-11-15 02:37:36 +01:00
// Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
else if ( var & & var - > _type = = Variables : : pointer & &
Token : : Match ( start , " %var% = new|malloc|calloc|g_malloc|kmalloc|vmalloc " ) )
{
2010-12-21 08:13:40 +01:00
bool allocate = true ;
if ( start - > strAt ( 2 ) = = " new " )
{
// is it a user defined type?
if ( ! start - > tokAt ( 3 ) - > isStandardType ( ) )
{
// lookup the type
2011-03-11 01:43:29 +01:00
const Scope * type = symbolDatabase - > findVariableType ( & ( * scope ) , start - > tokAt ( 3 ) ) ;
2010-12-21 08:13:40 +01:00
// unknown type?
if ( ! type )
allocate = false ;
// has default constructor or
// has members with unknown type or default constructor
2011-01-17 18:29:19 +01:00
else if ( type - > needInitialization = = Scope : : False )
2010-12-21 08:13:40 +01:00
allocate = false ;
}
}
if ( allocate )
2010-12-20 18:31:16 +01:00
variables . allocateMemory ( varid1 ) ;
2010-12-21 08:13:40 +01:00
else
variables . write ( varid1 ) ;
2010-11-15 02:37:36 +01:00
}
2010-12-27 14:06:32 +01:00
else if ( varid1 & & Token : : Match ( tok , " %varid% . " , varid1 ) )
2010-12-25 19:17:53 +01:00
{
variables . use ( varid1 ) ;
}
2010-04-29 07:10:50 +02:00
else
2010-11-15 02:37:36 +01:00
{
2010-04-29 07:10:50 +02:00
variables . write ( varid1 ) ;
2010-11-15 02:37:36 +01:00
}
2010-08-31 20:58:37 +02:00
Variables : : VariableUsage * var2 = variables . find ( tok - > varId ( ) ) ;
2010-12-19 18:27:31 +01:00
if ( var2 )
2010-08-31 20:58:37 +02:00
{
2010-12-19 18:27:31 +01:00
if ( var2 - > _type = = Variables : : reference )
{
variables . writeAliases ( tok - > varId ( ) ) ;
variables . read ( tok - > varId ( ) ) ;
}
else if ( tok - > varId ( ) ! = varid1 & & Token : : Match ( tok , " %var% . " ) )
variables . use ( tok - > varId ( ) ) ;
else if ( tok - > varId ( ) ! = varid1 & &
var2 - > _type = = Variables : : standard & &
tok - > strAt ( - 1 ) ! = " & " )
variables . use ( tok - > varId ( ) ) ;
2010-08-31 20:58:37 +02:00
}
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-11-15 02:37:36 +01:00
// Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
if ( var - > _type = = Variables : : pointer & &
Token : : Match ( tok - > next ( ) - > link ( ) , " ] = new|malloc|calloc|g_malloc|kmalloc|vmalloc " ) )
{
variables . allocateMemory ( varid ) ;
}
else 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-12-21 19:02:00 +01:00
else if ( Token : : Match ( tok , " [;{}] %var% >> " ) )
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
2011-02-01 21:46:07 +01:00
else if ( Token : : Match ( tok , " %var% ( " ) )
2010-12-02 20:08:05 +01:00
{
2010-06-21 18:12:01 +02:00
variables . read ( tok - > varId ( ) ) ;
2010-12-02 20:08:05 +01:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " %var% = " ) )
variables . read ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
}
2010-06-21 18:12:01 +02:00
2011-02-09 19:20:44 +01:00
else if ( Token : : Match ( tok , " [{,] %var% [,}] " ) )
variables . read ( tok - > next ( ) - > varId ( ) ) ;
2011-02-01 21:46:07 +01: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
2011-04-08 19:40:22 +02:00
else if ( ( Token : : Match ( tok , " [(=&!] " ) | | tok - > isExtendedOp ( ) ) & &
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
2011-04-08 19:40:22 +02:00
else if ( Token : : Match ( tok , " %var% " ) & & ( tok - > next ( ) - > str ( ) = = " ) " | | tok - > next ( ) - > isExtendedOp ( ) ) )
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-11-02 20:01:12 +01:00
if ( Token : : Match ( tok , " ++|-- %var% " ) )
{
if ( tok - > strAt ( - 1 ) ! = " ; " )
variables . use ( tok - > next ( ) - > varId ( ) ) ;
else
variables . modified ( tok - > next ( ) - > varId ( ) ) ;
}
2010-04-15 18:44:52 +02:00
else if ( Token : : Match ( tok , " %var% ++|-- " ) )
2010-11-02 20:01:12 +01:00
{
if ( tok - > strAt ( - 1 ) ! = " ; " )
variables . use ( tok - > varId ( ) ) ;
else
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 ;
2010-11-15 02:37:36 +01:00
// variable has had memory allocated for it, but hasn't done
// anything with that memory other than, perhaps, freeing it
if ( usage . unused ( ) & & ! usage . _modified & & usage . _allocateMemory )
allocatedButUnusedVariableError ( usage . _name , varname ) ;
2010-06-23 06:54:14 +02:00
// variable has not been written, read, or modified
2010-11-15 02:37:36 +01:00
else if ( usage . unused ( ) & & ! usage . _modified )
2010-04-27 05:05:32 +02:00
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-11-15 02:37:36 +01:00
else if ( ! usage . _write & & ! usage . _allocateMemory )
2010-04-27 05:05:32 +02:00
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 ) ;
}
2010-11-15 02:37:36 +01:00
void CheckOther : : allocatedButUnusedVariableError ( const Token * tok , const std : : string & varname )
{
2011-01-16 18:45:05 +01:00
reportError ( tok , Severity : : style , " unusedAllocatedMemory " , " Variable ' " + varname + " ' is allocated memory that is never used " ) ;
2010-11-15 02:37:36 +01:00
}
2010-02-18 18:45:13 +01:00
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
{
2011-01-05 21:20:21 +01:00
if ( ! _settings - > isEnabled ( " information " ) )
2010-04-21 08:38:25 +02:00
return ;
2011-01-16 18:13:54 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-12-16 19:04:47 +01:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-16 19:04:47 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2009-01-26 20:14:46 +01:00
{
2010-12-16 19:04:47 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-16 19:04:47 +01:00
continue ;
// Walk through all tokens..
int indentlevel = 0 ;
2011-01-17 18:29:19 +01:00
for ( const Token * tok = scope - > classStart ; tok ; tok = tok - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-12-16 19:04:47 +01:00
// Skip function local class and struct declarations..
if ( ( tok - > str ( ) = = " class " ) | | ( tok - > str ( ) = = " struct " ) | | ( tok - > str ( ) = = " union " ) )
2009-01-26 20:14:46 +01:00
{
2010-12-16 19:04:47 +01:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-01-26 20:14:46 +01:00
{
2010-12-16 19:04:47 +01:00
if ( tok2 - > str ( ) = = " { " )
{
tok = tok2 - > link ( ) ;
break ;
}
if ( Token : : Match ( tok2 , " [,);] " ) )
{
break ;
}
2009-01-26 20:14:46 +01:00
}
2010-12-16 19:04:47 +01:00
if ( ! tok )
2009-01-26 20:14:46 +01:00
break ;
}
2010-12-16 19:04:47 +01:00
else if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel = = 0 )
break ; ;
}
2009-01-26 20:14:46 +01:00
2010-12-16 19:04:47 +01:00
if ( indentlevel > 0 & & Token : : Match ( tok , " [{};] " ) )
2009-08-16 21:12:57 +02:00
{
2010-12-16 19:04:47 +01:00
// First token of statement..
const Token * tok1 = tok - > next ( ) ;
if ( ! tok1 )
continue ;
if ( ( tok1 - > str ( ) = = " return " ) | |
( tok1 - > str ( ) = = " throw " ) | |
( tok1 - > str ( ) = = " delete " ) | |
( tok1 - > str ( ) = = " goto " ) | |
( tok1 - > str ( ) = = " else " ) )
continue ;
// Variable declaration?
if ( Token : : Match ( tok1 , " %type% %var% ; %var% = %num% ; " ) )
2009-08-16 21:12:57 +02:00
{
2010-12-16 19:04:47 +01: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 ( ) ;
if ( firstVarId > 0 & & firstVarId = = secondVarId )
{
lookupVar ( tok1 - > tokAt ( 6 ) , tok1 - > strAt ( 1 ) ) ;
}
}
else if ( tok1 - > isStandardType ( ) & & Token : : Match ( tok1 , " %type% %var% [ ; = ] " ))
{
lookupVar ( tok1 , tok1 - > strAt ( 1 ) ) ;
2009-08-16 21:12:57 +02:00
}
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
{
2011-01-17 20:51:15 +01:00
if ( tok - > strAt ( - 1 ) = = " = " )
{
if ( Token : : findmatch ( tok , varname . c_str ( ) , tok - > link ( ) ) )
{
return ;
}
tok = tok - > link ( ) ;
}
else
+ + indentlevel ;
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
{
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 ;
2011-01-16 19:57:29 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
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.
2011-01-16 19:57:29 +01:00
if ( symbolDatabase - > isClassOrStruct ( tok - > strAt ( 2 ) ) )
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-12-05 18:33:53 +01:00
// declaring a POD variable?
if ( ! tok - > next ( ) - > isStandardType ( ) )
continue ;
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 ;
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 ( ) = = " ( " )
2011-03-30 21:57:01 +02:00
{
2011-01-13 20:12:57 +01:00
tok = tok - > link ( ) ;
2011-03-30 21:57:01 +02:00
if ( Token : : simpleMatch ( tok , " ) { " ) & & Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " } ; " ) )
tok = tok - > next ( ) - > link ( ) ;
}
2009-01-26 20:14:46 +01:00
2011-01-13 20:12:57 +01:00
else if ( Token : : simpleMatch ( tok , " = { " ) )
tok = tok - > next ( ) - > link ( ) ;
2009-01-26 20:14:46 +01:00
2011-01-19 18:37:33 +01:00
else if ( tok - > str ( ) = = " { " && Token::Match(tok->tokAt(-2), " % type % % var % " ))
tok = tok - > link ( ) ;
2011-01-13 20:12:57 +01:00
else if ( Token : : Match ( tok , " [;{}] %str% " ) | | Token : : Match ( tok , " [;{}] %num% " ) )
2009-02-11 16:17:13 +01:00
{
2011-01-13 20:12:57 +01:00
// bailout if there is a "? :" in this statement
bool bailout = false ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-02-12 13:59:43 +01:00
{
2011-01-13 20:12:57 +01:00
if ( tok2 - > str ( ) = = " ? " )
bailout = true ;
else if ( tok2 - > str ( ) = = " ; " )
break ;
2009-02-12 13:59:43 +01:00
}
2011-01-13 20:12:57 +01:00
if ( bailout )
continue ;
2009-02-12 13:59:43 +01:00
2011-01-13 20:12:57 +01:00
constStatementError ( tok - > next ( ) , tok - > next ( ) - > isNumber ( ) ? " numeric " : " string " ) ;
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..
2010-10-28 18:51:55 +02:00
if ( _tokenizer - > isJavaOrCSharp ( ) )
2010-10-19 21:54:15 +02:00
{
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-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
}
}
2011-03-13 08:38:40 +01:00
/** Is there a function with given name? */
static bool isFunction ( const std : : string & name , const Token * startToken )
{
const std : : string pattern1 ( name + " ( " ) ;
for ( const Token * tok = startToken ; tok ; tok = tok - > next ( ) )
{
// skip executable scopes etc
2011-03-20 09:55:26 +01:00
if ( tok - > str ( ) = = " ( " )
{
2011-03-13 08:38:40 +01:00
tok = tok - > link ( ) ;
2011-03-20 09:55:26 +01:00
if ( Token : : simpleMatch ( tok , " ) { " ) )
tok = tok - > next ( ) - > link ( ) ;
else if ( Token : : simpleMatch ( tok , " ) const { " ))
tok = tok - > tokAt ( 2 ) - > link ( ) ;
}
2011-03-13 08:38:40 +01:00
// function declaration/implementation found
2011-03-20 09:55:26 +01:00
if ( ( tok - > str ( ) = = " * " | | ( tok - > isName ( ) & & tok - > str ( ) . find ( " : " ) = = std : : string : : npos ) )
& & Token : : simpleMatch ( tok - > next ( ) , pattern1 . c_str ( ) ) )
2011-03-13 08:38:40 +01:00
return true ;
}
return false ;
}
2010-10-01 17:23:22 +02:00
void CheckOther : : checkMisusedScopedObject ( )
{
2010-12-25 08:43:52 +01:00
// Skip this check for .c files
{
const std : : string fname = _tokenizer - > getFiles ( ) - > at ( 0 ) ;
const std : : string ext = fname . substr ( fname . rfind ( " . " ) ) ;
if ( ext = = " .c " | | ext = = " .C " )
return ;
}
2011-01-16 19:57:29 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-10-01 17:23:22 +02:00
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : const_iterator scope ;
2010-12-18 20:35:40 +01:00
2011-03-11 01:43:29 +01:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
2010-10-01 17:23:22 +02:00
{
2010-12-18 20:35:40 +01:00
// only check functions
2011-01-17 18:29:19 +01:00
if ( scope - > type ! = Scope : : eFunction )
2010-12-18 20:35:40 +01:00
continue ;
unsigned int depth = 0 ;
2011-01-17 18:29:19 +01:00
for ( const Token * tok = scope - > classStart ; tok ; tok = tok - > next ( ) )
2010-10-01 17:23:22 +02:00
{
if ( tok - > str ( ) = = " { " )
{
+ + depth ;
}
else if ( tok - > str ( ) = = " } " )
{
- - depth ;
2010-12-18 20:35:40 +01:00
if ( depth = = 0 )
break ;
2010-10-01 17:23:22 +02:00
}
2010-12-18 20:35:40 +01:00
if ( Token : : Match ( tok , " [;{}] %var% ( " )
2011-02-02 17:12:46 +01:00
& & Token : : simpleMatch ( tok - > tokAt ( 2 ) - > link ( ) , " ) ; " )
2011-01-16 19:57:29 +01:00
& & symbolDatabase - > isClassOrStruct ( tok - > next ( ) - > str ( ) )
2011-03-13 08:38:40 +01:00
& & ! isFunction ( tok - > next ( ) - > str ( ) , _tokenizer - > tokens ( ) ) )
2010-10-01 17:23:22 +02:00
{
tok = tok - > next ( ) ;
misusedScopeObjectError ( tok , tok - > str ( ) ) ;
tok = tok - > next ( ) ;
}
}
}
}
2011-02-08 19:49:29 +01:00
void CheckOther : : checkIncorrectStringCompare ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " . substr ( %any% , %num% ) ==|!= %str% " ) )
{
size_t clen = MathLib : : toLongNumber ( tok - > tokAt ( 5 ) - > str ( ) ) ;
size_t slen = Token : : getStrLength ( tok - > tokAt ( 8 ) ) ;
if ( clen ! = slen )
{
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > tokAt ( 8 ) - > str ( ) , tok - > tokAt ( 5 ) - > str ( ) ) ;
}
}
if ( Token : : Match ( tok , " %str% ==|!= %var% . substr ( %any% , %num% ) " ) )
{
size_t clen = MathLib : : toLongNumber ( tok - > tokAt ( 8 ) - > str ( ) ) ;
size_t slen = Token : : getStrLength ( tok ) ;
if ( clen ! = slen )
{
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > str ( ) , tok - > tokAt ( 8 ) - > str ( ) ) ;
}
}
}
}
2011-04-09 21:14:01 +02:00
//-----------------------------------------------------------------------------
// check for duplicate expressions in if statements
// if (a) { } else if (a) { }
//-----------------------------------------------------------------------------
static const std : : string stringifyTokens ( const Token * start , const Token * end )
{
const Token * tok = start ;
std : : string stringified = tok - > str ( ) ;
while ( tok & & tok - > next ( ) & & tok ! = end )
{
tok = tok - > next ( ) ;
stringified . append ( " " ) ;
stringified . append ( tok - > str ( ) ) ;
}
return stringified ;
}
static bool expressionHasSideEffects ( const Token * first , const Token * last )
{
for ( const Token * tok = first ; tok ! = last - > next ( ) ; tok = tok - > next ( ) )
{
// check for assignment
if ( tok - > isAssignmentOp ( ) )
return true ;
// check for inc/dec
else if ( Token : : Match ( tok , " ++|-- " ) )
return true ;
// check for function call
else if ( Token : : Match ( tok , " %var% ( " ) & &
! ( Token : : Match ( tok , " c_str|string " ) | | tok - > isStandardType ( ) ) )
return true ;
}
return false ;
}
void CheckOther : : checkDuplicateIf ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : list < Scope > : : const_iterator scope ;
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
{
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
// check all the code in the function for if (...) and else if (...) statements
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " if ( " ) & & tok - > strAt ( - 1 ) ! = " else " & &
Token : : Match ( tok - > next ( ) - > link ( ) , " ) { " ) )
{
std : : map < std : : string , const Token * > expressionMap ;
// get the expression from the token stream
std : : string expression = stringifyTokens ( tok - > tokAt ( 2 ) , tok - > next ( ) - > link ( ) - > previous ( ) ) ;
// save the expression and its location
expressionMap . insert ( std : : make_pair ( expression , tok ) ) ;
// find the next else if (...) statement
const Token * tok1 = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
// check all the else if (...) statements
while ( Token : : Match ( tok1 , " } else if ( " ) & &
Token : : Match ( tok1 - > tokAt ( 3 ) - > link ( ) , " ) { " ) )
{
// get the expression from the token stream
expression = stringifyTokens ( tok1 - > tokAt ( 4 ) , tok1 - > tokAt ( 3 ) - > link ( ) - > previous ( ) ) ;
// try to look up the expression to check for duplicates
std : : map < std : : string , const Token * > : : iterator it = expressionMap . find ( expression ) ;
// found a duplicate
if ( it ! = expressionMap . end ( ) )
{
// check for expressions that have side effects and ignore them
if ( ! expressionHasSideEffects ( tok1 - > tokAt ( 4 ) , tok1 - > tokAt ( 3 ) - > link ( ) - > previous ( ) ) )
duplicateIfError ( it - > second , tok1 - > next ( ) ) ;
}
// not a duplicate expression so save it and its location
else
expressionMap . insert ( std : : make_pair ( expression , tok1 - > next ( ) ) ) ;
// find the next else if (...) statement
tok1 = tok1 - > tokAt ( 3 ) - > link ( ) - > next ( ) - > link ( ) ;
}
tok = tok - > next ( ) - > link ( ) - > next ( ) ;
}
}
}
}
void CheckOther : : duplicateIfError ( const Token * tok1 , const Token * tok2 )
{
std : : list < const Token * > toks ;
toks . push_back ( tok2 ) ;
toks . push_back ( tok1 ) ;
reportError ( toks , Severity : : style , " duplicateIf " , " Found duplicate if expressions. \n "
" Finding the same expression more than once is suspicious and might indicate "
" a cut and paste or logic error. Please examine this code carefully to determine "
" if it is correct. " ) ;
}
2011-04-09 23:05:27 +02:00
//-----------------------------------------------------------------------------
// check for duplicate code in if and else branches
// if (a) { b = true; } else { b = true; }
//-----------------------------------------------------------------------------
void CheckOther : : checkDuplicateBranch ( )
{
if ( ! _settings - > _checkCodingStyle )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : list < Scope > : : const_iterator scope ;
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope )
{
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
// check all the code in the function for if (..) else
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " if ( " ) & & tok - > strAt ( - 1 ) ! = " else " & &
Token : : Match ( tok - > next ( ) - > link ( ) , " ) { " ) & &
Token : : Match ( tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) , " } else { " ) )
{
// save if branch code
std : : string branch1 = stringifyTokens ( tok - > next ( ) - > link ( ) - > tokAt ( 2 ) , tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) - > previous ( ) ) ;
// find else branch
const Token * tok1 = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
// save else branch code
std : : string branch2 = stringifyTokens ( tok1 - > tokAt ( 3 ) , tok1 - > tokAt ( 2 ) - > link ( ) - > previous ( ) ) ;
// check for duplicates
if ( branch1 = = branch2 )
duplicateBranchError ( tok , tok1 - > tokAt ( 2 ) ) ;
tok = tok - > next ( ) - > link ( ) - > next ( ) ;
}
}
}
}
void CheckOther : : duplicateBranchError ( const Token * tok1 , const Token * tok2 )
{
std : : list < const Token * > toks ;
toks . push_back ( tok2 ) ;
toks . push_back ( tok1 ) ;
reportError ( toks , Severity : : style , " duplicateBranch " , " Found duplicate branches for if and else. \n "
" Finding the same code for an if branch and an else branch is suspicious and "
" might indicate a cut and paste or logic error. Please examine this code "
" carefully to determine if it is correct. " ) ;
}
2011-04-09 21:14:01 +02:00
//-----------------------------------------------------------------------------
2009-03-21 17:58:13 +01:00
void CheckOther : : cstyleCastError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " cstyleCast " , " C-style pointer casting " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : 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 )
{
2010-12-26 20:40:58 +01:00
reportError ( tok , Severity : : error , " sprintfOverlappingData " ,
" Undefined behavior: variable is used as parameter and destination in s[n]printf(). \n "
2011-02-04 10:10:24 +01:00
" The variable ' " + varname + " ' is used both as a parameter and as a destination in "
" s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) "
" documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
2010-12-26 20:40:58 +01:00
" '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-11-27 09:46:34 +01:00
reportError ( tok , Severity : : performance , " passedByValue " ,
2010-11-27 19:41:08 +01:00
" Function parameter ' " + parname + " ' should be passed by reference. \n "
" Parameter ' " + parname + " ' is passed as a value. It could be passed "
2010-11-27 09:46:34 +01:00
" as a (const) reference which is usually faster and recommended in C++. " ) ;
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 ,
2010-12-27 11:46:18 +01:00
Severity : : information ,
2010-07-19 11:30:01 +02:00
" variableScope " ,
2011-01-03 05:15:20 +01:00
" The scope of the variable ' " + varname + " ' can be reduced \n "
" The scope of the variable ' " + varname + " ' can be reduced. Warning: It can be unsafe "
2010-11-11 19:54:43 +01:00
" to fix this message. Be careful. Especially when there are inner loops. Here is an "
" example where cppcheck will write that the scope for 'i' can be reduced: \n "
2010-07-23 12:29:21 +02:00
" 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 "
" 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-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-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 ( ) )
{
2011-02-02 17:56:02 +01:00
if ( Token : : Match ( tok , " sizeof (| sizeof " ) )
{
2010-05-15 14:06:45 +02:00
sizeofsizeofError ( tok ) ;
2011-02-02 17:56:02 +01:00
tok = tok - > next ( ) ;
}
2010-05-15 14:06:45 +02:00
}
}
void CheckOther : : sizeofsizeofError ( const Token * tok )
{
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning ,
2010-11-28 13:20:46 +01:00
" sizeofsizeof " , " Calling sizeof for 'sizeof'. \n "
2011-02-04 10:10:24 +01:00
" Calling sizeof for 'sizeof looks like a suspicious code and "
" most likely there should be just 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
2011-02-19 09:33:29 +01:00
void CheckOther : : switchCaseFallThrough ( const Token * tok )
{
2011-03-05 21:42:15 +01:00
reportError ( tok , Severity : : style ,
2011-02-19 09:33:29 +01:00
" switchCaseFallThrough " , " Switch falls through case without comment " ) ;
}
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-11-29 19:12:21 +01:00
" assignmentInAssert " , " Assert statement modifies ' " + varname + " '. \n "
2011-02-04 10:10:24 +01:00
" Variable ' " + varname + " ' is modified insert assert statement. "
2010-11-29 19:12:21 +01:00
" Assert statements are removed from release builds so the code inside "
" assert statement is not run. If the code is needed also in release "
" builds this is a bug. " ) ;
2010-10-10 22:05:06 +02:00
}
2010-10-25 03:14:21 +02:00
void CheckOther : : incorrectLogicOperatorError ( const Token * tok )
{
reportError ( tok , Severity : : warning ,
" incorrectLogicOperator " , " Mutual exclusion over || always evaluates to true. Did you intend to use && instead? " ) ;
}
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 " ) ;
}
2010-12-31 12:01:38 +01:00
void CheckOther : : catchExceptionByValueError ( const Token * tok )
{
reportError ( tok , Severity : : style ,
2010-12-31 21:48:24 +01:00
" catchExceptionByValue " , " Exception should be caught by reference. \n "
2010-12-31 12:01:38 +01:00
" The exception is caught as a value. It could be caught "
" as a (const) reference which is usually recommended in C++. " ) ;
}
2011-01-06 11:31:58 +01:00
void CheckOther : : memsetZeroBytesError ( const Token * tok , const std : : string & varname )
{
2011-01-06 16:27:22 +01:00
const std : : string summary ( " memset() called to fill 0 bytes of \' " + varname + " \' " ) ;
const std : : string verbose ( summary + " . Second and third arguments might be inverted. " ) ;
reportError ( tok , Severity : : warning , " memsetZeroBytes " , summary + " \n " + verbose ) ;
2011-01-06 11:31:58 +01:00
}
2011-02-08 19:49:29 +01:00
void CheckOther : : incorrectStringCompareError ( const Token * tok , const std : : string & func , const std : : string & string , const std : : string & len )
{
reportError ( tok , Severity : : warning , " incorrectStringCompare " , " String literal " + string + " doesn't match length argument for " + func + " ( " + len + " ). " ) ;
}
2011-02-27 21:30:22 +01:00
void CheckOther : : comparisonOfBoolWithIntError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInt " ,
" Comparison of a boolean with a non-zero integer \n "
" The expression \" ! " + varname + " \" is of type 'bool' but is compared against a non-zero 'int'. " ) ;
}