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
2011-10-05 20:30:36 +02:00
# include <cctype>
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)
2011-10-13 20:53:06 +02:00
namespace {
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-10-13 20:53:06 +02: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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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
2011-10-13 20:53:06 +02:00
if ( cond - > str ( ) = = " ) " ) {
2011-04-02 11:43:20 +02:00
clarifyCalculationError ( cond , op ) ;
2011-10-13 20:53:06 +02: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-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " ( %var% [=&|^] " ) ) {
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-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " <|<=|==|!=|>|>= " ) ) {
2011-08-19 18:06:28 +02:00
// This might be a template
2011-10-16 08:09:57 +02:00
if ( ! _tokenizer - > code_is_c ( ) & & Token : : Match ( tok2 - > previous ( ) , " %var% < " ) )
2011-08-19 18:06:28 +02:00
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-10-13 20:53:06 +02:00
} else if ( ! tok2 - > isName ( ) & & ! tok2 - > isNumber ( ) & & tok2 - > str ( ) ! = " . " )
2011-08-19 13:54:06 +02:00
break ;
2011-03-09 22:20:14 +01:00
}
}
}
2011-08-19 13:40:54 +02:00
// using boolean result in bitwise operation ! x [&|^]
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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-10-13 20:53: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-10-13 20:53:06 +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 , " & ,|> " ) | |
2011-10-27 10:41:34 +02:00
Token : : simpleMatch ( 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-10-06 22:01:48 +02:00
//---------------------------------------------------------------------------
// if (bool & bool) -> if (bool && bool)
// if (bool | bool) -> if (bool || bool)
//---------------------------------------------------------------------------
void CheckOther : : checkBitwiseOnBoolean ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
// danmar: this is inconclusive because I don't like that there are
// warnings for calculations. Example: set_flag(a & b);
if ( ! _settings - > inconclusive )
return ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " (|.|return %var% [&|] " ) ) {
if ( tok - > next ( ) - > varId ( ) ) {
2011-10-06 22:01:48 +02:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & ( var - > typeStartToken ( ) = = var - > typeEndToken ( ) ) & &
2011-10-13 20:53:06 +02:00
var - > typeStartToken ( ) - > str ( ) = = " bool " ) {
2011-10-06 22:01:48 +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 )
{
reportInconclusiveError ( tok , Severity : : style , " bitwiseOnBoolean " ,
" Boolean variable ' " + varname + " ' is used in bitwise operation. Did you mean " + op + " ? " ) ;
}
2011-10-11 08:41:39 +02:00
void CheckOther : : checkSuspiciousSemicolon ( )
{
if ( ! _settings - > inconclusive | | ! _settings - > isEnabled ( " style " ) )
return ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2011-10-11 08:41:39 +02:00
// Look for "if(); {}", "for(); {}" or "while(); {}"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " if|for|while ( " ) ) {
2011-10-11 08:41:39 +02:00
const Token * end = tok - > next ( ) - > link ( ) ;
if ( ! end )
continue ;
// Ensure the semicolon is at the same line number as the if/for/while statement
// and the {..} block follows it without an extra empty line.
if ( Token : : simpleMatch ( end , " ) { ; } { " ) & &
end - > linenr ( ) = = end - > tokAt ( 2 ) - > linenr ( )
2011-10-13 20:53:06 +02:00
& & end - > linenr ( ) + 1 > = end - > tokAt ( 4 ) - > linenr ( ) ) {
2011-10-11 08:41:39 +02:00
SuspiciousSemicolonError ( tok ) ;
}
}
}
}
void CheckOther : : SuspiciousSemicolonError ( const Token * tok )
{
reportInconclusiveError ( tok , Severity : : warning , " suspiciousSemicolon " ,
2011-10-12 15:08:54 +02:00
" Suspicious use of ; at the end of 'if/for/while' statement. " ) ;
2011-10-11 08:41:39 +02:00
}
2011-10-06 22:01:48 +02:00
//---------------------------------------------------------------------------
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-10-26 21:17:27 +02:00
if ( ! _settings - > isEnabled ( " style " ) ) {
2010-04-21 08:38:25 +02:00
return ;
2011-10-26 21:17:27 +02:00
}
if ( ! _tokenizer - > isCPP ( ) ) {
return ;
}
2010-04-21 08:38:25 +02:00
2011-10-13 20:53:06 +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 ;
2011-10-31 02:24:59 +01:00
unsigned char addToIndex = 0 ;
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( 1 ) = = " const " )
2009-07-20 21:52:27 +02:00
addToIndex = 1 ;
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( 4 + addToIndex ) = = " const " )
2009-06-18 22:26:21 +02:00
continue ;
2009-01-26 20:14:46 +01:00
// Is "type" a class?
2011-11-13 13:10:59 +01:00
const std : : string pattern ( " class " + tok - > strAt ( 1 + addToIndex ) ) ;
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 ( ) ;
2011-10-27 10:54:50 +02:00
while ( tok & & ( ( tok = Token : : findsimplematch ( tok , " fflush ( stdin ) " ) ) ! = NULL ) ) {
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 ( )
{
2011-10-13 20:53:06 +02:00
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% " )
2011-10-13 20:53:06 +02:00
) {
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-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " sizeof ( %var% ) " ) | | Token : : Match ( tok , " sizeof %var% " ) ) {
2011-10-31 02:24:59 +01:00
unsigned short tokIdx = 1 ;
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( tokIdx ) = = " ( " ) {
2011-01-22 19:21:56 +01:00
+ + tokIdx ;
}
2011-10-13 20:53:06 +02:00
if ( tok - > tokAt ( tokIdx ) - > varId ( ) > 0 ) {
2011-08-14 16:21:07 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( tokIdx ) - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( var ) {
2011-08-14 16:21:07 +02:00
const Token * declTok = var - > nameToken ( ) ;
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( declTok - > next ( ) , " [ " ) ) {
2011-01-25 09:57:58 +01:00
declTok = declTok - > next ( ) - > link ( ) ;
// multidimensional array
2011-10-13 20:53:06 +02:00
while ( Token : : simpleMatch ( declTok - > next ( ) , " [ " ) ) {
2011-01-25 09:57:58 +01:00
declTok = declTok - > next ( ) - > link ( ) ;
}
2011-10-13 20:53:06 +02:00
if ( ! ( Token : : Match ( declTok - > next ( ) , " = %str% " ) ) & & ! ( Token : : simpleMatch ( declTok - > next ( ) , " = { " ) ) & & ! ( Token : : simpleMatch ( declTok - > next ( ) , " ; " ) ) ) {
if ( Token : : simpleMatch ( declTok - > next ( ) , " , " ) ) {
2011-01-26 20:08:06 +01:00
declTok = declTok - > next ( ) ;
2011-10-13 20:53:06 +02:00
while ( ! Token : : simpleMatch ( declTok , " ; " ) ) {
if ( Token : : simpleMatch ( declTok , " ) " ) ) {
2011-01-26 20:08:06 +01:00
sizeofForArrayParameterError ( tok ) ;
break ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( declTok , " (|[|{ " ) ) {
2011-01-26 20:08:06 +01:00
declTok = declTok - > link ( ) ;
}
declTok = declTok - > next ( ) ;
}
}
}
2011-10-13 20:53:06 +02:00
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
2011-10-28 22:06:55 +02:00
void CheckOther : : checkSizeofForStrncmpSize ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-10-29 12:27:19 +02:00
const char pattern1 [ ] = " strncmp ( %any% , %any% , sizeof ( %var% ) ) " ;
const char pattern2 [ ] = " strncmp ( %any% , %any% , sizeof %var% ) " ;
2011-10-29 12:52:46 +02:00
// danmar : this is inconclusive in case the size parameter is
// sizeof(char *) by intention.
2011-10-29 12:27:19 +02:00
if ( ! _settings - > inconclusive )
return ;
2011-10-28 22:06:55 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , pattern1 ) | | Token : : Match ( tok , pattern2 ) ) {
2011-10-31 02:24:59 +01:00
unsigned short tokIdx = 7 ;
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( tokIdx ) = = " ( " )
2011-10-28 22:06:55 +02:00
+ + tokIdx ;
const Token * tokVar = tok - > tokAt ( tokIdx ) ;
if ( tokVar - > varId ( ) > 0 ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tokVar - > varId ( ) ) ;
if ( var & & var - > nameToken ( ) - > strAt ( - 1 ) = = " * " ) {
sizeofForStrncmpError ( tokVar ) ;
}
}
}
}
}
void CheckOther : : sizeofForStrncmpError ( const Token * tok )
{
2011-10-29 15:16:27 +02:00
reportInconclusiveError ( tok , Severity : : warning , " strncmpLen " ,
" Passing sizeof(pointer) as the last argument to strncmp. \n "
" Passing a pointer to sizeof returns the size of the pointer, not "
" the number of characters pointed to by that pointer. This "
" means that only 4 or 8 (on 64-bit systems) characters are "
" compared, which is probably not what was expected. " ) ;
2011-10-28 22:06:55 +02: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 ) ;
2011-10-13 20:53:06 +02:00
while ( tok ) {
2010-06-30 09:10:30 +02:00
// Check the contents of the switch statement
std : : map < unsigned int , const Token * > varsAssigned ;
2011-10-13 10:27:22 +02:00
std : : map < unsigned int , const Token * > stringsCopied ;
2010-06-30 09:10:30 +02:00
int indentLevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > tokAt ( 5 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " { " ) {
2010-06-30 09:10:30 +02:00
// 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
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " )|else { " ) & & tok2 - > link ( ) ) {
2010-06-30 09:10:30 +02:00
const Token * endOfConditional = tok2 - > link ( ) ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok3 = tok2 ; tok3 ! = endOfConditional ; tok3 = tok3 - > next ( ) ) {
if ( tok3 - > varId ( ) ! = 0 ) {
2010-06-30 09:10:30 +02:00
varsAssigned . erase ( tok3 - > varId ( ) ) ;
2011-10-13 10:27:22 +02:00
stringsCopied . erase ( tok3 - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok3 , functionPattern ) | | Token : : Match ( tok3 , breakPattern ) ) {
2010-06-30 09:10:30 +02:00
varsAssigned . clear ( ) ;
2011-10-13 10:27:22 +02:00
if ( tok3 - > str ( ) ! = " strcpy " & & tok3 - > str ( ) ! = " strncpy " )
stringsCopied . clear ( ) ;
}
2010-06-30 09:10:30 +02:00
}
tok2 = endOfConditional ;
2011-10-13 20:53:06 +02:00
} else
2010-06-30 09:10:30 +02:00
+ + indentLevel ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " } " ) {
2010-06-30 09:10:30 +02:00
- - 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;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " ;|{|}|: %var% = %any% ; " ) & & tok2 - > varId ( ) ! = 0 ) {
2010-06-30 09:10:30 +02:00
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 ( ) ) ;
2011-10-13 10:27:22 +02:00
stringsCopied . erase ( tok2 - > varId ( ) ) ;
}
// String copy. Report an error if it's copied to twice before a break. E.g.:
// case 3: strcpy(str, "a"); // <== redundant
// case 4: strcpy(str, "b");
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 - > previous ( ) , " ; | { | } | : strcpy | strncpy ( % var % , " ) && tok2->tokAt(2)->varId() != 0) {
2011-10-13 10:27:22 +02:00
std : : map < unsigned int , const Token * > : : iterator i = stringsCopied . find ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
if ( i = = stringsCopied . end ( ) )
stringsCopied [ tok2 - > tokAt ( 2 ) - > varId ( ) ] = tok2 - > tokAt ( 2 ) ;
else
redundantStrcpyInSwitchError ( i - > second , i - > second - > str ( ) ) ;
2010-06-30 09:10:30 +02:00
}
// 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;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , functionPattern ) | | Token : : Match ( tok2 , breakPattern ) ) {
2010-06-30 09:10:30 +02:00
varsAssigned . clear ( ) ;
2011-10-13 10:27:22 +02:00
if ( tok2 - > str ( ) ! = " strcpy " & & tok2 - > str ( ) ! = " strncpy " )
stringsCopied . clear ( ) ;
}
2010-06-30 09:10:30 +02:00
}
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-10-13 10:27:22 +02:00
void CheckOther : : redundantStrcpyInSwitchError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
" redundantStrcpyInSwitch " ,
" Switch case fall-through. Redundant strcpy of \" " + varname + " \" . \n "
" Switch case fall-through. Redundant strcpy of \" " + varname + " \" . The string is overwritten in a later case block. " ) ;
}
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 ) ;
2011-10-13 20:53:06 +02:00
while ( tok ) {
2011-02-19 09:33:29 +01:00
// 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-11-20 15:09:57 +01:00
for ( const Token * tok2 = tok - > next ( ) - > link ( ) - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 , " if ( " ) ) {
2011-11-20 15:09:57 +01:00
tok2 = tok2 - > next ( ) - > link ( ) - > next ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > link ( ) = = NULL ) {
2011-02-19 21:43:24 +01:00
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-10-13 20:53:06 +02:00
} else if ( Token : : simpleMatch ( tok2 , " while ( " ) ) {
2011-11-20 15:09:57 +01:00
tok2 = tok2 - > next ( ) - > link ( ) - > next ( ) ;
2011-02-19 21:43:24 +01:00
// skip over "do { } while ( ) ;" case
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " { " ) {
if ( tok2 - > link ( ) = = NULL ) {
2011-02-19 21:43:24 +01:00
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-10-13 20:53:06 +02:00
} else if ( Token : : simpleMatch ( tok2 , " do { " ) ) {
2011-11-20 15:09:57 +01:00
tok2 = tok2 - > next ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > link ( ) = = NULL ) {
2011-02-19 21:43:24 +01:00
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-10-13 20:53:06 +02:00
} else if ( Token : : simpleMatch ( tok2 , " for ( " ) ) {
2011-11-20 15:09:57 +01:00
tok2 = tok2 - > next ( ) - > link ( ) - > next ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > link ( ) = = NULL ) {
2011-02-19 21:43:24 +01:00
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 ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok2 , switchPattern ) ) {
2011-02-19 20:02:28 +01:00
// skip over nested switch, we'll come to that soon
2011-11-20 15:09:57 +01:00
tok2 = tok2 - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok2 , breakPattern ) ) {
if ( loopnest . empty ( ) ) {
2011-02-19 20:02:28 +01:00
justbreak = true ;
}
2011-10-27 10:54:50 +02:00
tok2 = Token : : findsimplematch ( tok2 , " ; " ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok2 , " case|default " ) ) {
if ( ! justbreak & & ! firstcase ) {
2011-02-19 09:33:29 +01:00
switchCaseFallThrough ( tok2 ) ;
}
2011-10-27 10:54:50 +02:00
tok2 = Token : : findsimplematch ( tok2 , " : " ) ;
2011-02-19 20:02:28 +01:00
justbreak = true ;
2011-02-23 10:45:21 +01:00
firstcase = false ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " { " ) {
2011-02-19 20:02:28 +01:00
scopenest . push ( tok2 - > link ( ) ) ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " } " ) {
if ( ! ifnest . empty ( ) & & tok2 = = ifnest . top ( ) . first ) {
if ( tok2 - > next ( ) - > str ( ) = = " else " ) {
2011-02-19 20:02:28 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
ifnest . pop ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > link ( ) = = NULL ) {
2011-02-20 11:44:18 +01:00
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 ;
2011-10-13 20:53:06 +02:00
} else {
2011-02-19 20:02:28 +01:00
justbreak & = ifnest . top ( ) . second ;
ifnest . pop ( ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( ! loopnest . empty ( ) & & tok2 = = loopnest . top ( ) ) {
2011-02-19 20:02:28 +01:00
loopnest . pop ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( ! scopenest . empty ( ) & & tok2 = = scopenest . top ( ) ) {
2011-02-19 20:02:28 +01:00
scopenest . pop ( ) ;
2011-10-13 20:53:06 +02:00
} else {
if ( ! ifnest . empty ( ) | | ! loopnest . empty ( ) | | ! scopenest . empty ( ) ) {
2011-02-19 21:43:24 +01:00
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 ;
}
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) ! = " ; " ) {
2011-02-19 20:02:28 +01:00
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
2011-10-22 17:12:52 +02:00
//---------------------------------------------------------------------------
// std::cout << std::cout;
//---------------------------------------------------------------------------
void CheckOther : : checkCoutCerrMisusage ( )
{
bool firstCout = false ;
2011-10-22 20:43:42 +02:00
unsigned int roundbraces = 0 ;
2011-10-22 17:12:52 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2011-10-22 20:43:42 +02:00
if ( tok - > str ( ) = = " ( " )
+ + roundbraces ;
else if ( tok - > str ( ) = = " ) " ) {
if ( ! roundbraces )
break ;
- - roundbraces ;
}
if ( roundbraces )
continue ;
2011-10-22 17:12:52 +02:00
if ( Token : : Match ( tok , " std :: cout|cerr " ) ) {
if ( firstCout & & tok - > strAt ( - 1 ) = = " << " & & tok - > strAt ( 3 ) ! = " . " ) {
coutCerrMisusageError ( tok , tok - > strAt ( 2 ) ) ;
firstCout = false ;
} else if ( tok - > strAt ( 3 ) = = " << " )
firstCout = true ;
} else if ( firstCout & & tok - > str ( ) = = " ; " )
firstCout = false ;
}
}
void CheckOther : : coutCerrMisusageError ( const Token * tok , const std : : string & streamName )
{
reportError ( tok , Severity : : error , " coutCerrMisusage " , " Invalid usage of output stream: '<< std:: " + streamName + " '. " ) ;
}
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 ;
2011-10-13 20:53:06 +02:00
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 ) ;
2011-10-13 20:53:06 +02:00
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 ( ) & &
2011-10-13 20:53:06 +02:00
pod . find ( tok - > varId ( ) ) ! = pod . end ( ) ) {
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-10-13 20:53:06 +02:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " ) { %var% = %var% ; } else { %varid% = " , tok - > varId ( ) ) ) {
2011-08-19 07:23:11 +02:00
// Find the 'if' token
2011-11-20 14:22:39 +01:00
const Token * tokif = tok - > linkAt ( - 2 ) - > previous ( ) ;
2011-08-19 07:23:11 +02:00
// find the '}' that terminates the 'else'-block
2011-11-20 14:22:39 +01:00
const Token * else_end = tok - > linkAt ( 6 ) ;
2011-08-19 07:23:11 +02:00
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 ;
2011-10-13 20:53:06 +02:00
while ( tok & & endTok ) {
2010-10-10 22:05:06 +02:00
const Token * varTok = Token : : findmatch ( tok - > tokAt ( 2 ) , " %var% --|++|+=|-=|*=|/=|&=|^=|= " , endTok ) ;
2011-10-13 20:53:06 +02:00
if ( varTok ) {
2010-10-10 22:05:06 +02:00
assignmentInAssertError ( tok , varTok - > str ( ) ) ;
2011-10-13 20:53:06 +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 ;
2011-10-13 20:53:06 +02:00
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-10-13 20:53:06 +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 ) ;
2011-10-13 20:53:06 +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-11-20 15:09:57 +01:00
op1Tok = logicTok - > next ( ) ;
2011-07-17 04:06:23 +02:00
op2Tok = logicTok - > tokAt ( 3 ) ;
op3Tok = logicTok - > tokAt ( 5 ) ;
nextTok = logicTok - > tokAt ( 7 ) ;
2010-10-25 03:14:21 +02:00
}
2011-10-13 20:53:06 +02:00
if ( logicTok ) {
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-10-13 20:53:06 +02:00
if ( Token : : Match ( term1Tok , " %var% %any% %num% " ) ) {
2011-08-19 19:28:37 +02:00
varTok = term1Tok ;
varId = varTok - > varId ( ) ;
2011-10-13 20:53:06 +02: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 ;
2011-11-13 13:10:59 +01:00
firstConstant = term1Tok - > strAt ( 2 ) ;
2011-10-13 20:53:06 +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-10-13 20:53:06 +02:00
if ( ! varId ) {
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 ( ) ;
2011-10-13 20:53:06 +02:00
} else {
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-10-13 20:53:06 +02:00
if ( Token : : Match ( term2Tok , " %var% %any% %num% " ) ) {
2011-07-17 04:06:23 +02:00
const unsigned int varId2 = term2Tok - > varId ( ) ;
2011-10-13 20:53:06 +02:00
if ( ! varId2 | | varId ! = varId2 ) {
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 ;
2011-11-13 13:10:59 +01:00
secondConstant = term2Tok - > strAt ( 2 ) ;
2011-07-17 04:06:23 +02:00
variableTested = varId ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( term2Tok , " %num% %any% %var% " ) ) {
2011-07-17 04:06:23 +02:00
const unsigned int varId2 = term1Tok - > tokAt ( 2 ) - > varId ( ) ;
2011-10-13 20:53:06 +02:00
if ( ! varId2 | | varId ! = varId2 ) {
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 ;
2011-10-13 20:53:06 +02:00
} else {
2011-07-17 04:06:23 +02:00
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-10-13 20:53:06 +02:00
if ( variableTested = = 0 | | firstConstant . empty ( ) | | secondConstant . empty ( ) ) {
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-10-22 12:31:47 +02:00
static const struct Condition {
2011-07-17 04:06:23 +02:00
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-10-13 20:53:06 +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
} ;
2011-10-13 20:53:06 +02:00
for ( unsigned int i = 0 ; i < ( sizeof ( conditions ) / sizeof ( conditions [ 0 ] ) ) ; i + + ) {
2011-07-17 04:06:23 +02:00
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 ) ) | |
2011-10-13 20:53:06 +02:00
( 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 ) ;
2011-10-13 20:53:06 +02:00
else {
2011-08-19 19:28:37 +02:00
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 ) ;
2011-11-20 14:22:39 +01:00
const Token * endTok = tok ? tok - > linkAt ( 2 ) : NULL ;
2010-12-31 12:01:38 +01:00
2011-10-13 20:53:06 +02:00
while ( tok & & endTok ) {
2010-12-31 12:01:38 +01:00
// 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 ) ;
2011-10-13 20:53:06 +02:00
if ( tokType & & ! tokType - > isStandardType ( ) ) {
2010-12-31 12:01:38 +01:00
catchExceptionByValueError ( tokType ) ;
}
tok = Token : : findmatch ( endTok - > next ( ) , catchPattern ) ;
2011-11-20 14:22:39 +01:00
endTok = tok ? tok - > linkAt ( 2 ) : NULL ;
2010-12-31 12:01:38 +01:00
}
}
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..
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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..
2011-10-31 02:24:59 +01:00
unsigned int param = 1 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
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 ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " , " ) {
2009-01-26 20:14:46 +01:00
+ + param ;
2011-10-13 20:53:06 +02:00
if ( param = = 3 ) {
if ( Token : : Match ( tok2 , " , %num% ) " ) ) {
2010-11-20 11:28:47 +01:00
const MathLib : : bigint radix = MathLib : : toLongNumber ( tok2 - > next ( ) - > str ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( ! ( radix = = 0 | | ( radix > = 2 & & radix < = 36 ) ) ) {
2009-03-21 17:58:13 +01:00
dangerousUsageStrtolError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
}
}
break ;
}
}
}
}
// sprintf|snprintf overlapping data
2011-10-13 20:53:06 +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?
2011-10-31 02:24:59 +01:00
unsigned int parlevel = 0 ;
2011-10-13 20:53:06 +02:00
while ( ( tok2 = tok2 - > next ( ) ) ! = NULL ) {
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " ) " ) {
2011-10-31 02:24:59 +01:00
if ( ! parlevel )
2009-01-26 20:14:46 +01:00
break ;
2011-10-31 02:24:59 +01:00
- - parlevel ;
2011-10-13 20:53:06 +02:00
} else if ( parlevel = = 0 & & Token : : Match ( tok2 , " , %varid% [,) ] " , varid)) {
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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2010-08-14 15:15:12 +02:00
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 ( ) ) ;
2011-10-13 20:53:06 +02:00
for ( unsigned int i = 1 ; i < formatstr . length ( ) ; i + + ) {
2010-08-14 15:15:12 +02:00
if ( formatstr [ i ] = = ' % ' )
format = ! format ;
else if ( ! format )
continue ;
2011-10-13 20:53:06 +02:00
else if ( std : : isdigit ( formatstr [ i ] ) ) {
2010-08-14 15:15:12 +02:00
format = false ;
}
2011-10-13 20:53:06 +02:00
else if ( std : : isalpha ( formatstr [ i ] ) ) {
2010-08-14 15:15:12 +02:00
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-11-05 07:29:53 +01:00
//---------------------------------------------------------------------------
// printf("%u", "xyz"); // Wrong argument type. TODO.
// printf("%u%s", 1); // Too few arguments
// printf("", 1); // Too much arguments
//---------------------------------------------------------------------------
void CheckOther : : checkWrongPrintfScanfArguments ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( ! tok - > isName ( ) ) continue ;
const Token * argListTok = 0 ; // Points to first va_list argument
std : : string formatString ;
if ( Token : : Match ( tok , " printf|scanf ( %str% " ) ) {
formatString = tok - > strAt ( 2 ) ;
2011-11-08 23:16:37 +01:00
if ( tok - > strAt ( 3 ) = = " , " ) {
2011-11-05 07:29:53 +01:00
argListTok = tok - > tokAt ( 4 ) ;
2011-11-08 23:16:37 +01:00
} else if ( tok - > strAt ( 3 ) = = " ) " ) {
2011-11-05 07:29:53 +01:00
argListTok = 0 ;
2011-11-08 23:16:37 +01:00
} else {
continue ;
}
2011-11-05 07:29:53 +01:00
} else if ( Token : : Match ( tok , " sprintf|fprintf|sscanf|fscanf ( %any% " ) ) {
const Token * formatStringTok = tok - > tokAt ( 2 ) - > nextArgument ( ) ; // Find second parameter (format string)
2011-11-08 23:16:37 +01:00
if ( Token : : Match ( formatStringTok , " %str% , " ) ) {
2011-11-05 07:29:53 +01:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find third parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
2011-11-08 23:16:37 +01:00
} else if ( Token : : Match ( formatStringTok , " %str% ) " )) {
argListTok = 0 ; // Find third parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
} else {
continue ;
2011-11-05 07:29:53 +01:00
}
} else if ( Token : : Match ( tok , " snprintf|fnprintf ( %any% " ) ) {
const Token * formatStringTok = tok - > tokAt ( 2 ) ;
for ( int i = 0 ; i < 2 & & formatStringTok ; i + + ) {
formatStringTok = formatStringTok - > nextArgument ( ) ; // Find third parameter (format string)
}
2011-11-08 23:16:37 +01:00
if ( Token : : Match ( formatStringTok , " %str% , " ) ) {
2011-11-05 07:29:53 +01:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find fourth parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
}
2011-11-08 23:16:37 +01:00
if ( Token : : Match ( formatStringTok , " %str% ) " ) ) {
argListTok = 0 ; // Find fourth parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
} else {
continue ;
}
2011-11-05 07:29:53 +01:00
} else {
continue ;
}
// Count format string parameters..
unsigned int numFormat = 0 ;
bool percent = false ;
for ( std : : string : : iterator i = formatString . begin ( ) ; i ! = formatString . end ( ) ; + + i ) {
if ( * i = = ' % ' ) {
percent = ! percent ;
2011-11-14 22:36:20 +01:00
} else if ( percent & & * i = = ' [ ' ) {
while ( i ! = formatString . end ( ) ) {
if ( * i = = ' ] ' ) {
numFormat + + ;
percent = false ;
break ;
}
+ + i ;
}
if ( i = = formatString . end ( ) )
break ;
2011-11-05 07:29:53 +01:00
} else if ( percent & & std : : isalpha ( * i ) ) {
numFormat + + ;
percent = false ;
}
}
// Count printf/scanf parameters..
unsigned int numFunction = 0 ;
while ( argListTok ) {
// TODO: Perform type checks
numFunction + + ;
argListTok = argListTok - > nextArgument ( ) ; // Find next argument
}
// Mismatching number of parameters => warning
if ( numFormat ! = numFunction )
wrongPrintfScanfArgumentsError ( tok , tok - > str ( ) , numFormat , numFunction ) ;
}
}
void CheckOther : : wrongPrintfScanfArgumentsError ( const Token * tok ,
const std : : string & functionName ,
unsigned int numFormat ,
unsigned int numFunction )
{
std : : ostringstream errmsg ;
errmsg < < functionName
< < " format string has "
< < numFormat
< < " parameters but "
< < ( numFormat > numFunction ? " only " : " " )
< < numFunction
< < " are given " ;
reportError ( tok ,
numFormat > numFunction ? Severity : : error : Severity : : warning ,
" wrongPrintfScanfArgs " ,
errmsg . str ( ) ) ;
}
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 ;
2011-10-05 20:30:36 +02:00
std : : map < unsigned int , bool > boolvars ; // Contains all declarated standard type variables and indicates whether its a bool or not.
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2011-11-20 15:09:57 +01:00
if ( Token : : Match ( tok , " [{};(,] %type% %var% [;=,)] " ) & & tok - > next ( ) - > isStandardType ( ) ) { // Declaration of standard type variable
2011-11-13 13:10:59 +01:00
boolvars [ tok - > tokAt ( 2 ) - > varId ( ) ] = ( tok - > strAt ( 1 ) = = " bool " ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " %var% >|>=|==|!=|<=|< %num% " ) ) { // Comparing variable with number
2011-10-05 20:30:36 +02:00
const Token * varTok = tok ;
const Token * numTok = tok - > tokAt ( 2 ) ;
std : : map < unsigned int , bool > : : const_iterator iVar = boolvars . find ( varTok - > varId ( ) ) ;
if ( iVar ! = boolvars . end ( ) & & iVar - > second & & // Variable has to be a boolean
2011-11-13 13:10:59 +01:00
( ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) | |
2011-10-16 08:09:57 +02:00
( ( MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 0 ) & & ( ! _tokenizer - > code_is_c ( ) | | MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 1 ) ) ) ) { // == 0 and != 0 are allowed, for C also == 1 and != 1
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( varTok , numTok - > str ( ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " %num% >|>=|==|!=|<=|< %var% " ) ) { // Comparing number with variable
2011-10-05 20:30:36 +02:00
const Token * varTok = tok - > tokAt ( 2 ) ;
const Token * numTok = tok ;
std : : map < unsigned int , bool > : : const_iterator iVar = boolvars . find ( varTok - > varId ( ) ) ;
if ( iVar ! = boolvars . end ( ) & & iVar - > second & & // Variable has to be a boolean
2011-11-13 13:10:59 +01:00
( ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) | |
2011-10-16 08:09:57 +02:00
( ( MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 0 ) & & ( ! _tokenizer - > code_is_c ( ) | | MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 1 ) ) ) ) { // == 0 and != 0 are allowed, for C also == 1 and != 1
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( varTok , numTok - > str ( ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " true|false >|>=|==|!=|<=|< %var% " ) ) { // Comparing boolean constant with variable
2011-10-05 20:30:36 +02:00
const Token * varTok = tok - > tokAt ( 2 ) ;
const Token * constTok = tok ;
std : : map < unsigned int , bool > : : const_iterator iVar = boolvars . find ( varTok - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( iVar ! = boolvars . end ( ) & & ! iVar - > second ) { // Variable has to be of non-boolean standard type
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( varTok , constTok - > str ( ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " %var% >|>=|==|!=|<=|< true|false " ) ) { // Comparing variable with boolean constant
2011-10-05 20:30:36 +02:00
const Token * varTok = tok ;
const Token * constTok = tok - > tokAt ( 2 ) ;
std : : map < unsigned int , bool > : : const_iterator iVar = boolvars . find ( varTok - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( iVar ! = boolvars . end ( ) & & ! iVar - > second ) { // Variable has to be of non-boolean standard type
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( varTok , constTok - > str ( ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " %var% >|>=|==|!=|<=|< %var% " ) ) { // Comparing two variables, one of them boolean, one of them integer
2011-10-05 20:30:36 +02:00
const Token * var1Tok = tok - > tokAt ( 2 ) ;
const Token * var2Tok = tok ;
std : : map < unsigned int , bool > : : const_iterator iVar1 = boolvars . find ( var1Tok - > varId ( ) ) ;
std : : map < unsigned int , bool > : : const_iterator iVar2 = boolvars . find ( var2Tok - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( iVar1 ! = boolvars . end ( ) & & iVar2 ! = boolvars . end ( ) ) {
2011-10-05 20:30:36 +02:00
if ( iVar1 - > second & & ! iVar2 - > second ) // Comparing boolean with non-bool standard type
comparisonOfBoolWithIntError ( var2Tok , var1Tok - > str ( ) ) ;
else if ( ! iVar1 - > second & & iVar2 - > second ) // Comparing non-bool standard type with boolean
comparisonOfBoolWithIntError ( var2Tok , var2Tok - > str ( ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " ( ! %var% ==|!= %num% ) " )) {
2011-02-27 21:30:22 +01:00
const Token * numTok = tok - > tokAt ( 4 ) ;
2011-11-06 08:21:34 +01:00
if ( numTok & & numTok - > str ( ) ! = " 0 " & & numTok - > str ( ) ! = " 1 " ) {
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( numTok , " ! " + tok - > strAt ( 2 ) ) ;
2011-02-27 21:30:22 +01:00
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " ( %num% ==|!= ! %var% ) " )) {
2011-11-20 15:09:57 +01:00
const Token * numTok = tok - > next ( ) ;
2011-11-06 08:21:34 +01:00
if ( numTok & & numTok - > str ( ) ! = " 0 " & & numTok - > str ( ) ! = " 1 " ) {
2011-10-05 20:30:36 +02:00
comparisonOfBoolWithIntError ( numTok , " ! " + tok - > strAt ( 4 ) ) ;
2011-02-27 21:30:22 +01:00
}
}
}
}
2011-10-05 20:30:36 +02:00
void CheckOther : : comparisonOfBoolWithIntError ( const Token * tok , const std : : string & expression )
2011-08-19 17:53:43 +02:00
{
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInt " ,
2011-11-06 08:21:34 +01:00
" Comparison of a boolean with integer that is neither 1 nor 0 \n "
" The expression \" " + expression + " \" is of type 'bool' "
" and it is compared against a integer value that is "
" neither 1 nor 0. " ) ;
2011-08-19 17:53:43 +02:00
}
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 ) ;
2011-10-13 20:53:06 +02:00
while ( tok ) {
2011-07-15 02:12:56 +02:00
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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " [{};(,] %type% %var% [;=,)] " ) ) {
2011-11-20 15:09:57 +01:00
if ( tok - > next ( ) - > 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
}
2011-10-13 20:53:06 +02:00
else if ( ! Token : : Match ( tok , " [) . ] " ) && Token::Match(tok->next(), " % var % / % num % " )) {
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' ) {
2011-11-20 15:09:57 +01:00
char sign1 = varsign [ tok - > next ( ) - > varId ( ) ] ;
2011-10-13 20:53:06 +02:00
if ( sign1 = = ' u ' ) {
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok , " (|[|=|%op% %num% / %var% " ) ) {
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' ) {
2009-10-11 16:52:35 +02:00
char sign2 = varsign [ tok - > tokAt ( 3 ) - > varId ( ) ] ;
2011-10-13 20:53:06 +02:00
if ( sign2 = = ' u ' ) {
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 ( )
{
2011-10-22 22:34:10 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : simpleMatch ( tok , " memset ( " ) ) {
2011-11-20 15:09:57 +01:00
const Token * lastParamTok = tok - > next ( ) - > link ( ) - > previous ( ) ;
2011-10-22 22:34:10 +02:00
if ( lastParamTok - > str ( ) = = " 0 " )
memsetZeroBytesError ( tok , tok - > strAt ( 2 ) ) ;
}
2011-01-06 11:31:58 +01:00
}
}
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-10-30 10:54:33 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
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-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
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..
2011-10-31 02:24:59 +01:00
unsigned int indentlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = scope - > classStart ; tok ; tok = tok - > next ( ) ) {
2010-12-16 19:04:47 +01:00
// Skip function local class and struct declarations..
2011-10-13 20:53:06 +02:00
if ( ( tok - > str ( ) = = " class " ) | | ( tok - > str ( ) = = " struct " ) | | ( tok - > str ( ) = = " union " ) ) {
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " { " ) {
2010-12-16 19:04:47 +01:00
tok = tok2 - > link ( ) ;
break ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [,);] " ) ) {
2010-12-16 19:04:47 +01:00
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 ;
}
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " { " ) {
2010-12-16 19:04:47 +01:00
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " } " ) {
2011-10-31 02:24:59 +01:00
if ( ! indentlevel )
break ;
2010-12-16 19:04:47 +01:00
- - indentlevel ;
}
2009-01-26 20:14:46 +01:00
2011-10-13 20:53:06 +02:00
if ( indentlevel > 0 & & Token : : Match ( tok , " [{};] " ) ) {
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?
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok1 , " %type% %var% ; %var% = %num% ; " ) ) {
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 ( ) ;
2011-10-13 20:53:06 +02:00
if ( firstVarId > 0 & & firstVarId = = secondVarId ) {
2010-12-16 19:04:47 +01:00
lookupVar ( tok1 - > tokAt ( 6 ) , tok1 - > strAt ( 1 ) ) ;
}
2011-10-13 20:53:06 +02:00
} else if ( tok1 - > isStandardType ( ) & & Token : : Match ( tok1 , " %type% %var% [ ; = ] " )) {
2010-12-16 19:04:47 +01:00
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
2011-10-31 02:24:59 +01:00
unsigned int indentlevel = 0 ;
2009-01-26 20:14:46 +01:00
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"
2011-10-13 20:53:06 +02:00
while ( tok ) {
if ( tok - > str ( ) = = " { " ) {
if ( tok - > strAt ( - 1 ) = = " = " ) {
if ( Token : : findmatch ( tok , varname . c_str ( ) , tok - > link ( ) ) ) {
2011-01-17 20:51:15 +01:00
return ;
}
tok = tok - > link ( ) ;
2011-10-13 20:53:06 +02:00
} else
2011-01-17 20:51:15 +01:00
+ + indentlevel ;
2009-01-26 20:14:46 +01:00
}
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " } " ) {
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 ;
2011-10-13 20:53:06 +02:00
if ( indentlevel = = 0 ) {
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
}
}
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " ( " ) {
2009-01-26 20:14:46 +01:00
+ + parlevel ;
}
2011-10-13 20:53:06 +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
2011-10-13 20:53:06 +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
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = varname ) {
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 ;
}
2011-10-13 20:53:06 +02:00
else if ( indentlevel = = 0 ) {
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 ( ) , " ( " ) & &
2011-10-13 20:53:06 +02:00
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) ) {
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-10-13 20:53:06 +02:00
else if ( tok - > str ( ) ! = " else " & & Token : : Match ( tok - > previous ( ) , " [ ; { } ] % type % { " )) {
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 ,
2011-10-05 19:44:00 +02:00
Severity : : style ,
2011-08-19 17:53:43 +02:00
" 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 ( ) ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " [,(] const std :: string %var% [,)] " ) ) {
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 5 ) ) ;
2009-01-26 20:14:46 +01:00
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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 ) ) ;
}
2011-10-13 20:53:06 +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-10-13 20:53:06 +02:00
if ( symbolDatabase - > isClassOrStruct ( tok - > strAt ( 2 ) ) ) {
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 ( ) ;
2011-10-13 20:53:06 +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% [;=,)] " ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( tok , " [{};(,] const| char %var% [ " ) ) {
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
2011-11-06 11:26:28 +01:00
const unsigned int varid = tok - > varId ( ) ;
if ( ! varid )
continue ;
2009-01-26 20:14:46 +01:00
// Check usage of char variable..
2011-10-31 02:24:59 +01:00
unsigned int indentlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " } " ) {
2011-10-31 02:24:59 +01:00
if ( ! indentlevel )
2009-01-26 20:14:46 +01:00
break ;
2011-10-31 02:24:59 +01:00
- - indentlevel ;
2009-01-26 20:14:46 +01:00
}
2011-10-13 20:53:06 +02:00
if ( ! isPointer ) {
2011-11-06 11:26:28 +01:00
if ( ( tok2 - > str ( ) ! = " . " ) & & Token : : Match ( tok2 - > next ( ) , " %var% [ %varid% ] " , varid ) ) {
2011-08-09 17:03:22 +02:00
charArrayIndexError ( tok2 - > next ( ) ) ;
break ;
}
2009-01-26 20:14:46 +01:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] %var% = %any% [&|] %any% ; " ) ) {
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-10-13 20:53:06 +02:00
if ( tok2 - > strAt ( 4 ) = = " & " ) {
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
2011-10-13 20:53:06 +02:00
if ( isPointer & & Token : : Match ( tok2 , " [;{}] %var% = %any% [&|] ( * %varid% ) ; " , tok - > varId ( ) ) ) {
2011-07-05 18:41:27 +02:00
// 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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " ( " ) {
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-11-05 20:28:52 +01:00
else if ( Token : : Match ( tok , " [;{}] %str% " ) | | Token : : Match ( tok , " [;{}] %num% " ) ) {
// No warning if numeric constant is followed by a "." or ","
if ( Token : : Match ( tok - > next ( ) , " %num% [,.] " ) )
continue ;
2011-01-13 20:12:57 +01:00
// bailout if there is a "? :" in this statement
bool bailout = false ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
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..
2011-10-13 20:53:06 +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
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2010-02-01 19:46:51 +01:00
// Declaring char variable..
2011-10-13 20:53:06 +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
//
2011-10-13 20:53:06 +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
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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 ( ) ) & &
2011-10-13 20:53:06 +02:00
MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) = = 0L ) {
2009-03-29 18:47:05 +02:00
zerodivError ( tok ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " div|ldiv|lldiv|imaxdiv ( %num% , %num% ) " ) & &
2011-11-13 13:10:59 +01:00
MathLib : : isInt ( tok - > strAt ( 4 ) ) & &
MathLib : : toLongNumber ( tok - > strAt ( 4 ) ) = = 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 ( )
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2011-10-22 12:31:47 +02:00
if ( tok - > varId ( ) = = 0 & & Token : : Match ( tok , " log|log10 ( %num% ) " ) ) {
2011-11-13 13:10:59 +01:00
bool isNegative = MathLib : : isNegative ( tok - > strAt ( 2 ) ) ;
bool isInt = MathLib : : isInt ( tok - > strAt ( 2 ) ) ;
bool isFloat = MathLib : : isFloat ( tok - > strAt ( 2 ) ) ;
if ( isNegative & & isInt & & MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) < = 0 ) {
2011-10-22 12:31:47 +02:00
mathfunctionCallError ( tok ) ; // case log(-2)
2011-11-13 13:10:59 +01:00
} else if ( isNegative & & isFloat & & MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) < = 0. ) {
2011-10-22 12:31:47 +02:00
mathfunctionCallError ( tok ) ; // case log(-2.0)
2011-11-13 13:10:59 +01:00
} else if ( ! isNegative & & isFloat & & MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) < = 0. ) {
2011-10-22 12:31:47 +02:00
mathfunctionCallError ( tok ) ; // case log(0.0)
2011-11-13 13:10:59 +01:00
} else if ( ! isNegative & & isInt & & MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) < = 0 ) {
2011-10-22 12:31:47 +02:00
mathfunctionCallError ( tok ) ; // case log(0)
}
2010-04-02 07:32:03 +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% ) " ) & &
2011-11-13 13:10:59 +01:00
std : : fabs ( MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) ) > 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% ) " ) & &
2011-11-13 13:10:59 +01:00
MathLib : : isNegative ( tok - > strAt ( 2 ) ) ) {
2010-04-05 20:20:20 +02:00
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% ) " ) & &
2011-11-13 13:10:59 +01:00
MathLib : : isNullValue ( tok - > strAt ( 2 ) ) & &
MathLib : : isNullValue ( tok - > strAt ( 4 ) ) ) {
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% ) " ) & &
2011-11-13 13:10:59 +01:00
MathLib : : isNullValue ( tok - > strAt ( 4 ) ) ) {
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% ) " ) & &
2011-11-13 13:10:59 +01:00
MathLib : : isNullValue ( tok - > strAt ( 2 ) ) & &
MathLib : : isNegative ( tok - > strAt ( 4 ) ) ) {
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 )
{
2011-10-13 20:53:06 +02:00
if ( tok ) {
2011-08-19 17:53:43 +02:00
if ( numParam = = 1 )
2011-11-13 13:10:59 +01:00
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " + tok - > strAt ( 2 ) + " to " + tok - > str ( ) + " () leads to undefined result " ) ;
2011-08-19 17:53:43 +02:00
else if ( numParam = = 2 )
2011-11-13 13:10:59 +01:00
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " + tok - > strAt ( 2 ) + " and " + tok - > strAt ( 4 ) + " to " + tok - > str ( ) + " () leads to undefined result " ) ;
2011-10-13 20:53:06 +02:00
} else
2011-08-19 17:53:43 +02:00
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value " " to " " () leads to undefined result " ) ;
}
2011-11-17 16:31:16 +01:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void CheckOther : : checkCCTypeFunctions ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) = = 0 & &
Token : : Match ( tok , " isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|isxdigit ( %num% ) " ) & &
MathLib : : isNegative ( tok - > strAt ( 2 ) ) ) {
cctypefunctionCallError ( tok , tok - > str ( ) , tok - > tokAt ( 2 ) - > str ( ) ) ;
}
}
}
void CheckOther : : cctypefunctionCallError ( const Token * tok , const std : : string & functionName , const std : : string & value )
{
reportError ( tok , Severity : : error , " wrongcctypecall " , " Passing value " + value + " to " + functionName + " () cause undefined behavior, which may lead to a crash " ) ;
}
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-03-13 08:38:40 +01:00
/** Is there a function with given name? */
static bool isFunction ( const std : : string & name , const Token * startToken )
{
const std : : string pattern1 ( name + " ( " ) ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = startToken ; tok ; tok = tok - > next ( ) ) {
2011-03-13 08:38:40 +01:00
// skip executable scopes etc
2011-10-13 20:53:06 +02: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 { " ))
2011-11-20 14:22:39 +01:00
tok = tok - > linkAt ( 2 ) ;
2011-03-20 09:55:26 +01:00
}
2011-03-13 08:38:40 +01:00
// function declaration/implementation found
2011-03-20 09:55:26 +01:00
if ( ( tok - > str ( ) = = " * " | | ( tok - > isName ( ) & & tok - > str ( ) . find ( " : " ) = = std : : string : : npos ) )
& & Token : : simpleMatch ( tok - > next ( ) , pattern1 . c_str ( ) ) )
2011-03-13 08:38:40 +01:00
return true ;
}
return false ;
}
2010-10-01 17:23:22 +02:00
void CheckOther : : checkMisusedScopedObject ( )
{
2010-12-25 08:43:52 +01:00
// Skip this check for .c files
2011-10-16 08:09:57 +02:00
if ( _tokenizer - > code_is_c ( ) ) {
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-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
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-10-13 20:53:06 +02:00
for ( const Token * tok = scope - > classStart ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " ) {
2010-10-01 17:23:22 +02:00
+ + depth ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " } " ) {
2011-10-31 15:05:52 +01:00
if ( depth < = 1 )
2010-12-18 20:35:40 +01:00
break ;
2011-10-31 02:24:59 +01:00
- - depth ;
2010-10-01 17:23:22 +02:00
}
2010-12-18 20:35:40 +01:00
if ( Token : : Match ( tok , " [;{}] %var% ( " )
2011-11-20 14:22:39 +01:00
& & Token : : simpleMatch ( tok - > linkAt ( 2 ) , " ) ; " )
2011-01-16 19:57:29 +01:00
& & symbolDatabase - > isClassOrStruct ( tok - > next ( ) - > str ( ) )
2011-10-13 20:53:06 +02: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 ( )
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " . substr ( %any% , %num% ) ==|!= %str% " ) ) {
2011-11-13 13:10:59 +01:00
size_t clen = MathLib : : toLongNumber ( tok - > strAt ( 5 ) ) ;
2011-02-08 19:49:29 +01:00
size_t slen = Token : : getStrLength ( tok - > tokAt ( 8 ) ) ;
2011-10-13 20:53:06 +02:00
if ( clen ! = slen ) {
2011-11-13 13:10:59 +01:00
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > strAt ( 8 ) , tok - > strAt ( 5 ) ) ;
2011-02-08 19:49:29 +01:00
}
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok , " %str% ==|!= %var% . substr ( %any% , %num% ) " ) ) {
2011-11-13 13:10:59 +01:00
size_t clen = MathLib : : toLongNumber ( tok - > strAt ( 8 ) ) ;
2011-02-08 19:49:29 +01:00
size_t slen = Token : : getStrLength ( tok ) ;
2011-10-13 20:53:06 +02:00
if ( clen ! = slen ) {
2011-11-13 13:10:59 +01:00
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > str ( ) , tok - > strAt ( 8 ) ) ;
2011-02-08 19:49:29 +01:00
}
}
2011-10-18 21:37:03 +02:00
if ( Token : : Match ( tok , " &&|%oror% %str% &&|%oror%|) " ) ) {
// assert(condition && "debug message") would be considered a fp.
2011-11-20 14:22:39 +01:00
if ( tok - > str ( ) = = " && " & & tok - > strAt ( 2 ) = = " ) " & & tok - > linkAt ( 2 ) - > previous ( ) - > str ( ) = = " assert " )
2011-10-18 21:37:03 +02:00
continue ;
2011-11-20 15:09:57 +01:00
incorrectStringBooleanError ( tok - > next ( ) , tok - > strAt ( 1 ) ) ;
2011-10-18 21:37:03 +02:00
}
if ( Token : : Match ( tok , " if|while|assert ( %str% &&|%oror%|) " ) ) {
// assert("debug message" && condition) would be considered a fp.
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( 3 ) = = " && " & & tok - > str ( ) = = " assert " )
2011-10-18 21:37:03 +02:00
continue ;
2011-11-13 13:10:59 +01:00
incorrectStringBooleanError ( tok - > tokAt ( 2 ) , tok - > strAt ( 2 ) ) ;
2011-10-18 21:37:03 +02:00
}
2011-02-08 19:49:29 +01:00
}
}
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-10-18 21:37:03 +02:00
void CheckOther : : incorrectStringBooleanError ( const Token * tok , const std : : string & string )
{
reportError ( tok , Severity : : warning , " incorrectStringBooleanError " , " A boolean comparison with the string literal " + string + " is always true. " ) ;
}
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
2011-10-13 20:53:06 +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 )
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = first ; tok ! = last - > next ( ) ; tok = tok - > next ( ) ) {
2011-04-09 21:14:01 +02:00
// 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 ;
2011-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
2011-04-09 21:14:01 +02:00
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
// check all the code in the function for if (...) and else if (...) statements
2011-10-13 20:53:06 +02:00
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 " & &
2011-10-13 20:53:06 +02:00
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 ( " ) & &
2011-11-20 14:22:39 +01:00
Token : : simpleMatch ( tok1 - > linkAt ( 3 ) , " ) { " ) ) {
2011-04-09 21:14:01 +02:00
// get the expression from the token stream
2011-11-20 14:22:39 +01:00
expression = stringifyTokens ( tok1 - > tokAt ( 4 ) , tok1 - > linkAt ( 3 ) - > previous ( ) ) ;
2011-04-09 21:14:01 +02:00
// try to look up the expression to check for duplicates
std : : map < std : : string , const Token * > : : iterator it = expressionMap . find ( expression ) ;
// found a duplicate
2011-10-13 20:53:06 +02:00
if ( it ! = expressionMap . end ( ) ) {
2011-04-09 21:14:01 +02:00
// check for expressions that have side effects and ignore them
2011-11-20 14:22:39 +01:00
if ( ! expressionHasSideEffects ( tok1 - > tokAt ( 4 ) , tok1 - > linkAt ( 3 ) - > previous ( ) ) )
2011-04-09 21:14:01 +02:00
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
2011-11-20 14:22:39 +01:00
tok1 = tok1 - > linkAt ( 3 ) - > next ( ) - > link ( ) ;
2011-04-09 21:14:01 +02:00
}
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 ;
2011-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
2011-04-09 23:05:27 +02:00
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
// check all the code in the function for if (..) else
2011-10-13 20:53:06 +02:00
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-10-13 20:53:06 +02:00
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
2011-11-20 14:22:39 +01:00
std : : string branch2 = stringifyTokens ( tok1 - > tokAt ( 3 ) , tok1 - > linkAt ( 2 ) - > previous ( ) ) ;
2011-04-09 23:05:27 +02:00
// 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 ) ;
2011-10-29 15:16:27 +02:00
reportInconclusiveError ( toks , Severity : : style , " duplicateBranch " , " Found duplicate branches for if and else. \n "
" Finding the same code for an if branch and an else branch is suspicious and "
" might indicate a cut and paste or logic error. Please examine this code "
" carefully to determine if it is correct. " ) ;
2011-04-09 23:05:27 +02:00
}
2011-11-08 21:22:31 +01:00
namespace {
class Expressions {
public :
void endExpr ( ) {
const std : : string & e = _expression . str ( ) ;
if ( ! e . empty ( ) ) {
std : : map < std : : string , int > : : const_iterator it = _expressions . find ( e ) ;
if ( it = = _expressions . end ( ) )
_expressions [ e ] = 1 ;
else
_expressions [ e ] + = 1 ;
}
_expression . str ( " " ) ;
}
void append ( const std : : string & tok ) {
_expression < < tok ;
}
std : : map < std : : string , int > & getMap ( ) {
return _expressions ;
}
private :
std : : map < std : : string , int > _expressions ;
std : : ostringstream _expression ;
} ;
}
void CheckOther : : checkExpressionRange ( const Token * start , const Token * end , const std : : string & toCheck )
{
if ( ! start | | ! end )
return ;
Expressions expressions ;
std : : string opName ;
for ( const Token * tok = start - > next ( ) ; tok & & tok ! = end ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , toCheck . c_str ( ) ) ) {
opName = tok - > str ( ) ;
expressions . endExpr ( ) ;
} else {
expressions . append ( tok - > str ( ) ) ;
}
}
expressions . endExpr ( ) ;
std : : map < std : : string , int > : : const_iterator it = expressions . getMap ( ) . begin ( ) ;
for ( ; it ! = expressions . getMap ( ) . end ( ) ; + + it ) {
if ( it - > second > 1 )
duplicateExpressionError ( start , start , opName ) ;
}
}
void CheckOther : : complexDuplicateExpressionCheck ( const Token * classStart ,
2011-11-09 20:34:58 +01:00
const std : : string & toCheck ,
const std : : string & alt )
2011-11-08 21:22:31 +01:00
{
std : : string statementStart ( " ,|=|return " ) ;
if ( ! alt . empty ( ) )
statementStart + = " | " + alt ;
std : : string statementEnd ( " ;|, " ) ;
if ( ! alt . empty ( ) )
statementEnd + = " | " + alt ;
for ( const Token * tok = classStart ; tok & & tok ! = classStart - > link ( ) ; tok = tok - > next ( ) ) {
if ( ! Token : : Match ( tok , toCheck . c_str ( ) ) )
continue ;
// look backward for the start of the statement
const Token * start = 0 ;
int level = 0 ;
for ( const Token * tok1 = tok - > previous ( ) ; tok1 & & tok1 ! = classStart ; tok1 = tok1 - > previous ( ) ) {
if ( tok1 - > str ( ) = = " ) " )
level + + ;
else if ( tok1 - > str ( ) = = " ( " )
level - - ;
if ( level < 0 | | Token : : Match ( tok1 , statementStart . c_str ( ) ) ) {
start = tok1 ;
break ;
}
}
const Token * end = 0 ;
level = 0 ;
// look for the end of the statement
for ( const Token * tok1 = tok - > next ( ) ; tok1 & & tok1 ! = classStart - > link ( ) ; tok1 = tok1 - > next ( ) ) {
if ( tok1 - > str ( ) = = " ) " )
level - - ;
else if ( tok1 - > str ( ) = = " ( " )
level + + ;
if ( level < 0 | | Token : : Match ( tok1 , statementEnd . c_str ( ) ) ) {
end = tok1 ;
break ;
}
}
checkExpressionRange ( start , end , toCheck ) ;
}
}
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 ;
2011-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
2011-04-10 16:25:02 +02:00
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
2011-11-08 21:24:44 +01:00
complexDuplicateExpressionCheck ( scope - > classStart , " %or% " , " " ) ;
2011-11-08 21:22:31 +01:00
complexDuplicateExpressionCheck ( scope - > classStart , " %oror% " , " " ) ;
2011-11-08 21:24:44 +01:00
complexDuplicateExpressionCheck ( scope - > classStart , " & " , " %oror%|%or% " ) ;
complexDuplicateExpressionCheck ( scope - > classStart , " && " , " %oror%|%or% " ) ;
2011-11-08 21:22:31 +01:00
2011-10-13 20:53:06 +02:00
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) ) {
2011-11-08 21:26:33 +01:00
if ( Token : : Match ( tok , " ,|=|return|(|&&|%oror% %var% ==|!=|<=|>=|<|>|- %var% )|&&|%oror%|;|, " ) & &
2011-10-13 20:53:06 +02:00
tok - > strAt ( 1 ) = = tok - > strAt ( 3 ) ) {
2011-04-19 01:20:27 +02:00
// float == float and float != float are valid NaN checks
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok - > tokAt ( 2 ) , " ==|!= " ) & & tok - > next ( ) - > varId ( ) ) {
2011-04-19 01:20:27 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
if ( var & & var - > typeStartToken ( ) = = var - > typeEndToken ( ) ) {
2011-04-19 01:20:27 +02:00
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 ) ) ;
2011-11-08 21:26:33 +01:00
} else if ( Token : : Match ( tok , " ,|=|return|(|&&|%oror% %var% . %var% ==|!=|<=|>=|<|>|- %var% . %var% ) | & & | % oror % | ; | , " ) &&
2011-10-13 20:53:06 +02:00
tok - > strAt ( 1 ) = = tok - > strAt ( 5 ) & & tok - > strAt ( 3 ) = = tok - > strAt ( 7 ) ) {
2011-04-10 16:25:02 +02:00
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 ;
2011-10-28 22:03:18 +02:00
const char pattern1 [ ] = " strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %str% , %str% " ;
2011-04-26 07:45:27 +02:00
const char pattern2 [ ] = " QString :: compare ( %str% , %str% ) " ;
2011-10-28 22:05:11 +02:00
const char pattern3 [ ] = " strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %var% , %var% " ;
2011-04-26 07:45:27 +02:00
const Token * tok = _tokenizer - > tokens ( ) ;
2011-10-13 20:53:06 +02:00
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 ( ) ;
2011-10-13 20:53:06 +02:00
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-10-28 22:05:11 +02:00
tok = _tokenizer - > tokens ( ) ;
while ( tok & & ( tok = Token : : findmatch ( tok , pattern3 ) ) ! = NULL ) {
const Token * var1 = tok - > tokAt ( 2 ) ;
const Token * var2 = tok - > tokAt ( 4 ) ;
2011-10-29 11:52:19 +02:00
const std : : string & str1 = var1 - > str ( ) ;
const std : : string & str2 = var2 - > str ( ) ;
if ( str1 = = str2 )
alwaysTrueStringVariableCompareError ( tok , str1 , str2 ) ;
2011-10-28 22:05:11 +02:00
tok = tok - > tokAt ( 5 ) ;
}
2011-04-26 07:45:27 +02:00
}
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 ) + " .. " ) ;
2011-10-13 20:53:06 +02:00
if ( str1 = = str2 ) {
2011-04-26 07:45:27 +02:00
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-10-13 20:53:06 +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-10-28 22:05:11 +02:00
void CheckOther : : alwaysTrueStringVariableCompareError ( const Token * tok , const std : : string & str1 , const std : : string & str2 )
{
2011-10-29 11:52:19 +02:00
reportError ( tok , Severity : : warning , " stringCompare " ,
" Comparison of identical string variables. \n "
" The compared strings, ' " + str1 + " ' and ' " + str2 + " ', are identical. "
" This could be a logic bug. " ) ;
2011-10-28 22:05:11 +02:00
}
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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : simpleMatch ( tok , " sizeof ( " ) ) {
2010-08-06 22:57:10 +02:00
unsigned int parlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-08-06 22:57:10 +02:00
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " ) " ) {
2010-08-06 22:57:10 +02:00
if ( parlevel < = 1 )
break ;
- - parlevel ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok2 , " +|/ " ) ) {
2010-08-06 22:57:10 +02:00
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 ( )
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " [;{}] %var% = %bool% ; " ) ) {
2011-07-28 07:28:24 +02:00
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
2011-10-10 19:11:17 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CheckOther : : checkComparisonOfBoolExpressionWithInt ( )
{
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " &&|%oror% %any% ) ==|!=|>|< %num% " ) ) {
2011-10-10 19:11:17 +02:00
const std : : string & op = tok - > strAt ( 3 ) ;
const std : : string & num = tok - > strAt ( 4 ) ;
2011-10-13 20:53:06 +02:00
if ( ( op = = " < " | | num ! = " 0 " ) & & ( op = = " > " | | num ! = " 1 " ) ) {
2011-10-10 19:11:17 +02:00
comparisonOfBoolExpressionWithIntError ( tok - > next ( ) ) ;
}
}
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok , " %num% ==|!=|>|< ( %any% &&|%oror% " ) ) {
2011-10-10 19:11:17 +02:00
const std : : string & op = tok - > strAt ( 1 ) ;
const std : : string & num = tok - > str ( ) ;
2011-10-13 20:53:06 +02:00
if ( ( op = = " > " | | num ! = " 0 " ) & & ( op = = " < " | | num ! = " 1 " ) ) {
2011-10-10 19:11:17 +02:00
comparisonOfBoolExpressionWithIntError ( tok - > next ( ) ) ;
}
}
}
}
void CheckOther : : comparisonOfBoolExpressionWithIntError ( const Token * tok )
{
reportError ( tok , Severity : : warning , " compareBoolExpressionWithInt " ,
" Comparison of a boolean expression with an integer other than 0 or 1. " ) ;
}
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 ;
2011-11-06 18:24:37 +01:00
const bool inconclusive = _tokenizer - > codeWithTemplates ( ) ;
if ( inconclusive & & ! _settings - > inconclusive )
return ;
2011-08-07 01:23:09 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : list < Scope > : : const_iterator scope ;
2011-10-13 20:53:06 +02:00
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
2011-08-07 01:23:09 +02:00
// only check functions
if ( scope - > type ! = Scope : : eFunction )
continue ;
// check all the code in the function
2011-10-13 20:53:06 +02:00
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classStart - > link ( ) ; tok = tok - > next ( ) ) {
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-11-06 18:24:37 +01:00
unsignedLessThanZeroError ( tok - > next ( ) , tok - > next ( ) - > str ( ) , inconclusive ) ;
2011-10-13 20:53:06 +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-11-06 18:24:37 +01:00
unsignedLessThanZeroError ( tok - > tokAt ( 3 ) , tok - > strAt ( 3 ) , inconclusive ) ;
2011-10-13 20:53:06 +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-11-06 18:24:37 +01:00
unsignedPositiveError ( tok - > tokAt ( 3 ) , tok - > strAt ( 3 ) , inconclusive ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " ;|(|&&|%oror% %var% >= 0 ;|)|&&|%oror% " ) & & tok - > next ( ) - > varId ( ) ) {
2011-09-27 03:24:34 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2011-11-06 18:24:37 +01:00
unsignedPositiveError ( tok - > next ( ) , tok - > next ( ) - > str ( ) , inconclusive ) ;
2011-09-27 03:24:34 +02:00
}
2011-08-07 01:23:09 +02:00
}
}
}
2011-11-06 18:24:37 +01:00
void CheckOther : : unsignedLessThanZeroError ( const Token * tok , const std : : string & varname , bool inconclusive )
{
if ( inconclusive ) {
reportInconclusiveError ( tok , Severity : : style , " unsignedLessThanZero " ,
" Checking if unsigned variable ' " + varname + " ' is less than zero. This might be a false warning. \n "
" Checking if unsigned variable ' " + varname + " ' is less than zero. An unsigned "
" variable will never be negative so it is either pointless or an error to check if it is. "
" It's not known if the used constant is a template parameter or not and therefore "
" this message might be a false warning " ) ;
} else {
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-07 01:23:09 +02:00
}
2011-11-06 18:24:37 +01:00
void CheckOther : : unsignedPositiveError ( const Token * tok , const std : : string & varname , bool inconclusive )
{
if ( inconclusive ) {
reportInconclusiveError ( tok , Severity : : style , " unsignedPositive " ,
" Checking if unsigned variable ' " + varname + " ' is positive is always true. This might be a false warning. \n "
" Checking if unsigned variable ' " + varname + " ' is positive is always true. "
" An unsigned variable will always be positive so it is either pointless or "
" an error to check if it is. It's not known if the used constant is a "
" template parameter or not and therefore this message might be a false warning " ) ;
} else {
reportError ( tok , Severity : : style , " unsignedPositive " ,
" Checking if unsigned variable ' " + varname + " ' is positive is always true. \n "
" An unsigned variable will always be positive so it is either pointless or "
" an error to check if it is. " ) ;
}
2011-08-07 01:23:09 +02:00
}