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-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
2011-02-11 23:38:23 +01:00
void CheckOther : : checkIncrementBoolean ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-02-11 23:38:23 +01:00
return ;
2011-08-14 16:16:39 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-02-11 23:38:23 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " %var% ++ " ) )
{
if ( tok - > varId ( ) )
{
2011-08-14 16:16:39 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " )
2011-02-11 23:38:23 +01:00
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 "
) ;
}
//---------------------------------------------------------------------------
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
2011-01-24 21:40:49 +01:00
void CheckOther : : clarifyCalculation ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-01-24 21:40:49 +01:00
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-09-06 22:37:19 +02:00
if ( cond & & cond - > str ( ) = = " ! " )
cond = cond - > previous ( ) ;
if ( ! cond )
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
}
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
2011-03-09 22:20:14 +01:00
// Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
2011-08-19 00:14:15 +02:00
// Clarify condition '(a & b == c)' into '((a & b) == c)' or '(a & (b == c))'
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
2011-03-09 22:20:14 +01:00
void CheckOther : : clarifyCondition ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-03-09 22:20:14 +01:00
return ;
2011-08-19 13:40:54 +02:00
2011-03-09 22:20:14 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-08-19 00:14:15 +02:00
if ( Token : : Match ( tok , " ( %var% [=&|^] " ) )
2011-03-09 22:20:14 +01:00
{
2011-08-19 13:54:06 +02:00
for ( const Token * tok2 = tok - > tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2011-03-09 22:20:14 +01:00
{
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " [ " )
tok2 = tok2 - > link ( ) ;
2011-08-19 00:56:15 +02:00
else if ( Token : : Match ( tok2 , " <|<=|==|!=|>|>= " ) )
2011-03-09 22:20:14 +01:00
{
2011-08-19 18:06:28 +02:00
// This might be a template
if ( ! code_is_c ( ) & & Token : : Match ( tok2 - > previous ( ) , " %var% < " ) )
break ;
2011-08-19 13:40:54 +02:00
clarifyConditionError ( tok , tok - > strAt ( 2 ) = = " = " , false ) ;
2011-03-09 22:20:14 +01:00
break ;
}
2011-08-19 13:54:06 +02:00
else if ( ! tok2 - > isName ( ) & & ! tok2 - > isNumber ( ) & & tok2 - > str ( ) ! = " . " )
break ;
2011-03-09 22:20:14 +01:00
}
}
}
2011-08-19 13:40:54 +02:00
// using boolean result in bitwise operation ! x [&|^]
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-08-19 18:55:20 +02:00
if ( Token : : Match ( tok , " !|<|<=|==|!=|>|>= " ) )
2011-08-19 13:40:54 +02:00
{
const Token * tok2 = tok - > next ( ) ;
2011-08-19 18:55:20 +02:00
// Todo: There are false positives if '(' if encountered. It
// is assumed there is something like '(char *)&..' and therefore
// it bails out.
if ( Token : : Match ( tok2 , " (|& " ) )
continue ;
2011-08-19 13:54:06 +02:00
while ( tok2 & & ( tok2 - > isName ( ) | | tok2 - > isNumber ( ) | | Token : : Match ( tok2 , " .|(|[ " ) ) )
2011-08-19 13:40:54 +02:00
{
if ( Token : : Match ( tok2 , " (|[ " ) )
tok2 = tok2 - > link ( ) ;
tok2 = tok2 - > next ( ) ;
}
2011-08-19 18:06:28 +02:00
2011-08-19 13:40:54 +02:00
if ( Token : : Match ( tok2 , " [&|^] " ) )
{
2011-08-19 18:06:28 +02:00
// don't write false positives when templates are used
2011-09-12 13:32:55 +02:00
if ( Token : : Match ( tok , " <|> " ) & & ( Token : : Match ( tok2 , " & ,|> " ) | |
Token : : Match ( tok2 - > previous ( ) , " const & " ) ) )
2011-08-19 18:06:28 +02:00
continue ;
2011-08-19 13:40:54 +02:00
clarifyConditionError ( tok , false , true ) ;
}
}
}
2011-03-09 22:20:14 +01:00
}
2011-08-19 13:40:54 +02:00
void CheckOther : : clarifyConditionError ( const Token * tok , bool assign , bool boolop )
2011-03-09 22:20:14 +01:00
{
2011-08-19 00:14:15 +02:00
std : : string errmsg ;
2011-08-19 13:40:54 +02:00
2011-08-19 00:14:15 +02:00
if ( assign )
errmsg = " Suspicious condition (assignment+comparison), it can be clarified with parentheses " ;
2011-08-19 13:40:54 +02:00
else if ( boolop )
errmsg = " Boolean result is used in bitwise operation. Clarify expression with parentheses \n "
" Suspicious expression. Boolean result is used in bitwise operation. The ! operator "
" and the comparison operators have higher precedence than bitwise operators. "
" It is recommended that the expression is clarified with parentheses. " ;
2011-08-19 00:14:15 +02:00
else
errmsg = " Suspicious condition (bitwise operator + comparison), it can be clarified with parentheses \n "
" Suspicious condition. Comparison operators have higher precedence than bitwise operators. Please clarify the condition with parentheses. " ;
2011-03-09 22:20:14 +01:00
reportError ( tok ,
Severity : : style ,
" clarifyCondition " ,
2011-08-19 00:14:15 +02:00
errmsg ) ;
2011-03-09 22:20:14 +01:00
}
2011-09-02 23:19:06 +02:00
//---------------------------------------------------------------------------
// if (bool & bool) -> if (bool && bool)
// if (bool | bool) -> if (bool || bool)
//---------------------------------------------------------------------------
void CheckOther : : checkBitwiseOnBoolean ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " (|.|return %var% [&|] " ) )
{
if ( tok - > next ( ) - > varId ( ) )
{
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & ( var - > typeStartToken ( ) = = var - > typeEndToken ( ) ) & &
2011-09-03 23:10:16 +02:00
var - > typeStartToken ( ) - > str ( ) = = " bool " )
2011-09-02 23:19:06 +02:00
{
bitwiseOnBooleanError ( tok - > next ( ) , tok - > next ( ) - > str ( ) , tok - > strAt ( 2 ) = = " & " ? " && " : " || " ) ;
}
}
}
}
}
void CheckOther : : bitwiseOnBooleanError ( const Token * tok , const std : : string & varname , const std : : string & op )
{
reportError ( tok , Severity : : style , " bitwiseOnBoolean " ,
" Boolean variable ' " + varname + " ' is used in bitwise operation. Did you mean " + op + " ? " ) ;
}
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : warningOldStylePointerCast ( )
2009-01-26 20:14:46 +01:00
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) | |
2010-04-25 14:56:04 +02:00
( _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
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : cstyleCastError ( const Token * tok )
{
reportError ( tok , Severity : : style , " cstyleCast " , " C-style pointer casting " ) ;
}
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-08-19 17:53:43 +02:00
void CheckOther : : fflushOnInputStreamError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error ,
" fflushOnInputStream " , " fflush() called on input stream \" " + varname + " \" may result in undefined behaviour " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-05-16 21:16:25 +02:00
void CheckOther : : checkSizeofForNumericParameter ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2011-05-26 20:04:47 +02:00
if ( Token : : Match ( tok , " sizeof ( %num% ) " )
| | Token : : Match ( tok , " sizeof ( - %num% ) " )
| | Token : : Match ( tok , " sizeof %num% " )
| | Token : : Match ( tok , " sizeof - %num% " )
)
2011-05-16 21:16:25 +02:00
{
sizeofForNumericParameterError ( tok ) ;
}
}
}
2011-01-22 19:21:56 +01:00
2011-08-19 17:53:43 +02:00
void CheckOther : : sizeofForNumericParameterError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
" sizeofwithnumericparameter " , " Using sizeof with a numeric constant as function "
" argument might not be what you intended. \n "
" It is unusual to use constant value with sizeof. For example, this code: \n "
" int f() { \n "
" return sizeof(10); \n "
" } \n "
" returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. "
) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-01-22 19:21:56 +01:00
void CheckOther : : checkSizeofForArrayParameter ( )
{
2011-08-14 16:21:07 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-01-22 19:21:56 +01:00
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 )
{
2011-08-14 16:21:07 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( tokIdx ) - > varId ( ) ) ;
if ( var )
2011-01-22 19:21:56 +01:00
{
2011-08-14 16:21:07 +02:00
const Token * declTok = var - > nameToken ( ) ;
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
}
}
}
}
}
}
2011-08-19 17:53:43 +02: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 "
" system). It does not return the size of the whole array in bytes as might be "
" 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). "
) ;
}
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 ) ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : redundantAssignmentInSwitchError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
" redundantAssignInSwitch " , " Redundant assignment of \" " + varname + " \" in switch " ) ;
}
2010-08-15 06:28:22 +02:00
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-02-19 09:33:29 +01:00
void CheckOther : : checkSwitchCaseFallThrough ( )
{
2011-08-07 09:28:08 +02:00
if ( ! ( _settings - > isEnabled ( " style " ) & & _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-07-30 04:37:05 +02:00
if ( Token : : simpleMatch ( 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-07-30 04:37:05 +02:00
else if ( Token : : simpleMatch ( 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 ;
}
2011-07-30 04:37:05 +02:00
else if ( Token : : simpleMatch ( tok2 , " do { " ) )
2011-02-19 20:02:28 +01:00
{
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 ;
}
2011-07-30 04:37:05 +02:00
else if ( Token : : simpleMatch ( tok2 , " for ( " ) )
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 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 ) ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : switchCaseFallThrough ( const Token * tok )
{
reportError ( tok , Severity : : style ,
" switchCaseFallThrough " , " Switch falls through case without comment " ) ;
}
2011-02-19 09:33:29 +01:00
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 ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-08-15 06:28:22 +02:00
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
{
2011-08-19 07:23:11 +02:00
bool err = true ;
// no false positive for 'x = x ? x : 1;'
2011-08-19 07:28:15 +02:00
// it is simplified to 'if (x) { x=x; } else { x=1; }'. The simplification
// always write all tokens on 1 line (even if the statement is several lines), so
// check if the linenr is the same for all the tokens.
2011-08-19 07:23:11 +02:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " ) { %var% = %var% ; } else { %varid% = " , tok - > varId ( ) ) )
{
// Find the 'if' token
const Token * tokif = tok - > tokAt ( - 2 ) - > link ( ) - > previous ( ) ;
// find the '}' that terminates the 'else'-block
const Token * else_end = tok - > tokAt ( 6 ) - > link ( ) ;
if ( tokif & & else_end & & tokif - > linenr ( ) = = else_end - > linenr ( ) )
err = false ;
}
if ( err )
selfAssignmentError ( tok , tok - > str ( ) ) ;
2010-08-15 06:28:22 +02:00
}
tok = Token : : findmatch ( tok - > next ( ) , selfAssignmentPattern ) ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : selfAssignmentError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
" selfAssignment " , " Redundant assignment of \" " + varname + " \" to itself " ) ;
}
2010-10-10 22:05:06 +02:00
//---------------------------------------------------------------------------
// int a = 1;
// assert(a = 2); // <- assert should not have a side-effect
//---------------------------------------------------------------------------
void CheckOther : : checkAssignmentInAssert ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-10-11 17:59:08 +02:00
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 ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : assignmentInAssertError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
" assignmentInAssert " , " Assert statement modifies ' " + varname + " '. \n "
" Variable ' " + varname + " ' is modified insert assert statement. "
" 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-25 03:14:21 +02:00
//---------------------------------------------------------------------------
2011-08-19 19:28:37 +02:00
// if ((x != 1) || (x != 3)) // expression always true
// if ((x == 1) && (x == 3)) // expression always false
// if ((x < 1) && (x > 3)) // expression always false
// if ((x > 3) || (x < 10)) // expression always true
// if ((x > 5) && (x != 1)) // second comparison always true
//
// Check for suspect logic for an expression consisting of 2 comparison
// expressions with a shared variable and constants and a logical operator
// between them.
//
// Suggest a different logical operator when the logical operator between
// the comparisons is probably wrong.
//
// Inform that second comparison is always true when first comparison is true.
2010-10-25 03:14:21 +02:00
//---------------------------------------------------------------------------
void CheckOther : : checkIncorrectLogicOperator ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-10-25 03:14:21 +02:00
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 )
{
2011-08-19 19:28:37 +02:00
// Find a pair of comparison expressions with or without parenthesis
// with a shared variable and constants and with a logical operator between them.
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 ;
2011-07-17 04:06:23 +02:00
const Token * op1Tok = NULL , * op2Tok = NULL , * op3Tok = NULL , * nextTok = NULL ;
2011-07-17 22:28:00 +02:00
if ( NULL ! = ( logicTok = Token : : findmatch ( tok , " ( %any% !=|==|<|>|>=|<= %any% ) &&|%oror% ( %any% !=|==|<|>|>=|<= %any% ) %any% " , endTok ) ) )
2010-10-25 03:14:21 +02:00
{
term1Tok = logicTok - > next ( ) ;
term2Tok = logicTok - > tokAt ( 7 ) ;
2011-07-17 04:06:23 +02:00
op1Tok = logicTok - > tokAt ( 2 ) ;
op2Tok = logicTok - > tokAt ( 5 ) ;
op3Tok = logicTok - > tokAt ( 8 ) ;
nextTok = logicTok - > tokAt ( 11 ) ;
2010-10-25 03:14:21 +02:00
}
2011-07-17 22:28:00 +02:00
else if ( NULL ! = ( logicTok = Token : : findmatch ( tok , " %any% !=|==|<|>|>=|<= %any% &&|%oror% %any% !=|==|<|>|>=|<= %any% %any% " , endTok ) ) )
2010-10-25 03:14:21 +02:00
{
term1Tok = logicTok ;
term2Tok = logicTok - > tokAt ( 4 ) ;
2011-07-17 04:06:23 +02:00
op1Tok = logicTok - > tokAt ( 1 ) ;
op2Tok = logicTok - > tokAt ( 3 ) ;
op3Tok = logicTok - > tokAt ( 5 ) ;
nextTok = logicTok - > tokAt ( 7 ) ;
2010-10-25 03:14:21 +02:00
}
2011-07-17 04:06:23 +02:00
if ( logicTok )
2010-10-25 03:14:21 +02:00
{
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 ;
2011-07-17 04:06:23 +02:00
bool varFirst1 , varFirst2 ;
unsigned int varId ;
2011-08-19 19:28:37 +02:00
const Token * varTok = NULL ;
2011-07-17 04:06:23 +02:00
if ( Token : : Match ( term1Tok , " %var% %any% %num% " ) )
2010-11-21 09:06:43 +01:00
{
2011-08-19 19:28:37 +02:00
varTok = term1Tok ;
varId = varTok - > 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
}
2011-07-17 04:06:23 +02:00
varFirst1 = true ;
2010-11-21 09:06:43 +01:00
firstConstant = term1Tok - > tokAt ( 2 ) - > str ( ) ;
2011-07-17 04:06:23 +02:00
}
else if ( Token : : Match ( term1Tok , " %num% %any% %var% " ) )
{
2011-08-19 19:28:37 +02:00
varTok = term1Tok - > tokAt ( 2 ) ;
varId = varTok - > varId ( ) ;
2011-07-17 04:06:23 +02:00
if ( ! varId )
2010-11-21 09:06:43 +01:00
{
2011-07-17 04:06:23 +02:00
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
2010-11-21 09:06:43 +01:00
}
2011-07-17 04:06:23 +02:00
varFirst1 = false ;
firstConstant = term1Tok - > str ( ) ;
2010-11-21 09:06:43 +01:00
}
2011-07-17 04:06:23 +02:00
else
2010-10-25 03:14:21 +02:00
{
2011-07-17 04:06:23 +02:00
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
}
2010-11-21 09:06:43 +01:00
2011-07-17 04:06:23 +02:00
if ( Token : : Match ( term2Tok , " %var% %any% %num% " ) )
{
const unsigned int varId2 = term2Tok - > varId ( ) ;
if ( ! varId2 | | varId ! = varId2 )
2010-11-21 09:06:43 +01:00
{
2011-07-17 04:06:23 +02:00
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
2010-11-21 09:06:43 +01:00
}
2011-07-17 04:06:23 +02:00
varFirst2 = true ;
secondConstant = term2Tok - > tokAt ( 2 ) - > str ( ) ;
variableTested = varId ;
}
else if ( Token : : Match ( term2Tok , " %num% %any% %var% " ) )
{
const unsigned int varId2 = term1Tok - > tokAt ( 2 ) - > varId ( ) ;
if ( ! varId2 | | varId ! = varId2 )
2010-11-21 09:06:43 +01:00
{
2011-07-17 04:06:23 +02:00
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
2010-11-21 09:06:43 +01:00
}
2011-07-17 04:06:23 +02:00
varFirst2 = false ;
secondConstant = term2Tok - > str ( ) ;
variableTested = varId ;
}
else
{
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
2010-10-25 03:14:21 +02:00
}
2010-11-21 09:06:43 +01:00
2011-07-17 04:06:23 +02:00
if ( variableTested = = 0 | | firstConstant . empty ( ) | | secondConstant . empty ( ) )
2010-10-25 03:14:21 +02:00
{
2011-07-17 04:06:23 +02:00
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
continue ;
}
enum Position { First , Second , NA } ;
enum Relation { Equal , NotEqual , Less , LessEqual , More , MoreEqual } ;
2011-08-19 19:28:37 +02:00
enum LogicError { Exclusion , AlwaysTrue , AlwaysFalse , AlwaysFalseOr } ;
2011-07-17 04:06:23 +02:00
struct Condition
{
const char * before ;
Position position1 ;
const char * op1TokStr ;
const char * op2TokStr ;
Position position2 ;
const char * op3TokStr ;
const char * after ;
Relation relation ;
2011-08-19 19:28:37 +02:00
LogicError error ;
2011-07-17 04:06:23 +02:00
} conditions [ ] =
{
2011-08-19 19:28:37 +02:00
{ " !!&& " , NA , " != " , " || " , NA , " != " , " !!&& " , NotEqual , Exclusion } , // (x != 1) || (x != 3) <- always true
{ " ( " , NA , " == " , " && " , NA , " == " , " ) " , NotEqual , AlwaysFalseOr } , // (x == 1) && (x == 3) <- always false
{ " ( " , First , " < " , " && " , First , " > " , " ) " , LessEqual , AlwaysFalseOr } , // (x < 1) && (x > 3) <- always false
{ " ( " , First , " > " , " && " , First , " < " , " ) " , MoreEqual , AlwaysFalseOr } , // (x > 3) && (x < 1) <- always false
{ " ( " , Second , " > " , " && " , First , " > " , " ) " , LessEqual , AlwaysFalseOr } , // (1 > x) && (x > 3) <- always false
{ " ( " , First , " > " , " && " , Second , " > " , " ) " , MoreEqual , AlwaysFalseOr } , // (x > 3) && (1 > x) <- always false
{ " ( " , First , " < " , " && " , Second , " < " , " ) " , LessEqual , AlwaysFalseOr } , // (x < 1) && (3 < x) <- always false
{ " ( " , Second , " < " , " && " , First , " < " , " ) " , MoreEqual , AlwaysFalseOr } , // (3 < x) && (x < 1) <- always false
{ " ( " , Second , " > " , " && " , Second , " < " , " ) " , LessEqual , AlwaysFalseOr } , // (1 > x) && (3 < x) <- always false
{ " ( " , Second , " < " , " && " , Second , " > " , " ) " , MoreEqual , AlwaysFalseOr } , // (3 < x) && (1 > x) <- always false
{ " ( " , First , " >|>= " , " || " , First , " <|<= " , " ) " , Less , Exclusion } , // (x > 3) || (x < 10) <- always true
{ " ( " , First , " <|<= " , " || " , First , " >|>= " , " ) " , More , Exclusion } , // (x < 10) || (x > 3) <- always true
{ " ( " , Second , " <|<= " , " || " , First , " <|<= " , " ) " , Less , Exclusion } , // (3 < x) || (x < 10) <- always true
{ " ( " , First , " <|<= " , " || " , Second , " <|<= " , " ) " , More , Exclusion } , // (x < 10) || (3 < x) <- always true
{ " ( " , First , " >|>= " , " || " , Second , " >|>= " , " ) " , Less , Exclusion } , // (x > 3) || (10 > x) <- always true
{ " ( " , Second , " >|>= " , " || " , First , " >|>= " , " ) " , More , Exclusion } , // (10 > x) || (x > 3) <- always true
{ " ( " , Second , " <|<= " , " || " , Second , " >|<= " , " ) " , Less , Exclusion } , // (3 < x) || (10 > x) <- always true
{ " ( " , Second , " >|>= " , " || " , Second , " <|<= " , " ) " , More , Exclusion } , // (10 > x) || (3 < x) <- always true
{ " ( " , First , " > " , " && " , NA , " != " , " ) " , More , AlwaysTrue } , // (x > 5) && (x != 1) <- second expression always true
{ " ( " , Second , " < " , " && " , NA , " != " , " ) " , More , AlwaysTrue } , // (5 < x) && (x != 1) <- second expression always true
{ " ( " , First , " > " , " && " , NA , " == " , " ) " , More , AlwaysFalse } , // (x > 5) && (x == 1) <- second expression always false
{ " ( " , Second , " < " , " && " , NA , " == " , " ) " , More , AlwaysFalse } , // (5 < x) && (x == 1) <- second expression always false
2011-07-17 04:06:23 +02:00
} ;
for ( unsigned int i = 0 ; i < ( sizeof ( conditions ) / sizeof ( conditions [ 0 ] ) ) ; i + + )
{
if ( ! ( ( conditions [ i ] . position1 = = NA ) | | ( ( ( conditions [ i ] . position1 = = First ) & & varFirst1 ) | | ( ( conditions [ i ] . position1 = = Second ) & & ! varFirst1 ) ) ) )
continue ;
if ( ! ( ( conditions [ i ] . position2 = = NA ) | | ( ( ( conditions [ i ] . position2 = = First ) & & varFirst2 ) | | ( ( conditions [ i ] . position2 = = Second ) & & ! varFirst2 ) ) ) )
continue ;
2011-07-17 22:28:00 +02:00
if ( ! Token : : Match ( op1Tok , conditions [ i ] . op1TokStr ) )
2011-07-17 04:06:23 +02:00
continue ;
2011-07-17 22:28:00 +02:00
if ( ! Token : : Match ( op2Tok , conditions [ i ] . op2TokStr ) )
2011-07-17 04:06:23 +02:00
continue ;
2011-07-17 22:28:00 +02:00
if ( ! Token : : Match ( op3Tok , conditions [ i ] . op3TokStr ) )
2011-07-17 04:06:23 +02:00
continue ;
2011-07-18 13:34:49 +02:00
if ( ! Token : : Match ( logicTok - > previous ( ) , conditions [ i ] . before ) )
2011-07-17 04:06:23 +02:00
continue ;
2011-07-18 13:34:49 +02:00
if ( ! Token : : Match ( nextTok , conditions [ i ] . after ) )
2011-07-17 04:06:23 +02:00
continue ;
2011-07-17 05:05:35 +02:00
if ( ( conditions [ i ] . relation = = Equal & & MathLib : : isEqual ( firstConstant , secondConstant ) ) | |
( conditions [ i ] . relation = = NotEqual & & MathLib : : isNotEqual ( firstConstant , secondConstant ) ) | |
( conditions [ i ] . relation = = Less & & MathLib : : isLess ( firstConstant , secondConstant ) ) | |
( conditions [ i ] . relation = = LessEqual & & MathLib : : isLessEqual ( firstConstant , secondConstant ) ) | |
( conditions [ i ] . relation = = More & & MathLib : : isGreater ( firstConstant , secondConstant ) ) | |
( conditions [ i ] . relation = = MoreEqual & & MathLib : : isGreaterEqual ( firstConstant , secondConstant ) ) )
2011-08-19 19:28:37 +02:00
{
if ( conditions [ i ] . error = = Exclusion | | conditions [ i ] . error = = AlwaysFalseOr )
incorrectLogicOperatorError ( term1Tok , conditions [ i ] . error = = Exclusion ) ;
else
{
std : : string text ( " When " + varTok - > str ( ) + " is greater than " + firstConstant + " , the comparison " +
varTok - > str ( ) + " " + conditions [ i ] . op3TokStr + " " + secondConstant +
" is always " + ( conditions [ i ] . error = = AlwaysTrue ? " true. " : " false. " ) ) ;
secondAlwaysTrueFalseWhenFirstTrueError ( term1Tok , text ) ;
}
}
2010-10-25 03:14:21 +02:00
}
}
tok = Token : : findmatch ( endTok - > next ( ) , conditionPattern ) ;
endTok = tok ? tok - > next ( ) - > link ( ) : NULL ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : incorrectLogicOperatorError ( const Token * tok , bool always )
{
if ( always )
reportError ( tok , Severity : : warning ,
" incorrectLogicOperator " , " Mutual exclusion over || always evaluates to true. Did you intend to use && instead? " ) ;
else
reportError ( tok , Severity : : warning ,
" incorrectLogicOperator " , " Expression always evaluates to false. Did you intend to use || instead? " ) ;
}
2011-08-19 19:28:37 +02:00
void CheckOther : : secondAlwaysTrueFalseWhenFirstTrueError ( const Token * tok , const std : : string & truefalse )
{
reportError ( tok , Severity : : style , " secondAlwaysTrueFalseWhenFirstTrue " , truefalse ) ;
}
2010-12-31 12:01:38 +01:00
//---------------------------------------------------------------------------
// try {} catch (std::exception err) {} <- Should be "std::exception& err"
//---------------------------------------------------------------------------
void CheckOther : : checkCatchExceptionByValue ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-12-31 12:01:38 +01:00
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 ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : catchExceptionByValueError ( const Token * tok )
{
reportError ( tok , Severity : : style ,
" catchExceptionByValue " , " Exception should be caught by reference. \n "
" The exception is caught as a value. It could be caught "
" as a (const) reference which is usually recommended in C++. " ) ;
}
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 ( ) ;
2011-07-28 08:12:21 +02:00
if ( ! tok2 )
continue ;
2009-01-26 20:14:46 +01:00
// 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 ;
}
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : dangerousUsageStrtolError ( const Token * tok )
{
reportError ( tok , Severity : : error , " dangerousUsageStrtol " , " Invalid radix in call to strtol or strtoul. Must be 0 or 2-36 " ) ;
}
void CheckOther : : sprintfOverlappingDataError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " sprintfOverlappingData " ,
" Undefined behavior: variable is used as parameter and destination in s[n]printf(). \n "
" 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): "
" 'If copying takes place between objects that overlap as a result of a call "
" to sprintf() or snprintf(), the results are undefined.' " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2010-08-14 15:15:12 +02:00
void CheckOther : : invalidScanf ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-08-14 15:15:12 +02:00
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-08-19 17:53:43 +02:00
void CheckOther : : invalidScanfError ( const Token * tok )
{
reportError ( tok , Severity : : warning ,
" invalidscanf " , " scanf without field width limits can crash with huge input data \n "
" scanf without field width limits can crash with huge input data. To fix this error "
" message add a field width specifier: \n "
" %s => %20s \n "
" %i => %3i \n "
" \n "
" Sample program that can crash: \n "
" \n "
" #include <stdio.h> \n "
" int main() \n "
" { \n "
" int a; \n "
" scanf( \" %i \" , &a); \n "
" return 0; \n "
" } \n "
" \n "
" To make it crash: \n "
" perl -e 'print \" 5 \" x2100000' | ./a.out " ) ;
}
2011-02-27 21:30:22 +01:00
//---------------------------------------------------------------------------
// if (!x==3) <- Probably meant to be "x!=3"
//---------------------------------------------------------------------------
void CheckOther : : checkComparisonOfBoolWithInt ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-02-27 21:30:22 +01:00
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-08-19 17:53:43 +02: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'. " ) ;
}
2011-07-15 02:12:56 +02:00
//---------------------------------------------------------------------------
// switch (x)
// {
// case 2:
// y = a;
// break;
// break; // <- Redundant break
// case 3:
// y = b;
// }
//---------------------------------------------------------------------------
void CheckOther : : checkDuplicateBreak ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-07-15 02:12:56 +02:00
return ;
const char breakPattern [ ] = " break|continue ; break|continue ; " ;
// Find consecutive break or continue statements. e.g.:
// break; break;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , breakPattern ) ;
while ( tok )
{
duplicateBreakError ( tok ) ;
tok = Token : : findmatch ( tok - > next ( ) , breakPattern ) ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : duplicateBreakError ( const Token * tok )
2010-08-14 15:15:12 +02:00
{
2011-08-19 17:53:43 +02:00
reportError ( tok , Severity : : style , " duplicateBreak " ,
" Consecutive break or continue statements are unnecessary \n "
" The second of the two statements can never be executed, and so should be removed \n " ) ;
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
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
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
2011-08-19 17:53:43 +02:00
void CheckOther : : udivError ( const Token * tok )
{
reportError ( tok , Severity : : error , " udivError " , " Unsigned division. The result will be wrong. " ) ;
}
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
2011-08-19 17:53:43 +02:00
void CheckOther : : memsetZeroBytesError ( const Token * tok , const std : : string & varname )
{
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 ) ;
}
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 ;
}
2011-05-06 21:16:01 +02:00
else 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..
2011-05-06 21:16:01 +02:00
else if ( tok - > str ( ) ! = " else " & & Token : : Match ( tok - > previous ( ) , " [ ; { } ] % type % { " ))
2010-08-26 21:57:48 +02:00
{
2011-05-06 21:16:01 +02:00
for_or_while = true ;
2010-08-26 21:57:48 +02:00
}
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
}
2011-08-19 17:53:43 +02:00
void CheckOther : : variableScopeError ( const Token * tok , const std : : string & varname )
{
reportError ( tok ,
Severity : : information ,
" variableScope " ,
" The scope of the variable ' " + varname + " ' can be reduced \n "
" The scope of the variable ' " + varname + " ' can be reduced. Warning: It can be unsafe "
" 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 "
" 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-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
{
2011-09-03 15:30:30 +02:00
if ( ! _settings - > isEnabled ( " performance " ) )
2010-04-21 08:38:25 +02:00
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
{
2011-04-20 06:41:26 +02:00
// TODO: False negatives. This pattern only checks for string.
// Investigate if there are other classes in the std
// namespace and add them to the pattern. There are
// streams for example (however it seems strange with
// const stream parameter).
2011-04-19 20:07:54 +02:00
if ( Token : : Match ( tok , " [,(] const std :: string %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
}
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : passedByValueError ( const Token * tok , const std : : string & parname )
{
reportError ( tok , Severity : : performance , " passedByValue " ,
" Function parameter ' " + parname + " ' should be passed by reference. \n "
" Parameter ' " + parname + " ' is passed as a value. It could be passed "
" as a (const) reference which is usually faster and recommended in C++. " ) ;
}
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
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-04-21 08:38:25 +02:00
return ;
2011-08-14 16:39:45 +02:00
const SymbolDatabase * 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
{
// Declaring the variable..
2011-07-05 18:41:27 +02:00
if ( Token : : Match ( tok , " [{};(,] const| char *| %var% [;=,)] " ) | |
Token : : Match ( tok , " [{};(,] const| char %var% [ " ) )
2009-01-26 20:14:46 +01:00
{
2011-07-05 18:41:27 +02:00
// goto 'char' token
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2010-03-28 15:56:13 +02:00
// Check for unsigned char
2011-07-05 18:41:27 +02:00
if ( tok - > 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
2011-07-05 18:41:27 +02:00
tok = tok - > next ( ) ;
const bool isPointer ( tok - > str ( ) = = " * " | | tok - > strAt ( 1 ) = = " [ " ) ;
if ( tok - > str ( ) = = " * " )
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 ;
}
2011-08-09 17:03:22 +02:00
if ( ! isPointer )
2009-01-26 20:14:46 +01:00
{
2011-08-09 17:03:22 +02:00
std : : string temp = " %var% [ " + tok - > str ( ) + " ] " ;
if ( ( tok2 - > str ( ) ! = " . " ) & & Token : : Match ( tok2 - > next ( ) , temp . c_str ( ) ) )
{
charArrayIndexError ( tok2 - > next ( ) ) ;
break ;
}
2009-01-26 20:14:46 +01:00
}
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..
2011-07-05 18:41:27 +02:00
if ( 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?
2011-08-14 16:39:45 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok2 - > next ( ) - > varId ( ) ) ;
if ( ! ( var & & Token : : Match ( var - > typeEndToken ( ) , " short|int|long " ) ) )
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 ;
}
2011-07-05 18:41:27 +02:00
if ( isPointer & & Token : : Match ( tok2 , " [;{}] %var% = %any% [&|] ( * %varid% ) ; " , tok - > varId ( ) ) )
{
// it's ok with a bitwise and where the other operand is 0xff or less..
if ( tok2 - > strAt ( 4 ) = = " & " & & tok2 - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 3 ) ) )
continue ;
// is the result stored in a short|int|long?
2011-08-14 16:39:45 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok2 - > next ( ) - > varId ( ) ) ;
if ( ! ( var & & Token : : Match ( var - > typeEndToken ( ) , " short|int|long " ) ) )
2011-07-05 18:41:27 +02:00
continue ;
// This is an error..
charBitOpError ( tok2 ) ;
break ;
}
2009-01-26 20:14:46 +01:00
}
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : charArrayIndexError ( const Token * tok )
{
reportError ( tok ,
Severity : : warning ,
" charArrayIndex " ,
" Using char type as array index \n "
" Using signed char type as array index. If the value "
" can be greater than 127 there will be a buffer overflow "
" (because of sign extension). " ) ;
}
2009-01-26 20:14:46 +01:00
2011-08-19 17:53:43 +02:00
void CheckOther : : charBitOpError ( const Token * tok )
{
reportError ( tok ,
Severity : : warning ,
" charBitOp " ,
" When using char variables in bit operations, sign extension can generate unexpected results. \n "
" When using char variables in bit operations, sign extension can generate unexpected results. For example: \n "
" char c = 0x80; \n "
" int i = 0 | c; \n "
" if (i & 0x8000) \n "
" printf( \" not expected \" ); \n "
" The 'not expected' will be printed on the screen. " ) ;
}
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
// Incomplete statement..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkIncompleteStatement ( )
2009-01-26 20:14:46 +01:00
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
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
{
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-08-16 20:16:33 +02: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
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : constStatementError ( const Token * tok , const std : : string & type )
{
reportError ( tok , Severity : : warning , " constStatement " , " Redundant code: Found a statement that begins with " + type + " constant " ) ;
}
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 ] = = ' \' ' )
2011-08-19 17:53:43 +02:00
strPlusCharError ( 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 ] )
2011-08-19 17:53:43 +02:00
strPlusCharError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-02-04 19:49:19 +01:00
2011-08-19 17:53:43 +02:00
void CheckOther : : strPlusCharError ( const Token * tok )
{
reportError ( tok , Severity : : error , " strPlusChar " , " Unusual pointer arithmetic " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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
{
2011-09-10 16:12:53 +02:00
if ( Token : : Match ( tok , " [/%] %num% " ) & &
2010-04-02 07:30:58 +02:00
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
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : zerodivError ( const Token * tok )
{
reportError ( tok , Severity : : error , " zerodiv " , " Division by zero " ) ;
}
2009-03-28 07:49:47 +01:00
2011-08-19 17:53:43 +02: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 & &
2011-04-19 01:20:27 +02:00
Token : : Match ( tok , " sqrt|sqrtf|sqrtl ( %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-08-19 17:53:43 +02:00
void CheckOther : : mathfunctionCallError ( const Token * tok , const unsigned int numParam )
{
if ( tok )
{
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 " ) ;
}
else
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " " to " " () leads to undefined result " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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 ;
}
2011-08-19 18:06:28 +02:00
bool CheckOther : : code_is_c ( ) const
{
const std : : string fname = _tokenizer - > getFiles ( ) - > at ( 0 ) ;
const size_t position = fname . rfind ( " . " ) ;
if ( position ! = std : : string : : npos )
{
const std : : string ext = fname . substr ( position ) ;
if ( ext = = " .c " | | ext = = " .C " )
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
2011-08-19 18:06:28 +02:00
if ( code_is_c ( ) )
2010-12-25 08:43:52 +01:00
{
2011-08-19 18:06:28 +02:00
return ;
2010-12-25 08:43:52 +01:00
}
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-08-19 17:53:43 +02:00
void CheckOther : : misusedScopeObjectError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error ,
" unusedScopedObject " , " instance of \" " + varname + " \" object destroyed immediately " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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-08-19 17:53:43 +02: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-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 ;
2011-04-10 15:57:09 +02:00
std : : string stringified ;
if ( tok - > isUnsigned ( ) )
stringified . append ( " unsigned " ) ;
else if ( tok - > isSigned ( ) )
stringified . append ( " signed " ) ;
if ( tok - > isLong ( ) )
stringified . append ( " long " ) ;
stringified . append ( tok - > str ( ) ) ;
2011-04-09 21:14:01 +02:00
while ( tok & & tok - > next ( ) & & tok ! = end )
{
2011-04-10 15:57:09 +02:00
if ( tok - > isUnsigned ( ) )
stringified . append ( " unsigned " ) ;
else if ( tok - > isSigned ( ) )
stringified . append ( " signed " ) ;
if ( tok - > isLong ( ) )
stringified . append ( " long " ) ;
2011-04-09 21:14:01 +02:00
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 ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-04-09 21:14:01 +02:00
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 ( ) )
{
2011-07-30 04:37:05 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) & & tok - > strAt ( - 1 ) ! = " else " & &
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) )
2011-04-09 21:14:01 +02:00
{
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
2011-07-30 04:37:05 +02:00
while ( Token : : simpleMatch ( tok1 , " } else if ( " ) & &
Token : : simpleMatch ( tok1 - > tokAt ( 3 ) - > link ( ) , " ) { " ) )
2011-04-09 21:14:01 +02:00
{
// 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 ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-04-09 23:05:27 +02:00
return ;
2011-05-08 19:22:42 +02:00
if ( ! _settings - > inconclusive )
return ;
2011-04-09 23:05:27 +02:00
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 ( ) )
{
2011-07-30 04:37:05 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) & & tok - > strAt ( - 1 ) ! = " else " & &
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) & &
Token : : simpleMatch ( tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) , " } else { " ) )
2011-04-09 23:05:27 +02:00
{
// 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-10 16:25:02 +02:00
//---------------------------------------------------------------------------
// check for the same expression on both sides of an operator
// (x == x), (x && x), (x || x)
// (x.y == x.y), (x.y && x.y), (x.y || x.y)
//---------------------------------------------------------------------------
void CheckOther : : checkDuplicateExpression ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-04-10 16:25:02 +02:00
return ;
// Parse all executing scopes..
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 ;
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " (|&&|%oror% %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% )|&&|%oror% " ) & &
tok - > strAt ( 1 ) = = tok - > strAt ( 3 ) )
{
2011-04-19 01:20:27 +02:00
// float == float and float != float are valid NaN checks
if ( Token : : Match ( tok - > tokAt ( 2 ) , " ==|!= " ) & & tok - > next ( ) - > varId ( ) )
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeStartToken ( ) = = var - > typeEndToken ( ) )
{
if ( Token : : Match ( var - > typeStartToken ( ) , " float|double " ) )
continue ;
}
}
2011-04-10 16:25:02 +02:00
duplicateExpressionError ( tok - > next ( ) , tok - > tokAt ( 3 ) , tok - > strAt ( 2 ) ) ;
}
else if ( Token : : Match ( tok , " (|&&|%oror% %var% . %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% . %var% )|&&|%oror% " ) & &
tok - > strAt ( 1 ) = = tok - > strAt ( 5 ) & & tok - > strAt ( 3 ) = = tok - > strAt ( 7 ) )
{
duplicateExpressionError ( tok - > next ( ) , tok - > tokAt ( 6 ) , tok - > strAt ( 4 ) ) ;
}
}
}
}
void CheckOther : : duplicateExpressionError ( const Token * tok1 , const Token * tok2 , const std : : string & op )
{
std : : list < const Token * > toks ;
toks . push_back ( tok2 ) ;
toks . push_back ( tok1 ) ;
reportError ( toks , Severity : : style , " duplicateExpression " , " Same expression on both sides of \' " + op + " \' . \n "
" Finding the same expression on both sides of an operator 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-26 07:45:27 +02:00
//---------------------------------------------------------------------------
// Check for string comparison involving two static strings.
// if(strcmp("00FF00","00FF00")==0) // <- statement is always true
//---------------------------------------------------------------------------
void CheckOther : : checkAlwaysTrueOrFalseStringCompare ( )
{
2011-09-03 15:30:30 +02:00
if ( ! _settings - > isEnabled ( " style " ) & & ! _settings - > isEnabled ( " performance " ) )
2011-04-26 07:45:27 +02:00
return ;
const char pattern1 [ ] = " strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %str% , %str% ) " ;
const char pattern2 [ ] = " QString :: compare ( %str% , %str% ) " ;
const Token * tok = _tokenizer - > tokens ( ) ;
while ( tok & & ( tok = Token : : findmatch ( tok , pattern1 ) ) ! = NULL )
{
2011-08-19 17:53:43 +02:00
alwaysTrueFalseStringCompareError ( tok , tok - > strAt ( 2 ) , tok - > strAt ( 4 ) ) ;
2011-04-26 07:45:27 +02:00
tok = tok - > tokAt ( 5 ) ;
}
tok = _tokenizer - > tokens ( ) ;
while ( tok & & ( tok = Token : : findmatch ( tok , pattern2 ) ) ! = NULL )
{
2011-08-19 17:53:43 +02:00
alwaysTrueFalseStringCompareError ( tok , tok - > strAt ( 4 ) , tok - > strAt ( 6 ) ) ;
2011-04-26 07:45:27 +02:00
tok = tok - > tokAt ( 7 ) ;
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : alwaysTrueFalseStringCompareError ( const Token * tok , const std : : string & str1 , const std : : string & str2 )
2011-04-26 07:45:27 +02:00
{
const size_t stringLen = 10 ;
const std : : string string1 = ( str1 . size ( ) < stringLen ) ? str1 : ( str1 . substr ( 0 , stringLen - 2 ) + " .. " ) ;
const std : : string string2 = ( str2 . size ( ) < stringLen ) ? str2 : ( str2 . substr ( 0 , stringLen - 2 ) + " .. " ) ;
if ( str1 = = str2 )
{
reportError ( tok , Severity : : warning , " staticStringCompare " ,
" Comparison of always identical static strings. \n "
" The compared strings, ' " + string1 + " ' and ' " + string2 + " ', are always identical. "
" If the purpose is to compare these two strings, the comparison is unnecessary. "
" If the strings are supposed to be different, then there is a bug somewhere. " ) ;
}
2011-09-03 15:30:30 +02:00
else if ( _settings - > isEnabled ( " performance " ) )
2011-04-26 07:45:27 +02:00
{
reportError ( tok , Severity : : performance , " staticStringCompare " ,
" Unnecessary comparison of static strings. \n "
" The compared strings, ' " + string1 + " ' and ' " + string2 + " ', are static and always different. "
" If the purpose is to compare these two strings, the comparison is unnecessary. " ) ;
}
}
2011-04-09 21:14:01 +02:00
//-----------------------------------------------------------------------------
2011-08-19 17:53:43 +02:00
//-----------------------------------------------------------------------------
2010-05-15 14:06:45 +02:00
void CheckOther : : sizeofsizeof ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-05-15 14:06:45 +02:00
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
2011-08-19 17:53:43 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
2010-08-06 22:57:10 +02:00
void CheckOther : : sizeofCalculation ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-08-06 22:57:10 +02:00
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() " ) ;
}
2011-08-19 17:53:43 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
2011-07-28 07:28:24 +02:00
void CheckOther : : checkAssignBoolToPointer ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " [;{}] %var% = %bool% ; " ) )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const Variable * var1 ( symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ) ;
// Is variable a pointer?
if ( var1 & & var1 - > nameToken ( ) - > strAt ( - 1 ) = = " * " )
assignBoolToPointerError ( tok - > next ( ) ) ;
}
}
}
void CheckOther : : assignBoolToPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " assignBoolToPointer " ,
" Assigning bool value to pointer (converting bool value to address) " ) ;
}
2011-08-07 01:23:09 +02:00
//---------------------------------------------------------------------------
// Check testing sign of unsigned variables.
//---------------------------------------------------------------------------
void CheckOther : : checkSignOfUnsignedVariable ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-08-07 01:23:09 +02:00
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 ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) )
{
2011-09-27 03:24:34 +02:00
if ( Token : : Match ( tok , " (|&&|%oror% %var% <|<= 0 )|&&|%oror% " ) & & tok - > next ( ) - > varId ( ) )
2011-08-07 01:23:09 +02:00
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2011-08-19 17:53:43 +02:00
unsignedLessThanZeroError ( tok - > next ( ) , tok - > next ( ) - > str ( ) ) ;
2011-08-07 01:23:09 +02:00
}
2011-09-27 03:24:34 +02:00
else if ( Token : : Match ( tok , " (|&&|%oror% 0 > %var% )|&&|%oror% " ) & & tok - > tokAt ( 3 ) - > varId ( ) )
2011-08-07 01:23:09 +02:00
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2011-08-19 17:53:43 +02:00
unsignedLessThanZeroError ( tok - > tokAt ( 3 ) , tok - > strAt ( 3 ) ) ;
2011-08-07 01:23:09 +02:00
}
2011-09-27 03:24:34 +02:00
else if ( Token : : Match ( tok , " (|&&|%oror% 0 <= %var% )|&&|%oror% " ) & & tok - > tokAt ( 3 ) - > varId ( ) )
2011-08-07 01:23:09 +02:00
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2011-08-19 17:53:43 +02:00
unsignedPositiveError ( tok - > tokAt ( 3 ) , tok - > strAt ( 3 ) ) ;
2011-08-07 01:23:09 +02:00
}
2011-09-27 03:24:34 +02:00
else if ( Token : : Match ( tok , " (|&&|%oror% %var% >= 0 )|&&|%oror% " ) & & tok - > next ( ) - > varId ( ) )
{
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
unsignedPositiveError ( tok - > next ( ) , tok - > next ( ) - > str ( ) ) ;
}
2011-08-07 01:23:09 +02:00
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : unsignedLessThanZeroError ( const Token * tok , const std : : string & varname )
2011-08-07 01:23:09 +02:00
{
reportError ( tok , Severity : : style , " unsignedLessThanZero " ,
" Checking if unsigned variable ' " + varname + " ' is less than zero. \n "
" An unsigned variable will never be negative so it is either pointless or "
" an error to check if it is. " ) ;
}
2011-08-19 17:53:43 +02:00
void CheckOther : : unsignedPositiveError ( const Token * tok , const std : : string & varname )
2011-08-07 01:23:09 +02:00
{
reportError ( tok , Severity : : style , " unsignedPositive " ,
" Checking if unsigned variable ' " + varname + " ' is positive is always true. \n "
2011-09-05 15:48:59 +02:00
" An unsigned variable will always be positive so it is either pointless or "
2011-08-07 01:23:09 +02:00
" an error to check if it is. " ) ;
}