2013-04-10 18:25:50 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2015-01-03 12:14:58 +01:00
* Copyright ( C ) 2007 - 2015 Daniel Marjamäki and Cppcheck team .
2013-04-10 18:25:50 +02: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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checkbool.h"
# include "mathlib.h"
# include "symboldatabase.h"
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
namespace {
CheckBool instance ;
}
2014-03-27 05:39:48 +01:00
static bool astIsBool ( const Token * expr )
{
2014-03-31 15:55:54 +02:00
return Token : : Match ( expr , " %comp%|%bool%|%oror%|&&|! " ) & & ! expr - > link ( ) ;
2014-03-27 05:39:48 +01:00
}
2013-04-10 18:25:50 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void CheckBool : : checkIncrementBoolean ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %var% ++ " ) ) {
2014-09-11 16:55:00 +02:00
const Variable * var = tok - > variable ( ) ;
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " )
incrementBooleanError ( tok ) ;
2013-04-10 18:25:50 +02:00
}
}
}
}
void CheckBool : : incrementBooleanError ( const Token * tok )
{
reportError (
tok ,
Severity : : style ,
" incrementboolean " ,
" Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead. \n "
" The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true. You should assign it the value 'true' instead. "
) ;
}
//---------------------------------------------------------------------------
// if (bool & bool) -> if (bool && bool)
// if (bool | bool) -> if (bool || bool)
//---------------------------------------------------------------------------
void CheckBool : : 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 ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " (|.|return|&&|%oror%|throw|, %var% [&|] " ) ) {
const Variable * var = tok - > next ( ) - > variable ( ) ;
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) == " ) " || tok->strAt(-1) == " ] " )) {
const Variable * var = tok - > next ( ) - > variable ( ) ;
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " ) {
bitwiseOnBooleanError ( tok - > next ( ) , var - > name ( ) , tok - > str ( ) = = " & " ? " && " : " || " ) ;
tok = tok - > tokAt ( 2 ) ;
}
}
}
}
}
void CheckBool : : bitwiseOnBooleanError ( const Token * tok , const std : : string & varname , const std : : string & op )
{
reportError ( tok , Severity : : style , " bitwiseOnBoolean " ,
2015-04-25 17:48:11 +02:00
" Boolean variable ' " + varname + " ' is used in bitwise operation. Did you mean ' " + op + " '? " ,
0U ,
true ) ;
2013-04-10 18:25:50 +02:00
}
//---------------------------------------------------------------------------
// if (!x==3) <- Probably meant to be "x!=3"
//---------------------------------------------------------------------------
static bool isBool ( const Variable * var )
{
2013-08-07 16:27:37 +02:00
return ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " ) ;
2013-04-10 18:25:50 +02:00
}
static bool isNonBoolStdType ( const Variable * var )
{
2013-08-07 16:27:37 +02:00
return ( var & & var - > typeEndToken ( ) - > isStandardType ( ) & & var - > typeEndToken ( ) - > str ( ) ! = " bool " ) ;
2013-04-10 18:25:50 +02:00
}
void CheckBool : : checkComparisonOfBoolWithInt ( )
{
2013-10-07 18:41:07 +02:00
if ( ! _settings - > isEnabled ( " warning " ) | | ! _tokenizer - > isCPP ( ) )
2013-04-10 18:25:50 +02:00
return ;
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2015-03-12 20:07:48 +01:00
const Token * const left = tok - > astOperand1 ( ) ;
const Token * const right = tok - > astOperand2 ( ) ;
if ( left & & right & & tok - > isComparisonOp ( ) ) {
if ( ( left - > varId ( ) & & right - > isNumber ( ) ) | | ( left - > isNumber ( ) & & right - > varId ( ) ) ) { // Comparing variable with number
const Token * varTok = left ;
2013-04-10 18:25:50 +02:00
const Token * numTok = right ;
2015-03-12 20:07:48 +01:00
if ( left - > isNumber ( ) & & right - > varId ( ) ) // num with var
2013-04-10 18:25:50 +02:00
std : : swap ( varTok , numTok ) ;
if ( isBool ( varTok - > variable ( ) ) & & // Variable has to be a boolean
2015-03-12 20:07:48 +01:00
( ( tok - > str ( ) ! = " == " & & tok - > str ( ) ! = " != " ) | |
2013-04-10 18:25:50 +02:00
( MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 0 & & MathLib : : toLongNumber ( numTok - > str ( ) ) ! = 1 ) ) ) { // == 0 and != 0 are allowed, for C also == 1 and != 1
2015-03-12 20:07:48 +01:00
comparisonOfBoolWithIntError ( varTok , numTok - > str ( ) , tok - > str ( ) = = " == " | | tok - > str ( ) = = " != " ) ;
2013-04-10 18:25:50 +02:00
}
2015-03-12 20:07:48 +01:00
} else if ( left - > isBoolean ( ) & & right - > varId ( ) ) { // Comparing boolean constant with variable
2013-04-10 18:25:50 +02:00
if ( isNonBoolStdType ( right - > variable ( ) ) ) { // Variable has to be of non-boolean standard type
2015-03-12 20:07:48 +01:00
comparisonOfBoolWithIntError ( right , left - > str ( ) , false ) ;
} else if ( tok - > str ( ) ! = " == " & & tok - > str ( ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , left - > str ( ) ) ;
2013-04-10 18:25:50 +02:00
}
2015-03-12 20:07:48 +01:00
} else if ( left - > varId ( ) & & right - > isBoolean ( ) ) { // Comparing variable with boolean constant
if ( isNonBoolStdType ( left - > variable ( ) ) ) { // Variable has to be of non-boolean standard type
comparisonOfBoolWithIntError ( left , right - > str ( ) , false ) ;
} else if ( tok - > str ( ) ! = " == " & & tok - > str ( ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , left - > str ( ) ) ;
2013-04-10 18:25:50 +02:00
}
2015-03-12 20:07:48 +01:00
} else if ( left - > isNumber ( ) & & right - > isBoolean ( ) ) { // number constant with boolean constant
comparisonOfBoolWithIntError ( left , right - > str ( ) , false ) ;
} else if ( left - > isBoolean ( ) & & right - > isNumber ( ) ) { // number constant with boolean constant
comparisonOfBoolWithIntError ( left , left - > str ( ) , false ) ;
} else if ( left - > varId ( ) & & right - > varId ( ) ) { // Comparing two variables, one of them boolean, one of them integer
2013-04-10 18:25:50 +02:00
const Variable * var1 = right - > variable ( ) ;
2015-03-12 20:07:48 +01:00
const Variable * var2 = left - > variable ( ) ;
2013-04-10 18:25:50 +02:00
if ( isBool ( var1 ) & & isNonBoolStdType ( var2 ) ) // Comparing boolean with non-bool standard type
2015-03-12 20:07:48 +01:00
comparisonOfBoolWithIntError ( left , var1 - > name ( ) , false ) ;
2013-04-10 18:25:50 +02:00
else if ( isNonBoolStdType ( var1 ) & & isBool ( var2 ) ) // Comparing non-bool standard type with boolean
2015-03-12 20:07:48 +01:00
comparisonOfBoolWithIntError ( left , var2 - > name ( ) , false ) ;
2013-04-10 18:25:50 +02:00
}
}
}
}
}
void CheckBool : : comparisonOfBoolWithIntError ( const Token * tok , const std : : string & expression , bool n0o1 )
{
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 an 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 an integer value. " ) ;
}
void CheckBool : : comparisonOfBoolWithInvalidComparator ( const Token * tok , const std : : string & expression )
{
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInvalidComparator " ,
" Comparison of a boolean value using relational operator (<, >, <= or >=). \n "
" The result of the expression ' " + expression + " ' is of type 'bool'. "
" Comparing 'bool' value using relational (<, >, <= or >=) "
" operator could cause unexpected results. " ) ;
}
//-------------------------------------------------------------------------------
// Comparing functions which are returning value of type bool
//-------------------------------------------------------------------------------
2014-08-25 09:49:17 +02:00
static bool tokenIsFunctionReturningBool ( const Token * tok )
{
2014-09-11 16:55:00 +02:00
const Function * func = tok - > function ( ) ;
2015-01-31 10:50:39 +01:00
if ( func & & Token : : Match ( tok , " %name% ( " ) ) {
2014-09-11 16:55:00 +02:00
if ( func - > tokenDef & & func - > tokenDef - > strAt ( - 1 ) = = " bool " ) {
2014-08-25 09:49:17 +02:00
return true ;
}
}
return false ;
}
2013-04-10 18:25:50 +02:00
void CheckBool : : checkComparisonOfFuncReturningBool ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
if ( ! _tokenizer - > isCPP ( ) )
return ;
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2014-08-25 09:49:17 +02:00
const std : : size_t functionsCount = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functionsCount ; + + i ) {
2013-04-10 18:25:50 +02:00
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > type ( ) ! = Token : : eComparisonOp | | tok - > str ( ) = = " == " | | tok - > str ( ) = = " != " )
continue ;
2014-08-25 09:49:17 +02:00
const Token * firstToken = tok - > previous ( ) ;
2013-04-10 18:25:50 +02:00
if ( tok - > strAt ( - 1 ) = = " ) " ) {
2014-08-25 09:49:17 +02:00
firstToken = firstToken - > link ( ) - > previous ( ) ;
2013-04-10 18:25:50 +02:00
}
2014-08-25 09:49:17 +02:00
const Token * secondToken = tok - > next ( ) ;
while ( secondToken - > str ( ) = = " ! " ) {
secondToken = secondToken - > next ( ) ;
2013-04-10 18:25:50 +02:00
}
2014-08-25 09:49:17 +02:00
const bool firstIsFunctionReturningBool = tokenIsFunctionReturningBool ( firstToken ) ;
const bool secondIsFunctionReturningBool = tokenIsFunctionReturningBool ( secondToken ) ;
if ( firstIsFunctionReturningBool & & secondIsFunctionReturningBool ) {
comparisonOfTwoFuncsReturningBoolError ( firstToken - > next ( ) , firstToken - > str ( ) , secondToken - > str ( ) ) ;
} else if ( firstIsFunctionReturningBool ) {
comparisonOfFuncReturningBoolError ( firstToken - > next ( ) , firstToken - > str ( ) ) ;
} else if ( secondIsFunctionReturningBool ) {
comparisonOfFuncReturningBoolError ( secondToken - > previous ( ) , secondToken - > str ( ) ) ;
2013-04-10 18:25:50 +02:00
}
}
}
}
void CheckBool : : comparisonOfFuncReturningBoolError ( const Token * tok , const std : : string & expression )
{
reportError ( tok , Severity : : style , " comparisonOfFuncReturningBoolError " ,
" Comparison of a function returning boolean value using relational (<, >, <= or >=) operator. \n "
" The return type of function ' " + expression + " ' is 'bool' "
" and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) "
" operator could cause unexpected results. " ) ;
}
void CheckBool : : comparisonOfTwoFuncsReturningBoolError ( const Token * tok , const std : : string & expression1 , const std : : string & expression2 )
{
reportError ( tok , Severity : : style , " comparisonOfTwoFuncsReturningBoolError " ,
" Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator. \n "
" The return type of function ' " + expression1 + " ' and function ' " + expression2 + " ' is 'bool' "
" and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=) "
" operator could cause unexpected results. " ) ;
}
//-------------------------------------------------------------------------------
// Comparison of bool with bool
//-------------------------------------------------------------------------------
void CheckBool : : checkComparisonOfBoolWithBool ( )
{
// FIXME: This checking is "experimental" because of the false positives
// when self checking lib/tokenize.cpp (#2617)
if ( ! _settings - > experimental )
return ;
if ( ! _settings - > isEnabled ( " style " ) )
return ;
if ( ! _tokenizer - > isCPP ( ) )
return ;
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > type ( ) ! = Token : : eComparisonOp | | tok - > str ( ) = = " == " | | tok - > str ( ) = = " != " )
continue ;
2014-12-01 16:22:56 +01:00
bool firstTokenBool = false ;
2013-04-10 18:25:50 +02:00
2014-12-01 16:22:56 +01:00
const Token * firstToken = tok - > previous ( ) ;
if ( firstToken - > varId ( ) ) {
if ( isBool ( firstToken - > variable ( ) ) ) {
firstTokenBool = true ;
2013-04-10 18:25:50 +02:00
}
}
2014-12-01 16:22:56 +01:00
if ( ! firstTokenBool )
2014-06-09 11:35:30 +02:00
continue ;
2014-12-01 16:22:56 +01:00
bool secondTokenBool = false ;
const Token * secondToken = tok - > next ( ) ;
if ( secondToken - > varId ( ) ) {
if ( isBool ( secondToken - > variable ( ) ) ) {
secondTokenBool = true ;
2013-04-10 18:25:50 +02:00
}
}
2014-12-01 16:22:56 +01:00
if ( secondTokenBool ) {
comparisonOfBoolWithBoolError ( firstToken - > next ( ) , secondToken - > str ( ) ) ;
2013-04-10 18:25:50 +02:00
}
}
}
}
void CheckBool : : comparisonOfBoolWithBoolError ( const Token * tok , const std : : string & expression )
{
reportError ( tok , Severity : : style , " comparisonOfBoolWithBoolError " ,
" Comparison of a variable having boolean value using relational (<, >, <= or >=) operator. \n "
" The variable ' " + expression + " ' is of type 'bool' "
" and comparing 'bool' value using relational (<, >, <= or >=) "
" operator could cause unexpected results. " ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CheckBool : : checkAssignBoolToPointer ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-03-27 05:39:48 +01:00
if ( tok - > str ( ) = = " = " & & astIsBool ( tok - > astOperand2 ( ) ) ) {
const Token * lhs = tok - > astOperand1 ( ) ;
2014-08-19 11:36:32 +02:00
while ( lhs & & ( lhs - > str ( ) = = " . " | | lhs - > str ( ) = = " :: " ) )
2014-03-27 05:39:48 +01:00
lhs = lhs - > astOperand2 ( ) ;
if ( ! lhs | | ! lhs - > variable ( ) | | ! lhs - > variable ( ) - > isPointer ( ) )
2013-10-05 08:53:37 +02:00
continue ;
2013-04-10 18:25:50 +02:00
2014-03-27 05:39:48 +01:00
assignBoolToPointerError ( tok ) ;
2013-04-10 18:25:50 +02:00
}
}
}
}
void CheckBool : : assignBoolToPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " assignBoolToPointer " ,
" Boolean value assigned to pointer. " ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CheckBool : : checkComparisonOfBoolExpressionWithInt ( )
{
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-03-27 16:10:43 +01:00
if ( ! tok - > isComparisonOp ( ) )
continue ;
2013-04-10 18:25:50 +02:00
const Token * numTok = 0 ;
2014-03-27 16:10:43 +01:00
const Token * boolExpr = 0 ;
bool numInRhs ;
if ( astIsBool ( tok - > astOperand1 ( ) ) ) {
boolExpr = tok - > astOperand1 ( ) ;
numTok = tok - > astOperand2 ( ) ;
numInRhs = true ;
} else if ( astIsBool ( tok - > astOperand2 ( ) ) ) {
boolExpr = tok - > astOperand2 ( ) ;
numTok = tok - > astOperand1 ( ) ;
numInRhs = false ;
} else {
continue ;
2013-04-10 18:25:50 +02:00
}
2014-06-09 11:35:30 +02:00
if ( ! numTok | | ! boolExpr )
2014-03-27 16:10:43 +01:00
continue ;
2013-09-07 11:32:11 +02:00
2014-06-09 11:35:30 +02:00
if ( Token : : Match ( boolExpr , " %bool% " ) )
// The CheckBool::checkComparisonOfBoolWithInt warns about this.
2014-03-27 16:10:43 +01:00
continue ;
2013-09-07 11:32:11 +02:00
2014-03-27 16:10:43 +01:00
if ( boolExpr - > isOp ( ) & & numTok - > isName ( ) & & Token : : Match ( tok , " ==|!= " ) )
// there is weird code such as: ((a<b)==c)
// but it is probably written this way by design.
continue ;
2013-09-07 11:32:11 +02:00
2014-03-27 16:10:43 +01:00
if ( numTok - > isNumber ( ) ) {
2015-01-09 23:43:45 +01:00
if ( numTok - > str ( ) = = " 0 " & &
( numInRhs ? Token : : Match ( tok , " >|==|!= " )
: Token : : Match ( tok , " <|==|!= " ) ) )
2014-03-27 16:10:43 +01:00
continue ;
2015-01-09 23:43:45 +01:00
if ( numTok - > str ( ) = = " 1 " & &
( numInRhs ? Token : : Match ( tok , " <|==|!= " )
: Token : : Match ( tok , " >|==|!= " ) ) )
2014-03-27 16:10:43 +01:00
continue ;
comparisonOfBoolExpressionWithIntError ( tok , true ) ;
} else if ( isNonBoolStdType ( numTok - > variable ( ) ) )
comparisonOfBoolExpressionWithIntError ( tok , false ) ;
2013-04-10 18:25:50 +02:00
}
}
}
void CheckBool : : comparisonOfBoolExpressionWithIntError ( const Token * tok , bool n0o1 )
{
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. " ) ;
}
2013-12-23 18:39:05 +01:00
void CheckBool : : pointerArithBool ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2015-03-12 20:07:48 +01:00
for ( std : : list < Scope > : : const_iterator scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
if ( scope - > type ! = Scope : : eIf & & scope - > type ! = Scope : : eWhile & & scope - > type ! = Scope : : eDo & & scope - > type ! = Scope : : eFor )
continue ;
const Token * tok = scope - > classDef - > next ( ) - > astOperand2 ( ) ;
if ( scope - > type = = Scope : : eFor ) {
tok = Token : : findsimplematch ( scope - > classDef - > tokAt ( 2 ) , " ; " ) ;
if ( tok )
tok = tok - > astOperand2 ( ) ;
if ( tok )
tok = tok - > astOperand1 ( ) ;
} else if ( scope - > type = = Scope : : eDo )
2015-04-06 17:23:48 +02:00
tok = ( scope - > classEnd - > tokAt ( 2 ) ) ? scope - > classEnd - > tokAt ( 2 ) - > astOperand2 ( ) : nullptr ;
2015-03-12 20:07:48 +01:00
pointerArithBoolCond ( tok ) ;
2013-12-23 18:39:05 +01:00
}
}
void CheckBool : : pointerArithBoolCond ( const Token * tok )
{
if ( ! tok )
return ;
if ( Token : : Match ( tok , " &&|%oror% " ) ) {
pointerArithBoolCond ( tok - > astOperand1 ( ) ) ;
pointerArithBoolCond ( tok - > astOperand2 ( ) ) ;
return ;
}
2015-03-12 20:07:48 +01:00
if ( tok - > str ( ) ! = " + " & & tok - > str ( ) ! = " - " )
2013-12-23 18:39:05 +01:00
return ;
if ( tok - > astOperand1 ( ) & &
tok - > astOperand1 ( ) - > isName ( ) & &
tok - > astOperand1 ( ) - > variable ( ) & &
tok - > astOperand1 ( ) - > variable ( ) - > isPointer ( ) & &
tok - > astOperand2 ( ) - > isNumber ( ) )
pointerArithBoolError ( tok ) ;
}
void CheckBool : : pointerArithBoolError ( const Token * tok )
{
reportError ( tok ,
Severity : : error ,
" pointerArithBool " ,
2013-12-25 19:56:00 +01:00
" Converting pointer arithmetic result to bool. The bool is always true unless there is undefined behaviour. \n "
" Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten. " ) ;
2013-12-23 18:39:05 +01:00
}
2014-05-24 18:35:49 +02:00
void CheckBool : : checkAssignBoolToFloat ( )
{
if ( ! _tokenizer - > isCPP ( ) )
return ;
if ( ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-05-24 20:02:12 +02:00
if ( Token : : Match ( tok , " %var% = " ) ) {
2014-09-11 16:55:00 +02:00
const Variable * const var = tok - > variable ( ) ;
2014-08-09 11:44:55 +02:00
if ( var & & var - > isFloatingType ( ) & & ! var - > isArrayOrPointer ( ) & & astIsBool ( tok - > next ( ) - > astOperand2 ( ) ) )
2014-05-24 18:35:49 +02:00
assignBoolToFloatError ( tok - > next ( ) ) ;
}
}
}
}
void CheckBool : : assignBoolToFloatError ( const Token * tok )
{
reportError ( tok , Severity : : style , " assignBoolToFloat " ,
" Boolean value assigned to floating point variable. " ) ;
}