2009-01-26 20:14:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2013-01-01 17:29:08 +01:00
* Copyright ( C ) 2007 - 2013 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 ( ) ;
2012-11-14 18:12:33 +01:00
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 , " %var% ++ " ) ) {
if ( tok - > varId ( ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > variable ( ) ;
2012-11-14 18:12:33 +01:00
if ( var & & var - > typeEndToken ( ) - > str ( ) = = " bool " )
incrementBooleanError ( tok ) ;
}
2011-02-11 23:38:23 +01:00
}
}
}
}
void CheckOther : : incrementBooleanError ( const Token * tok )
{
reportError (
tok ,
Severity : : style ,
" incrementboolean " ,
2012-09-16 19:44:02 +02:00
" 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. "
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
2012-11-14 18:12:33 +01:00
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 ( tok - > str ( ) = = " ? " ) {
// condition
const Token * cond = tok - > previous ( ) ;
if ( cond - > isName ( ) | | cond - > isNumber ( ) )
cond = cond - > previous ( ) ;
else if ( cond - > str ( ) = = " ) " )
cond = cond - > link ( ) - > previous ( ) ;
else
continue ;
2011-01-24 21:40:49 +01:00
2012-11-14 18:12:33 +01:00
if ( cond & & cond - > str ( ) = = " ! " )
cond = cond - > previous ( ) ;
2011-09-06 22:37:19 +02:00
2012-11-14 18:12:33 +01:00
if ( ! cond )
continue ;
2011-09-06 22:37:19 +02:00
2012-11-14 18:12:33 +01:00
// calculation
if ( ! cond - > isArithmeticalOp ( ) )
continue ;
2011-01-24 21:40:49 +01:00
2012-11-14 18:12:33 +01:00
const std : : string & op = cond - > str ( ) ;
cond = cond - > previous ( ) ;
2011-04-02 11:43:20 +02:00
2012-11-14 18:12:33 +01:00
// skip previous multiplications..
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
2012-11-14 18:12:33 +01:00
if ( ! cond )
continue ;
2011-01-24 21:40:49 +01:00
2012-11-14 18:12:33 +01:00
// first multiplication operand
if ( cond - > str ( ) = = " ) " ) {
2011-04-02 11:43:20 +02:00
clarifyCalculationError ( cond , op ) ;
2012-11-14 18:12:33 +01:00
} else if ( cond - > isName ( ) | | cond - > isNumber ( ) ) {
if ( Token : : Match ( cond - > previous ( ) , " return|=|+|-|,|( " ) | | cond - > strAt ( - 1 ) = = op )
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 " ,
2012-09-16 19:44:02 +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. "
2012-09-16 19:44:02 +02:00
" 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 ( ) ;
2012-11-14 18:12:33 +01:00
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 , " ( %var% [=&|^] " ) ) {
for ( const Token * tok2 = tok - > tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " [ " )
tok2 = tok2 - > link ( ) ;
else if ( tok2 - > type ( ) = = Token : : eComparisonOp ) {
// This might be a template
if ( ! isC & & tok2 - > link ( ) )
break ;
clarifyConditionError ( tok , tok - > strAt ( 2 ) = = " = " , false ) ;
2011-08-19 18:06:28 +02:00
break ;
2012-11-14 18:12:33 +01:00
} else if ( ! tok2 - > isName ( ) & & ! tok2 - > isNumber ( ) & & tok2 - > str ( ) ! = " . " )
break ;
}
2011-03-09 22:20:14 +01:00
}
}
}
2011-08-19 13:40:54 +02:00
// using boolean result in bitwise operation ! x [&|^]
2012-11-14 18:12:33 +01:00
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 ( ) ) {
2012-12-01 01:31:35 +01:00
if ( Token : : Match ( tok , " %comp%|! " ) ) {
2012-11-14 18:12:33 +01:00
if ( tok - > link ( ) ) // don't write false positives when templates are used
continue ;
2011-08-19 18:55:20 +02:00
2012-11-14 18:12:33 +01:00
const Token * tok2 = tok - > next ( ) ;
2011-08-19 18:06:28 +02:00
2012-11-14 18:12:33 +01: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 , " (|& " ) )
2011-08-19 18:06:28 +02:00
continue ;
2012-11-14 18:12:33 +01:00
while ( tok2 & & ( tok2 - > isName ( ) | | tok2 - > isNumber ( ) | | Token : : Match ( tok2 , " .|(|[ " ) ) ) {
if ( Token : : Match ( tok2 , " (|[ " ) )
tok2 = tok2 - > link ( ) ;
tok2 = tok2 - > next ( ) ;
2012-04-08 18:07:11 +02:00
}
2012-11-14 18:12:33 +01:00
if ( Token : : Match ( tok2 , " [&|^] " ) ) {
// don't write false positives when templates are used
if ( Token : : Match ( tok2 , " &|* ,|> " ) | | Token : : simpleMatch ( tok2 - > previous ( ) , " const & " ) )
continue ;
// #3609 - CWinTraits<WS_CHILD|WS_VISIBLE>::..
if ( ! isC & & Token : : Match ( tok - > previous ( ) , " %var% < " ) ) {
const Token * tok3 = tok2 ;
while ( Token : : Match ( tok3 , " [&|^] %var% " ) )
tok3 = tok3 - > tokAt ( 2 ) ;
if ( Token : : Match ( tok3 , " ,|> " ) )
continue ;
}
clarifyConditionError ( tok , false , true ) ;
}
2011-08-19 13:40:54 +02:00
}
}
}
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 )
2012-09-16 19:44:02 +02:00
errmsg = " Suspicious condition (assignment + comparison); Clarify expression with parentheses. " ;
2011-08-19 13:40:54 +02:00
else if ( boolop )
2012-09-16 19:44:02 +02:00
errmsg = " Boolean result is used in bitwise operation. Clarify expression with parentheses. \n "
" Suspicious expression. Boolean result is used in bitwise operation. The operator '!' "
2011-08-19 13:40:54 +02:00
" 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
2012-09-16 19:44:02 +02:00
errmsg = " Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses. \n "
2011-08-19 00:14:15 +02:00
" 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
//---------------------------------------------------------------------------
2013-02-10 07:43:09 +01:00
// Clarify (meaningless) statements like *foo++; with parentheses.
2012-08-24 11:28:50 +02:00
//---------------------------------------------------------------------------
void CheckOther : : clarifyStatement ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
2012-11-14 18:12:33 +01:00
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 ( ) ) {
if ( Token : : Match ( tok , " * %var% " ) ) {
const Token * tok2 = tok - > previous ( ) ;
while ( tok2 & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > previous ( ) ;
if ( Token : : Match ( tok2 , " [{};] " ) ) {
tok = tok - > tokAt ( 2 ) ;
for ( ; ; ) {
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 , " ++|-- [;,] " ) )
clarifyStatementError ( tok ) ;
2012-09-03 17:10:27 +02:00
}
2012-08-24 11:28:50 +02:00
}
}
}
}
2012-09-15 20:19:02 +02:00
void CheckOther : : clarifyStatementError ( const Token * tok )
2012-08-24 11:28:50 +02:00
{
2012-09-15 20:19:02 +02:00
reportError ( tok , Severity : : warning , " clarifyStatement " , " Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'? \n "
" A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. "
" Thus, the dereference is meaningless. Did you intend to write '(*A)++;'? " ) ;
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 ;
2012-11-14 18:12:33 +01:00
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% [&|] " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > next ( ) - > variable ( ) ;
2012-11-14 18:12:33 +01:00
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) == " ) " )) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > next ( ) - > variable ( ) ;
2012-11-14 18:12:33 +01:00
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 " ,
2012-09-16 19:44:02 +02:00
" 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 ;
2012-11-14 18:12:33 +01:00
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 ( ) ) {
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 ( ) ;
if ( nextTok & & nextTok - > str ( ) = = " ( " )
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 ( ) ;
2012-02-26 11:56:32 +01:00
nextTok = nextTok - > next ( ) ;
2012-11-14 18:12:33 +01:00
toTok = tok - > tokAt ( 2 ) ;
}
if ( toTok & & toTok - > str ( ) = = " const " )
toTok = toTok - > next ( ) ;
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
if ( ! nextTok | | ! toTok | | ! toTok - > isStandardType ( ) )
continue ;
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
// Find casted variable
2013-02-06 06:39:58 +01:00
const Variable * var = 0 ;
2012-11-14 18:12:33 +01:00
bool allocation = false ;
bool ref = false ;
if ( Token : : Match ( nextTok , " new %type% " ) )
allocation = true ;
else if ( Token : : Match ( nextTok , " %var% !![ " ) )
2013-02-06 06:39:58 +01:00
var = nextTok - > variable ( ) ;
2012-11-14 18:12:33 +01:00
else if ( Token : : Match ( nextTok , " & %var% " ) & & ! Token : : Match ( nextTok - > tokAt ( 2 ) , " (|[ " ) ) {
2013-02-06 06:39:58 +01:00
var = nextTok - > next ( ) - > variable ( ) ;
2012-11-14 18:12:33 +01:00
ref = true ;
}
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
const Token * fromTok = 0 ;
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
if ( allocation ) {
fromTok = nextTok - > next ( ) ;
} else {
if ( ! var | | ( ! ref & & ! var - > isPointer ( ) & & ! var - > isArray ( ) ) | | ( ref & & ( var - > isPointer ( ) | | var - > isArray ( ) ) ) )
continue ;
fromTok = var - > typeStartToken ( ) ;
}
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
while ( Token : : Match ( fromTok , " static|const " ) )
fromTok = fromTok - > next ( ) ;
if ( ! fromTok - > isStandardType ( ) )
continue ;
2012-02-26 11:56:32 +01:00
2012-11-14 18:12:33 +01:00
std : : string fromType = analyzeType ( fromTok ) ;
std : : string toType = analyzeType ( toTok ) ;
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 )
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : portability , " invalidPointerCast " , " Casting from " + from + " * to integer* is not portable due to different binary data representations on different platforms. " ) ;
2012-03-25 12:55:39 +02:00
else
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : portability , " invalidPointerCast " , " Casting from " + from + " * to char* is not portable due to different binary data representations on different platforms. " , true ) ;
2012-03-25 12:55:39 +02:00
} else
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : warning , " invalidPointerCast " , " Casting between " + from + " * and " + to + " * which have an incompatible binary data representation. " ) ;
2012-02-26 11:56:32 +01:00
}
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 ;
2012-11-14 18:12:33 +01:00
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 , " sizeof ( %num% ) " ) | |
Token : : Match ( tok , " sizeof %num% " ) ) {
sizeofForNumericParameterError ( tok ) ;
}
2011-05-16 21:16:25 +02:00
}
}
}
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 ,
2012-09-16 19:44:02 +02:00
" sizeofwithnumericparameter " , " Suspicious usage of 'sizeof' with a numeric constant as parameter. \n "
" It is unusual to use a 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 ( ) ;
2012-11-14 18:12:33 +01:00
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 , " sizeof ( %var% ) " ) | |
Token : : Match ( tok , " sizeof %var% !![ " ) ) {
const Token * varTok = tok - > next ( ) ;
if ( varTok - > str ( ) = = " ( " ) {
varTok = varTok - > next ( ) ;
}
if ( varTok - > varId ( ) > 0 ) {
2013-02-06 06:39:58 +01:00
const Variable * var = varTok - > variable ( ) ;
2012-11-14 18:12:33 +01: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 ,
2012-09-16 19:44:02 +02:00
" sizeofwithsilentarraypointer " , " Using 'sizeof' on array given as function argument "
" returns size of a pointer. \n "
" Using 'sizeof' for array given as function argument returns the size of a pointer. "
" It does not return the size of the whole array in bytes as might be "
2011-08-19 17:53:43 +02:00
" expected. For example, this code: \n "
" int f(char a[100]) { \n "
" return sizeof(a); \n "
" } \n "
2012-09-16 19:44:02 +02:00
" returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
2011-08-19 17:53:43 +02:00
" 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-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
2012-11-14 18:12:33 +01:00
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 ( ) ) {
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 ( ) ;
} else if ( Token : : simpleMatch ( tok , " memset ( " ) ) {
variable = tok - > tokAt ( 2 ) ;
tokVar = variable - > tokAt ( 2 ) - > nextArgument ( ) ;
// The following tests can be inconclusive in case the variable in sizeof
// is constant string by intention
} else if ( ! _settings - > inconclusive ) {
continue ;
2012-03-23 21:47:13 +01:00
2012-11-14 18:12:33 +01:00
} else if ( Token : : Match ( tok , " memcpy|memcmp|memmove|strncpy|strncmp|strncat ( " ) ) {
variable = tok - > tokAt ( 2 ) ;
variable2 = variable - > nextArgument ( ) ;
tokVar = variable2 - > nextArgument ( ) ;
2011-10-28 22:06:55 +02:00
2012-11-14 18:12:33 +01:00
} else {
continue ;
}
2011-10-28 22:06:55 +02:00
2012-11-14 18:12:33 +01:00
// Ensure the variables are in the symbol database
// Also ensure the variables are pointers
// Only keep variables which are pointers
2013-02-06 06:39:58 +01:00
const Variable * var = variable - > variable ( ) ;
2012-04-18 16:35:04 +02:00
if ( ! var | | ! var - > isPointer ( ) | | var - > isArray ( ) ) {
2012-11-14 18:12:33 +01:00
variable = 0 ;
2012-03-20 18:50:05 +01:00
}
2012-11-14 18:12:33 +01:00
if ( variable2 ) {
2013-02-06 06:39:58 +01:00
var = variable2 - > variable ( ) ;
2012-11-14 18:12:33 +01:00
if ( ! var | | ! var - > isPointer ( ) | | var - > isArray ( ) ) {
variable2 = 0 ;
}
}
// If there are no pointer variable at this point, there is
// no need to continue
if ( variable = = 0 & & variable2 = = 0 ) {
continue ;
}
2012-03-23 21:47:13 +01:00
2012-11-14 18:12:33 +01:00
// Jump to the next sizeof token in the function and in the parameter
// This is to allow generic operations with sizeof
for ( ; tokVar & & tokVar - > str ( ) ! = " ) " & & tokVar - > str ( ) ! = " , " & & tokVar - > str ( ) ! = " sizeof " ; tokVar = tokVar - > next ( ) ) { }
// Now check for the sizeof usage. Once here, everything using sizeof(varid) or sizeof(&varid)
// looks suspicious
// Do it for first variable
if ( variable & & ( Token : : Match ( tokVar , " sizeof ( &| %varid% ) " , variable - > varId ( ) ) | |
Token : : Match ( tokVar , " sizeof &| %varid% " , variable - > varId ( ) ) ) ) {
sizeofForPointerError ( variable , variable - > str ( ) ) ;
} else if ( variable2 & & ( Token : : Match ( tokVar , " sizeof ( &| %varid% ) " , variable2 - > varId ( ) ) | |
Token : : Match ( tokVar , " sizeof &| %varid% " , variable2 - > varId ( ) ) ) ) {
sizeofForPointerError ( variable2 , variable2 - > str ( ) ) ;
}
2012-03-23 21:47:13 +01:00
}
}
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 " ,
2012-09-16 19:44:02 +02:00
" Size of pointer ' " + varname + " ' used instead of size of its data. \n "
" Size of pointer ' " + varname + " ' used instead of size of its data. "
2012-05-06 19:37:41 +02:00
" This is likely to lead to a buffer overflow. You probably intend to "
2012-09-16 19:44:02 +02:00
" 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 ) ;
2012-12-07 20:45:20 +01:00
if ( ! var | | ( ! var - > isLocal ( ) & & ! var - > isArgument ( ) ) | | var - > isStatic ( ) ) {
2012-09-03 10:46:51 +02:00
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 : : 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
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 ;
}
2012-11-15 07:48:45 +01:00
if ( Token : : simpleMatch ( tok - > tokAt ( 2 ) , " 0 ; " ) )
varAssignments . erase ( tok - > varId ( ) ) ;
else
varAssignments [ tok - > varId ( ) ] = tok ;
2012-09-02 13:09:32 +02:00
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 ( ) ) ;
2012-09-07 11:59:20 +02:00
} else if ( ! Token : : simpleMatch ( tok - > tokAt ( - 2 ) , " sizeof ( " ) ) { // Other usage of variable
2012-09-02 13:09:32 +02:00
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
2012-11-06 19:54:52 +01:00
bool memfunc = Token : : Match ( tok , " memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat " ) ;
2012-09-02 13:09:32 +02:00
if ( memfunc ) {
const Token * param1 = tok - > tokAt ( 2 ) ;
writtenArgumentsEnd = param1 - > next ( ) ;
2012-11-06 19:54:52 +01:00
if ( param1 - > varId ( ) & & param1 - > strAt ( 1 ) = = " , " & & ! Token : : Match ( tok , " strcat|strncat|wcscat|wcsncat " ) ) {
2012-09-02 13:09:32 +02:00
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
2013-01-31 06:41:18 +01:00
const Function * func = tok - > function ( ) ;
2012-09-02 13:09:32 +02:00
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 " ,
2012-09-16 19:44:02 +02:00
" Buffer ' " + var + " ' is being written before its old content has been used. 'break;' missing? " ) ;
2012-09-02 13:09:32 +02:00
}
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 " ,
2012-09-16 19:44:02 +02:00
" Variable ' " + var + " ' is reassigned a value before the old one has been used. 'break;' missing? " ) ;
2012-09-02 13:09:32 +02:00
}
2010-06-30 09:10:30 +02:00
//---------------------------------------------------------------------------
// switch (x)
// {
// case 2:
// y = a; // <- this assignment is redundant
// case 3:
// y = b; // <- case 2 falls through and sets y twice
// }
//---------------------------------------------------------------------------
2013-01-17 10:15:01 +01:00
static inline bool isFunctionOrBreakPattern ( const Token * tok )
{
if ( Token : : Match ( tok , " %var% ( " ) | | Token : : Match ( tok , " break|continue|return|exit|goto|throw " ) )
return true ;
return false ;
}
2010-06-30 09:10:30 +02:00
void CheckOther : : checkRedundantAssignmentInSwitch ( )
{
2011-12-16 19:21:14 +01:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
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 ( ) ) ;
2013-01-17 10:15:01 +01:00
} else if ( isFunctionOrBreakPattern ( tok3 ) ) {
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;
2013-01-17 10:15:01 +01:00
if ( isFunctionOrBreakPattern ( tok2 ) ) {
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 ,
2012-09-16 19:44:02 +02:00
" redundantBitwiseOperationInSwitch " , " Redundant bitwise operation on ' " + varname + " ' in 'switch' statement. 'break;' missing? " ) ;
2012-05-29 06:19:22 +02:00
}
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 ( ) ;
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 ( ) ;
2013-01-17 10:15:01 +01:00
} else if ( Token : : Match ( tok2 , " break|continue|return|exit|goto|throw " ) ) {
2011-10-13 20:53:06 +02:00
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 ,
2012-09-16 19:44:02 +02:00
" switchCaseFallThrough " , " Switch falls through case without comment. 'break;' missing? " ) ;
2011-08-19 17:53:43 +02:00
}
2011-02-19 09:33:29 +01:00
2012-12-07 21:27:32 +01:00
//---------------------------------------------------------------------------
// Check for statements like case A||B: in switch()
//---------------------------------------------------------------------------
void CheckOther : : checkSuspiciousCaseInSwitch ( )
{
if ( ! _settings - > inconclusive | | ! _settings - > isEnabled ( " style " ) )
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
if ( i - > type ! = Scope : : eSwitch )
continue ;
for ( const Token * tok = i - > classStart - > next ( ) ; tok ! = i - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " case " ) {
2012-12-07 21:44:30 +01:00
const Token * end = 0 ;
2012-12-07 21:27:32 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2012-12-07 21:44:30 +01:00
if ( tok2 - > str ( ) = = " : " ) {
end = tok2 ;
2012-12-07 21:27:32 +01:00
break ;
2012-12-07 21:44:30 +01:00
}
if ( Token : : Match ( tok2 , " [?;}{] " ) ) {
break ;
}
}
if ( end ) {
const Token * finding = Token : : findmatch ( tok - > next ( ) , " &&|%oror% " , end ) ;
if ( finding )
suspiciousCaseInSwitchError ( tok , finding - > str ( ) ) ;
2012-12-07 21:27:32 +01:00
}
}
}
}
}
void CheckOther : : suspiciousCaseInSwitchError ( const Token * tok , const std : : string & operatorString )
{
reportError ( tok , Severity : : warning , " suspiciousCase " ,
" Found suspicious case label in switch(). Operator ' " + operatorString + " ' probably doesn't work as intended. \n "
" Using an operator like ' " + operatorString + " ' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead? " , true ) ;
}
2013-01-18 08:03:04 +01:00
//---------------------------------------------------------------------------
// if (x == 1)
// x == 0; // <- suspicious equality comparison.
//---------------------------------------------------------------------------
void CheckOther : : checkSuspiciousEqualityComparison ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : simpleMatch ( tok , " for ( " ) ) {
2013-01-19 01:34:15 +01:00
const Token * const openParen = tok - > next ( ) ;
const Token * const closeParen = tok - > linkAt ( 1 ) ;
2013-01-18 08:03:04 +01:00
// Search for any suspicious equality comparison in the initialization
// or increment-decrement parts of the for() loop.
// For example:
// for (i == 2; i < 10; i++)
// or
// for (i = 0; i < 10; i == a)
2013-01-19 01:34:15 +01:00
const Token * tok2 = Token : : findmatch ( openParen , " [;(] %var% == %any% [;)] " , closeParen ) ;
if ( tok2 & & ( tok2 = = openParen | | tok2 - > tokAt ( 4 ) = = closeParen ) ) {
2013-01-18 08:03:04 +01:00
suspiciousEqualityComparisonError ( tok2 - > tokAt ( 2 ) ) ;
}
// Equality comparisons with 0 are simplified to negation. For instance,
// (x == 0) is simplified to (!x), so also check for suspicious negation
// in the initialization or increment-decrement parts of the for() loop.
// For example:
// for (!i; i < 10; i++)
2013-01-19 01:34:15 +01:00
const Token * tok3 = Token : : findmatch ( openParen , " [;(] ! %var% [;)] " , closeParen ) ;
if ( tok3 & & ( tok3 = = openParen | | tok3 - > tokAt ( 3 ) = = closeParen ) ) {
2013-01-18 08:03:04 +01:00
suspiciousEqualityComparisonError ( tok3 - > tokAt ( 2 ) ) ;
}
// Skip over for() loop conditions because "for (;running==1;)"
// is a bit strange, but not necessarily incorrect.
2013-01-19 01:34:15 +01:00
tok = closeParen ;
2013-01-18 08:03:04 +01:00
}
if ( Token : : Match ( tok , " [;{}] *| %var% == %any% ; " ) ) {
// Exclude compound statements surrounded by parentheses, such as
// printf("%i\n", ({x==0;}));
// because they may appear as an expression in GNU C/C++.
// See http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
const Token * afterStatement = tok - > strAt ( 1 ) = = " * " ? tok - > tokAt ( 6 ) : tok - > tokAt ( 5 ) ;
if ( ! Token : : simpleMatch ( afterStatement , " } ) " ) )
suspiciousEqualityComparisonError ( tok - > next ( ) ) ;
}
}
}
void CheckOther : : suspiciousEqualityComparisonError ( const Token * tok )
{
reportError ( tok , Severity : : warning , " suspiciousEqualityComparison " ,
" Found suspicious equality comparison. Did you intend to assign a value instead? " , true ) ;
}
2012-12-07 21:27:32 +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
}
2013-01-17 10:15:01 +01:00
static inline const Token * findSelfAssignPattern ( const Token * start )
{
return Token : : findmatch ( start , " %var% = %var% ;|=|) " ) ;
}
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 ;
2013-01-17 10:15:01 +01:00
const Token * tok = findSelfAssignPattern ( _tokenizer - > tokens ( ) ) ;
2011-10-13 20:53:06 +02:00
while ( tok ) {
2012-11-03 21:16:05 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [;{}.] " ) & &
2011-02-12 14:27:07 +01:00
tok - > varId ( ) & & tok - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) & &
2013-02-06 06:39:58 +01:00
isTypeWithoutSideEffects ( _tokenizer , tok - > variable ( ) ) ) {
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
}
2013-01-17 10:15:01 +01:00
tok = findSelfAssignPattern ( tok - > next ( ) ) ;
2010-08-15 06:28:22 +02:00
}
}
2011-08-19 17:53:43 +02:00
void CheckOther : : selfAssignmentError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : warning ,
2012-09-16 19:44:02 +02:00
" selfAssignment " , " Redundant assignment of ' " + varname + " ' to itself. " ) ;
2011-08-19 17:53:43 +02:00
}
2010-10-10 22:05:06 +02:00
//---------------------------------------------------------------------------
// int a = 1;
// assert(a = 2); // <- assert should not have a side-effect
//---------------------------------------------------------------------------
2013-01-17 10:15:01 +01:00
static inline const Token * findAssertPattern ( const Token * start )
{
return Token : : findmatch ( start , " assert ( %any% " ) ;
}
2010-10-10 22:05:06 +02:00
void CheckOther : : checkAssignmentInAssert ( )
{
2011-08-07 09:28:08 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
2010-10-11 17:59:08 +02:00
return ;
2013-01-17 10:15:01 +01:00
const Token * tok = findAssertPattern ( _tokenizer - > tokens ( ) ) ;
2010-10-10 22:05:06 +02:00
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
}
2013-01-17 10:15:01 +01:00
tok = findAssertPattern ( endTok - > next ( ) ) ;
2010-10-10 22:05:06 +02:00
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 "
2012-09-16 19:44:02 +02:00
" assert statement is not executed. If the code is needed also in release "
" builds, this is a bug. " ) ;
2011-08-19 17:53:43 +02:00
}
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-11-13 18:30:33 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t ii = 0 ; ii < functions ; + + ii ) {
const Scope * scope = symbolDatabase - > functionScopes [ ii ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2013-01-16 15:37:07 +01:00
// Find a pair of comparison expressions with or without parentheses
2012-11-13 18:30:33 +01:00
// with a shared variable and constants and with a logical operator between them.
// e.g. if (x != 3 || x != 4)
const Token * term1Tok = NULL , * term2Tok = NULL ;
const Token * op1Tok = NULL , * op2Tok = NULL , * op3Tok = NULL , * nextTok = NULL ;
2012-12-01 01:31:35 +01:00
if ( Token : : Match ( tok , " ( %any% %comp% %any% ) &&|%oror% " ) ) {
2012-11-13 18:30:33 +01:00
term1Tok = tok - > next ( ) ;
op1Tok = tok - > tokAt ( 2 ) ;
op2Tok = tok - > tokAt ( 5 ) ;
2012-12-01 01:31:35 +01:00
} else if ( Token : : Match ( tok , " %any% %comp% %any% &&|%oror% " ) ) {
2012-11-13 18:30:33 +01:00
term1Tok = tok ;
op1Tok = tok - > next ( ) ;
op2Tok = tok - > tokAt ( 3 ) ;
}
if ( op2Tok ) {
2012-12-01 01:31:35 +01:00
if ( Token : : Match ( op2Tok - > next ( ) , " ( %any% %comp% %any% ) %any% " ) ) {
2012-11-13 18:30:33 +01:00
term2Tok = op2Tok - > tokAt ( 2 ) ;
op3Tok = op2Tok - > tokAt ( 3 ) ;
nextTok = op2Tok - > tokAt ( 6 ) ;
2012-12-01 01:31:35 +01:00
} else if ( Token : : Match ( op2Tok - > next ( ) , " %any% %comp% %any% %any% " ) ) {
2012-11-13 18:30:33 +01:00
term2Tok = op2Tok - > next ( ) ;
op3Tok = op2Tok - > tokAt ( 2 ) ;
nextTok = op2Tok - > tokAt ( 4 ) ;
}
2012-03-12 19:06:30 +01:00
}
2010-10-25 03:14:21 +02:00
2012-11-13 18:30:33 +01:00
if ( nextTok ) {
// Find the common variable and the two different-valued constants
std : : string firstConstant , secondConstant ;
bool varFirst1 , varFirst2 ;
unsigned int varId ;
const Token * var1Tok = NULL , * var2Tok = NULL ;
if ( Token : : Match ( term1Tok , " %var% %any% %num% " ) ) {
var1Tok = term1Tok ;
varId = var1Tok - > varId ( ) ;
if ( ! varId ) {
continue ;
}
varFirst1 = true ;
firstConstant = term1Tok - > strAt ( 2 ) ;
} else if ( Token : : Match ( term1Tok , " %num% %any% %var% " ) ) {
var1Tok = term1Tok - > tokAt ( 2 ) ;
varId = var1Tok - > varId ( ) ;
if ( ! varId ) {
continue ;
}
varFirst1 = false ;
firstConstant = term1Tok - > str ( ) ;
} else {
2010-12-29 10:07:28 +01:00
continue ;
2011-01-16 22:57:29 +01:00
}
2012-11-13 18:30:33 +01:00
if ( Token : : Match ( term2Tok , " %var% %any% %num% " ) ) {
var2Tok = term2Tok ;
varFirst2 = true ;
secondConstant = term2Tok - > strAt ( 2 ) ;
} else if ( Token : : Match ( term2Tok , " %num% %any% %var% " ) ) {
var2Tok = term2Tok - > tokAt ( 2 ) ;
varFirst2 = false ;
secondConstant = term2Tok - > str ( ) ;
} else {
2011-07-17 04:06:23 +02:00
continue ;
2010-11-21 09:06:43 +01:00
}
2012-11-13 18:30:33 +01:00
if ( varId ! = var2Tok - > varId ( ) | | firstConstant . empty ( ) | | secondConstant . empty ( ) ) {
2011-07-17 04:06:23 +02:00
continue ;
2012-11-13 18:30:33 +01:00
}
2011-07-17 04:06:23 +02:00
2012-11-13 18:30:33 +01:00
enum LogicError { AlwaysFalse , AlwaysTrue , FirstTrue , FirstFalse , SecondTrue , SecondFalse } ;
static const struct LinkedConditions {
const char * before ;
Condition c1 ;
const char * op2TokStr ;
Condition c2 ;
const char * after ;
Relation relation ;
LogicError error ;
} conditions [ ] = {
{ " !!&& " , { 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
{ " !!&& " , { 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
{ " !!&& " , { 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
{ 0 , { First , " >|>= " } , " && " , { First , " >|>= " } , 0 , MoreEqual , SecondTrue } , // (x > 4) && (x > 5) <- second expression always true
{ 0 , { First , " <|<= " } , " && " , { First , " <|<= " } , 0 , MoreEqual , SecondTrue } , // (x < 5) && (x < 4) <- second expression always true
{ 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
} ;
for ( unsigned int i = 0 ; i < ( sizeof ( conditions ) / sizeof ( conditions [ 0 ] ) ) ; i + + ) {
if ( ! Token : : Match ( op2Tok , conditions [ i ] . op2TokStr ) )
continue ;
2011-07-17 04:06:23 +02:00
2012-11-13 18:30:33 +01:00
if ( conditions [ i ] . before ! = 0 & & ! Token : : Match ( tok - > previous ( ) , conditions [ i ] . before ) )
continue ;
2011-07-17 04:06:23 +02:00
2012-11-13 18:30:33 +01:00
if ( conditions [ i ] . after ! = 0 & & ! Token : : Match ( nextTok , conditions [ i ] . after ) )
continue ;
2012-04-02 11:21:04 +02:00
2012-11-13 18:30:33 +01:00
if ( tok - > previous ( ) - > isArithmeticalOp ( ) | | nextTok - > isArithmeticalOp ( ) )
continue ;
std : : string cond1str = var1Tok - > str ( ) + " " + ( varFirst1 ? op1Tok - > str ( ) : invertOperatorForOperandSwap ( op1Tok - > str ( ) ) ) + " " + firstConstant ;
std : : string cond2str = var2Tok - > str ( ) + " " + ( varFirst2 ? op3Tok - > str ( ) : invertOperatorForOperandSwap ( op3Tok - > str ( ) ) ) + " " + secondConstant ;
// 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 ) ;
if ( ! error )
std : : swap ( cond1str , cond2str ) ;
// 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 ) {
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 +
" is always " + ( ( conditions [ i ] . error = = SecondTrue | | conditions [ i ] . error = = AlwaysTrue ) ? " true " : " false " ) + " . " ;
redundantConditionError ( term1Tok , text ) ;
}
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 "
2012-11-10 11:31:36 +01:00
" Logical disjunction always evaluates to true: " + condition + " . "
2012-03-15 20:38:28 +01:00
" 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 "
2012-11-10 11:31:36 +01:00
" Logical conjunction always evaluates to false: " + condition + " . "
2012-03-15 20:38:28 +01:00
" 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 ( ) ) {
2012-11-06 19:54:52 +01:00
if ( ! Token : : Match ( tok , " strtol|strtoul|strtoll|strtoull|wcstol|wcstoul|wcstoll|wcstoull ( " ) )
2009-01-26 20:14:46 +01:00
continue ;
2012-09-16 19:44:02 +02:00
const std : : string & funcname = tok - > str ( ) ;
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 ) ) ) {
2012-09-16 19:44:02 +02:00
dangerousUsageStrtolError ( tok , funcname ) ;
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 ;
2012-11-06 19:54:52 +01:00
if ( Token : : Match ( tok , " sprintf|snprintf|swprintf ( %var% , " ) )
2009-01-26 20:14:46 +01:00
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
2012-11-06 19:54:52 +01:00
else if ( Token : : Match ( tok , " sprintf|snprintf|swprintf ( %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 ","
2012-11-06 19:54:52 +01:00
if ( tok - > str ( ) = = " snprintf " | | tok - > str ( ) = = " swprintf " ) { // Jump over second parameter for snprintf and swprintf
2011-11-26 21:15:16 +01:00
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 ) ) {
2012-09-16 19:44:02 +02:00
sprintfOverlappingDataError ( tok2 , tok2 - > 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
}
}
2012-09-16 19:44:02 +02:00
void CheckOther : : dangerousUsageStrtolError ( const Token * tok , const std : : string & funcname )
2011-08-19 17:53:43 +02:00
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " dangerousUsageStrtol " , " Invalid radix in call to " + funcname + " (). It must be 0 or 2-36. " ) ;
2011-08-19 17:53:43 +02:00
}
void CheckOther : : sprintfOverlappingDataError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " sprintfOverlappingData " ,
2012-09-16 19:44:02 +02:00
" Undefined behavior: Variable ' " + varname + " ' is used as parameter and destination in s[n]printf(). \n "
" The variable ' " + varname + " ' is used both as a parameter and as destination in "
2011-08-19 17:53:43 +02:00
" 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): "
2012-09-16 19:44:02 +02:00
" \" If copying takes place between objects that overlap as a result of a call "
" to sprintf() or snprintf(), the results are undefined. \" " ) ;
2011-08-19 17:53:43 +02:00
}
//---------------------------------------------------------------------------
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 ( ) ;
2012-11-15 07:11:45 +01:00
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 - > next ( ) & & tok - > next ( ) - > type ( ) = = Token : : eComparisonOp & & ( ! tok - > previous ( ) | | ! tok - > previous ( ) - > isArithmeticalOp ( ) ) & & ( ! tok - > tokAt ( 3 ) | | ! tok - > tokAt ( 3 ) - > isArithmeticalOp ( ) ) ) {
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 ) ;
2013-02-06 06:39:58 +01:00
if ( isBool ( varTok - > variable ( ) ) & & // Variable has to be a boolean
2012-11-15 07:11:45 +01:00
( ( 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
2013-02-06 06:39:58 +01:00
if ( isNonBoolStdType ( right - > variable ( ) ) ) { // Variable has to be of non-boolean standard type
2012-11-15 07:11:45 +01:00
comparisonOfBoolWithIntError ( right , tok - > str ( ) , false ) ;
} else if ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , tok - > str ( ) ) ;
}
} else if ( tok - > varId ( ) & & right - > isBoolean ( ) ) { // Comparing variable with boolean constant
2013-02-06 06:39:58 +01:00
if ( isNonBoolStdType ( tok - > variable ( ) ) ) { // Variable has to be of non-boolean standard type
2012-11-15 07:11:45 +01:00
comparisonOfBoolWithIntError ( tok , right - > str ( ) , false ) ;
} else if ( tok - > strAt ( 1 ) ! = " == " & & tok - > strAt ( 1 ) ! = " != " ) {
comparisonOfBoolWithInvalidComparator ( right , tok - > str ( ) ) ;
}
} else if ( tok - > isNumber ( ) & & right - > isBoolean ( ) ) { // number constant with boolean constant
2012-04-02 15:45:51 +02:00
comparisonOfBoolWithIntError ( tok , right - > str ( ) , false ) ;
2012-11-15 07:11:45 +01:00
} 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
2013-02-06 06:39:58 +01:00
const Variable * var1 = right - > variable ( ) ;
const Variable * var2 = tok - > variable ( ) ;
2012-11-15 07:11:45 +01:00
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 ) ;
2012-04-02 15:45:51 +02:00
}
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 " ,
2012-09-16 19:44:02 +02:00
" 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 "
2012-04-02 15:45:51 +02:00
" neither 1 nor 0. " ) ;
else
reportError ( tok , Severity : : warning , " comparisonOfBoolWithInt " ,
2012-09-16 19:44:02 +02:00
" Comparison of a boolean with an integer. \n "
" The expression ' " + expression + " ' is of type 'bool' "
" and it is compared against an 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 " ,
2012-09-16 19:44:02 +02:00
" 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 >=) "
2012-07-03 06:39:13 +02:00
" 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 "
2012-09-16 19:44:02 +02:00
" Consecutive return, break, continue, goto or throw statements are unnecessary. "
" The second statement 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
//---------------------------------------------------------------------------
2013-01-30 16:50:12 +01:00
bool CheckOther : : isUnsigned ( const Variable * var ) const
2011-12-17 19:04:03 +01:00
{
2013-01-30 16:50:12 +01:00
return ( var & & var - > typeStartToken ( ) - > isUnsigned ( ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & _tokenizer - > sizeOfType ( var - > typeStartToken ( ) ) > = _settings - > sizeof_int ) ;
2012-01-28 12:32:28 +01:00
}
2013-01-30 16:50:12 +01:00
bool CheckOther : : isSigned ( const Variable * var ) const
2012-01-28 12:32:28 +01:00
{
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
{
2012-01-28 12:32:28 +01:00
bool style = _settings - > isEnabled ( " style " ) ;
2011-12-17 19:04:03 +01:00
2012-11-15 07:11:45 +01:00
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 ] ;
const Token * ifTok = 0 ;
// Check for "ivar / uvar" and "uvar / ivar"
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-01-28 12:32:28 +01:00
2012-11-15 07:11:45 +01:00
if ( Token : : Match ( tok , " [).] " ) ) // Don't check members or casted variables
continue ;
if ( Token : : Match ( tok - > next ( ) , " %var% / %num% " ) ) {
2013-02-06 06:39:58 +01:00
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' & & isUnsigned ( tok - > next ( ) - > variable ( ) ) ) {
2012-11-15 07:11:45 +01:00
udivError ( tok - > next ( ) , false ) ;
}
} else if ( Token : : Match ( tok - > next ( ) , " %num% / %var% " ) ) {
2013-02-06 06:39:58 +01:00
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' & & isUnsigned ( tok - > tokAt ( 3 ) - > variable ( ) ) ) {
2012-11-15 07:11:45 +01:00
udivError ( tok - > next ( ) , false ) ;
}
} else if ( Token : : Match ( tok - > next ( ) , " %var% / %var% " ) & & _settings - > inconclusive & & style & & ! ifTok ) {
2013-02-06 06:39:58 +01:00
const Variable * var1 = tok - > next ( ) - > variable ( ) ;
const Variable * var2 = tok - > tokAt ( 3 ) - > variable ( ) ;
2012-11-15 07:11:45 +01:00
if ( ( isUnsigned ( var1 ) & & isSigned ( var2 ) ) | | ( isUnsigned ( var2 ) & & isSigned ( var1 ) ) ) {
udivError ( tok - > next ( ) , true ) ;
}
} else if ( ! ifTok & & Token : : simpleMatch ( tok , " if ( " ) )
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 ;
2012-11-15 07:11:45 +01:00
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 : : simpleMatch ( tok , " memset ( " ) ) {
const Token * lastParamTok = tok - > next ( ) - > link ( ) - > previous ( ) ;
if ( lastParamTok - > str ( ) = = " 0 " )
memsetZeroBytesError ( tok , tok - > strAt ( 2 ) ) ;
}
2011-10-22 22:34:10 +02:00
}
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 )
{
2012-09-16 19:44:02 +02:00
const std : : string summary ( " memset() called to fill 0 bytes of ' " + varname + " '. " ) ;
2011-08-19 17:53:43 +02:00
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..
2013-02-10 07:43:09 +01:00
bool used1 = false ; // used in one sub-scope -> reducible
bool used2 = false ; // used in more sub-scopes -> not reducible
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 " ,
2012-09-16 19:44:02 +02:00
" The scope of the variable ' " + varname + " ' can be reduced. \n "
" The scope of the variable ' " + varname + " ' can be reduced. Warning: Be careful "
" when fixing this message, especially when there are inner loops. Here is an "
2011-08-19 17:53:43 +02:00
" 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 "
2012-09-16 19:44:02 +02:00
" // it's safe to move 'int i = 0;' here \n "
2011-08-19 17:53:43 +02:00
" for (int n = 0; n < 10; ++n) { \n "
2012-09-16 19:44:02 +02:00
" // it is possible but not safe to move 'int i = 0;' here \n "
2011-08-19 17:53:43 +02:00
" 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
{
2012-09-10 19:02:32 +02:00
if ( ! _settings - > isEnabled ( " performance " ) | | _tokenizer - > isC ( ) )
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-09-07 11:59:20 +02:00
} else if ( Token : : Match ( tok , " std :: %type% < " ) & & ! Token : : simpleMatch ( 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 "
2012-09-16 19:44:02 +02:00
" Parameter ' " + parname + " ' is passed by value. It could be passed "
2011-08-19 17:53:43 +02:00
" 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 ( ) ;
2012-11-15 07:11:45 +01:00
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 ( ) ) {
if ( ( tok - > str ( ) ! = " . " ) & & Token : : Match ( tok - > next ( ) , " %var% [ %var% ] " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * arrayvar = tok - > next ( ) - > variable ( ) ;
const Variable * indexvar = tok - > tokAt ( 3 ) - > variable ( ) ;
2012-11-15 07:11:45 +01:00
const MathLib : : bigint arraysize = ( arrayvar & & arrayvar - > isArray ( ) ) ? arrayvar - > dimension ( 0U ) : 0 ;
if ( isSignedChar ( indexvar ) & & arraysize > 0x80 )
charArrayIndexError ( tok - > next ( ) ) ;
}
else if ( Token : : Match ( tok , " [;{}] %var% = %any% [&^|] %any% ; " ) ) {
// is a char variable used in the calculation?
2013-02-06 06:39:58 +01:00
if ( ! isSignedChar ( tok - > tokAt ( 3 ) - > variable ( ) ) & &
! isSignedChar ( tok - > tokAt ( 5 ) - > variable ( ) ) )
2012-11-15 07:11:45 +01:00
continue ;
2011-08-14 16:39:45 +02:00
2012-11-15 07:11:45 +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 ;
}
2011-11-06 11:26:28 +01:00
2012-11-15 07:11:45 +01:00
// is the result stored in a short|int|long?
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > next ( ) - > variable ( ) ;
2012-11-15 07:11:45 +01:00
if ( var & & Token : : Match ( var - > typeStartToken ( ) , " short|int|long " ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) )
charBitOpError ( tok - > tokAt ( 4 ) ) ; // This is an error..
2011-12-17 19:04:03 +01:00
}
2009-06-20 19:24:58 +02:00
2012-11-15 07:11:45 +01:00
else if ( Token : : Match ( tok , " [;{}] %var% = %any% [&^|] ( * %var% ) ; " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > tokAt ( 7 ) - > variable ( ) ;
2012-11-15 07:11:45 +01:00
if ( ! var | | ! var - > isPointer ( ) | | var - > typeStartToken ( ) - > str ( ) ! = " char " | | var - > typeStartToken ( ) - > isUnsigned ( ) )
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
2012-11-15 07:11:45 +01:00
// is the result stored in a short|int|long?
2013-02-06 06:39:58 +01:00
var = tok - > next ( ) - > variable ( ) ;
2012-11-15 07:11:45 +01:00
if ( var & & Token : : Match ( var - > typeStartToken ( ) , " short|int|long " ) & & ! var - > isPointer ( ) & & ! var - > isArray ( ) )
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 " ,
2012-09-16 19:44:02 +02:00
" Signed 'char' type used as array index. \n "
" Signed 'char' type used as array index. If the value "
" can be greater than 127 there will be a buffer underflow "
" because of sign extension. " ) ;
2011-08-19 17:53:43 +02:00
}
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 " ,
2012-09-16 19:44:02 +02:00
" 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 "
2011-08-19 17:53:43 +02:00
" char c = 0x80; \n "
" int i = 0 | c; \n "
" if (i & 0x8000) \n "
" printf( \" not expected \" ); \n "
2012-09-16 19:44:02 +02:00
" The \" not expected \" will be printed on the screen. " ) ;
2011-08-19 17:53:43 +02:00
}
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 )
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : warning , " constStatement " , " Redundant code: Found a statement that begins with " + type + " constant. " ) ;
2011-08-19 17:53:43 +02:00
}
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 ( )
{
2011-12-17 19:04:03 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-11-15 07:11:45 +01:00
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 , " [=(] %str% + %any% " ) ) {
// char constant..
if ( tok - > tokAt ( 3 ) - > type ( ) = = Token : : eChar )
strPlusCharError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
2012-11-15 07:11:45 +01:00
// char variable..
2013-02-06 06:39:58 +01:00
if ( isChar ( tok - > tokAt ( 3 ) - > variable ( ) ) )
2012-11-15 07:11:45 +01: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 )
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " strPlusChar " , " Unusual pointer arithmetic. A value of type 'char' is added to a string literal. " ) ;
2011-08-19 17:53:43 +02:00
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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 )
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " zerodiv " , " Division by zero. " ) ;
2011-08-19 17:53:43 +02:00
}
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-11-15 07:11:45 +01:00
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 ( ) ) {
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
2013-01-16 15:37:07 +01:00
// acos( x ), asin( x ) where x is defined for interval [-1,+1], but not beyond
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 )
2012-09-16 19:44:02 +02: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 )
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing values " + tok - > strAt ( 2 ) + " and " + tok - > strAt ( 4 ) + " to " + tok - > str ( ) + " () leads to undefined result. " ) ;
2011-10-13 20:53:06 +02:00
} else
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " wrongmathcall " , " Passing value '#' to #() leads to undefined result. " ) ;
2011-08-19 17:53:43 +02:00
}
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 ) ) ) {
2012-09-07 12:36:40 +02:00
cctypefunctionCallError ( tok , tok - > str ( ) , tok - > strAt ( 2 ) ) ;
2011-11-17 16:31:16 +01:00
}
}
}
void CheckOther : : cctypefunctionCallError ( const Token * tok , const std : : string & functionName , const std : : string & value )
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : error , " wrongcctypecall " , " Passing value " + value + " to " + functionName + " () causes undefined behavior which may lead to a crash. " ) ;
2011-11-17 16:31:16 +01:00
}
2012-05-24 17:40:43 +02:00
2011-08-19 17:53:43 +02:00
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
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 ( ) ;
2012-11-15 07:11:45 +01:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
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 ( ) )
2013-01-31 06:41:18 +01:00
& & ! tok - > next ( ) - > function ( ) ) {
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-09-16 19:44:02 +02:00
" unusedScopedObject " , " Instance of ' " + varname + " ' object is destroyed immediately. " ) ;
2011-08-19 17:53:43 +02:00
}
2012-09-26 18:18:36 +02:00
//-------------------------------------------------------------------------------
// Comparing functions which are returning value of type bool
//-------------------------------------------------------------------------------
void CheckOther : : checkComparisonOfFuncReturningBool ( )
{
if ( ! _settings - > isEnabled ( " style " ) )
return ;
if ( ! _tokenizer - > isCPP ( ) )
return ;
2012-09-29 11:23:30 +02:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-10-11 06:12:24 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
2012-10-10 20:42:07 +02:00
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2012-10-01 15:38:31 +02:00
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-10-02 15:19:29 +02:00
if ( tok - > type ( ) ! = Token : : eComparisonOp | | tok - > str ( ) = = " == " | | tok - > str ( ) = = " != " )
continue ;
const Token * first_token ;
bool first_token_func_of_type_bool = false ;
if ( Token : : simpleMatch ( tok - > previous ( ) , " ) " ) ) {
first_token = tok - > previous ( ) - > link ( ) - > previous ( ) ;
} else {
first_token = tok - > previous ( ) ;
}
if ( Token : : Match ( first_token , " %var% ( " ) & & ! Token : : Match ( first_token - > previous ( ) , " ::|. " ) ) {
2013-01-31 06:41:18 +01:00
const Function * func = first_token - > function ( ) ;
2012-10-02 15:19:29 +02:00
if ( func & & func - > tokenDef & & func - > tokenDef - > strAt ( - 1 ) = = " bool " ) {
first_token_func_of_type_bool = true ;
2012-09-26 18:18:36 +02:00
}
2012-10-02 15:19:29 +02:00
}
2012-09-26 18:18:36 +02:00
2012-10-02 15:19:29 +02:00
Token * second_token = tok - > next ( ) ;
bool second_token_func_of_type_bool = false ;
while ( second_token - > str ( ) = = " ! " ) {
second_token = second_token - > next ( ) ;
}
if ( Token : : Match ( second_token , " %var% ( " ) & & ! Token : : Match ( second_token - > previous ( ) , " ::|. " ) ) {
2013-01-31 06:41:18 +01:00
const Function * func = second_token - > function ( ) ;
2012-10-02 15:19:29 +02:00
if ( func & & func - > tokenDef & & func - > tokenDef - > strAt ( - 1 ) = = " bool " ) {
second_token_func_of_type_bool = true ;
2012-09-26 18:18:36 +02:00
}
2012-10-02 15:19:29 +02:00
}
2012-09-29 11:23:30 +02:00
2012-10-02 15:19:29 +02:00
if ( ( first_token_func_of_type_bool = = true ) & & ( second_token_func_of_type_bool = = true ) ) {
comparisonOfTwoFuncsReturningBoolError ( first_token - > next ( ) , first_token - > str ( ) , second_token - > str ( ) ) ;
} else if ( first_token_func_of_type_bool = = true ) {
comparisonOfFuncReturningBoolError ( first_token - > next ( ) , first_token - > str ( ) ) ;
} else if ( second_token_func_of_type_bool = = true ) {
comparisonOfFuncReturningBoolError ( second_token - > previous ( ) , second_token - > str ( ) ) ;
2012-09-26 18:18:36 +02:00
}
}
}
}
void CheckOther : : 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 CheckOther : : 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 CheckOther : : checkComparisonOfBoolWithBool ( )
{
2012-09-28 19:11:36 +02:00
// FIXME: This checking is "experimental" because of the false positives
// when self checking lib/tokenize.cpp (#2617)
if ( ! _settings - > experimental )
return ;
2012-09-26 18:18:36 +02:00
if ( ! _settings - > isEnabled ( " style " ) )
return ;
if ( ! _tokenizer - > isCPP ( ) )
return ;
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-10-11 06:12:24 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
2012-10-10 20:42:07 +02:00
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2012-10-01 15:38:31 +02:00
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2012-10-02 15:19:29 +02:00
if ( tok - > type ( ) ! = Token : : eComparisonOp | | tok - > str ( ) = = " == " | | tok - > str ( ) = = " != " )
continue ;
bool first_token_bool = false ;
bool second_token_bool = false ;
const Token * first_token = tok - > previous ( ) ;
if ( first_token - > varId ( ) ) {
2013-02-06 06:39:58 +01:00
if ( isBool ( first_token - > variable ( ) ) ) {
2012-10-02 15:19:29 +02:00
first_token_bool = true ;
2012-10-01 15:38:31 +02:00
}
2012-10-02 15:19:29 +02:00
}
const Token * second_token = tok - > next ( ) ;
if ( second_token - > varId ( ) ) {
2013-02-06 06:39:58 +01:00
if ( isBool ( second_token - > variable ( ) ) ) {
2012-10-02 15:19:29 +02:00
second_token_bool = true ;
2012-09-26 18:18:36 +02:00
}
}
2012-10-02 15:19:29 +02:00
if ( ( first_token_bool = = true ) & & ( second_token_bool = = true ) ) {
comparisonOfBoolWithBoolError ( first_token - > next ( ) , first_token - > str ( ) ) ;
}
2012-09-26 18:18:36 +02:00
}
}
}
void CheckOther : : 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. " ) ;
}
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 ;
2012-11-15 07:11:45 +01:00
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 ( ) ) {
2012-12-20 20:48:48 +01:00
// skip "assert(str && ..)" and "assert(.. && str)"
if ( Token : : Match ( tok , " %var% ( " ) & &
( Token : : Match ( tok - > tokAt ( 2 ) , " %str% && " ) | | Token : : Match ( tok - > next ( ) - > link ( ) - > tokAt ( - 2 ) , " && %str% ) " ) ) & &
( tok - > str ( ) . find ( " assert " ) + 6U = = tok - > str ( ) . size ( ) | | tok - > str ( ) . find ( " ASSERT " ) + 6U = = tok - > str ( ) . size ( ) ) )
tok = tok - > next ( ) - > link ( ) ;
2012-11-15 07:11:45 +01:00
if ( Token : : Match ( tok , " . substr ( %any% , %num% ) ==|!= %str% " ) ) {
MathLib : : bigint clen = MathLib : : toLongNumber ( tok - > strAt ( 5 ) ) ;
std : : size_t slen = Token : : getStrLength ( tok - > tokAt ( 8 ) ) ;
if ( clen ! = ( int ) slen ) {
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > strAt ( 8 ) ) ;
}
} else if ( Token : : Match ( tok , " %str% ==|!= %var% . substr ( %any% , %num% ) " )) {
MathLib : : bigint clen = MathLib : : toLongNumber ( tok - > strAt ( 8 ) ) ;
std : : size_t slen = Token : : getStrLength ( tok ) ;
if ( clen ! = ( int ) slen ) {
incorrectStringCompareError ( tok - > next ( ) , " substr " , tok - > str ( ) ) ;
}
2012-12-20 20:48:48 +01:00
} else if ( Token : : Match ( tok , " &&|%oror%|( %str% &&|%oror%|) " ) && !Token::Match(tok, " ( % str % ) " )) {
2012-11-15 07:11:45 +01:00
incorrectStringBooleanError ( tok - > next ( ) , tok - > strAt ( 1 ) ) ;
2012-12-20 20:48:48 +01:00
} else if ( Token : : Match ( tok , " if|while ( %str% ) " )) {
2012-11-15 07:11:45 +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
}
}
2012-09-16 19:44:02 +02:00
void CheckOther : : incorrectStringCompareError ( const Token * tok , const std : : string & func , const std : : string & string )
2011-08-19 17:53:43 +02:00
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : warning , " incorrectStringCompare " , " String literal " + string + " doesn't match length argument for " + func + " (). " ) ;
2011-08-19 17:53:43 +02:00
}
2011-10-18 21:37:03 +02:00
void CheckOther : : incorrectStringBooleanError ( const Token * tok , const std : : string & string )
{
2012-09-16 19:44:02 +02:00
reportError ( tok , Severity : : warning , " incorrectStringBooleanError " , " Conversion of string literal " + string + " to bool always evaluates to true. " ) ;
2011-10-18 21:37:03 +02:00
}
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 ) ) ;
2013-02-04 21:12:12 +01:00
// 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
2013-02-04 21:12:12 +01:00
// check all the else { if (...) statements
while ( Token : : simpleMatch ( tok1 , " } else { if ( " ) & &
Token : : simpleMatch ( tok1 - > linkAt ( 4 ) , " ) { " ) ) {
2011-12-09 22:28:10 +01:00
// get the expression from the token stream
2013-02-04 21:12:12 +01:00
expression = tok1 - > tokAt ( 5 ) - > stringifyList ( tok1 - > linkAt ( 4 ) ) ;
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
2013-02-04 21:12:12 +01:00
if ( ! expressionHasSideEffects ( tok1 - > tokAt ( 5 ) , tok1 - > linkAt ( 4 ) - > previous ( ) ) )
2011-12-09 22:28:10 +01:00
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
2013-02-04 21:12:12 +01:00
// find the next else { if (...) statement
tok1 = tok1 - > linkAt ( 4 ) - > 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 ) ;
2012-09-16 19:44:02 +02:00
reportError ( toks , Severity : : style , " duplicateIf " , " Duplicate conditions in 'if' and related 'else if'. \n "
" Duplicate conditions in 'if' and related 'else if'. This is suspicious and might indicate "
2011-04-09 21:14:01 +02:00
" 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-09-16 19:44:02 +02:00
void CheckOther : : duplicateBranchError ( const Token * tok1 , const Token * tok2 )
{
std : : list < const Token * > toks ;
toks . push_back ( tok2 ) ;
toks . push_back ( tok1 ) ;
reportError ( toks , Severity : : style , " duplicateBranch " , " Found duplicate branches for 'if' and 'else'. \n "
" Finding the same code in an 'if' and related '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. " ) ;
}
2012-09-05 08:31:23 +02:00
//-----------------------------------------------------------------------------
// Check for a free() of an invalid address
// char* p = malloc(100);
// free(p + 10);
//-----------------------------------------------------------------------------
void CheckOther : : checkInvalidFree ( )
{
2012-11-06 06:02:51 +01:00
std : : map < unsigned int , bool > allocatedVariables ;
2012-09-05 08:31:23 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
// Keep track of which variables were assigned addresses to newly-allocated memory
if ( Token : : Match ( tok , " %var% = malloc|g_malloc|new " ) ) {
2012-11-06 06:02:51 +01:00
allocatedVariables . insert ( std : : make_pair ( tok - > varId ( ) , false ) ) ;
2012-09-05 08:31:23 +02:00
}
2012-11-06 06:02:51 +01:00
// If a previously-allocated pointer is incremented or decremented, any subsequent
// free involving pointer arithmetic may or may not be invalid, so we should only
// report an inconclusive result.
else if ( Token : : Match ( tok , " %var% = %var% +|- " ) & &
tok - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) & &
allocatedVariables . find ( tok - > varId ( ) ) ! = allocatedVariables . end ( ) ) {
if ( _settings - > inconclusive )
allocatedVariables [ tok - > varId ( ) ] = true ;
else
allocatedVariables . erase ( tok - > varId ( ) ) ;
}
// If a previously-allocated pointer is assigned a completely new value,
// we can't know if any subsequent free() on that pointer is valid or not.
else if ( Token : : Match ( tok , " %var% = " ) ) {
2012-09-05 08:31:23 +02:00
allocatedVariables . erase ( tok - > varId ( ) ) ;
}
// If a variable that was previously assigned a newly-allocated memory location is
// added or subtracted from when used to free the memory, report an error.
else if ( Token : : Match ( tok , " free|g_free|delete ( %any% +|- %any% " ) | |
Token : : Match ( tok , " delete [ ] ( %any% +|- %any% " ) | |
Token : : Match ( tok , " delete %any% +|- %any% " ) ) {
2012-11-06 06:02:51 +01:00
const int varIdx = tok - > strAt ( 1 ) = = " ( " ? 2 :
tok - > strAt ( 3 ) = = " ( " ? 4 : 1 ;
const unsigned int var1 = tok - > tokAt ( varIdx ) - > varId ( ) ;
const unsigned int var2 = tok - > tokAt ( varIdx + 2 ) - > varId ( ) ;
const std : : map < unsigned int , bool > : : iterator alloc1 = allocatedVariables . find ( var1 ) ;
const std : : map < unsigned int , bool > : : iterator alloc2 = allocatedVariables . find ( var2 ) ;
if ( alloc1 ! = allocatedVariables . end ( ) ) {
invalidFreeError ( tok , alloc1 - > second ) ;
} else if ( alloc2 ! = allocatedVariables . end ( ) ) {
invalidFreeError ( tok , alloc2 - > second ) ;
2012-09-05 08:31:23 +02:00
}
}
// If the previously-allocated variable is passed in to another function
// as a parameter, it might be modified, so we shouldn't report an error
// if it is later used to free memory
else if ( Token : : Match ( tok , " %var% ( " ) ) {
const Token * tok2 = Token : : findmatch ( tok - > tokAt ( 1 ) , " %var% " , tok - > linkAt ( 1 ) ) ;
while ( tok2 ! = NULL ) {
allocatedVariables . erase ( tok2 - > varId ( ) ) ;
tok2 = Token : : findmatch ( tok2 - > next ( ) , " %var% " , tok - > linkAt ( 1 ) ) ;
}
}
}
}
2012-11-06 06:02:51 +01:00
void CheckOther : : invalidFreeError ( const Token * tok , bool inconclusive )
2012-09-05 08:31:23 +02:00
{
2012-11-06 06:02:51 +01:00
reportError ( tok , Severity : : error , " invalidFree " , " Invalid memory address freed. " , inconclusive ) ;
2012-09-05 08:31:23 +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 ( ) ) {
// 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 ( ) )
2012-09-07 12:36:40 +02:00
doubleFreeError ( tok , tok - > strAt ( 2 ) ) ;
2012-01-15 01:19:34 +01:00
else
freedVariables . insert ( var ) ;
} else if ( tok - > str ( ) = = " closedir " ) {
if ( closeDirVariables . find ( var ) ! = closeDirVariables . end ( ) )
2012-09-07 12:36:40 +02:00
doubleCloseDirError ( tok , tok - > strAt ( 2 ) ) ;
2012-01-15 01:19:34 +01:00
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 ( ) )
2012-09-07 12:36:40 +02:00
doubleFreeError ( tok , tok - > strAt ( varIdx ) ) ;
2012-01-15 01:19:34 +01:00
else
freedVariables . insert ( var ) ;
}
}
// If this scope doesn't return, clear the set of previously freed variables
2013-01-06 04:02:19 +01:00
else if ( tok - > str ( ) = = " } " & & _tokenizer - > IsScopeNoReturn ( tok ) ) {
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.
2012-12-28 20:16:51 +01:00
else if ( tok - > str ( ) = = " } " & & tok - > link ( ) & & tok - > link ( ) - > tokAt ( - 1 ) & &
tok - > link ( ) - > linkAt ( - 1 ) & &
2012-06-16 22:03:51 +02:00
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-11-06 19:54:52 +01:00
else if ( Token : : Match ( tok , " %var% ( " ) & & ! Token : : Match ( tok , " printf|sprintf|snprintf|fprintf|wprintf|swprintf|fwprintf " ) ) {
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-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
2013-02-06 06:39:58 +01:00
bool inconclusiveFunctionCall ( 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 ) ;
2013-02-06 06:39:58 +01:00
v = scope - > variable ( ) ;
2011-11-10 21:49:14 +01:00
}
// hard coded list of safe, no-side-effect functions
2012-11-06 19:54:52 +01:00
if ( v = = 0 & & Token : : Match ( prev , " strcmp|strncmp|strlen|wcscmp|wcsncmp|wcslen|memcmp|strcasecmp|strncasecmp " ) )
2011-11-10 21:49:14 +01:00
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 :
2013-02-08 11:43:35 +01:00
Expressions ( const 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
_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 (
2013-02-06 06:39:58 +01:00
_constFunctions , exprTokens ) ;
2011-12-01 19:46:57 +01:00
_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 ;
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 ;
2013-02-08 11:43:35 +01:00
Expressions expressions ( 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 ;
2013-01-16 15:37:07 +01:00
unsigned int parentheses = 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 ( ) = = " ( " ) {
2013-01-16 15:37:07 +01:00
+ + parentheses ;
2011-12-01 17:43:29 +01:00
} else if ( tok - > str ( ) = = " ) " ) {
2013-01-16 15:37:07 +01:00
if ( parentheses = = 0 ) {
2011-12-01 17:07:55 +01:00
valid = false ;
break ;
}
2013-01-16 15:37:07 +01:00
- - parentheses ;
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
}
}
2013-01-16 15:37:07 +01:00
if ( ! valid | | parentheses ! = 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 ( ) ) {
2012-12-01 01:31:35 +01:00
if ( Token : : Match ( tok , " ,|=|return|(|&&|%oror% %var% %comp%|- %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
2013-01-31 17:29:31 +01:00
// float - float is a valid Inf check
if ( Token : : Match ( tok - > tokAt ( 2 ) , " ==|!=|- " ) & & tok - > next ( ) - > varId ( ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > next ( ) - > variable ( ) ;
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 ) ) ;
2012-12-01 01:31:35 +01:00
} else if ( Token : : Match ( tok , " ,|=|return|(|&&|%oror% %var% . %var% %comp%|- %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 ;
const Token * tok = _tokenizer - > tokens ( ) ;
2013-01-16 22:05:28 +01:00
while ( tok & & ( tok = Token : : findmatch ( tok , " strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp|wcsncmp ( %str% , %str% " ) ) ! = 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 ( ) ;
2013-01-16 22:05:28 +01:00
while ( tok & & ( tok = Token : : findmatch ( tok , " QString :: compare ( %str% , %str% ) " ) ) ! = 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 ( ) ;
2013-01-16 22:05:28 +01:00
while ( tok & & ( tok = Token : : findmatch ( tok , " strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp|wcsncmp ( %var% , %var% " ) ) ! = 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 ( ) ;
2012-11-16 06:50:49 +01:00
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 - > next ( ) - > type ( ) ! = Token : : eComparisonOp )
continue ;
2012-08-24 14:25:17 +02:00
2012-11-16 06:50:49 +01:00
const Token * varTok = tok ;
const Token * litTok = tok - > tokAt ( 2 ) ;
2012-08-24 14:25:17 +02:00
2012-11-16 06:50:49 +01:00
if ( varTok - > strAt ( - 1 ) = = " + " | | litTok - > strAt ( 1 ) = = " + " )
continue ;
2012-08-24 14:25:17 +02:00
2012-11-16 06:50:49 +01:00
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 ) ;
2012-08-24 14:25:17 +02:00
2013-02-06 06:39:58 +01:00
const Variable * var = varTok - > variable ( ) ;
2012-11-16 06:50:49 +01:00
if ( var ) {
if ( _tokenizer - > isC ( ) | |
( var - > isPointer ( ) & & varTok - > strAt ( - 1 ) ! = " * " & & ! Token : : Match ( varTok - > next ( ) , " [.([] " ) ) )
suspiciousStringCompareError ( tok , var - > name ( ) ) ;
}
2012-10-07 16:26:03 +02:00
}
2012-08-24 14:25:17 +02:00
}
}
}
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 ( )
{
2012-11-15 07:11:45 +01:00
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 ( ) ) {
2012-12-01 01:31:35 +01:00
if ( ( Token : : Match ( tok , " % %num% %comp% %num% " ) ) & &
2012-11-15 07:11:45 +01:00
( ! tok - > tokAt ( 4 ) | | ! tok - > tokAt ( 4 ) - > isArithmeticalOp ( ) ) ) {
if ( MathLib : : isLessEqual ( tok - > strAt ( 1 ) , tok - > strAt ( 3 ) ) )
moduloAlwaysTrueFalseError ( tok , tok - > strAt ( 1 ) ) ;
}
2012-04-26 15:23:47 +02:00
}
}
}
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 ,
2012-09-16 19:44:02 +02:00
" sizeofsizeof " , " Calling 'sizeof' on '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-07 11:59:20 +02:00
if ( tok2 - > isOp ( ) & & ( ! tok2 - > isExpandedMacro ( ) | | _settings - > inconclusive ) & & ! Token : : Match ( tok2 , " >|<|& " ) & & ( Token : : Match ( tok2 - > previous ( ) , " %var% " ) | | tok2 - > str ( ) ! = " * " ) ) {
2012-09-03 15:56:10 +02:00
if ( ! ( Token : : Match ( tok2 - > previous ( ) , " %type% " ) | | Token : : Match ( tok2 - > next ( ) , " %type% " ) ) ) {
sizeofCalculationError ( tok2 , tok2 - > isExpandedMacro ( ) ) ;
break ;
}
2012-11-06 20:39:47 +01:00
} else if ( tok2 - > type ( ) = = Token : : eIncDecOp )
sizeofCalculationError ( tok2 , tok2 - > isExpandedMacro ( ) ) ;
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 ,
2012-09-16 19:44:02 +02:00
" sizeofCalculation " , " Found calculation inside sizeof(). " , inconclusive ) ;
2010-08-06 22:57:10 +02:00
}
2012-11-09 18:08:20 +01:00
//-----------------------------------------------------------------------------
// Check for code like sizeof()*sizeof() or sizeof(ptr)/value
//-----------------------------------------------------------------------------
void CheckOther : : suspiciousSizeofCalculation ( )
{
if ( ! _settings - > isEnabled ( " style " ) | | ! _settings - > inconclusive )
return ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : simpleMatch ( tok , " sizeof ( " ) ) {
const Token * const end = tok - > linkAt ( 1 ) ;
2013-02-06 06:39:58 +01:00
const Variable * var = end - > previous ( ) - > variable ( ) ;
2012-11-09 18:08:20 +01:00
if ( end - > strAt ( - 1 ) = = " * " | | ( var & & var - > isPointer ( ) & & ! var - > isArray ( ) ) ) {
if ( end - > strAt ( 1 ) = = " / " )
divideSizeofError ( tok ) ;
} else if ( Token : : simpleMatch ( end , " ) * sizeof " ) )
multiplySizeofError ( tok ) ;
}
}
}
void CheckOther : : multiplySizeofError ( const Token * tok )
{
reportError ( tok , Severity : : warning ,
" multiplySizeof " , " Multiplying sizeof() with sizeof() indicates a logic error. " , true ) ;
}
void CheckOther : : divideSizeofError ( const Token * tok )
{
reportError ( tok , Severity : : warning ,
" divideSizeof " , " Division of result of sizeof() on pointer type. \n "
" Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, "
" not the size of the memory area it points to. " , true ) ;
}
2011-08-19 17:53:43 +02:00
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
2011-07-28 07:28:24 +02:00
void CheckOther : : checkAssignBoolToPointer ( )
{
2012-11-15 07:11:45 +01:00
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 ( ) ) {
if ( Token : : Match ( tok , " !!* %var% = %bool% ; " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var1 ( tok - > next ( ) - > variable ( ) ) ;
2011-07-28 07:28:24 +02:00
2012-11-15 07:11:45 +01:00
// Is variable a pointer?
if ( var1 & & var1 - > isPointer ( ) )
assignBoolToPointerError ( tok - > next ( ) ) ;
}
2011-07-28 07:28:24 +02:00
}
}
}
void CheckOther : : assignBoolToPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " assignBoolToPointer " ,
2012-09-16 19:44:02 +02:00
" Boolean value assigned to pointer. " ) ;
2011-07-28 07:28:24 +02:00
}
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-11-15 07:11:45 +01:00
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 ( ) ) {
// Skip template parameters
if ( tok - > str ( ) = = " < " & & tok - > link ( ) ) {
tok = tok - > link ( ) ;
continue ;
}
2012-05-22 19:01:21 +02:00
2012-11-15 07:11:45 +01:00
const Token * numTok = 0 ;
const Token * opTok = 0 ;
char op = 0 ;
2012-12-01 01:31:35 +01:00
if ( Token : : Match ( tok , " &&|%oror% %any% ) %comp% %any% " ) ) {
2012-11-15 07:11:45 +01:00
numTok = tok - > tokAt ( 4 ) ;
opTok = tok - > tokAt ( 3 ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] ;
2012-12-01 01:31:35 +01:00
} else if ( Token : : Match ( tok , " %any% %comp% ( %any% &&|%oror% " ) ) {
2012-11-15 07:11:45 +01:00
numTok = tok ;
opTok = tok - > next ( ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] = = ' > ' ? ' < ' : ' > ' ;
}
2012-04-02 15:45:51 +02:00
2012-12-01 01:31:35 +01:00
else if ( Token : : Match ( tok , " ! %var% %comp% %any% " ) ) {
2012-11-15 07:11:45 +01:00
numTok = tok - > tokAt ( 3 ) ;
opTok = tok - > tokAt ( 2 ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] ;
2012-12-01 01:31:35 +01:00
} else if ( Token : : Match ( tok , " %any% %comp% ! %var% " ) ) {
2012-11-15 07:11:45 +01:00
numTok = tok ;
opTok = tok - > next ( ) ;
if ( Token : : Match ( opTok , " <|> " ) )
op = opTok - > str ( ) [ 0 ] = = ' > ' ? ' < ' : ' > ' ;
}
2012-04-02 15:45:51 +02:00
2012-11-15 07:11:45 +01:00
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 ) ;
2013-02-06 06:39:58 +01:00
} else if ( isNonBoolStdType ( numTok - > variable ( ) ) )
2012-11-15 07:11:45 +01:00
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 ( ) ;
2012-11-15 07:11:45 +01:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2011-08-07 01:23:09 +02:00
// check all the code in the function
2012-11-15 07:11:45 +01:00
for ( const Token * tok = scope - > classStart - > next ( ) ; 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 ) , " +|- " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > variable ( ) ;
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 ( ) , " +|-|<<|>>|~ " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > tokAt ( 2 ) - > variable ( ) ;
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 ( ) , " +|-|<<|>>|~ " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > tokAt ( 2 ) - > variable ( ) ;
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 ) , " +|- " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > variable ( ) ;
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 "
2012-09-16 19:44:02 +02:00
" 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 " ,
2012-09-16 19:44:02 +02:00
" Unsigned variable ' " + varname + " ' can't be negative so it is unnecessary to test it. \n "
" The unsigned variable ' " + varname + " ' can't be negative so it is unnecessary to test it. "
2012-05-06 19:37:41 +02:00
" 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-09-16 19:44:02 +02:00
" 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 ( )
{
2012-09-10 19:02:32 +02:00
if ( ! _settings - > isEnabled ( " performance " ) | | _tokenizer - > isC ( ) )
2012-07-22 09:17:00 +02:00
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 ;
2013-01-31 06:41:18 +01:00
const Function * func = tok - > function ( ) ;
2012-09-11 18:03:47 +02:00
if ( func & & func - > tokenDef - > previous ( ) & & func - > tokenDef - > previous ( ) - > str ( ) = = " & " ) {
2012-08-24 00:03:22 +02:00
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 " ,
2012-09-16 19:44:02 +02:00
" Use const reference for ' " + varname + " ' to avoid unnecessary data copying. \n "
" The const variable ' " + varname + " ' is assigned a copy of the data. You can avoid "
" the unnecessary data copying by converting ' " + varname + " ' to const reference. " ) ;
2012-08-24 00:03:22 +02:00
}
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 ( )
{
2012-09-04 12:36:00 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-11-16 06:50:49 +01:00
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 , " %var% >>|<< %num% " ) | | Token : : Match ( tok , " %num% >>|<< %num% " ) ) & & ! Token : : Match ( tok - > previous ( ) , " >>|<< " ) ) {
if ( tok - > isName ( ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > variable ( ) ;
2012-11-16 06:50:49 +01:00
if ( var & & var - > typeStartToken ( ) - > isStandardType ( ) & & ( tok - > strAt ( 2 ) ) [ 0 ] = = ' - ' )
negativeBitwiseShiftError ( tok ) ;
} else {
if ( ( tok - > strAt ( 2 ) ) [ 0 ] = = ' - ' )
negativeBitwiseShiftError ( tok ) ;
}
2012-09-04 12:36:00 +02:00
}
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 ( ) ;
2012-11-16 06:50:49 +01:00
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 , " memset|memcpy|memmove ( %var% , " ) & & Token : : Match ( tok - > linkAt ( 1 ) - > tokAt ( - 2 ) , " , %num% ) " ) ) {
2013-02-06 06:39:58 +01:00
const Variable * var = tok - > tokAt ( 2 ) - > variable ( ) ;
2012-11-16 06:50:49 +01:00
if ( ! var | | ! var - > isArray ( ) | | var - > dimensions ( ) . empty ( ) | | ! var - > dimension ( 0 ) )
continue ;
2012-08-24 11:28:50 +02:00
2012-11-16 06:50:49 +01:00
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 ) | | var - > typeEndToken ( ) - > str ( ) = = " * " )
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 ) ;
}
2012-08-24 11:28:50 +02:00
}
}
}
}
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 ) ;
}
2012-09-05 13:48:00 +02:00
2012-10-21 18:18:29 +02:00
void CheckOther : : oppositeInnerCondition ( )
2012-09-05 13:48:00 +02:00
{
2012-10-21 18:18:29 +02:00
// FIXME: This check is experimental because of #4170 and #4186. Fix those tickets and remove the "experimental".
if ( ! _settings - > isEnabled ( " style " ) | | ! _settings - > inconclusive | | ! _settings - > experimental )
2012-09-05 13:48:00 +02:00
return ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( std : : list < Scope > : : const_iterator scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
const Token * const toke = scope - > classDef ;
if ( scope - > type = = Scope : : eIf & & toke ) {
const Token * op1Tok , * op2Tok ;
op1Tok = scope - > classDef - > tokAt ( 2 ) ;
op2Tok = scope - > classDef - > tokAt ( 4 ) ;
if ( scope - > classDef - > strAt ( 6 ) = = " { " ) {
2012-12-24 12:21:48 +01:00
const char * oppositeCondition = NULL ;
if ( scope - > classDef - > strAt ( 3 ) = = " == " )
oppositeCondition = " if ( %any% !=|<|>|<=|>= %any% ) " ;
else if ( scope - > classDef - > strAt ( 3 ) = = " != " )
oppositeCondition = " if ( %any% ==|>=|<= %any% ) " ;
else if ( scope - > classDef - > strAt ( 3 ) = = " < " )
oppositeCondition = " if ( %any% >|>=|== %any% ) " ;
else if ( scope - > classDef - > strAt ( 3 ) = = " <= " )
oppositeCondition = " if ( %any% > %any% ) " ;
else if ( scope - > classDef - > strAt ( 3 ) = = " > " )
oppositeCondition = " if ( %any% <|<=|== %any% ) " ;
else if ( scope - > classDef - > strAt ( 3 ) = = " >= " )
oppositeCondition = " if ( %any% < %any% ) " ;
if ( oppositeCondition ) {
2012-09-15 15:54:52 +02:00
int flag = 0 ;
2012-09-05 13:48:00 +02:00
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd & & flag = = 0 ; tok = tok - > next ( ) ) {
if ( ( tok - > str ( ) = = op1Tok - > str ( ) | | tok - > str ( ) = = op2Tok - > str ( ) ) & & tok - > strAt ( 1 ) = = " = " )
break ;
else if ( Token : : Match ( tok , " %any% ( %any% ) " )) {
if ( ( tok - > strAt ( 2 ) = = op1Tok - > str ( ) | | tok - > strAt ( 2 ) = = op2Tok - > str ( ) ) )
break ;
} else if ( Token : : Match ( tok , " %any% ( %any% , %any% " ) ) {
for ( const Token * tok2 = tok - > next ( ) ; tok2 ! = tok - > linkAt ( 1 ) ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = op1Tok - > str ( ) ) {
flag = 1 ;
break ;
}
}
2012-12-24 12:21:48 +01:00
} else if ( Token : : Match ( tok , oppositeCondition ) ) {
2012-09-05 13:48:00 +02:00
if ( ( tok - > strAt ( 2 ) = = op1Tok - > str ( ) & & tok - > strAt ( 4 ) = = op2Tok - > str ( ) ) | | ( tok - > strAt ( 2 ) = = op2Tok - > str ( ) & & tok - > strAt ( 4 ) = = op1Tok - > str ( ) ) )
2012-10-21 18:18:29 +02:00
oppositeInnerConditionError ( toke ) ;
2012-09-05 13:48:00 +02:00
}
}
}
}
}
}
}
2012-10-21 18:18:29 +02:00
void CheckOther : : oppositeInnerConditionError ( const Token * tok )
2012-09-05 13:48:00 +02:00
{
2012-10-21 18:18:29 +02:00
reportError ( tok , Severity : : warning , " oppositeInnerCondition " , " Opposite conditions in nested 'if' blocks lead to a dead code block. " , true ) ;
2012-09-05 13:48:00 +02:00
}
2013-01-13 12:02:10 +01:00
void CheckOther : : checkVarFuncNullUB ( )
{
if ( ! _settings - > isEnabled ( " portability " ) )
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 ( ) ) {
// Is NULL passed to a function?
if ( Token : : Match ( tok , " [(,] NULL [,)] " ) ) {
// Locate function name in this function call.
const Token * ftok = tok ;
2013-01-16 15:37:07 +01:00
std : : size_t argnr = 1 ;
2013-01-13 12:02:10 +01:00
while ( ftok & & ftok - > str ( ) ! = " ( " ) {
if ( ftok - > str ( ) = = " ) " )
ftok = ftok - > link ( ) ;
2013-01-14 06:44:52 +01:00
else if ( ftok - > str ( ) = = " , " )
+ + argnr ;
2013-01-13 12:02:10 +01:00
ftok = ftok - > previous ( ) ;
}
ftok = ftok ? ftok - > previous ( ) : NULL ;
if ( ftok & & ftok - > isName ( ) ) {
// If this is a variadic function then report error
2013-01-31 06:41:18 +01:00
const Function * f = ftok - > function ( ) ;
2013-01-14 06:44:52 +01:00
if ( f & & f - > argCount ( ) < = argnr ) {
2013-01-13 12:02:10 +01:00
const Token * tok2 = f - > argDef ;
tok2 = tok2 ? tok2 - > link ( ) : NULL ; // goto ')'
if ( Token : : simpleMatch ( tok2 - > tokAt ( - 3 ) , " . . . " ) )
varFuncNullUBError ( tok ) ;
}
}
}
}
}
}
void CheckOther : : varFuncNullUBError ( const Token * tok )
{
reportError ( tok ,
Severity : : portability ,
" varFuncNullUB " ,
2013-01-14 18:11:16 +01:00
" Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. \n "
" Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. \n "
" The C99 standard, in section 7.15.1.1, states that if the type used by va_arg() is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined. \n "
" The value of the NULL macro is an implementation-defined null pointer constant (7.17), which can be any integer constant expression with the value 0, or such an expression casted to (void*) (6.3.2.3). This includes values like 0, 0L, or even 0LL. \n "
" In practice on common architectures, this will cause real crashes if sizeof(int) != sizeof(void*), and NULL is defined to 0 or any other null pointer constant that promotes to int. \n "
" To reproduce you might be able to use this little code example on 64bit platforms. If the output includes \" ERROR \" , the sentinel had only 4 out of 8 bytes initialized to zero and was not detected as the final argument to stop argument processing via va_arg(). Changing the 0 to (void*)0 or 0L will make the \" ERROR \" output go away. \n "
2013-01-13 12:02:10 +01:00
" #include <stdarg.h> \n "
" #include <stdio.h> \n "
" \n "
" void f(char *s, ...) { \n "
" va_list ap; \n "
" va_start(ap,s); \n "
" for (;;) { \n "
" char *p = va_arg(ap,char*); \n "
" printf( \" %018p, %s \n \" , p, (long)p & 255 ? p : \" \" ); \n "
" if(!p) break; \n "
" } \n "
" va_end(ap); \n "
" } \n "
" \n "
" void g() { \n "
" char *s2 = \" x \" ; \n "
2013-01-14 18:11:16 +01:00
" char *s3 = \" ERROR \" ; \n "
2013-01-13 12:02:10 +01:00
" \n "
2013-01-14 18:11:16 +01:00
" // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64 \n "
2013-01-13 12:02:10 +01:00
" f( \" first \" , s2, s2, s2, s2, s2, 0, s3, (char*)0); \n "
" } \n "
" \n "
" void h() { \n "
" int i; \n "
" volatile unsigned char a[1000]; \n "
" for (i = 0; i<sizeof(a); i++) \n "
" a[i] = -1; \n "
" } \n "
" \n "
" int main() { \n "
" h(); \n "
" g(); \n "
" return 0; \n "
" } " ) ;
}