2009-01-26 20:14:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2012-01-01 00:05:37 +01:00
* Copyright ( C ) 2007 - 2012 Daniel Marjamäki and Cppcheck team .
2009-01-26 20:14:46 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-26 20:14:46 +01:00
*/
//---------------------------------------------------------------------------
# include "checkother.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2010-12-16 19:04:47 +01:00
# include "symboldatabase.h"
2010-10-31 12:31:11 +01:00
2010-04-02 20:23:37 +02:00
# include <cmath> // fabs()
2011-02-19 20:02:28 +01:00
# include <stack>
2011-11-29 19:46:36 +01:00
# include <algorithm> // find_if()
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 "
2011-12-30 00:22:16 +01:00
" 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. "
2011-02-11 23:38:23 +01:00
) ;
}
//---------------------------------------------------------------------------
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-11-30 20:23:29 +01:00
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2011-12-23 12:13:39 +01:00
if ( tok - > str ( ) = = " ? " & & tok - > previous ( ) ) {
2011-01-24 21:40:49 +01:00
// condition
2011-12-23 12:13:39 +01:00
const Token * cond = tok - > previous ( ) ;
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..
2011-12-23 12:13:39 +01:00
while ( cond & & cond - > previous ( ) ) {
if ( ( cond - > isName ( ) | | cond - > isNumber ( ) ) & & cond - > previous ( ) - > str ( ) = = " * " )
cond = cond - > tokAt ( - 2 ) ;
else if ( cond - > str ( ) = = " ) " )
cond = cond - > link ( ) - > previous ( ) ;
else
break ;
}
2011-01-24 21:40:49 +01:00
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 ( ) ) {
2012-05-24 15:34:59 +02:00
if ( Token : : Match ( cond - > previous ( ) , " return|=|+|-|,|( " ) | | cond - > strAt ( - 1 ) = = op )
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
2012-06-23 07:29:49 +02:00
const bool isC = _tokenizer - > isC ( ) ;
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 ( ) ;
2012-04-26 23:04:55 +02:00
else if ( tok2 - > type ( ) = = Token : : eComparisonOp ) {
2011-08-19 18:06:28 +02:00
// This might be a template
2012-08-02 13:03:01 +02:00
if ( ! isC & & tok2 - > link ( ) )
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 , " !|<|<=|==|!=|>|>= " ) ) {
2012-08-02 13:03:01 +02:00
if ( tok - > link ( ) ) // don't write false positives when templates are used
continue ;
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
2012-08-02 13:03:01 +02:00
if ( Token : : Match ( tok2 , " &|* ,|> " ) | | Token : : simpleMatch ( tok2 - > previous ( ) , " const & " ) )
2011-08-19 18:06:28 +02:00
continue ;
2012-04-08 18:07:11 +02:00
// #3609 - CWinTraits<WS_CHILD|WS_VISIBLE>::..
2012-06-23 07:29:49 +02:00
if ( ! isC & & Token : : Match ( tok - > previous ( ) , " %var% < " ) ) {
2012-04-08 18:07:11 +02:00
const Token * tok3 = tok2 ;
while ( Token : : Match ( tok3 , " [&|^] %var% " ) )
tok3 = tok3 - > tokAt ( 2 ) ;
if ( Token : : Match ( tok3 , " ,|> " ) )
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
}
2012-08-24 11:28:50 +02:00
//---------------------------------------------------------------------------
// Clarify (meaningless) statements like *foo++; with parantheses.
//---------------------------------------------------------------------------
void CheckOther : : clarifyStatement ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2012-09-03 17:10:27 +02:00
if ( Token : : Match ( tok , " * %var% " ) ) {
const Token * tok2 = tok - > previous ( ) ;
while ( Token : : Match ( tok2 , " * " ) )
tok2 = tok2 - > previous ( ) ;
if ( Token : : Match ( tok2 , " [{};] " ) ) {
tok = tok - > tokAt ( 2 ) ;
while ( tok ) {
if ( tok - > str ( ) = = " [ " )
tok = tok - > link ( ) - > next ( ) ;
if ( Token : : Match ( tok , " .|:: %var% " ) ) {
if ( tok - > strAt ( 2 ) = = " ( " )
tok = tok - > linkAt ( 2 ) - > next ( ) ;
else
tok = tok - > tokAt ( 2 ) ;
} else
break ;
}
if ( Token : : Match ( tok , " ++|-- [;,] " ) )
2012-09-04 02:03:38 +02:00
//TODO: change the string in order to remove the excessive spaces between the tokens.
clarifyStatementError ( tok ,
tok2 - > next ( ) - > stringifyList ( tok - > tokAt ( 2 ) ) ,
" ( " + tok2 - > next ( ) - > stringifyList ( tok ) + " ) " + tok - > stringifyList ( tok - > tokAt ( 2 ) ) ) ;
2012-08-24 11:28:50 +02:00
}
}
}
}
2012-09-04 02:03:38 +02:00
void CheckOther : : clarifyStatementError ( const Token * tok , const std : : string & expr , const std : : string & suggested )
2012-08-24 11:28:50 +02:00
{
2012-09-04 02:03:38 +02:00
reportError ( tok , Severity : : warning , " clarifyStatement " , " Ineffective statement: ' " + expr + " '. Did you intend to write ' " + suggested + " '? \n "
" A statement like '*expr++;' might not do what you intended. 'operator*' is executed before postfix 'operator++'. "
" Thus, the dereference is meaningless. Did you intend to write '(*expr)++;'? " ) ;
2012-08-24 11:28:50 +02:00
}
2011-10-06 22:01:48 +02:00
//---------------------------------------------------------------------------
2012-08-24 00:03:22 +02:00
// if (bool & bool) -> if (bool && bool)
2011-10-06 22:01:48 +02:00
// 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 ( ) ) {
2012-03-03 21:14:20 +01:00
if ( Token : : Match ( tok , " (|.|return|&&|%oror%|throw|, %var% [&|] " ) ) {
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " ) {
bitwiseOnBooleanError ( tok - > next ( ) , var - > name ( ) , tok - > strAt ( 2 ) = = " & " ? " && " : " || " ) ;
tok = tok - > tokAt ( 2 ) ;
}
} else if ( Token : : Match ( tok , " [&|] %var% ) | . | return | & & | % oror % | throw | , " ) && (!tok->previous() || !tok->previous()->isExtendedOp() || tok->strAt(-1) == " ) " )) {
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " ) {
bitwiseOnBooleanError ( tok - > next ( ) , var - > name ( ) , tok - > str ( ) = = " & " ? " && " : " || " ) ;
tok = tok - > tokAt ( 2 ) ;
2011-10-06 22:01:48 +02:00
}
}
}
}
void CheckOther : : bitwiseOnBooleanError ( const Token * tok , const std : : string & varname , const std : : string & op )
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : style , " bitwiseOnBoolean " ,
" Boolean variable ' " + varname + " ' is used in bitwise operation. Did you mean " + op + " ? " , true ) ;
2011-10-06 22:01:48 +02:00
}
2011-10-11 08:41:39 +02:00
void CheckOther : : checkSuspiciousSemicolon ( )
{
if ( ! _settings - > inconclusive | | ! _settings - > isEnabled ( " style " ) )
return ;
2011-12-09 22:28:10 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
// Look for "if(); {}", "for(); {}" or "while(); {}"
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
if ( i - > type = = Scope : : eIf | | i - > type = = Scope : : eElse | | i - > type = = Scope : : eElseIf | | i - > type = = Scope : : eWhile | | i - > type = = Scope : : eFor ) {
2011-10-11 08:41:39 +02:00
// 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.
2012-05-24 15:34:59 +02:00
if ( Token : : simpleMatch ( i - > classStart , " { ; } { " ) & &
i - > classStart - > previous ( ) - > linenr ( ) = = i - > classStart - > tokAt ( 2 ) - > linenr ( )
& & i - > classStart - > linenr ( ) + 1 > = i - > classStart - > tokAt ( 3 ) - > linenr ( ) ) {
SuspiciousSemicolonError ( i - > classStart ) ;
2011-10-11 08:41:39 +02:00
}
}
}
}
void CheckOther : : SuspiciousSemicolonError ( const Token * tok )
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : warning , " suspiciousSemicolon " ,
" Suspicious use of ; at the end of 'if/for/while' statement. " , true ) ;
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
{
2012-03-03 21:14:20 +01:00
// Only valid on C++ code
if ( ! _settings - > isEnabled ( " style " ) | | ! _tokenizer - > isCPP ( ) )
2011-10-26 21:17:27 +02:00
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..
2011-12-04 19:49:01 +01:00
if ( ! Token : : Match ( tok , " ( const| %type% * ) (| %var% " ) & &
2010-04-02 07:30:58 +02:00
! Token : : Match ( tok , " ( const| %type% * ) (| new " ) )
2009-01-26 20:14:46 +01:00
continue ;
2011-11-13 13:10:59 +01:00
if ( tok - > strAt ( 1 ) = = " const " )
2012-03-03 21:14:20 +01:00
tok = tok - > next ( ) ;
2009-07-20 21:52:27 +02:00
2012-03-03 21:14:20 +01:00
if ( tok - > strAt ( 4 ) = = " const " )
2009-06-18 22:26:21 +02:00
continue ;
2009-01-26 20:14:46 +01:00
// Is "type" a class?
2012-03-03 21:14:20 +01:00
const std : : string pattern ( " class|struct " + tok - > strAt ( 1 ) ) ;
2012-05-24 15:34:59 +02:00
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) , tok ) )
2012-03-03 21:14:20 +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 " ) ;
}
2012-02-26 11:56:32 +01:00
//---------------------------------------------------------------------------
// float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
//---------------------------------------------------------------------------
static std : : string analyzeType ( const Token * tok )
{
2012-03-01 18:38:20 +01:00
if ( tok - > str ( ) = = " double " ) {
2012-02-26 11:56:32 +01:00
if ( tok - > isLong ( ) )
return " long double " ;
else
return " double " ;
2012-02-27 14:13:34 +01:00
}
2012-02-26 11:56:32 +01:00
if ( tok - > str ( ) = = " float " )
return " float " ;
2012-03-25 12:55:39 +02:00
if ( Token : : Match ( tok , " int|long|short|char|size_t " ) )
2012-02-26 11:56:32 +01:00
return " integer " ;
return " " ;
}
void CheckOther : : invalidPointerCast ( )
{
if ( ! _settings - > isEnabled ( " style " ) & & ! _settings - > isEnabled ( " portability " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
const Token * toTok = 0 ;
const Token * nextTok = 0 ;
// Find cast
if ( Token : : Match ( tok , " ( const| %type% const| * ) " ) | | Token : : Match ( tok , " ( const| %type% %type% const| * ) " ) ) {
toTok = tok - > next ( ) ;
nextTok = tok - > link ( ) - > next ( ) ;
2012-09-03 11:30:36 +02:00
if ( nextTok & & nextTok - > str ( ) = = " ( " )
2012-02-26 11:56:32 +01:00
nextTok = nextTok - > next ( ) ;
} else if ( Token : : Match ( tok , " reinterpret_cast < const| %type% const| * > ( " ) | | Token : : Match ( tok , " reinterpret_cast < const| %type% %type% const| * > ( " ) ) {
nextTok = tok - > tokAt ( 5 ) ;
while ( nextTok - > str ( ) ! = " ( " )
nextTok = nextTok - > next ( ) ;
nextTok = nextTok - > next ( ) ;
toTok = tok - > tokAt ( 2 ) ;
}
if ( toTok & & toTok - > str ( ) = = " const " )
toTok = toTok - > next ( ) ;
if ( ! nextTok | | ! toTok | | ! toTok - > isStandardType ( ) )
continue ;
// Find casted variable
unsigned int varid = 0 ;
bool allocation = false ;
bool ref = false ;
if ( Token : : Match ( nextTok , " new %type% " ) )
allocation = true ;
else if ( Token : : Match ( nextTok , " %var% !![ " ) )
varid = nextTok - > varId ( ) ;
else if ( Token : : Match ( nextTok , " & %var% " ) & & ! Token : : Match ( nextTok - > tokAt ( 2 ) , " (|[ " ) ) {
varid = nextTok - > next ( ) - > varId ( ) ;
ref = true ;
}
const Token * fromTok = 0 ;
if ( allocation ) {
fromTok = nextTok - > next ( ) ;
} else {
const Variable * var = symbolDatabase - > getVariableFromVarId ( varid ) ;
if ( ! var | | ( ! ref & & ! var - > isPointer ( ) & & ! var - > isArray ( ) ) | | ( ref & & ( var - > isPointer ( ) | | var - > isArray ( ) ) ) )
continue ;
fromTok = var - > typeStartToken ( ) ;
}
while ( Token : : Match ( fromTok , " static|const " ) )
fromTok = fromTok - > next ( ) ;
if ( ! fromTok - > isStandardType ( ) )
continue ;
std : : string fromType = analyzeType ( fromTok ) ;
std : : string toType = analyzeType ( toTok ) ;
2012-03-25 12:55:39 +02:00
if ( fromType ! = toType & & ! fromType . empty ( ) & & ! toType . empty ( ) & & ( toType ! = " integer " | | _settings - > isEnabled ( " portability " ) ) & & ( toTok - > str ( ) ! = " char " | | _settings - > inconclusive ) )
invalidPointerCastError ( tok , fromType , toType , toTok - > str ( ) = = " char " ) ;
2012-02-26 11:56:32 +01:00
}
}
2012-03-25 12:55:39 +02:00
void CheckOther : : invalidPointerCastError ( const Token * tok , const std : : string & from , const std : : string & to , bool inconclusive )
2012-02-26 11:56:32 +01:00
{
2012-03-25 12:55:39 +02:00
if ( to = = " integer " ) { // If we cast something to int*, this can be useful to play with its binary data representation
if ( ! inconclusive )
reportError ( tok , Severity : : portability , " invalidPointerCast " , " Casting from " + from + " * to integer* is not portable due to different binary data representations on different platforms " ) ;
else
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : portability , " invalidPointerCast " , " Casting from " + from + " * to char* might be not portable due to different binary data representations on different platforms " , true ) ;
2012-03-25 12:55:39 +02:00
} else
2012-02-26 11:56:32 +01:00
reportError ( tok , Severity : : warning , " invalidPointerCast " , " Casting between " + from + " * and " + to + " * which have an incompatible binary data representation " ) ;
}
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-05-16 21:16:25 +02:00
void CheckOther : : checkSizeofForNumericParameter ( )
{
2011-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-11-27 18:50:21 +01:00
return ;
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 )
{
2011-12-16 19:21:14 +01:00
reportError ( tok , Severity : : warning ,
2011-08-19 17:53:43 +02:00
" sizeofwithnumericparameter " , " Using sizeof with a numeric constant as function "
" argument might not be what you intended. \n "
2011-12-16 19:21:14 +01:00
" It is unusual to use constant value with sizeof. For example, sizeof(10) "
" returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. sizeof('A') "
" and sizeof(char) can return different results. " ) ;
2011-08-19 17:53:43 +02:00
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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 ( ) ) {
2012-05-24 09:39:16 +02:00
if ( Token : : Match ( tok , " sizeof ( %var% ) " ) | | Token : : Match ( tok , " sizeof %var% !![ " ) ) {
2012-03-03 21:14:20 +01:00
const Token * varTok = tok - > next ( ) ;
if ( varTok - > str ( ) = = " ( " ) {
varTok = varTok - > next ( ) ;
2011-01-22 19:21:56 +01:00
}
2012-03-03 21:14:20 +01:00
if ( varTok - > varId ( ) > 0 ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( varTok - > varId ( ) ) ;
2012-05-24 09:39:16 +02:00
if ( var & & var - > isArray ( ) & & var - > isArgument ( ) ) {
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
2012-03-23 21:47:13 +01:00
void CheckOther : : checkSizeofForPointerSize ( )
2011-10-28 22:06:55 +02:00
{
2012-03-03 21:14:20 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-03-23 21:47:13 +01:00
2012-03-25 11:51:59 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2012-03-23 21:47:13 +01:00
return ;
2012-03-03 21:14:20 +01:00
2011-10-28 22:06:55 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2012-03-23 21:47:13 +01:00
const Token * tokVar ;
const Token * variable ;
const Token * variable2 = 0 ;
// Find any function that may use sizeof on a pointer
// Once leaving those tests, it is mandatory to have:
// - variable matching the used pointer
// - tokVar pointing on the argument where sizeof may be used
if ( Token : : Match ( tok , " [*;{}] %var% = malloc|alloca ( " ) ) {
variable = tok - > next ( ) ;
tokVar = tok - > tokAt ( 5 ) ;
} else if ( Token : : Match ( tok , " [*;{}] %var% = calloc ( " ) ) {
variable = tok - > next ( ) ;
tokVar = tok - > tokAt ( 5 ) - > nextArgument ( ) ;
2012-07-11 17:45:16 +02:00
} else if ( Token : : simpleMatch ( tok , " memset ( " ) ) {
2012-03-23 21:47:13 +01:00
variable = tok - > tokAt ( 2 ) ;
tokVar = variable - > tokAt ( 2 ) - > nextArgument ( ) ;
2012-03-25 11:51:59 +02:00
// The following tests can be inconclusive in case the variable in sizeof
// is constant string by intention
2012-03-23 21:47:13 +01:00
} else if ( ! _settings - > inconclusive ) {
continue ;
} else if ( Token : : Match ( tok , " memcpy|memcmp|memmove|strncpy|strncmp|strncat ( " ) ) {
variable = tok - > tokAt ( 2 ) ;
variable2 = variable - > nextArgument ( ) ;
tokVar = variable2 - > nextArgument ( ) ;
} else {
continue ;
2011-10-28 22:06:55 +02:00
}
2012-03-23 21:47:13 +01:00
// Ensure the variables are in the symbol database
// Also ensure the variables are pointers
// Only keep variables which are pointers
const Variable * var = symbolDatabase - > getVariableFromVarId ( variable - > varId ( ) ) ;
2012-04-18 16:35:04 +02:00
if ( ! var | | ! var - > isPointer ( ) | | var - > isArray ( ) ) {
2012-03-23 21:47:13 +01:00
variable = 0 ;
}
2011-10-28 22:06:55 +02:00
2012-03-23 21:47:13 +01:00
if ( variable2 ) {
var = symbolDatabase - > getVariableFromVarId ( variable2 - > varId ( ) ) ;
2012-04-18 16:35:04 +02:00
if ( ! var | | ! var - > isPointer ( ) | | var - > isArray ( ) ) {
2012-03-25 11:51:59 +02:00
variable2 = 0 ;
2012-03-20 18:50:05 +01:00
}
}
2012-03-23 21:47:13 +01:00
// If there are no pointer variable at this point, there is
// no need to continue
if ( variable = = 0 & & variable2 = = 0 ) {
continue ;
}
// Jump to the next sizeof token in the function and in the parameter
// This is to allow generic operations with sizeof
2012-05-18 20:00:10 +02:00
for ( ; tokVar & & tokVar - > str ( ) ! = " ) " & & tokVar - > str ( ) ! = " , " & & tokVar - > str ( ) ! = " sizeof " ; tokVar = tokVar - > next ( ) ) { }
2012-03-23 21:47:13 +01:00
2012-08-20 19:08:18 +02:00
// Now check for the sizeof usage. Once here, everything using sizeof(varid) or sizeof(&varid)
2012-03-23 21:47:13 +01:00
// looks suspicious
// Do it for first variable
2012-08-20 19:08:18 +02:00
if ( variable & & ( Token : : Match ( tokVar , " sizeof ( &| %varid% ) " , variable - > varId ( ) ) | |
Token : : Match ( tokVar , " sizeof &| %varid% " , variable - > varId ( ) ) ) ) {
2012-03-23 21:47:13 +01:00
sizeofForPointerError ( variable , variable - > str ( ) ) ;
2012-08-20 19:08:18 +02:00
} else if ( variable2 & & ( Token : : Match ( tokVar , " sizeof ( &| %varid% ) " , variable2 - > varId ( ) ) | |
Token : : Match ( tokVar , " sizeof &| %varid% " , variable2 - > varId ( ) ) ) ) {
2012-03-23 21:47:13 +01:00
sizeofForPointerError ( variable2 , variable2 - > str ( ) ) ;
}
}
2012-03-20 18:50:05 +01:00
}
2012-03-23 21:47:13 +01:00
void CheckOther : : sizeofForPointerError ( const Token * tok , const std : : string & varname )
2012-03-20 18:50:05 +01:00
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : warning , " pointerSize " ,
" Using size of pointer " + varname + " instead of size of its data. \n "
" Using size of pointer " + varname + " instead of size of its data. "
" This is likely to lead to a buffer overflow. You probably intend to "
" write sizeof(* " + varname + " ) " , true ) ;
2012-03-20 18:50:05 +01:00
}
2012-09-02 13:09:32 +02:00
//---------------------------------------------------------------------------
// Detect redundant assignments: x = 0; x = 4;
//---------------------------------------------------------------------------
2012-09-03 10:46:51 +02:00
static void eraseNotLocalArg ( std : : map < unsigned int , const Token * > & container , const SymbolDatabase * symbolDatabase )
{
for ( std : : map < unsigned int , const Token * > : : iterator i = container . begin ( ) ; i ! = container . end ( ) ; ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( i - > first ) ;
if ( ! var | | ( ! var - > isLocal ( ) & & ! var - > isArgument ( ) ) ) {
container . erase ( i + + ) ;
if ( i = = container . end ( ) )
break ;
} else
+ + i ;
}
}
2012-09-02 13:09:32 +02:00
void CheckOther : : checkRedundantAssignment ( )
{
if ( ! _settings - > isEnabled ( " performance " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-09-02 17:00:16 +02:00
for ( std : : list < Scope > : : const_iterator scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
if ( ! scope - > isExecutable ( ) )
2012-09-02 13:09:32 +02:00
continue ;
///std::cout << std::endl << "scope: " << i->className << std::endl;
std : : map < unsigned int , const Token * > varAssignments ;
std : : map < unsigned int , const Token * > memAssignments ;
const Token * writtenArgumentsEnd = 0 ;
2012-09-02 17:00:16 +02:00
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-09-02 13:09:32 +02:00
if ( tok = = writtenArgumentsEnd )
writtenArgumentsEnd = 0 ;
if ( tok - > str ( ) = = " { " & & tok - > strAt ( - 1 ) ! = " { " & & tok - > strAt ( - 1 ) ! = " = " & & tok - > strAt ( - 4 ) ! = " case " & & tok - > strAt ( - 3 ) ! = " default " ) { // conditional or non-executable inner scope: Skip it and reset status
tok = tok - > link ( ) ;
varAssignments . clear ( ) ;
memAssignments . clear ( ) ;
} else if ( Token : : Match ( tok , " for|if|while ( " ) ) {
tok = tok - > linkAt ( 1 ) ;
} else if ( Token : : Match ( tok , " break|return|continue|throw|goto " ) ) {
varAssignments . clear ( ) ;
memAssignments . clear ( ) ;
} else if ( tok - > type ( ) = = Token : : eVariable ) {
std : : map < unsigned int , const Token * > : : iterator it = varAssignments . find ( tok - > varId ( ) ) ;
if ( tok - > next ( ) - > isAssignmentOp ( ) & & Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) { // Assignment
///std::cout << "assign: " << tok->varId() << std::endl;
if ( it ! = varAssignments . end ( ) ) {
bool error = true ; // Ensure that variable is not used on right side
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ; " )
break ;
else if ( tok2 - > varId ( ) = = tok - > varId ( ) )
error = false ;
}
if ( error ) {
2012-09-02 17:00:16 +02:00
if ( scope - > type = = Scope : : eSwitch & & Token : : findmatch ( it - > second , " default|case " , tok ) )
2012-09-02 13:09:32 +02:00
redundantAssignmentInSwitchError ( it - > second , tok , tok - > str ( ) ) ;
else
redundantAssignmentError ( it - > second , tok , tok - > str ( ) ) ;
}
it - > second = tok ;
}
varAssignments [ tok - > varId ( ) ] = tok ;
memAssignments . erase ( tok - > varId ( ) ) ;
} else if ( tok - > next ( ) - > type ( ) = = Token : : eIncDecOp | | ( tok - > previous ( ) - > type ( ) = = Token : : eIncDecOp & & ! Token : : Match ( tok - > next ( ) , " .|[|( " ) ) ) { // Variable incremented/decremented
varAssignments [ tok - > varId ( ) ] = tok ;
memAssignments . erase ( tok - > varId ( ) ) ;
} else if ( ! Token : : Match ( tok - > tokAt ( - 2 ) , " sizeof ( " ) ) { // Other usage of variable
///std::cout << "use: " << tok->varId() << std::endl;
if ( it ! = varAssignments . end ( ) )
varAssignments . erase ( it ) ;
if ( ! writtenArgumentsEnd ) // Indicates that we are in the first argument of strcpy/memcpy/... function
memAssignments . erase ( tok - > varId ( ) ) ;
}
} else if ( Token : : Match ( tok , " %var% ( " ) ) { // Function call. Global variables might be used. Reset their status
bool memfunc = Token : : Match ( tok , " memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat " ) ;
if ( memfunc ) {
const Token * param1 = tok - > tokAt ( 2 ) ;
writtenArgumentsEnd = param1 - > next ( ) ;
if ( param1 - > varId ( ) & & param1 - > strAt ( 1 ) = = " , " & & tok - > str ( ) ! = " strcat " & & tok - > str ( ) ! = " strncat " ) {
std : : map < unsigned int , const Token * > : : iterator it = memAssignments . find ( param1 - > varId ( ) ) ;
if ( it = = memAssignments . end ( ) )
memAssignments [ param1 - > varId ( ) ] = tok ;
else {
2012-09-02 17:00:16 +02:00
if ( scope - > type = = Scope : : eSwitch & & Token : : findmatch ( it - > second , " default|case " , tok ) )
2012-09-02 13:09:32 +02:00
redundantCopyInSwitchError ( it - > second , tok , param1 - > str ( ) ) ;
else
redundantCopyError ( it - > second , tok , param1 - > str ( ) ) ;
}
}
2012-09-03 12:03:30 +02:00
} else if ( scope - > type = = Scope : : eSwitch ) { // Avoid false positives if noreturn function is called in switch
2012-09-02 13:09:32 +02:00
const Function * func = symbolDatabase - > findFunctionByToken ( _tokenizer - > getFunctionTokenByName ( tok - > str ( ) . c_str ( ) ) ) ;
if ( ! func | | ! func - > hasBody ) {
varAssignments . clear ( ) ;
memAssignments . clear ( ) ;
continue ;
}
const Token * funcEnd = func - > functionScope - > classEnd ;
bool noreturn ;
if ( ! _tokenizer - > IsScopeNoReturn ( funcEnd , & noreturn ) & & ! noreturn ) {
2012-09-03 10:46:51 +02:00
eraseNotLocalArg ( varAssignments , symbolDatabase ) ;
eraseNotLocalArg ( memAssignments , symbolDatabase ) ;
2012-09-02 13:09:32 +02:00
} else {
varAssignments . clear ( ) ;
memAssignments . clear ( ) ;
}
2012-09-03 12:03:30 +02:00
} else { // Noreturn functions outside switch don't cause problems
eraseNotLocalArg ( varAssignments , symbolDatabase ) ;
eraseNotLocalArg ( memAssignments , symbolDatabase ) ;
2012-09-02 13:09:32 +02:00
}
}
}
}
}
void CheckOther : : redundantCopyError ( const Token * tok1 , const Token * tok2 , const std : : string & var )
{
std : : list < const Token * > callstack ;
callstack . push_back ( tok1 ) ;
callstack . push_back ( tok2 ) ;
reportError ( callstack , Severity : : performance , " redundantCopy " ,
" Buffer ' " + var + " ' is being written before its old content has been used. " ) ;
}
void CheckOther : : redundantCopyInSwitchError ( const Token * tok1 , const Token * tok2 , const std : : string & var )
{
std : : list < const Token * > callstack ;
callstack . push_back ( tok1 ) ;
callstack . push_back ( tok2 ) ;
reportError ( callstack , Severity : : warning , " redundantCopyInSwitch " ,
" Buffer ' " + var + " ' is being written before its old content has been used. This might indicate a missing 'break;'. " ) ;
}
void CheckOther : : redundantAssignmentError ( const Token * tok1 , const Token * tok2 , const std : : string & var )
{
std : : list < const Token * > callstack ;
callstack . push_back ( tok1 ) ;
callstack . push_back ( tok2 ) ;
reportError ( callstack , Severity : : performance , " redundantAssignment " ,
" Variable ' " + var + " ' is reassigned a value before the old one has been used. " ) ;
}
void CheckOther : : redundantAssignmentInSwitchError ( const Token * tok1 , const Token * tok2 , const std : : string & var )
{
std : : list < const Token * > callstack ;
callstack . push_back ( tok1 ) ;
callstack . push_back ( tok2 ) ;
reportError ( callstack , Severity : : warning , " redundantAssignInSwitch " ,
" Variable ' " + var + " ' is reassigned a value before the old one has been used. This might indicate a missing 'break;'. " ) ;
}
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 ( )
{
2011-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
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% ( " ;
2012-03-03 21:14:20 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-06-30 09:10:30 +02:00
// Find the beginning of a switch. E.g.:
// switch (var) { ...
2012-03-03 21:14:20 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
if ( i - > type ! = Scope : : eSwitch | | ! i - > classStart )
continue ;
2010-06-30 09:10:30 +02:00
// Check the contents of the switch statement
2012-05-29 06:19:22 +02:00
std : : map < unsigned int , const Token * > varsWithBitsSet ;
std : : map < unsigned int , std : : string > bitOperations ;
2012-03-03 21:14:20 +01:00
for ( const Token * tok2 = i - > classStart - > next ( ) ; tok2 ! = i - > classEnd ; tok2 = tok2 - > next ( ) ) {
2011-10-13 20:53:06 +02:00
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 ) {
2012-05-29 06:19:22 +02:00
varsWithBitsSet . erase ( tok3 - > varId ( ) ) ;
bitOperations . erase ( tok3 - > varId ( ) ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok3 , functionPattern ) | | Token : : Match ( tok3 , breakPattern ) ) {
2012-05-29 06:19:22 +02:00
varsWithBitsSet . clear ( ) ;
bitOperations . clear ( ) ;
2011-10-13 10:27:22 +02:00
}
2010-06-30 09:10:30 +02:00
}
tok2 = endOfConditional ;
2012-03-03 21:14:20 +01:00
}
2010-06-30 09:10:30 +02:00
}
// 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;
2012-08-22 14:40:57 +02:00
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " ;|{|}|: %var% = %any% ; " ) & & tok2 - > varId ( ) ! = 0 ) {
2012-05-29 06:19:22 +02:00
varsWithBitsSet . erase ( tok2 - > varId ( ) ) ;
bitOperations . erase ( tok2 - > varId ( ) ) ;
}
// Bitwise operation. Report an error if it's performed twice before a break. E.g.:
// case 3: b |= 1; // <== redundant
// case 4: b |= 1;
else if ( Token : : Match ( tok2 - > previous ( ) , " ; | { | } | : % var % = % var % % or % | & % num % ; " ) &&
tok2 - > varId ( ) ! = 0 & & tok2 - > varId ( ) = = tok2 - > tokAt ( 2 ) - > varId ( ) ) {
std : : string bitOp = tok2 - > strAt ( 3 ) + tok2 - > strAt ( 4 ) ;
std : : map < unsigned int , const Token * > : : iterator i2 = varsWithBitsSet . find ( tok2 - > varId ( ) ) ;
// This variable has not had a bit operation performed on it yet, so just make a note of it
if ( i2 = = varsWithBitsSet . end ( ) ) {
varsWithBitsSet [ tok2 - > varId ( ) ] = tok2 ;
bitOperations [ tok2 - > varId ( ) ] = bitOp ;
}
// The same bit operation has been performed on the same variable twice, so report an error
else if ( bitOperations [ tok2 - > varId ( ) ] = = bitOp )
redundantBitwiseOperationInSwitchError ( i2 - > second , i2 - > second - > str ( ) ) ;
// A different bit operation was performed on the variable, so clear it
else {
varsWithBitsSet . erase ( tok2 - > varId ( ) ) ;
bitOperations . erase ( tok2 - > varId ( ) ) ;
}
2011-10-13 10:27:22 +02:00
}
2012-05-29 06:19:22 +02:00
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++;
2012-05-29 06:19:22 +02:00
else if ( tok2 - > varId ( ) ! = 0 & & tok2 - > strAt ( 1 ) ! = " | " & & tok2 - > strAt ( 1 ) ! = " & " ) {
varsWithBitsSet . erase ( tok2 - > varId ( ) ) ;
bitOperations . erase ( tok2 - > varId ( ) ) ;
}
2010-06-30 09:10:30 +02:00
// 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 ) ) {
2012-05-29 06:19:22 +02:00
varsWithBitsSet . clear ( ) ;
bitOperations . clear ( ) ;
2011-10-13 10:27:22 +02:00
}
2010-06-30 09:10:30 +02:00
}
}
}
2012-05-29 06:19:22 +02:00
void CheckOther : : redundantBitwiseOperationInSwitchError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
" redundantBitwiseOperationInSwitch " , " Redundant bitwise operation on \" " + varname + " \" in switch " ) ;
}
2011-10-13 10:27:22 +02:00
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-02-19 09:33:29 +01:00
void CheckOther : : checkSwitchCaseFallThrough ( )
{
2011-08-07 09:28:08 +02:00
if ( ! ( _settings - > isEnabled ( " style " ) & & _settings - > experimental ) )
2011-03-05 21:42:15 +01:00
return ;
2011-12-09 22:28:10 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
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
2011-12-09 22:28:10 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
2012-01-21 19:55:32 +01:00
if ( i - > type ! = Scope : : eSwitch | | ! i - > classStart ) // Find the beginning of a switch
2011-12-09 22:28:10 +01:00
continue ;
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 ;
2012-01-21 19:55:32 +01:00
for ( const Token * tok2 = i - > classStart ; tok2 ! = i - > classEnd ; 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-12-09 22:28:10 +01:00
} else if ( Token : : simpleMatch ( tok2 , " switch ( " ) ) {
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
}
}
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : switchCaseFallThrough ( const Token * tok )
{
reportError ( tok , Severity : : style ,
" switchCaseFallThrough " , " Switch falls through case without comment " ) ;
}
2011-02-19 09:33:29 +01:00
2010-08-15 06:28:22 +02:00
//---------------------------------------------------------------------------
// int x = 1;
// x = x; // <- redundant assignment to self
//
// int y = y; // <- redundant initialization to self
//---------------------------------------------------------------------------
2012-08-20 17:57:28 +02:00
static bool isTypeWithoutSideEffects ( const Tokenizer * tokenizer , const Variable * var )
2011-12-17 19:04:03 +01:00
{
2012-08-21 20:15:04 +02:00
return ( ( var & & ( ! var - > isClass ( ) | | var - > isPointer ( ) | | Token : : simpleMatch ( var - > typeStartToken ( ) , " std :: " ) ) ) | | ! tokenizer - > isCPP ( ) ) ;
2011-12-17 19:04:03 +01:00
}
2010-08-15 06:28:22 +02:00
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-12-17 19:04:03 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-02-12 14:27:07 +01:00
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 ( ) & &
2012-08-20 17:57:28 +02:00
isTypeWithoutSideEffects ( _tokenizer , symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ) ) {
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 ) {
2012-01-21 19:55:32 +01:00
for ( tok = tok - > tokAt ( 2 ) ; tok ! = endTok ; tok = tok - > next ( ) ) {
2012-04-25 09:56:07 +02:00
if ( tok - > isName ( ) & & ( tok - > next ( ) - > isAssignmentOp ( ) | | tok - > next ( ) - > type ( ) = = Token : : eIncDecOp ) )
2012-01-21 19:55:32 +01:00
assignmentInAssertError ( tok , tok - > str ( ) ) ;
else if ( Token : : Match ( tok , " --|++ %var% " ) )
assignmentInAssertError ( tok , tok - > strAt ( 1 ) ) ;
2010-10-10 22:05:06 +02:00
}
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
//---------------------------------------------------------------------------
2012-03-12 19:06:30 +01:00
enum Position { First , Second , NA } ;
enum Relation { Equal , NotEqual , Less , LessEqual , More , MoreEqual } ;
struct Condition {
Position position ;
const char * opTokStr ;
} ;
static std : : string invertOperatorForOperandSwap ( std : : string s )
{
for ( std : : string : : size_type i = 0 ; i < s . length ( ) ; i + + ) {
if ( s [ i ] = = ' > ' )
s [ i ] = ' < ' ;
else if ( s [ i ] = = ' < ' )
s [ i ] = ' > ' ;
}
return s ;
}
static bool analyzeLogicOperatorCondition ( const Condition & c1 , const Condition & c2 ,
bool inv1 , bool inv2 ,
bool varFirst1 , bool varFirst2 ,
const std : : string & firstConstant , const std : : string & secondConstant ,
const Token * op1Tok , const Token * op3Tok ,
Relation relation )
{
if ( ! ( c1 . position = = NA | | ( c1 . position = = First & & varFirst1 ) | | ( c1 . position = = Second & & ! varFirst1 ) ) )
return false ;
if ( ! ( c2 . position = = NA | | ( c2 . position = = First & & varFirst2 ) | | ( c2 . position = = Second & & ! varFirst2 ) ) )
return false ;
if ( ! Token : : Match ( op1Tok , inv1 ? invertOperatorForOperandSwap ( c1 . opTokStr ) . c_str ( ) : c1 . opTokStr ) )
return false ;
if ( ! Token : : Match ( op3Tok , inv2 ? invertOperatorForOperandSwap ( c2 . opTokStr ) . c_str ( ) : c2 . opTokStr ) )
return false ;
return ( relation = = Equal & & MathLib : : isEqual ( firstConstant , secondConstant ) ) | |
( relation = = NotEqual & & MathLib : : isNotEqual ( firstConstant , secondConstant ) ) | |
( relation = = Less & & MathLib : : isLess ( firstConstant , secondConstant ) ) | |
( relation = = LessEqual & & MathLib : : isLessEqual ( firstConstant , secondConstant ) ) | |
( relation = = More & & MathLib : : isGreater ( firstConstant , secondConstant ) ) | |
( relation = = MoreEqual & & MathLib : : isGreaterEqual ( firstConstant , secondConstant ) ) ;
}
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 ;
2012-03-12 19:06:30 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
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)
2012-03-12 19:06:30 +01:00
const Token * term1Tok = NULL , * term2Tok = NULL ;
2011-07-17 04:06:23 +02:00
const Token * op1Tok = NULL , * op2Tok = NULL , * op3Tok = NULL , * nextTok = NULL ;
2012-03-12 19:06:30 +01:00
if ( Token : : Match ( tok , " ( %any% !=|==|<|>|>=|<= %any% ) &&|%oror% " ) ) {
term1Tok = tok - > next ( ) ;
op1Tok = tok - > tokAt ( 2 ) ;
op2Tok = tok - > tokAt ( 5 ) ;
} else if ( Token : : Match ( tok , " %any% !=|==|<|>|>=|<= %any% &&|%oror% " ) ) {
term1Tok = tok ;
op1Tok = tok - > next ( ) ;
op2Tok = tok - > tokAt ( 3 ) ;
}
if ( op2Tok ) {
if ( Token : : Match ( op2Tok - > next ( ) , " ( %any% !=|==|<|>|>=|<= %any% ) %any% " ) ) {
term2Tok = op2Tok - > tokAt ( 2 ) ;
op3Tok = op2Tok - > tokAt ( 3 ) ;
nextTok = op2Tok - > tokAt ( 6 ) ;
} else if ( Token : : Match ( op2Tok - > next ( ) , " %any% !=|==|<|>|>=|<= %any% %any% " ) ) {
term2Tok = op2Tok - > next ( ) ;
op3Tok = op2Tok - > tokAt ( 2 ) ;
nextTok = op2Tok - > tokAt ( 4 ) ;
}
2010-10-25 03:14:21 +02:00
}
2012-03-12 19:06:30 +01:00
if ( nextTok ) {
2010-11-21 09:06:43 +01:00
// Find the common variable and the two different-valued constants
std : : string firstConstant , secondConstant ;
2011-07-17 04:06:23 +02:00
bool varFirst1 , varFirst2 ;
unsigned int varId ;
2012-03-15 20:38:28 +01:00
const Token * var1Tok = NULL , * var2Tok = NULL ;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( term1Tok , " %var% %any% %num% " ) ) {
2012-03-15 20:38:28 +01:00
var1Tok = term1Tok ;
varId = var1Tok - > varId ( ) ;
2011-10-13 20:53:06 +02:00
if ( ! varId ) {
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% " ) ) {
2012-03-15 20:38:28 +01:00
var1Tok = term1Tok - > tokAt ( 2 ) ;
varId = var1Tok - > varId ( ) ;
2011-10-13 20:53:06 +02:00
if ( ! varId ) {
2011-07-17 04:06:23 +02:00
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
continue ;
}
2010-11-21 09:06:43 +01:00
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( term2Tok , " %var% %any% %num% " ) ) {
2012-03-15 20:38:28 +01:00
var2Tok = term2Tok ;
2011-07-17 04:06:23 +02:00
varFirst2 = true ;
2011-11-13 13:10:59 +01:00
secondConstant = term2Tok - > strAt ( 2 ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( term2Tok , " %num% %any% %var% " ) ) {
2012-03-15 20:38:28 +01:00
var2Tok = term2Tok - > tokAt ( 2 ) ;
2011-07-17 04:06:23 +02:00
varFirst2 = false ;
secondConstant = term2Tok - > str ( ) ;
2011-10-13 20:53:06 +02:00
} else {
2011-07-17 04:06:23 +02:00
continue ;
2010-10-25 03:14:21 +02:00
}
2010-11-21 09:06:43 +01:00
2012-03-15 20:38:28 +01:00
if ( varId ! = var2Tok - > varId ( ) | | firstConstant . empty ( ) | | secondConstant . empty ( ) ) {
2011-07-17 04:06:23 +02:00
continue ;
}
2012-03-12 19:06:30 +01:00
enum LogicError { AlwaysFalse , AlwaysTrue , FirstTrue , FirstFalse , SecondTrue , SecondFalse } ;
static const struct LinkedConditions {
2011-07-17 04:06:23 +02:00
const char * before ;
2012-03-12 19:06:30 +01:00
Condition c1 ;
2011-07-17 04:06:23 +02:00
const char * op2TokStr ;
2012-03-12 19:06:30 +01:00
Condition c2 ;
2011-07-17 04:06:23 +02:00
const char * after ;
Relation relation ;
2011-08-19 19:28:37 +02:00
LogicError error ;
2011-10-13 20:53:06 +02:00
} conditions [ ] = {
2012-03-15 20:38:28 +01:00
{ " !!&& " , { NA , " != " } , " %oror% " , { NA , " != " } , " !!&& " , NotEqual , AlwaysTrue } , // (x != 1) || (x != 3) <- always true
{ 0 , { NA , " == " } , " && " , { NA , " == " } , 0 , NotEqual , AlwaysFalse } , // (x == 1) && (x == 3) <- always false
{ " !!&& " , { First , " > " } , " %oror% " , { First , " < " } , " !!&& " , Less , AlwaysTrue } , // (x > 3) || (x < 10) <- always true
{ " !!&& " , { First , " >= " } , " %oror% " , { First , " <|<= " } , " !!&& " , LessEqual , AlwaysTrue } , // (x >= 3) || (x < 10) <- always true
{ " !!&& " , { First , " > " } , " %oror% " , { First , " <= " } , " !!&& " , LessEqual , AlwaysTrue } , // (x > 3) || (x <= 10) <- always true
{ 0 , { First , " < " } , " && " , { First , " > " } , 0 , LessEqual , AlwaysFalse } , // (x < 1) && (x > 3) <- always false
{ 0 , { First , " <= " } , " && " , { First , " >|>= " } , 0 , Less , AlwaysFalse } , // (x <= 1) && (x > 3) <- always false
{ 0 , { First , " < " } , " && " , { First , " >= " } , 0 , Less , AlwaysFalse } , // (x < 1) && (x >= 3) <- always false
{ 0 , { First , " > " } , " && " , { NA , " == " } , 0 , MoreEqual , AlwaysFalse } , // (x > 5) && (x == 1) <- always false
{ 0 , { First , " < " } , " && " , { NA , " == " } , 0 , LessEqual , AlwaysFalse } , // (x < 1) && (x == 3) <- always false
{ 0 , { First , " >= " } , " && " , { NA , " == " } , 0 , More , AlwaysFalse } , // (x >= 5) && (x == 1) <- always false
{ 0 , { First , " <= " } , " && " , { NA , " == " } , 0 , Less , AlwaysFalse } , // (x <= 1) && (x == 3) <- always false
2012-07-13 15:01:19 +02:00
{ " !!&& " , { NA , " == " } , " %oror% " , { First , " > " } , " !!&& " , More , SecondTrue } , // (x == 4) || (x > 3) <- second expression always true
{ " !!&& " , { NA , " == " } , " %oror% " , { First , " < " } , " !!&& " , Less , SecondTrue } , // (x == 4) || (x < 5) <- second expression always true
{ " !!&& " , { NA , " == " } , " %oror% " , { First , " >= " } , " !!&& " , MoreEqual , SecondTrue } , // (x == 4) || (x >= 3) <- second expression always true
{ " !!&& " , { NA , " == " } , " %oror% " , { First , " <= " } , " !!&& " , LessEqual , SecondTrue } , // (x == 4) || (x <= 5) <- second expression always true
2012-03-15 20:38:28 +01:00
{ " !!&& " , { First , " > " } , " %oror% " , { NA , " != " } , " !!&& " , MoreEqual , SecondTrue } , // (x > 5) || (x != 1) <- second expression always true
{ " !!&& " , { First , " < " } , " %oror% " , { NA , " != " } , " !!&& " , LessEqual , SecondTrue } , // (x < 1) || (x != 3) <- second expression always true
{ " !!&& " , { First , " >= " } , " %oror% " , { NA , " != " } , " !!&& " , More , SecondTrue } , // (x >= 5) || (x != 1) <- second expression always true
{ " !!&& " , { First , " <= " } , " %oror% " , { NA , " != " } , " !!&& " , Less , SecondTrue } , // (x <= 1) || (x != 3) <- second expression always true
{ 0 , { First , " > " } , " && " , { NA , " != " } , 0 , MoreEqual , SecondTrue } , // (x > 5) && (x != 1) <- second expression always true
{ 0 , { First , " < " } , " && " , { NA , " != " } , 0 , LessEqual , SecondTrue } , // (x < 1) && (x != 3) <- second expression always true
{ 0 , { First , " >= " } , " && " , { NA , " != " } , 0 , More , SecondTrue } , // (x >= 5) && (x != 1) <- second expression always true
{ 0 , { First , " <= " } , " && " , { NA , " != " } , 0 , Less , SecondTrue } , // (x <= 1) && (x != 3) <- second expression always true
{ " !!&& " , { First , " >|>= " } , " %oror% " , { First , " >|>= " } , " !!&& " , LessEqual , SecondTrue } , // (x > 4) || (x > 5) <- second expression always true
{ " !!&& " , { First , " <|<= " } , " %oror% " , { First , " <|<= " } , " !!&& " , MoreEqual , SecondTrue } , // (x < 5) || (x < 4) <- second expression always true
2012-06-15 16:54:02 +02:00
{ 0 , { First , " >|>= " } , " && " , { First , " >|>= " } , 0 , MoreEqual , SecondTrue } , // (x > 4) && (x > 5) <- second expression always true
2012-03-15 20:38:28 +01:00
{ 0 , { First , " <|<= " } , " && " , { First , " <|<= " } , 0 , MoreEqual , SecondTrue } , // (x < 5) && (x < 4) <- second expression always true
2012-09-01 13:39:32 +02:00
{ 0 , { NA , " == " } , " && " , { NA , " != " } , 0 , NotEqual , SecondTrue } , // (x == 3) && (x != 4) <- second expression always true
{ " !!&& " , { NA , " == " } , " %oror% " , { NA , " != " } , " !!&& " , NotEqual , SecondTrue } , // (x == 3) || (x != 4) <- second expression always true
{ 0 , { NA , " != " } , " && " , { NA , " == " } , 0 , Equal , AlwaysFalse } , // (x != 3) && (x == 3) <- expression always false
{ " !!&& " , { NA , " != " } , " %oror% " , { NA , " == " } , " !!&& " , Equal , AlwaysTrue } , // (x != 3) || (x == 3) <- expression always true
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 22:28:00 +02:00
if ( ! Token : : Match ( op2Tok , conditions [ i ] . op2TokStr ) )
2011-07-17 04:06:23 +02:00
continue ;
2012-03-12 19:06:30 +01:00
if ( conditions [ i ] . before ! = 0 & & ! Token : : Match ( tok - > previous ( ) , conditions [ i ] . before ) )
2011-07-17 04:06:23 +02:00
continue ;
2012-03-12 19:06:30 +01:00
if ( conditions [ i ] . after ! = 0 & & ! Token : : Match ( nextTok , conditions [ i ] . after ) )
2011-07-17 04:06:23 +02:00
continue ;
2012-04-02 11:21:04 +02:00
if ( tok - > previous ( ) - > isArithmeticalOp ( ) | | nextTok - > isArithmeticalOp ( ) )
continue ;
2012-03-15 20:38:28 +01:00
std : : string cond1str = var1Tok - > str ( ) + " " + ( varFirst1 ? op1Tok - > str ( ) : invertOperatorForOperandSwap ( op1Tok - > str ( ) ) ) + " " + firstConstant ;
std : : string cond2str = var2Tok - > str ( ) + " " + ( varFirst2 ? op3Tok - > str ( ) : invertOperatorForOperandSwap ( op3Tok - > str ( ) ) ) + " " + secondConstant ;
2012-03-12 19:06:30 +01:00
// cond1 op cond2
bool error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , false , false ,
varFirst1 , varFirst2 , firstConstant , secondConstant ,
op1Tok , op3Tok ,
conditions [ i ] . relation ) ;
// inv(cond1) op cond2 // invert first condition
if ( ! error & & conditions [ i ] . c1 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , true , false ,
! varFirst1 , varFirst2 , firstConstant , secondConstant ,
op1Tok , op3Tok ,
conditions [ i ] . relation ) ;
// cond1 op inv(cond2) // invert second condition
if ( ! error & & conditions [ i ] . c2 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , false , true ,
varFirst1 , ! varFirst2 , firstConstant , secondConstant ,
op1Tok , op3Tok ,
conditions [ i ] . relation ) ;
// inv(cond1) op inv(cond2) // invert both conditions
if ( ! error & & conditions [ i ] . c1 . position ! = NA & & conditions [ i ] . c2 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , true , true ,
! varFirst1 , ! varFirst2 , firstConstant , secondConstant ,
op1Tok , op3Tok ,
conditions [ i ] . relation ) ;
2012-03-15 20:38:28 +01:00
if ( ! error )
std : : swap ( cond1str , cond2str ) ;
2012-03-12 19:06:30 +01:00
// cond2 op cond1 // swap conditions
if ( ! error )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , false , false ,
varFirst2 , varFirst1 , secondConstant , firstConstant ,
op3Tok , op1Tok ,
conditions [ i ] . relation ) ;
// cond2 op inv(cond1) // swap conditions; invert first condition
if ( ! error & & conditions [ i ] . c1 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , true , false ,
! varFirst2 , varFirst1 , secondConstant , firstConstant ,
op3Tok , op1Tok ,
conditions [ i ] . relation ) ;
// inv(cond2) op cond1 // swap conditions; invert second condition
if ( ! error & & conditions [ i ] . c2 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , false , true ,
varFirst2 , ! varFirst1 , secondConstant , firstConstant ,
op3Tok , op1Tok ,
conditions [ i ] . relation ) ;
// inv(cond2) op inv(cond1) // swap conditions; invert both conditions
if ( ! error & & conditions [ i ] . c1 . position ! = NA & & conditions [ i ] . c2 . position ! = NA )
error = analyzeLogicOperatorCondition ( conditions [ i ] . c1 , conditions [ i ] . c2 , true , true ,
! varFirst2 , ! varFirst1 , secondConstant , firstConstant ,
op3Tok , op1Tok ,
conditions [ i ] . relation ) ;
if ( error ) {
2012-03-15 20:38:28 +01:00
if ( conditions [ i ] . error = = AlwaysFalse | | conditions [ i ] . error = = AlwaysTrue ) {
const std : : string text = cond1str + " " + op2Tok - > str ( ) + " " + cond2str ;
incorrectLogicOperatorError ( term1Tok , text , conditions [ i ] . error = = AlwaysTrue ) ;
} else {
const std : : string text = " If " + cond1str + " , the comparison " + cond2str +
2012-03-15 21:06:24 +01:00
" is always " + ( ( conditions [ i ] . error = = SecondTrue | | conditions [ i ] . error = = AlwaysTrue ) ? " true " : " false " ) + " . " ;
2012-03-15 20:38:28 +01:00
redundantConditionError ( term1Tok , text ) ;
2011-08-19 19:28:37 +02:00
}
2012-03-12 19:06:30 +01:00
break ;
2011-08-19 19:28:37 +02:00
}
2010-10-25 03:14:21 +02:00
}
}
}
}
2012-03-15 20:38:28 +01:00
void CheckOther : : incorrectLogicOperatorError ( const Token * tok , const std : : string & condition , bool always )
2011-08-19 17:53:43 +02:00
{
if ( always )
2012-03-15 20:38:28 +01:00
reportError ( tok , Severity : : warning , " incorrectLogicOperator " ,
" Logical disjunction always evaluates to true: " + condition + " . \n "
" Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables? " ) ;
2011-08-19 17:53:43 +02:00
else
2012-03-15 20:38:28 +01:00
reportError ( tok , Severity : : warning , " incorrectLogicOperator " ,
" Logical conjunction always evaluates to false: " + condition + " . \n "
" Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables? " ) ;
2011-08-19 17:53:43 +02:00
}
2012-03-15 20:38:28 +01:00
void CheckOther : : redundantConditionError ( const Token * tok , const std : : string & text )
2011-08-19 19:28:37 +02:00
{
2012-03-15 20:38:28 +01:00
reportError ( tok , Severity : : style , " redundantCondition " , " Redundant condition: " + text ) ;
2011-08-19 19:28:37 +02:00
}
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 ;
2012-03-03 21:14:20 +01:00
tok = tok - > tokAt ( 2 ) ;
2009-01-26 20:14:46 +01:00
// Locate the third parameter of the function call..
2012-03-03 21:14:20 +01:00
for ( int i = 0 ; i < 2 & & tok ; i + + )
tok = tok - > nextArgument ( ) ;
if ( Token : : Match ( tok , " %num% ) " ) ) {
const MathLib : : bigint radix = MathLib : : toLongNumber ( tok - > str ( ) ) ;
if ( ! ( radix = = 0 | | ( radix > = 2 & & radix < = 36 ) ) ) {
dangerousUsageStrtolError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
2012-03-03 21:14:20 +01:00
} else
break ;
2009-01-26 20:14:46 +01:00
}
// 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 ) ;
2011-11-26 21:15:16 +01:00
while ( tok2 - > str ( ) ! = " , " )
2009-01-26 20:14:46 +01:00
tok2 = tok2 - > next ( ) ;
2011-11-26 21:15:16 +01:00
tok2 = tok2 - > next ( ) ; // Jump behind ","
if ( tok - > str ( ) = = " snprintf " ) { // Jump over second parameter for snprintf
tok2 = tok2 - > nextArgument ( ) ;
if ( ! tok2 )
continue ;
}
2009-01-26 20:14:46 +01:00
// is any source buffer overlapping the target buffer?
2011-11-26 21:15:16 +01:00
do {
if ( 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-12-01 10:48:14 +01:00
} while ( NULL ! = ( tok2 = tok2 - > nextArgument ( ) ) ) ;
2009-01-26 20:14:46 +01:00
}
}
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.' " ) ;
}
//---------------------------------------------------------------------------
2011-02-27 21:30:22 +01:00
// if (!x==3) <- Probably meant to be "x!=3"
//---------------------------------------------------------------------------
2012-03-03 21:14:20 +01:00
static bool isBool ( const Variable * var )
{
return ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " ) ;
}
static bool isNonBoolStdType ( const Variable * var )
{
return ( var & & var - > typeEndToken ( ) - > isStandardType ( ) & & var - > typeEndToken ( ) - > str ( ) ! = " bool " ) ;
}
2011-02-27 21:30:22 +01:00
void CheckOther : : checkComparisonOfBoolWithInt ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-02-27 21:30:22 +01:00
return ;
2012-03-03 21:14:20 +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 ( ) ) {
2012-04-26 23:04:55 +02:00
if ( tok - > next ( ) & & tok - > next ( ) - > type ( ) = = Token : : eComparisonOp & & ( ! tok - > previous ( ) | | ! tok - > previous ( ) - > isArithmeticalOp ( ) ) & & ( ! tok - > tokAt ( 3 ) | | ! tok - > tokAt ( 3 ) - > isArithmeticalOp ( ) ) ) {
2012-04-02 15:45:51 +02:00
const Token * const right = tok - > tokAt ( 2 ) ;
if ( ( tok - > varId ( ) & & right - > isNumber ( ) ) | | ( tok - > isNumber ( ) & & right - > varId ( ) ) ) { // Comparing variable with number
const Token * varTok = tok ;
const Token * numTok = right ;
if ( tok - > isNumber ( ) & & right - > varId ( ) ) // num with var
std : : swap ( varTok , numTok ) ;
if ( isBool ( symbolDatabase - > getVariableFromVarId ( varTok - > varId ( ) ) ) & & // Variable has to be a boolean
( ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) | |
( MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 0 & & MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 1 ) ) ) { // == 0 and != 0 are allowed, for C also == 1 and != 1
comparisonOfBoolWithIntError ( varTok , numTok - > str ( ) , tok - > strAt ( 1 ) = = " == " | | tok - > strAt ( 1 ) = = " != " ) ;
}
} else if ( tok - > isBoolean ( ) & & right - > varId ( ) ) { // Comparing boolean constant with variable
if ( isNonBoolStdType ( symbolDatabase - > getVariableFromVarId ( right - > varId ( ) ) ) ) { // Variable has to be of non-boolean standard type
comparisonOfBoolWithIntError ( right , tok - > str ( ) , false ) ;
2012-07-03 06:39:13 +02:00
} else if ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , tok - > str ( ) ) ;
2012-04-02 15:45:51 +02:00
}
} else if ( tok - > varId ( ) & & right - > isBoolean ( ) ) { // Comparing variable with boolean constant
if ( isNonBoolStdType ( symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ) ) { // Variable has to be of non-boolean standard type
comparisonOfBoolWithIntError ( tok , right - > str ( ) , false ) ;
2012-07-03 06:39:13 +02:00
} else if ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , tok - > str ( ) ) ;
2012-04-02 15:45:51 +02:00
}
} else if ( tok - > isNumber ( ) & & right - > isBoolean ( ) ) { // number constant with boolean constant
comparisonOfBoolWithIntError ( tok , right - > str ( ) , false ) ;
} else if ( tok - > isBoolean ( ) & & right - > isNumber ( ) ) { // number constant with boolean constant
comparisonOfBoolWithIntError ( tok , tok - > str ( ) , false ) ;
} else if ( tok - > varId ( ) & & right - > varId ( ) ) { // Comparing two variables, one of them boolean, one of them integer
const Variable * var1 = symbolDatabase - > getVariableFromVarId ( right - > varId ( ) ) ;
const Variable * var2 = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
if ( isBool ( var1 ) & & isNonBoolStdType ( var2 ) ) // Comparing boolean with non-bool standard type
comparisonOfBoolWithIntError ( tok , var1 - > name ( ) , false ) ;
else if ( isNonBoolStdType ( var1 ) & & isBool ( var2 ) ) // Comparing non-bool standard type with boolean
comparisonOfBoolWithIntError ( tok , var2 - > name ( ) , false ) ;
2011-02-27 21:30:22 +01:00
}
}
}
}
2012-04-02 15:45:51 +02:00
void CheckOther : : comparisonOfBoolWithIntError ( const Token * tok , const std : : string & expression , bool n0o1 )
2011-08-19 17:53:43 +02:00
{
2012-04-02 15:45:51 +02:00
if ( n0o1 )
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInt " ,
" Comparison of a boolean with an 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. " ) ;
else
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInt " ,
" Comparison of a boolean with an integer \n "
" The expression \" " + expression + " \" is of type 'bool' "
" and it is compared against a integer value. " ) ;
2011-08-19 17:53:43 +02:00
}
2012-07-03 06:39:13 +02:00
void CheckOther : : comparisonOfBoolWithInvalidComparator ( const Token * tok , const std : : string & expression )
{
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInvalidComparator " ,
" Comparison of a boolean value using relational (<, >, <= or >=) operator. \n "
" The expression \" " + expression + " \" is of type 'bool' "
" and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) "
" operator could cause unexpected results. " ) ;
}
2011-07-15 02:12:56 +02:00
//---------------------------------------------------------------------------
2011-12-03 11:43:23 +01:00
// Find consecutive return, break, continue, goto or throw statements. e.g.:
// break; break;
// Detect dead code, that follows such a statement. e.g.:
// return(0); foo();
2011-07-15 02:12:56 +02:00
//---------------------------------------------------------------------------
2011-12-03 11:43:23 +01:00
void CheckOther : : checkUnreachableCode ( )
2011-07-15 02:12:56 +02:00
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2011-07-15 02:12:56 +02:00
return ;
2011-12-03 11:43:23 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
const Token * secondBreak = 0 ;
2011-12-31 23:11:03 +01:00
const Token * labelName = 0 ;
2011-12-07 18:20:52 +01:00
if ( tok - > str ( ) = = " ( " )
tok = tok - > link ( ) ;
else if ( Token : : Match ( tok , " break|continue ; " ) )
2011-12-03 11:43:23 +01:00
secondBreak = tok - > tokAt ( 2 ) ;
2011-12-07 18:20:52 +01:00
else if ( Token : : Match ( tok , " [;{}:] return|throw " ) ) {
tok = tok - > next ( ) ; // tok should point to return or throw
2011-12-03 11:43:23 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
if ( tok2 - > str ( ) = = " ; " ) {
2011-12-07 18:20:52 +01:00
secondBreak = tok2 - > next ( ) ;
2011-12-03 11:43:23 +01:00
break ;
}
2011-12-31 23:11:03 +01:00
} else if ( Token : : Match ( tok , " goto %any% ; " ) ) {
2011-12-03 11:43:23 +01:00
secondBreak = tok - > tokAt ( 3 ) ;
2012-05-19 10:51:47 +02:00
labelName = tok - > next ( ) ;
2011-12-31 23:11:03 +01:00
}
2011-12-03 11:43:23 +01:00
2012-04-05 10:38:29 +02:00
// Statements follow directly, no line between them. (#3383)
// TODO: Try to find a better way to avoid false positives due to preprocessor configurations.
bool inconclusive = secondBreak & & ( secondBreak - > linenr ( ) - 1 > secondBreak - > previous ( ) - > linenr ( ) ) ;
if ( secondBreak & & ( _settings - > inconclusive | | ! inconclusive ) ) {
2011-12-03 11:43:23 +01:00
if ( Token : : Match ( secondBreak , " continue|goto|throw " ) | |
( secondBreak - > str ( ) = = " return " & & ( tok - > str ( ) = = " return " | | secondBreak - > strAt ( 1 ) = = " ; " ) ) ) { // return with value after statements like throw can be necessary to make a function compile
2012-04-05 10:38:29 +02:00
duplicateBreakError ( secondBreak , inconclusive ) ;
2011-12-03 11:43:23 +01:00
tok = Token : : findmatch ( secondBreak , " [}:] " ) ;
} else if ( secondBreak - > str ( ) = = " break " ) { // break inside switch as second break statement should not issue a warning
if ( tok - > str ( ) = = " break " ) // If the previous was a break, too: Issue warning
2012-04-05 10:38:29 +02:00
duplicateBreakError ( secondBreak , inconclusive ) ;
2011-12-03 11:43:23 +01:00
else {
2012-08-12 12:13:07 +02:00
if ( tok - > scope ( ) - > type ! = Scope : : eSwitch ) // Check, if the enclosing scope is a switch
duplicateBreakError ( secondBreak , inconclusive ) ;
2011-12-03 11:43:23 +01:00
}
tok = Token : : findmatch ( secondBreak , " [}:] " ) ;
} else if ( ! Token : : Match ( secondBreak , " return|}|case|default " ) & & secondBreak - > strAt ( 1 ) ! = " : " ) { // TODO: No bailout for unconditional scopes
2011-12-31 23:11:03 +01:00
// If the goto label is followed by a loop construct in which the label is defined it's quite likely
// that the goto jump was intended to skip some code on the first loop iteration.
bool labelInFollowingLoop = false ;
if ( labelName & & Token : : Match ( secondBreak , " while|do|for " ) ) {
2012-01-21 19:55:32 +01:00
const Token * scope = Token : : findsimplematch ( secondBreak , " { " ) ;
2011-12-31 23:11:03 +01:00
if ( scope ) {
for ( const Token * tokIter = scope ; tokIter ! = scope - > link ( ) & & tokIter ; tokIter = tokIter - > next ( ) ) {
if ( Token : : Match ( tokIter , " [;{}] %any% : " ) & & labelName - > str ( ) = = tokIter - > strAt ( 1 ) ) {
labelInFollowingLoop = true ;
break ;
}
}
}
}
if ( ! labelInFollowingLoop )
2012-04-05 10:38:29 +02:00
unreachableCodeError ( secondBreak , inconclusive ) ;
2011-12-03 11:43:23 +01:00
tok = Token : : findmatch ( secondBreak , " [}:] " ) ;
} else
tok = secondBreak ;
2011-12-23 12:46:59 +01:00
if ( ! tok )
break ;
2011-12-03 11:43:23 +01:00
}
2011-07-15 02:12:56 +02:00
}
}
2012-04-05 10:38:29 +02:00
void CheckOther : : duplicateBreakError ( const Token * tok , bool inconclusive )
2010-08-14 15:15:12 +02:00
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : style , " duplicateBreak " ,
" Consecutive return, break, continue, goto or throw statements are unnecessary. \n "
" The second of the two statements can never be executed, and so should be removed. " , inconclusive ) ;
2010-08-14 15:15:12 +02:00
}
2009-01-26 20:14:46 +01:00
2012-04-05 10:38:29 +02:00
void CheckOther : : unreachableCodeError ( const Token * tok , bool inconclusive )
2011-12-03 11:43:23 +01:00
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : style , " unreachableCode " ,
" Statements following return, break, continue, goto or throw will never be executed. " , inconclusive ) ;
2011-12-03 11:43:23 +01:00
}
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
// Check for unsigned divisions
//---------------------------------------------------------------------------
2011-12-17 19:04:03 +01:00
static bool isUnsigned ( const Variable * var )
{
2012-01-28 12:32:28 +01:00
return ( var & & var - > typeStartToken ( ) - > isUnsigned ( ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) ) ;
}
static bool isSigned ( const Variable * var )
{
return ( var & & ! var - > typeStartToken ( ) - > isUnsigned ( ) & & Token : : Match ( var - > typeEndToken ( ) , " int|char|short|long " ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) ) ;
2011-12-17 19:04:03 +01:00
}
2009-07-05 22:16:43 +02:00
void CheckOther : : checkUnsignedDivision ( )
2009-01-26 20:14:46 +01:00
{
2011-12-17 19:04:03 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-01-28 12:32:28 +01:00
bool style = _settings - > isEnabled ( " style " ) ;
2011-12-17 19:04:03 +01:00
2012-01-28 12:32:28 +01:00
const Token * ifTok = 0 ;
2009-01-26 20:14:46 +01:00
// Check for "ivar / uvar" and "uvar / ivar"
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2012-01-28 12:32:28 +01:00
if ( Token : : Match ( tok , " [).] " ) ) // Don't check members or casted variables
continue ;
if ( Token : : Match ( tok - > next ( ) , " %var% / %num% " ) ) {
2011-12-17 19:04:03 +01:00
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' & & isUnsigned ( symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ) ) {
2012-01-28 12:32:28 +01:00
udivError ( tok - > next ( ) , false ) ;
2009-01-26 20:14:46 +01:00
}
2012-01-28 12:32:28 +01:00
} else if ( Token : : Match ( tok - > next ( ) , " %num% / %var% " ) ) {
2011-12-17 19:04:03 +01:00
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' & & isUnsigned ( symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ) ) {
2012-01-28 12:32:28 +01:00
udivError ( tok - > next ( ) , false ) ;
2009-01-26 20:14:46 +01:00
}
2012-01-28 12:32:28 +01:00
} else if ( Token : : Match ( tok - > next ( ) , " %var% / %var% " ) & & _settings - > inconclusive & & style & & ! ifTok ) {
const Variable * var1 = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
const Variable * var2 = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( ( isUnsigned ( var1 ) & & isSigned ( var2 ) ) | | ( isUnsigned ( var2 ) & & isSigned ( var1 ) ) ) {
udivError ( tok - > next ( ) , true ) ;
}
2012-01-28 20:31:12 +01:00
} else if ( ! ifTok & & Token : : simpleMatch ( tok , " if ( " ) )
2012-01-28 12:32:28 +01:00
ifTok = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
else if ( ifTok = = tok )
ifTok = 0 ;
2009-01-26 20:14:46 +01:00
}
}
2011-01-06 11:31:58 +01:00
2012-01-28 12:32:28 +01:00
void CheckOther : : udivError ( const Token * tok , bool inconclusive )
2011-08-19 17:53:43 +02:00
{
2012-01-28 12:32:28 +01:00
if ( inconclusive )
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : warning , " udivError " , " Division with signed and unsigned operators. The result might be wrong. " , true ) ;
2012-01-28 12:32:28 +01:00
else
reportError ( tok , Severity : : error , " udivError " , " Unsigned division. The result will be wrong. " ) ;
2011-08-19 17:53:43 +02:00
}
2011-01-06 11:31:58 +01:00
//---------------------------------------------------------------------------
// memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
//---------------------------------------------------------------------------
void CheckOther : : checkMemsetZeroBytes ( )
{
2011-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
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
2012-05-24 15:34:59 +02:00
for ( unsigned int i = 1 ; i < symbolDatabase - > getVariableListSize ( ) ; i + + ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( i ) ;
2012-08-20 17:57:28 +02:00
if ( ! var | | ! var - > isLocal ( ) | | ( ! var - > isPointer ( ) & & ! var - > typeStartToken ( ) - > isStandardType ( ) & & ! var - > typeStartToken ( ) - > next ( ) - > isStandardType ( ) ) )
2010-12-16 19:04:47 +01:00
continue ;
2012-05-24 15:34:59 +02:00
bool forHead = false ; // Don't check variables declared in header of a for loop
for ( const Token * tok = var - > typeStartToken ( ) ; tok ; tok = tok - > previous ( ) ) {
if ( tok - > str ( ) = = " ( " ) {
forHead = true ;
break ;
} else if ( tok - > str ( ) = = " { " || tok->str() == " ; " || tok->str() == " } " )
break ;
2009-01-26 20:14:46 +01:00
}
2012-05-24 15:34:59 +02:00
if ( forHead )
continue ;
const Token * tok = var - > nameToken ( ) - > next ( ) ;
if ( Token : : Match ( tok , " ; %varid% = %any% ; " , var - > varId ( ) ) ) {
tok = tok - > tokAt ( 3 ) ;
if ( ! tok - > isNumber ( ) & & tok - > type ( ) ! = Token : : eString & & tok - > type ( ) ! = Token : : eChar & & ! tok - > isBoolean ( ) )
continue ;
2012-07-29 15:50:05 +02:00
} else if ( ( tok - > str ( ) = = " = " | | tok - > str ( ) = = " ( " ) & &
2012-05-24 15:34:59 +02:00
( ( ! tok - > next ( ) - > isNumber ( ) & & tok - > next ( ) - > type ( ) ! = Token : : eString & & tok - > next ( ) - > type ( ) ! = Token : : eChar & & ! tok - > next ( ) - > isBoolean ( ) ) | | tok - > strAt ( 2 ) ! = " ; " ) )
continue ;
lookupVar ( tok , var ) ;
2009-01-26 20:14:46 +01:00
}
}
2012-05-24 15:34:59 +02:00
void CheckOther : : lookupVar ( const Token * tok , const Variable * var )
2009-01-26 20:14:46 +01:00
{
// 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 ) = = " = " ) {
2012-05-24 15:34:59 +02:00
if ( Token : : findmatch ( tok , " %varid% " , tok - > link ( ) , var - > varId ( ) ) ) {
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
2012-05-24 15:34:59 +02:00
else if ( Token : : Match ( tok , " & %varid% " , var - > varId ( ) ) ) {
2009-05-27 19:38:26 +02:00
return ;
}
2009-01-26 20:14:46 +01:00
2012-05-24 15:34:59 +02:00
else if ( tok - > varId ( ) = = var - > varId ( ) ) {
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2010-01-21 18:50:56 +01:00
return ;
2012-05-24 15:34:59 +02:00
if ( tok - > strAt ( - 1 ) = = " = " & & ( var - > isArray ( ) | | var - > isPointer ( ) ) ) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
return ;
2010-01-21 18:50:56 +01:00
used1 = true ;
2012-03-11 11:01:39 +01:00
if ( for_or_while & & tok - > strAt ( 1 ) ! = " = " )
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
2012-03-11 11:01:39 +01:00
if ( tok - > strAt ( 1 ) = = " ( " & &
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 )
2012-05-24 15:34:59 +02:00
variableScopeError ( var - > nameToken ( ) , var - > name ( ) ) ;
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 ( ) ;
2012-05-24 17:40:43 +02:00
for ( unsigned int i = 1 ; i < symbolDatabase - > getVariableListSize ( ) ; i + + ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( i ) ;
if ( ! var | | ! var - > isArgument ( ) | | ! var - > isClass ( ) | | ! var - > isConst ( ) | | var - > isPointer ( ) | | var - > isArray ( ) | | var - > isReference ( ) )
continue ;
2012-06-08 18:05:02 +02:00
const Token * const tok = var - > typeStartToken ( ) ;
2012-05-24 17:40:43 +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).
if ( Token : : Match ( tok , " std :: string|wstring " ) ) {
passedByValueError ( tok , var - > name ( ) ) ;
2012-07-23 10:41:20 +02:00
} else if ( Token : : Match ( tok , " std :: %type% < " ) & & ! Token : : Match ( tok - > linkAt ( 3 ) , " > :: " ) ) {
2012-05-24 17:40:43 +02:00
passedByValueError ( tok , var - > name ( ) ) ;
} else if ( var - > type ( ) | | symbolDatabase - > isClassOrStruct ( tok - > str ( ) ) ) { // Check if type is a struct or class.
passedByValueError ( tok , var - > name ( ) ) ;
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..
//---------------------------------------------------------------------------
2012-01-28 12:32:28 +01:00
static bool isChar ( const Variable * var )
{
2012-06-08 18:05:02 +02:00
return ( var & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & var - > typeStartToken ( ) - > str ( ) = = " char " ) ;
2012-01-28 12:32:28 +01:00
}
2011-12-17 19:04:03 +01:00
static bool isSignedChar ( const Variable * var )
{
2012-08-20 17:57:28 +02:00
return ( isChar ( var ) & & ! var - > typeStartToken ( ) - > isUnsigned ( ) ) ;
2011-12-17 19:04:03 +01:00
}
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 ( ) ) {
2011-12-17 19:04:03 +01:00
if ( ( tok - > str ( ) ! = " . " ) & & Token : : Match ( tok - > next ( ) , " %var% [ %var% ] " ) ) {
2012-03-10 12:19:28 +01:00
const Variable * arrayvar = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
const Variable * indexvar = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
const MathLib : : bigint arraysize = ( arrayvar & & arrayvar - > isArray ( ) ) ? arrayvar - > dimension ( 0U ) : 0 ;
if ( isSignedChar ( indexvar ) & & arraysize > 0x80 )
2011-12-17 19:04:03 +01:00
charArrayIndexError ( tok - > next ( ) ) ;
}
2009-01-26 20:14:46 +01:00
2012-04-25 09:56:07 +02:00
else if ( Token : : Match ( tok , " [;{}] %var% = %any% [&^|] %any% ; " ) ) {
2011-12-17 19:04:03 +01:00
// is a char variable used in the calculation?
if ( ! isSignedChar ( symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 3 ) - > varId ( ) ) ) & &
! isSignedChar ( symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 5 ) - > varId ( ) ) ) )
2011-11-06 11:26:28 +01:00
continue ;
2011-12-17 19:04:03 +01:00
// it's ok with a bitwise and where the other operand is 0xff or less..
if ( tok - > strAt ( 4 ) = = " & " ) {
if ( tok - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok - > strAt ( 3 ) ) )
continue ;
if ( tok - > tokAt ( 5 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok - > strAt ( 5 ) ) )
continue ;
}
2009-06-20 19:24:58 +02:00
2011-12-17 19:04:03 +01:00
// is the result stored in a short|int|long?
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & Token : : Match ( var - > typeStartToken ( ) , " short|int|long " ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) )
2012-02-26 11:56:32 +01:00
charBitOpError ( tok - > tokAt ( 4 ) ) ; // This is an error..
2011-12-17 19:04:03 +01:00
}
2011-07-05 18:41:27 +02:00
2012-04-25 09:56:07 +02:00
else if ( Token : : Match ( tok , " [;{}] %var% = %any% [&^|] ( * %var% ) ; " ) ) {
2011-12-17 19:04:03 +01:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 7 ) - > varId ( ) ) ;
2012-06-09 08:43:13 +02:00
if ( ! var | | ! var - > isPointer ( ) | | var - > typeStartToken ( ) - > str ( ) ! = " char " | | var - > typeStartToken ( ) - > isUnsigned ( ) )
2011-12-17 19:04:03 +01:00
continue ;
// it's ok with a bitwise and where the other operand is 0xff or less..
if ( tok - > strAt ( 4 ) = = " & " & & tok - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok - > strAt ( 3 ) ) )
continue ;
2011-07-05 18:41:27 +02:00
2011-12-17 19:04:03 +01:00
// is the result stored in a short|int|long?
var = symbolDatabase - > getVariableFromVarId ( tok - > next ( ) - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & Token : : Match ( var - > typeStartToken ( ) , " short|int|long " ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) )
2012-02-26 11:56:32 +01:00
charBitOpError ( tok - > tokAt ( 4 ) ) ; // This is an error..
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
//---------------------------------------------------------------------------
2011-12-17 19:04:03 +01:00
2009-01-26 20:14:46 +01:00
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 ;
}
2011-12-17 19:04:03 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
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 ( ) ) {
2011-12-17 19:04:03 +01:00
if ( Token : : Match ( tok , " [=(] %str% + %any% " ) ) {
2009-01-26 20:14:46 +01:00
// char constant..
2012-05-24 17:40:43 +02:00
if ( tok - > tokAt ( 3 ) - > type ( ) = = Token : : eChar )
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 ( ) ;
2011-12-17 19:04:03 +01:00
if ( isChar ( symbolDatabase - > getVariableFromVarId ( 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 ( )
{
2012-01-08 12:07:25 +01:00
const SymbolDatabase * db = _tokenizer - > getSymbolDatabase ( ) ;
std : : list < Scope > : : const_iterator scope ;
for ( scope = db - > scopeList . begin ( ) ; scope ! = db - > scopeList . end ( ) ; + + scope ) {
if ( scope - > type ! = Scope : : eFunction )
continue ;
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-01-28 12:32:28 +01:00
if ( tok - > varId ( ) )
continue ;
if ( Token : : Match ( tok , " log|log10 ( %num% ) " ) ) {
2012-01-08 12:07:25 +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 ) {
mathfunctionCallError ( tok ) ; // case log(-2)
} else if ( isNegative & & isFloat & & MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) < = 0. ) {
mathfunctionCallError ( tok ) ; // case log(-2.0)
} else if ( ! isNegative & & isFloat & & MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) < = 0. ) {
mathfunctionCallError ( tok ) ; // case log(0.0)
} else if ( ! isNegative & & isInt & & MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) < = 0 ) {
mathfunctionCallError ( tok ) ; // case log(0)
}
2011-10-22 12:31:47 +02:00
}
2010-04-02 07:32:03 +02:00
2012-01-08 12:07:25 +01:00
// acos( x ), asin( x ) where x is defined for intervall [-1,+1], but not beyound
2012-01-28 12:32:28 +01:00
else if ( Token : : Match ( tok , " acos|asin ( %num% ) " ) & &
2012-01-08 12:07:25 +01:00
std : : fabs ( MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) ) > 1.0 ) {
mathfunctionCallError ( tok ) ;
}
// sqrt( x ): if x is negative the result is undefined
2012-01-28 12:32:28 +01:00
else if ( Token : : Match ( tok , " sqrt|sqrtf|sqrtl ( %num% ) " ) & &
2012-01-08 12:07:25 +01:00
MathLib : : isNegative ( tok - > strAt ( 2 ) ) ) {
mathfunctionCallError ( tok ) ;
}
// atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
2012-01-28 12:32:28 +01:00
else if ( Token : : Match ( tok , " atan2 ( %num% , %num% ) " ) & &
2012-01-08 12:07:25 +01:00
MathLib : : isNullValue ( tok - > strAt ( 2 ) ) & &
MathLib : : isNullValue ( tok - > strAt ( 4 ) ) ) {
mathfunctionCallError ( tok , 2 ) ;
}
// fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
2012-01-28 12:32:28 +01:00
else if ( Token : : Match ( tok , " fmod ( %any% " ) ) {
const Token * nextArg = tok - > tokAt ( 2 ) - > nextArgument ( ) ;
if ( nextArg & & nextArg - > isNumber ( ) & & MathLib : : isNullValue ( nextArg - > str ( ) ) )
mathfunctionCallError ( tok , 2 ) ;
2012-01-08 12:07:25 +01:00
}
// pow ( x , y) If x is zero, and y is negative --> division by zero
2012-01-28 12:32:28 +01:00
else if ( Token : : Match ( tok , " pow ( %num% , %num% ) " ) & &
2012-01-08 12:07:25 +01:00
MathLib : : isNullValue ( tok - > strAt ( 2 ) ) & &
MathLib : : isNegative ( tok - > strAt ( 4 ) ) ) {
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 " ) ;
}
2012-05-24 17:40:43 +02:00
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 & &
2011-12-29 08:08:37 +01:00
Token : : Match ( tok , " isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|isxdigit ( %num% ,|) " ) & &
2011-11-17 16:31:16 +01:00
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 " ) ;
}
2012-05-24 17:40:43 +02:00
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-12-28 23:36:16 +01:00
if ( _tokenizer - > isC ( ) ) {
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
2012-01-21 19:55:32 +01:00
for ( std : : list < Scope > : : const_iterator 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 ;
2012-01-21 19:55:32 +01:00
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
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 ,
2012-04-17 12:54:01 +02:00
" unusedScopedObject " , " Instance of \" " + varname + " \" object destroyed immediately. " ) ;
2011-08-19 17:53:43 +02:00
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
2011-02-08 19:49:29 +01:00
void CheckOther : : checkIncorrectStringCompare ( )
{
2011-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
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-12-01 18:27:25 +01:00
MathLib : : bigint clen = MathLib : : toLongNumber ( tok - > strAt ( 5 ) ) ;
2011-11-22 21:14:14 +01:00
std : : size_t slen = Token : : getStrLength ( tok - > tokAt ( 8 ) ) ;
2011-12-03 09:57:56 +01:00
if ( clen ! = ( int ) 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-12-16 19:21:14 +01:00
} else if ( Token : : Match ( tok , " %str% ==|!= %var% . substr ( %any% , %num% ) " )) {
2011-12-01 18:27:25 +01:00
MathLib : : bigint clen = MathLib : : toLongNumber ( tok - > strAt ( 8 ) ) ;
2011-11-22 21:14:14 +01:00
std : : size_t slen = Token : : getStrLength ( tok ) ;
2011-12-03 09:57:56 +01:00
if ( clen ! = ( int ) 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-12-16 19:21:14 +01:00
} else if ( Token : : Match ( tok , " &&|%oror% %str% &&|%oror%|) " )) {
2011-10-18 21:37:03 +02:00
// 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-12-16 19:21:14 +01:00
} else if ( Token : : Match ( tok , " if|while|assert ( %str% &&|%oror%|) " )) {
2011-10-18 21:37:03 +02:00
// 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) { }
2012-08-24 00:03:22 +02:00
//-----------------------------------------------------------------------------
2011-04-09 21:14:01 +02:00
2012-08-24 00:03:22 +02:00
static bool expressionHasSideEffects ( const Token * first , const Token * last )
{
for ( const Token * tok = first ; tok ! = last - > next ( ) ; tok = tok - > next ( ) ) {
// check for assignment
if ( tok - > isAssignmentOp ( ) )
return true ;
2011-04-09 21:14:01 +02:00
2012-08-24 00:03:22 +02:00
// check for inc/dec
else if ( tok - > type ( ) = = Token : : eIncDecOp )
return true ;
2011-04-09 21:14:01 +02:00
2012-08-24 00:03:22 +02:00
// check for function call
else if ( Token : : Match ( tok , " %var% ( " ) & &
! ( Token : : Match ( tok , " c_str|string " ) | | tok - > isStandardType ( ) ) )
return true ;
2012-08-23 21:28:40 +02:00
}
2012-08-24 00:03:22 +02:00
return false ;
2011-04-09 21:14:01 +02:00
}
2012-08-24 00:03:22 +02:00
void CheckOther : : checkDuplicateIf ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( std : : list < Scope > : : const_iterator scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
const Token * const tok = scope - > classDef ;
// only check if statements
if ( scope - > type ! = Scope : : eIf | | ! tok )
continue ;
std : : map < std : : string , const Token * > expressionMap ;
// get the expression from the token stream
std : : string expression = tok - > tokAt ( 2 ) - > stringifyList ( tok - > next ( ) - > link ( ) ) ;
// save the expression and its location
expressionMap . insert ( std : : make_pair ( expression , tok ) ) ;
// find the next else if (...) statement
2012-08-20 17:57:28 +02:00
const Token * tok1 = scope - > classEnd ;
2011-04-09 21:14:01 +02:00
2011-12-09 22:28:10 +01:00
// check all the else if (...) statements
while ( Token : : simpleMatch ( tok1 , " } else if ( " ) & &
Token : : simpleMatch ( tok1 - > linkAt ( 3 ) , " ) { " ) ) {
// get the expression from the token stream
2012-04-16 19:51:07 +02:00
expression = tok1 - > tokAt ( 4 ) - > stringifyList ( tok1 - > linkAt ( 3 ) ) ;
2011-04-09 21:14:01 +02:00
2011-12-09 22:28:10 +01:00
// try to look up the expression to check for duplicates
std : : map < std : : string , const Token * > : : iterator it = expressionMap . find ( expression ) ;
2011-04-09 21:14:01 +02:00
2011-12-09 22:28:10 +01:00
// found a duplicate
if ( it ! = expressionMap . end ( ) ) {
// check for expressions that have side effects and ignore them
if ( ! expressionHasSideEffects ( tok1 - > tokAt ( 4 ) , tok1 - > linkAt ( 3 ) - > previous ( ) ) )
duplicateIfError ( it - > second , tok1 - > next ( ) ) ;
}
2011-04-09 21:14:01 +02:00
2011-12-09 22:28:10 +01:00
// not a duplicate expression so save it and its location
else
expressionMap . insert ( std : : make_pair ( expression , tok1 - > next ( ) ) ) ;
2011-04-09 21:14:01 +02:00
2011-12-09 22:28:10 +01:00
// find the next else if (...) statement
tok1 = tok1 - > linkAt ( 3 ) - > next ( ) - > link ( ) ;
2011-04-09 21:14:01 +02:00
}
}
}
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 ;
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 ) {
2012-05-24 17:40:43 +02:00
if ( scope - > type ! = Scope : : eIf & & scope - > type ! = Scope : : eElseIf )
2011-12-13 21:42:38 +01:00
continue ;
2011-04-09 23:05:27 +02:00
// check all the code in the function for if (..) else
2012-05-24 17:40:43 +02:00
if ( Token : : simpleMatch ( scope - > classEnd , " } else { " ) ) {
2011-12-09 22:28:10 +01:00
// save if branch code
2012-05-24 17:40:43 +02:00
std : : string branch1 = scope - > classStart - > next ( ) - > stringifyList ( scope - > classEnd ) ;
2011-04-09 23:05:27 +02:00
2011-12-09 22:28:10 +01:00
// save else branch code
2012-05-24 17:40:43 +02:00
std : : string branch2 = scope - > classEnd - > tokAt ( 3 ) - > stringifyList ( scope - > classEnd - > linkAt ( 2 ) ) ;
2011-04-09 23:05:27 +02:00
2011-12-09 22:28:10 +01:00
// check for duplicates
if ( branch1 = = branch2 )
2012-06-08 19:35:08 +02:00
duplicateBranchError ( scope - > classDef , scope - > classEnd - > next ( ) ) ;
2011-04-09 23:05:27 +02:00
}
}
}
2012-01-15 01:19:34 +01:00
//-----------------------------------------------------------------------------
// Check for double free
// free(p); free(p);
//-----------------------------------------------------------------------------
void CheckOther : : checkDoubleFree ( )
{
2012-01-21 19:55:32 +01:00
std : : set < unsigned int > freedVariables ;
std : : set < unsigned int > closeDirVariables ;
2012-01-15 01:19:34 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2012-06-16 22:03:51 +02:00
bool isUnknown = true ;
2012-01-15 01:19:34 +01:00
// Keep track of any variables passed to "free()", "g_free()" or "closedir()",
// and report an error if the same variable is passed twice.
if ( Token : : Match ( tok , " free|g_free|closedir ( %var% ) " ) ) {
2012-01-21 19:55:32 +01:00
unsigned int var = tok - > tokAt ( 2 ) - > varId ( ) ;
2012-01-15 01:19:34 +01:00
if ( var ) {
if ( Token : : Match ( tok , " free|g_free " ) ) {
if ( freedVariables . find ( var ) ! = freedVariables . end ( ) )
doubleFreeError ( tok , tok - > tokAt ( 2 ) - > str ( ) ) ;
else
freedVariables . insert ( var ) ;
} else if ( tok - > str ( ) = = " closedir " ) {
if ( closeDirVariables . find ( var ) ! = closeDirVariables . end ( ) )
doubleCloseDirError ( tok , tok - > tokAt ( 2 ) - > str ( ) ) ;
else
closeDirVariables . insert ( var ) ;
}
}
}
// Keep track of any variables operated on by "delete" or "delete[]"
// and report an error if the same variable is delete'd twice.
else if ( Token : : Match ( tok , " delete %var% ; " ) | | Token : : Match ( tok , " delete [ ] %var% ; " ) ) {
int varIdx = ( tok - > strAt ( 1 ) = = " [ " ) ? 3 : 1 ;
2012-01-21 19:55:32 +01:00
unsigned int var = tok - > tokAt ( varIdx ) - > varId ( ) ;
2012-01-15 01:19:34 +01:00
if ( var ) {
if ( freedVariables . find ( var ) ! = freedVariables . end ( ) )
doubleFreeError ( tok , tok - > tokAt ( varIdx ) - > str ( ) ) ;
else
freedVariables . insert ( var ) ;
}
}
// If this scope doesn't return, clear the set of previously freed variables
2012-06-16 22:03:51 +02:00
else if ( tok - > str ( ) = = " } " & & _tokenizer - > IsScopeNoReturn ( tok , & isUnknown ) & & ! isUnknown ) {
2012-01-15 01:19:34 +01:00
freedVariables . clear ( ) ;
closeDirVariables . clear ( ) ;
}
2012-06-16 22:03:51 +02:00
// If this scope is a "for" or "while" loop that contains "break" or "continue",
// give up on trying to figure out the flow of execution and just clear the set
// of previously freed variables.
// TODO: There are false negatives. This bailout is only needed when the
// loop will exit without free()'ing the memory on the last iteration.
else if ( tok - > str ( ) = = " } " & & tok - > link ( ) & & tok - > link ( ) - > linkAt ( - 1 ) & &
Token : : Match ( tok - > link ( ) - > linkAt ( - 1 ) - > previous ( ) , " while|for " ) & &
Token : : findmatch ( tok - > link ( ) - > linkAt ( - 1 ) , " break|continue ; " , tok ) ! = NULL ) {
2012-06-11 02:38:31 +02:00
freedVariables . clear ( ) ;
closeDirVariables . clear ( ) ;
}
2012-01-25 07:43:44 +01:00
2012-01-15 01:19:34 +01:00
// If a variable is passed to a function, remove it from the set of previously freed variables
2012-02-17 06:03:38 +01:00
else if ( Token : : Match ( tok , " %var% ( " ) & & ! Token : : Match ( tok , " printf|sprintf|snprintf|fprintf " ) ) {
2012-01-25 07:43:44 +01:00
// If this is a new function definition, clear all variables
2012-01-28 20:31:12 +01:00
if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) ) {
2012-01-25 07:43:44 +01:00
freedVariables . clear ( ) ;
closeDirVariables . clear ( ) ;
}
// If it is a function call, then clear those variables in its argument list
2012-01-28 20:31:12 +01:00
else if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) ; " )) {
2012-01-25 07:43:44 +01:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = tok - > linkAt ( 1 ) ; tok2 = tok2 - > next ( ) ) {
if ( Token : : Match ( tok2 , " %var% " ) ) {
unsigned int var = tok2 - > varId ( ) ;
if ( var ) {
freedVariables . erase ( var ) ;
closeDirVariables . erase ( var ) ;
}
2012-01-15 01:19:34 +01:00
}
}
}
}
// If a pointer is assigned a new value, remove it from the set of previously freed variables
else if ( Token : : Match ( tok , " %var% = " ) ) {
2012-01-21 19:55:32 +01:00
unsigned int var = tok - > varId ( ) ;
2012-01-15 01:19:34 +01:00
if ( var ) {
freedVariables . erase ( var ) ;
closeDirVariables . erase ( var ) ;
}
}
// Any control statements in-between delete, free() or closedir() statements
// makes it unclear whether any subsequent statements would be redundant.
2012-02-17 06:03:38 +01:00
if ( Token : : Match ( tok , " if|else|for|while|break|continue|goto|return|throw|switch " ) ) {
2012-01-15 01:19:34 +01:00
freedVariables . clear ( ) ;
closeDirVariables . clear ( ) ;
}
}
}
void CheckOther : : doubleFreeError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " doubleFree " , " Memory pointed to by ' " + varname + " ' is freed twice. " ) ;
}
void CheckOther : : doubleCloseDirError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " doubleCloseDir " , " Directory handle ' " + varname + " ' closed twice. " ) ;
}
2011-04-09 23:05:27 +02:00
void CheckOther : : duplicateBranchError ( const Token * tok1 , const Token * tok2 )
{
std : : list < const Token * > toks ;
toks . push_back ( tok2 ) ;
toks . push_back ( tok1 ) ;
2011-12-17 11:39:20 +01:00
reportError ( toks , Severity : : style , " duplicateBranch " , " Found duplicate branches for if and else. \n "
" Finding the same code for an if branch and an else branch is suspicious and "
" might indicate a cut and paste or logic error. Please examine this code "
" carefully to determine if it is correct. " ) ;
2011-04-09 23:05:27 +02:00
}
2011-11-08 21:22:31 +01:00
namespace {
2011-11-10 21:49:14 +01:00
struct ExpressionTokens {
const Token * start ;
const Token * end ;
int count ;
2011-12-01 19:46:57 +01:00
bool inconclusiveFunction ;
ExpressionTokens ( const Token * s , const Token * e ) : start ( s ) , end ( e ) , count ( 1 ) , inconclusiveFunction ( false ) { }
2011-11-10 21:49:14 +01:00
} ;
struct FuncFilter {
FuncFilter ( const Scope * scope , const Token * tok ) : _scope ( scope ) , _tok ( tok ) { }
2012-05-24 17:40:43 +02:00
bool operator ( ) ( const Function * func ) const {
bool matchingFunc = func - > type = = Function : : eFunction & &
_tok - > str ( ) = = func - > token - > str ( ) ;
2011-11-10 21:49:14 +01:00
// either a class function, or a global function with the same name
2012-05-24 17:40:43 +02:00
return ( _scope & & _scope = = func - > nestedIn & & matchingFunc ) | |
2011-11-10 21:49:14 +01:00
( ! _scope & & matchingFunc ) ;
}
const Scope * _scope ;
const Token * _tok ;
2011-11-08 21:22:31 +01:00
} ;
2011-11-10 21:49:14 +01:00
bool inconclusiveFunctionCall ( const SymbolDatabase * symbolDatabase ,
2012-05-24 17:40:43 +02:00
const std : : list < const Function * > & constFunctions ,
2011-11-10 21:49:14 +01:00
const ExpressionTokens & tokens )
{
const Token * start = tokens . start ;
const Token * end = tokens . end ;
// look for function calls between start and end...
for ( const Token * tok = start ; tok & & tok ! = end ; tok = tok - > next ( ) ) {
if ( tok ! = start & & tok - > str ( ) = = " ( " ) {
// go back to find the function call.
const Token * prev = tok - > previous ( ) ;
2011-12-01 19:50:26 +01:00
if ( ! prev )
continue ;
2011-11-10 21:49:14 +01:00
if ( prev - > str ( ) = = " > " ) {
// ignore template functions like boo<double>()
return true ;
}
2011-12-01 19:50:26 +01:00
if ( prev - > isName ( ) ) {
2011-11-10 21:49:14 +01:00
const Variable * v = 0 ;
if ( Token : : Match ( prev - > tokAt ( - 2 ) , " %var% . " ) ) {
const Token * scope = prev - > tokAt ( - 2 ) ;
v = symbolDatabase - > getVariableFromVarId ( scope - > varId ( ) ) ;
}
// hard coded list of safe, no-side-effect functions
if ( v = = 0 & & Token : : Match ( prev , " strcmp|strncmp|strlen|memcmp|strcasecmp|strncasecmp " ) )
return false ;
2012-05-24 17:40:43 +02:00
std : : list < const Function * > : : const_iterator it = std : : find_if ( constFunctions . begin ( ) ,
2011-11-29 20:44:23 +01:00
constFunctions . end ( ) ,
FuncFilter ( v ? v - > type ( ) : 0 , prev ) ) ;
2011-11-10 21:49:14 +01:00
if ( it = = constFunctions . end ( ) )
return true ;
}
}
}
return false ;
}
2011-12-01 19:46:57 +01:00
class Expressions {
public :
Expressions ( const SymbolDatabase * symbolDatabase , const
2012-05-24 17:40:43 +02:00
std : : list < const Function * > & constFunctions )
2011-12-01 19:46:57 +01:00
: _start ( 0 ) ,
2011-12-01 19:49:04 +01:00
_lastTokens ( 0 ) ,
2011-12-01 19:46:57 +01:00
_symbolDatabase ( symbolDatabase ) ,
_constFunctions ( constFunctions ) { }
void endExpr ( const Token * end ) {
const std : : string & e = _expression . str ( ) ;
if ( ! e . empty ( ) ) {
std : : map < std : : string , ExpressionTokens > : : iterator it = _expressions . find ( e ) ;
2011-12-01 19:49:04 +01:00
bool lastInconclusive = _lastTokens & & _lastTokens - > inconclusiveFunction ;
2011-12-01 19:46:57 +01:00
if ( it = = _expressions . end ( ) ) {
ExpressionTokens exprTokens ( _start , end ) ;
2011-12-01 19:49:04 +01:00
exprTokens . inconclusiveFunction = lastInconclusive | | inconclusiveFunctionCall (
2011-12-01 19:46:57 +01:00
_symbolDatabase , _constFunctions , exprTokens ) ;
_expressions . insert ( std : : make_pair ( e , exprTokens ) ) ;
2011-12-01 19:49:04 +01:00
_lastTokens = & _expressions . find ( e ) - > second ;
2011-12-01 19:46:57 +01:00
} else {
2011-12-01 19:49:04 +01:00
ExpressionTokens & expr = it - > second ;
expr . count + = 1 ;
expr . inconclusiveFunction = expr . inconclusiveFunction | | lastInconclusive ;
_lastTokens = & expr ;
2011-12-01 19:46:57 +01:00
}
}
_expression . str ( " " ) ;
_start = 0 ;
}
void append ( const Token * tok ) {
if ( ! _start )
_start = tok ;
_expression < < tok - > str ( ) ;
}
std : : map < std : : string , ExpressionTokens > & getMap ( ) {
return _expressions ;
}
private :
std : : map < std : : string , ExpressionTokens > _expressions ;
std : : ostringstream _expression ;
const Token * _start ;
2011-12-01 19:49:04 +01:00
ExpressionTokens * _lastTokens ;
2011-12-01 19:46:57 +01:00
const SymbolDatabase * _symbolDatabase ;
2012-05-24 17:40:43 +02:00
const std : : list < const Function * > & _constFunctions ;
2011-12-01 19:46:57 +01:00
} ;
2012-05-24 17:40:43 +02:00
bool notconst ( const Function * func )
2011-11-10 21:49:14 +01:00
{
2012-05-24 17:40:43 +02:00
return ! func - > isConst ;
2011-11-10 21:49:14 +01:00
}
2012-05-24 17:40:43 +02:00
void getConstFunctions ( const SymbolDatabase * symbolDatabase , std : : list < const Function * > & constFunctions )
2011-11-10 21:49:14 +01:00
{
std : : list < Scope > : : const_iterator scope ;
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
std : : list < Function > : : const_iterator func ;
// only add const functions that do not have a non-const overloaded version
// since it is pretty much impossible to tell which is being called.
2012-05-24 17:40:43 +02:00
typedef std : : map < std : : string , std : : list < const Function * > > StringFunctionMap ;
2011-11-10 21:49:14 +01:00
StringFunctionMap functionsByName ;
for ( func = scope - > functionList . begin ( ) ; func ! = scope - > functionList . end ( ) ; + + func ) {
2012-05-24 17:40:43 +02:00
functionsByName [ func - > tokenDef - > str ( ) ] . push_back ( & * func ) ;
2011-11-10 21:49:14 +01:00
}
for ( StringFunctionMap : : iterator it = functionsByName . begin ( ) ;
it ! = functionsByName . end ( ) ; + + it ) {
2012-05-24 17:40:43 +02:00
std : : list < const Function * > : : const_iterator nc = std : : find_if ( it - > second . begin ( ) , it - > second . end ( ) , notconst ) ;
2011-11-10 21:49:14 +01:00
if ( nc = = it - > second . end ( ) ) {
// ok to add all of them
constFunctions . splice ( constFunctions . end ( ) , it - > second ) ;
}
}
}
}
2011-11-08 21:22:31 +01:00
}
2012-05-24 17:40:43 +02:00
void CheckOther : : checkExpressionRange ( const std : : list < const Function * > & constFunctions ,
2011-11-10 21:49:14 +01:00
const Token * start ,
const Token * end ,
const std : : string & toCheck )
2011-11-08 21:22:31 +01:00
{
if ( ! start | | ! end )
return ;
2011-12-01 19:46:57 +01:00
Expressions expressions ( _tokenizer - > getSymbolDatabase ( ) , constFunctions ) ;
2011-11-08 21:22:31 +01:00
std : : string opName ;
2011-11-12 10:23:34 +01:00
int level = 0 ;
2011-11-08 21:22:31 +01:00
for ( const Token * tok = start - > next ( ) ; tok & & tok ! = end ; tok = tok - > next ( ) ) {
2011-11-12 10:23:34 +01:00
if ( tok - > str ( ) = = " ) " )
level - - ;
else if ( tok - > str ( ) = = " ( " )
level + + ;
if ( level = = 0 & & Token : : Match ( tok , toCheck . c_str ( ) ) ) {
2011-11-08 21:22:31 +01:00
opName = tok - > str ( ) ;
2011-11-10 21:49:14 +01:00
expressions . endExpr ( tok ) ;
2011-11-08 21:22:31 +01:00
} else {
2011-11-10 21:49:14 +01:00
expressions . append ( tok ) ;
2011-11-08 21:22:31 +01:00
}
}
2011-11-10 21:49:14 +01:00
expressions . endExpr ( end ) ;
std : : map < std : : string , ExpressionTokens > : : const_iterator it = expressions . getMap ( ) . begin ( ) ;
2011-11-08 21:22:31 +01:00
for ( ; it ! = expressions . getMap ( ) . end ( ) ; + + it ) {
2011-12-01 17:07:55 +01:00
// check expression..
bool valid = true ;
2012-07-31 23:35:56 +02:00
unsigned int parenthesis = 0 ; // ()
2011-12-01 17:07:55 +01:00
unsigned int brackets = 0 ; // []
2011-12-01 17:43:29 +01:00
2011-12-23 16:08:53 +01:00
// taking address?
if ( Token : : Match ( it - > second . end - > previous ( ) , " %op% & " ) ) {
continue ;
}
2011-12-01 17:43:29 +01:00
for ( const Token * tok = it - > second . start ; tok & & tok ! = it - > second . end ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " ( " ) {
2012-07-31 23:35:56 +02:00
+ + parenthesis ;
2011-12-01 17:43:29 +01:00
} else if ( tok - > str ( ) = = " ) " ) {
2012-07-31 23:35:56 +02:00
if ( parenthesis = = 0 ) {
2011-12-01 17:07:55 +01:00
valid = false ;
break ;
}
2012-07-31 23:35:56 +02:00
- - parenthesis ;
2011-12-01 17:43:29 +01:00
} else if ( tok - > str ( ) = = " [ " ) {
2011-12-01 17:07:55 +01:00
+ + brackets ;
2011-12-01 17:43:29 +01:00
} else if ( tok - > str ( ) = = " ] " ) {
2011-12-01 17:07:55 +01:00
if ( brackets = = 0 ) {
valid = false ;
break ;
}
- - brackets ;
2012-04-25 09:56:07 +02:00
} else if ( tok - > type ( ) = = Token : : eIncDecOp ) {
2011-12-01 17:46:33 +01:00
valid = false ;
break ;
2011-12-01 17:07:55 +01:00
}
}
2012-07-31 23:35:56 +02:00
if ( ! valid | | parenthesis ! = 0 | | brackets ! = 0 )
2011-12-01 17:07:55 +01:00
continue ;
2011-12-01 19:46:57 +01:00
const ExpressionTokens & expr = it - > second ;
if ( expr . count > 1 & & ! expr . inconclusiveFunction ) {
duplicateExpressionError ( expr . start , expr . start , opName ) ;
2011-11-10 21:49:14 +01:00
}
2011-11-08 21:22:31 +01:00
}
}
2012-05-24 17:40:43 +02:00
void CheckOther : : complexDuplicateExpressionCheck ( const std : : list < const Function * > & constFunctions ,
2011-11-29 20:44:23 +01:00
const Token * classStart ,
const std : : string & toCheck ,
const std : : string & alt )
2011-11-08 21:22:31 +01:00
{
2012-06-23 19:54:15 +02:00
std : : string statementStart ( " ,|=|?|:|return " ) ;
2011-11-08 21:22:31 +01:00
if ( ! alt . empty ( ) )
statementStart + = " | " + alt ;
2012-06-23 19:54:15 +02:00
std : : string statementEnd ( " ;|,|?|: " ) ;
2011-11-08 21:22:31 +01:00
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 - - ;
2011-11-12 10:23:34 +01:00
if ( level < 0 | | ( level = = 0 & & Token : : Match ( tok1 , statementStart . c_str ( ) ) ) ) {
2011-11-08 21:22:31 +01:00
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 + + ;
2011-11-12 10:23:34 +01:00
if ( level < 0 | | ( level = = 0 & & Token : : Match ( tok1 , statementEnd . c_str ( ) ) ) ) {
2011-11-08 21:22:31 +01:00
end = tok1 ;
break ;
}
}
2011-11-10 21:49:14 +01:00
checkExpressionRange ( constFunctions , start , end , toCheck ) ;
2011-11-08 21:22:31 +01:00
}
}
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 ;
2012-05-24 17:40:43 +02:00
std : : list < const Function * > constFunctions ;
2011-11-10 21:49:14 +01:00
getConstFunctions ( symbolDatabase , constFunctions ) ;
2011-04-10 16:25:02 +02:00
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-10 21:49:14 +01:00
complexDuplicateExpressionCheck ( constFunctions , scope - > classStart , " %or% " , " " ) ;
complexDuplicateExpressionCheck ( constFunctions , scope - > classStart , " %oror% " , " " ) ;
complexDuplicateExpressionCheck ( constFunctions , scope - > classStart , " & " , " %oror%|%or% " ) ;
complexDuplicateExpressionCheck ( constFunctions , 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 ;
}
}
2012-05-17 07:26:57 +02:00
// If either variable token is an expanded macro then
// don't write the warning
if ( tok - > next ( ) - > isExpandedMacro ( ) | | tok - > tokAt ( 3 ) - > isExpandedMacro ( ) )
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 ) ) {
2012-05-17 07:26:57 +02:00
// If either variable token is an expanded macro then
// don't write the warning
if ( tok - > next ( ) - > isExpandedMacro ( ) | | tok - > tokAt ( 6 ) - > isExpandedMacro ( ) )
continue ;
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 ( )
{
2012-03-15 20:38:28 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
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 ) {
2012-03-11 11:01:39 +01:00
const std : : string & str1 = tok - > strAt ( 2 ) ;
const std : : string & str2 = tok - > strAt ( 4 ) ;
2012-03-15 20:38:28 +01:00
alwaysTrueFalseStringCompareError ( tok , str1 , str2 ) ;
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 ) {
2012-03-11 11:01:39 +01:00
const std : : string & str1 = tok - > strAt ( 4 ) ;
const std : : string & str2 = tok - > strAt ( 6 ) ;
2012-03-15 20:38:28 +01:00
alwaysTrueFalseStringCompareError ( tok , str1 , str2 ) ;
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 ) {
2012-03-11 11:01:39 +01:00
const std : : string & str1 = tok - > strAt ( 2 ) ;
const std : : string & str2 = tok - > strAt ( 4 ) ;
2011-10-29 11:52:19 +02:00
if ( str1 = = str2 )
alwaysTrueStringVariableCompareError ( tok , str1 , str2 ) ;
2011-10-28 22:05:11 +02:00
tok = tok - > tokAt ( 5 ) ;
}
2012-03-11 11:01:39 +01:00
tok = _tokenizer - > tokens ( ) ;
while ( tok & & ( tok = Token : : findmatch ( tok , " !!+ %str% ==|!= %str% !!+ " ) ) ! = NULL ) {
const std : : string & str1 = tok - > strAt ( 1 ) ;
const std : : string & str2 = tok - > strAt ( 3 ) ;
2012-03-15 20:38:28 +01:00
alwaysTrueFalseStringCompareError ( tok , str1 , str2 ) ;
2012-03-11 11:01:39 +01:00
tok = tok - > tokAt ( 5 ) ;
}
2011-04-26 07:45:27 +02:00
}
2012-03-15 20:38:28 +01:00
void CheckOther : : alwaysTrueFalseStringCompareError ( const Token * tok , const std : : string & str1 , const std : : string & str2 )
2011-04-26 07:45:27 +02:00
{
2011-11-22 21:14:14 +01:00
const std : : size_t stringLen = 10 ;
2011-04-26 07:45:27 +02:00
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 ) + " .. " ) ;
2012-03-15 20:38:28 +01:00
reportError ( tok , Severity : : warning , " staticStringCompare " ,
2012-04-26 23:04:55 +02:00
" Unnecessary comparison of static strings. \n "
2012-03-15 20:38:28 +01:00
" The compared strings, ' " + string1 + " ' and ' " + string2 + " ', are always " + ( str1 = = str2 ? " identical " : " unequal " ) + " . "
2012-04-26 23:04:55 +02:00
" Therefore the comparison is unnecessary and looks suspicious. " ) ;
2011-04-26 07:45:27 +02:00
}
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
}
2012-08-24 14:25:17 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CheckOther : : checkSuspiciousStringCompare ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( const Token * tok = _tokenizer - > list . front ( ) ; tok & & tok - > tokAt ( 3 ) ; tok = tok - > next ( ) ) {
if ( tok - > next ( ) - > type ( ) ! = Token : : eComparisonOp )
continue ;
const Token * varTok = tok ;
const Token * litTok = tok - > tokAt ( 2 ) ;
if ( varTok - > strAt ( - 1 ) = = " + " | | litTok - > strAt ( 1 ) = = " + " )
continue ;
if ( ( varTok - > type ( ) = = Token : : eString | | varTok - > type ( ) = = Token : : eVariable ) & & ( litTok - > type ( ) = = Token : : eString | | litTok - > type ( ) = = Token : : eVariable ) & & litTok - > type ( ) ! = varTok - > type ( ) ) {
if ( varTok - > type ( ) = = Token : : eString )
std : : swap ( varTok , litTok ) ;
const Variable * var = symbolDatabase - > getVariableFromVarId ( varTok - > varId ( ) ) ;
if ( var & & var - > isPointer ( ) )
suspiciousStringCompareError ( tok , var - > name ( ) ) ;
}
}
}
void CheckOther : : suspiciousStringCompareError ( const Token * tok , const std : : string & var )
{
reportError ( tok , Severity : : warning , " literalWithCharPtrCompare " ,
" String literal compared with variable ' " + var + " '. Did you intend to use strcmp() instead? " ) ;
}
2012-04-26 15:23:47 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CheckOther : : checkModuloAlwaysTrueFalse ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " % %num% ==|!=|<=|<|>|>= %num% " ) & & ( ! tok - > tokAt ( 4 ) | | ! tok - > tokAt ( 4 ) - > isArithmeticalOp ( ) ) ) {
if ( MathLib : : isLessEqual ( tok - > strAt ( 1 ) , tok - > strAt ( 3 ) ) )
moduloAlwaysTrueFalseError ( tok , tok - > strAt ( 1 ) ) ;
}
}
}
void CheckOther : : moduloAlwaysTrueFalseError ( const Token * tok , const std : : string & maxVal )
{
reportError ( tok , Severity : : warning , " moduloAlwaysTrueFalse " ,
2012-04-26 23:04:55 +02:00
" Comparison of modulo result is predetermined, because it is always less than " + maxVal + " . " ) ;
2012-04-26 15:23:47 +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-12-16 19:21:14 +01:00
2011-10-13 20:53:06 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : simpleMatch ( tok , " sizeof ( " ) ) {
2012-03-25 11:32:00 +02:00
const Token * const end = tok - > linkAt ( 1 ) ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = end ; tok2 = tok2 - > next ( ) ) {
2012-09-03 15:56:10 +02:00
if ( tok2 - > isOp ( ) & & ( ! tok2 - > isExpandedMacro ( ) | | _settings - > inconclusive ) & & ! Token : : Match ( tok2 , " >|<|& " ) & & ( Token : : Match ( tok2 - > previous ( ) , " %var% " ) | | ! Token : : Match ( tok2 , " * " ) ) ) {
if ( ! ( Token : : Match ( tok2 - > previous ( ) , " %type% " ) | | Token : : Match ( tok2 - > next ( ) , " %type% " ) ) ) {
sizeofCalculationError ( tok2 , tok2 - > isExpandedMacro ( ) ) ;
break ;
}
2010-08-06 22:57:10 +02:00
}
}
}
}
}
2012-03-25 11:32:00 +02:00
void CheckOther : : sizeofCalculationError ( const Token * tok , bool inconclusive )
2010-08-06 22:57:10 +02:00
{
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : warning ,
" sizeofCalculation " , " Found calculation inside sizeof() " , inconclusive ) ;
2010-08-06 22:57:10 +02:00
}
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 ( ) ) {
2012-05-25 12:09:41 +02:00
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?
2012-05-25 12:09:41 +02:00
if ( var1 & & var1 - > isPointer ( ) )
2011-07-28 07:28:24 +02:00
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-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
2012-04-02 15:45:51 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-10-10 19:11:17 +02:00
2012-04-02 15:45:51 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2012-05-22 19:01:21 +02:00
// Skip template parameters
if ( tok - > str ( ) = = " < " & & tok - > link ( ) ) {
tok = tok - > link ( ) ;
continue ;
}
2012-04-02 15:45:51 +02:00
const Token * numTok = 0 ;
const Token * opTok = 0 ;
char op = 0 ;
if ( Token : : Match ( tok , " &&|%oror% %any% ) >|>=|==|!=|<=|< %any% " ) ) {
numTok = tok - > tokAt ( 4 ) ;
opTok = tok - > tokAt ( 3 ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] ;
} else if ( Token : : Match ( tok , " %any% >|>=|==|!=|<=|< ( %any% &&|%oror% " ) ) {
numTok = tok ;
opTok = tok - > next ( ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] = = ' > ' ? ' < ' : ' > ' ;
}
else if ( Token : : Match ( tok , " ! %var% >|>=|==|!=|<=|< %any% " ) ) {
numTok = tok - > tokAt ( 3 ) ;
opTok = tok - > tokAt ( 2 ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] ;
} else if ( Token : : Match ( tok , " %any% >|>=|==|!=|<=|< ! %var% " ) ) {
numTok = tok ;
opTok = tok - > next ( ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] = = ' > ' ? ' < ' : ' > ' ;
}
if ( numTok & & opTok ) {
if ( numTok - > isNumber ( ) ) {
if ( ( ( numTok - > str ( ) ! = " 0 " & & numTok - > str ( ) ! = " 1 " ) | | ! Token : : Match ( opTok , " !=|== " ) ) & & ! ( ( op = = ' < ' & & numTok - > str ( ) = = " 1 " ) | | ( op = = ' > ' & & numTok - > str ( ) = = " 0 " ) ) )
comparisonOfBoolExpressionWithIntError ( tok , true ) ;
} else if ( isNonBoolStdType ( symbolDatabase - > getVariableFromVarId ( numTok - > varId ( ) ) ) )
comparisonOfBoolExpressionWithIntError ( tok , false ) ;
2011-10-10 19:11:17 +02:00
}
}
}
2012-04-02 15:45:51 +02:00
void CheckOther : : comparisonOfBoolExpressionWithIntError ( const Token * tok , bool n0o1 )
2011-10-10 19:11:17 +02:00
{
2012-04-02 15:45:51 +02:00
if ( n0o1 )
reportError ( tok , Severity : : warning , " compareBoolExpressionWithInt " ,
" Comparison of a boolean expression with an integer other than 0 or 1. " ) ;
else
reportError ( tok , Severity : : warning , " compareBoolExpressionWithInt " ,
" Comparison of a boolean expression with an integer. " ) ;
2011-10-10 19:11:17 +02:00
}
2011-08-07 01:23:09 +02:00
//---------------------------------------------------------------------------
2012-08-21 12:28:02 +02:00
// Check testing sign of unsigned variables and pointers.
2011-08-07 01:23:09 +02:00
//---------------------------------------------------------------------------
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
2012-08-21 12:28:02 +02:00
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-03-25 11:32:00 +02:00
if ( Token : : Match ( tok , " %var% <|<= 0 " ) & & tok - > varId ( ) & & ! Token : : Match ( tok - > previous ( ) , " ++|--|)|+|-|*|/|~|<<|>> " ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " +|- " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
2011-08-07 01:23:09 +02:00
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2012-08-21 12:28:02 +02:00
unsignedLessThanZeroError ( tok , var - > name ( ) , inconclusive ) ;
else if ( var & & var - > isPointer ( ) & & tok - > strAt ( - 1 ) ! = " * " )
pointerLessThanZeroError ( tok , inconclusive ) ;
2012-03-25 11:32:00 +02:00
} else if ( Token : : Match ( tok , " 0 >|>= %var% " ) & & tok - > tokAt ( 2 ) - > varId ( ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " +|-|*|/ " ) & & ! Token : : Match ( tok - > previous ( ) , " +|-|<<|>>|~ " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
2011-08-07 01:23:09 +02:00
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2012-08-21 12:28:02 +02:00
unsignedLessThanZeroError ( tok , var - > name ( ) , inconclusive ) ;
else if ( var & & var - > isPointer ( ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " [.[] " ) )
pointerLessThanZeroError ( tok , inconclusive ) ;
2012-03-25 11:32:00 +02:00
} else if ( Token : : Match ( tok , " 0 <= %var% " ) & & tok - > tokAt ( 2 ) - > varId ( ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " +|-|*|/ " ) & & ! Token : : Match ( tok - > previous ( ) , " +|-|<<|>>|~ " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
2011-08-07 01:23:09 +02:00
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2012-08-21 12:28:02 +02:00
unsignedPositiveError ( tok , var - > name ( ) , inconclusive ) ;
else if ( var & & var - > isPointer ( ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " [.[] " ) )
pointerPositiveError ( tok , inconclusive ) ;
2012-03-25 11:32:00 +02:00
} else if ( Token : : Match ( tok , " %var% >= 0 " ) & & tok - > varId ( ) & & ! Token : : Match ( tok - > previous ( ) , " ++|--|)|+|-|*|/|~|<<|>> " ) & & ! Token : : Match ( tok - > tokAt ( 3 ) , " +|- " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
2011-09-27 03:24:34 +02:00
if ( var & & var - > typeEndToken ( ) - > isUnsigned ( ) )
2012-08-21 12:28:02 +02:00
unsignedPositiveError ( tok , var - > name ( ) , inconclusive ) ;
else if ( var & & var - > isPointer ( ) & & tok - > strAt ( - 1 ) ! = " * " )
pointerPositiveError ( tok , 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 ) {
2012-05-06 19:37:41 +02:00
reportError ( 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 " , true ) ;
2011-11-06 18:24:37 +01:00
} else {
reportError ( tok , Severity : : style , " unsignedLessThanZero " ,
" Checking if unsigned variable ' " + varname + " ' is less than zero. \n "
2012-06-23 10:08:18 +02:00
" The unsigned variable ' " + varname + " ' will never be negative so it "
2012-03-25 11:32:00 +02:00
" is either pointless or an error to check if it is. " ) ;
2011-11-06 18:24:37 +01:00
}
2011-08-07 01:23:09 +02:00
}
2012-08-21 12:28:02 +02:00
void CheckOther : : pointerLessThanZeroError ( const Token * tok , bool inconclusive )
{
reportError ( tok , Severity : : style , " pointerLessThanZero " ,
" A pointer can not be negative so it is either pointless or an error to check if it is. " , inconclusive ) ;
}
2011-11-06 18:24:37 +01:00
void CheckOther : : unsignedPositiveError ( const Token * tok , const std : : string & varname , bool inconclusive )
{
if ( inconclusive ) {
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : style , " unsignedPositive " ,
" An unsigned variable ' " + varname + " ' can't be negative so it is unnecessary to test it. This might be a false warning. \n "
" An unsigned variable ' " + varname + " ' can't be negative so it is unnecessary to test it. "
" It's not known if the used constant is a "
" template parameter or not and therefore this message might be a false warning " , true ) ;
2011-11-06 18:24:37 +01:00
} else {
reportError ( tok , Severity : : style , " unsignedPositive " ,
2012-01-14 11:50:09 +01:00
" An unsigned variable ' " + varname + " ' can't be negative so it is unnecessary to test it. " ) ;
2011-11-06 18:24:37 +01:00
}
2011-08-07 01:23:09 +02:00
}
2012-07-22 09:17:00 +02:00
2012-08-21 12:28:02 +02:00
void CheckOther : : pointerPositiveError ( const Token * tok , bool inconclusive )
{
reportError ( tok , Severity : : style , " pointerPositive " ,
" A pointer can not be negative so it is either pointless or an error to check if it is not. " , inconclusive ) ;
}
2012-07-22 09:17:00 +02:00
/*
This check rule works for checking the " const A a = getA() " usage when getA ( ) returns " const A & " or " A & " .
In most scenarios , " const A & a = getA() " will be more efficient .
*/
void CheckOther : : checkRedundantCopy ( )
{
if ( ! _settings - > isEnabled ( " performance " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
const char * expect_end_token ;
2012-08-24 00:03:22 +02:00
if ( Token : : Match ( tok , " const %type% %var% = " ) ) {
//match "const A a =" usage
expect_end_token = " ; " ;
} else if ( Token : : Match ( tok , " const %type% %var% ( " ) ) {
//match "const A a (" usage
expect_end_token = " ) " ;
} else {
continue ;
}
if ( tok - > strAt ( 1 ) = = tok - > strAt ( 4 ) ) //avoid "const A a = A();"
continue ;
if ( ! symbolDatabase - > isClassOrStruct ( tok - > next ( ) - > str ( ) ) ) //avoid when %type% is standard type
continue ;
const Token * var_tok = tok - > tokAt ( 2 ) ;
tok = tok - > tokAt ( 4 ) ;
while ( tok & & Token : : Match ( tok , " %var% . " ) )
tok = tok - > tokAt ( 2 ) ;
if ( ! Token : : Match ( tok , " %var% ( " ) )
break ;
const Token * match_end = ( tok - > next ( ) - > link ( ) ! = NULL ) ? tok - > next ( ) - > link ( ) - > next ( ) : NULL ;
if ( match_end = = NULL | | ! Token : : Match ( match_end , expect_end_token ) ) //avoid usage like "const A a = getA()+3"
break ;
const Token * fToken = _tokenizer - > getFunctionTokenByName ( tok - > str ( ) . c_str ( ) ) ;
if ( fToken & & fToken - > previous ( ) & & fToken - > previous ( ) - > str ( ) = = " & " ) {
redundantCopyError ( var_tok , var_tok - > str ( ) ) ;
}
}
}
void CheckOther : : redundantCopyError ( const Token * tok , const std : : string & varname )
2012-07-22 09:17:00 +02:00
{
2012-08-24 00:03:22 +02:00
reportError ( tok , Severity : : performance , " redundantCopyLocalConst " ,
" Use const reference for " + varname + " to avoid unnecessary data copying. \n "
" The const " + varname + " gets a copy of the data since const reference is not used. You can avoid the unnecessary data copying by converting " + varname + " to const reference instead of just const. " ) ;
}
2012-08-22 15:44:20 +02:00
2012-08-24 00:03:22 +02:00
//---------------------------------------------------------------------------
// Checking for shift by negative values
//---------------------------------------------------------------------------
2012-08-22 15:44:20 +02:00
2012-08-24 00:03:22 +02:00
void CheckOther : : checkNegativeBitwiseShift ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " %var% >>|<< %num% " ) | | Token : : Match ( tok , " %num >>|<< %num% " ) ) {
if ( ( tok - > strAt ( 2 ) ) [ 0 ] = = ' - ' )
negativeBitwiseShiftError ( tok ) ;
2012-08-22 15:44:20 +02:00
}
}
}
2012-08-24 00:03:22 +02:00
void CheckOther : : negativeBitwiseShiftError ( const Token * tok )
2012-08-22 15:44:20 +02:00
{
2012-08-24 00:03:22 +02:00
reportError ( tok , Severity : : error , " shiftNegative " , " Shifting by a negative value. " ) ;
2012-08-22 15:44:20 +02:00
}
2012-08-24 11:28:50 +02:00
//---------------------------------------------------------------------------
// Check for incompletely filled buffers.
//---------------------------------------------------------------------------
void CheckOther : : checkIncompleteArrayFill ( )
{
if ( ! _settings - > inconclusive | | ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( const Token * tok = _tokenizer - > list . front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " memset|memcpy|memmove ( %var% , " ) & & Token : : Match ( tok - > linkAt ( 1 ) - > tokAt ( - 2 ) , " , %num% ) " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
if ( ! var | | ! var - > isArray ( ) | | var - > dimensions ( ) . empty ( ) | | ! var - > dimension ( 0 ) )
continue ;
if ( MathLib : : toLongNumber ( tok - > linkAt ( 1 ) - > strAt ( - 1 ) ) = = var - > dimension ( 0 ) ) {
unsigned int size = _tokenizer - > sizeOfType ( var - > typeStartToken ( ) ) ;
if ( ( size ! = 1 & & size ! = 100 & & size ! = 0 ) | | Token : : Match ( var - > typeEndToken ( ) , " * " ) )
incompleteArrayFillError ( tok , var - > name ( ) , tok - > str ( ) , false ) ;
else if ( var - > typeStartToken ( ) - > str ( ) = = " bool " & & _settings - > isEnabled ( " portability " ) ) // sizeof(bool) is not 1 on all platforms
incompleteArrayFillError ( tok , var - > name ( ) , tok - > str ( ) , true ) ;
}
}
}
}
void CheckOther : : incompleteArrayFillError ( const Token * tok , const std : : string & buffer , const std : : string & function , bool boolean )
{
if ( boolean )
reportError ( tok , Severity : : portability , " incompleteArrayFill " ,
" Array ' " + buffer + " ' might be filled incompletely. Did you forget to multiply the size given to ' " + function + " ()' with 'sizeof(* " + buffer + " )'? \n "
" The array ' " + buffer + " ' is filled incompletely. The function ' " + function + " ()' needs the size given in bytes, but the type 'bool' is larger than 1 on some platforms. Did you forget to multiply the size with 'sizeof(* " + buffer + " )'? " , true ) ;
else
reportError ( tok , Severity : : warning , " incompleteArrayFill " ,
" Array ' " + buffer + " ' is filled incompletely. Did you forget to multiply the size given to ' " + function + " ()' with 'sizeof(* " + buffer + " )'? \n "
" The array ' " + buffer + " ' is filled incompletely. The function ' " + function + " ()' needs the size given in bytes, but an element of the given array is larger than one byte. Did you forget to multiply the size with 'sizeof(* " + buffer + " )'? " , true ) ;
}