2011-08-19 20:35:25 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2011-08-19 20:35:25 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checkunusedvar.h"
2017-05-27 04:33:47 +02:00
2018-04-17 14:23:04 +02:00
# include "astutils.h"
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2022-12-13 22:29:23 +01:00
# include "fwdanalysis.h"
2022-01-27 19:03:20 +01:00
# include "library.h"
2020-06-30 10:59:57 +02:00
# include "preprocessor.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
2011-08-19 20:35:25 +02:00
# include "symboldatabase.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
# include "tokenize.h"
2022-01-27 19:03:20 +01:00
# include "tokenlist.h"
# include "utils.h"
2022-07-08 16:42:57 +02:00
# include "valueflow.h"
2017-05-27 04:33:47 +02:00
2012-12-17 18:19:05 +01:00
# include <algorithm>
2017-05-27 04:33:47 +02:00
# include <list>
# include <set>
2013-04-01 12:41:14 +02:00
# include <utility>
2017-05-27 04:33:47 +02:00
# include <vector>
2011-08-19 20:35:25 +02:00
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
2011-10-13 20:53:06 +02:00
namespace {
CheckUnusedVar instance ;
2011-08-19 20:35:25 +02:00
}
2023-10-08 09:10:17 +02:00
static const CWE CWE563 ( 563U ) ; // Assignment to Variable without Use ('Unused Variable')
static const CWE CWE665 ( 665U ) ; // Improper Initialization
2016-07-15 15:49:21 +02:00
2020-09-27 19:15:15 +02:00
/** Is scope a raii class scope */
static bool isRaiiClassScope ( const Scope * classScope )
{
return classScope & & classScope - > getDestructor ( ) ! = nullptr ;
}
/** Is ValueType a raii class? */
static bool isRaiiClass ( const ValueType * valueType , bool cpp , bool defaultReturn = true )
{
if ( ! cpp )
return false ;
if ( ! valueType )
return defaultReturn ;
2022-05-27 17:17:50 +02:00
if ( ( valueType - > smartPointerType & & isRaiiClassScope ( valueType - > smartPointerType - > classScope ) ) | | ( ! valueType - > smartPointerType & & valueType - > type = = ValueType : : Type : : SMART_POINTER ) )
2020-09-27 19:15:15 +02:00
return true ;
switch ( valueType - > type ) {
case ValueType : : Type : : UNKNOWN_TYPE :
case ValueType : : Type : : NONSTD :
return defaultReturn ;
case ValueType : : Type : : RECORD :
if ( isRaiiClassScope ( valueType - > typeScope ) )
return true ;
return defaultReturn ;
2022-03-30 19:30:02 +02:00
case ValueType : : Type : : POD :
2021-08-14 19:00:58 +02:00
case ValueType : : Type : : SMART_POINTER :
2020-09-27 19:15:15 +02:00
case ValueType : : Type : : CONTAINER :
case ValueType : : Type : : ITERATOR :
case ValueType : : Type : : VOID :
case ValueType : : Type : : BOOL :
case ValueType : : Type : : CHAR :
case ValueType : : Type : : SHORT :
case ValueType : : Type : : WCHAR_T :
case ValueType : : Type : : INT :
case ValueType : : Type : : LONG :
case ValueType : : Type : : LONGLONG :
case ValueType : : Type : : UNKNOWN_INT :
case ValueType : : Type : : FLOAT :
case ValueType : : Type : : DOUBLE :
case ValueType : : Type : : LONGDOUBLE :
return false ;
}
return defaultReturn ;
}
2016-07-15 15:49:21 +02:00
2011-08-19 20:35:25 +02:00
/**
* @ brief This class is used create a list of variables within a function .
*/
2011-10-13 20:53:06 +02:00
class Variables {
2011-08-19 20:35:25 +02:00
public :
2011-12-18 20:15:41 +01:00
enum VariableType { standard , array , pointer , reference , pointerArray , referenceArray , pointerPointer , none } ;
2011-08-19 20:35:25 +02:00
/** Store information about variable usage */
2011-10-13 20:53:06 +02:00
class VariableUsage {
2011-08-19 20:35:25 +02:00
public :
2014-11-13 21:39:14 +01:00
explicit VariableUsage ( const Variable * var = nullptr ,
VariableType type = standard ,
bool read = false ,
bool write = false ,
bool modified = false ,
bool allocateMemory = false ) :
2012-09-04 14:53:24 +02:00
_var ( var ) ,
2017-08-09 20:00:26 +02:00
_lastAccess ( var ? var - > nameToken ( ) : nullptr ) ,
2018-06-16 20:25:54 +02:00
mType ( type ) ,
2011-08-19 20:35:25 +02:00
_read ( read ) ,
_write ( write ) ,
_modified ( modified ) ,
2021-08-07 20:51:18 +02:00
_allocateMemory ( allocateMemory ) { }
2011-08-19 20:35:25 +02:00
/** variable is used.. set both read+write */
2018-12-17 17:48:45 +01:00
void use ( ) {
2011-08-19 20:35:25 +02:00
_read = true ;
_write = true ;
}
/** is variable unused? */
2014-11-20 14:20:09 +01:00
bool unused ( ) const {
2017-10-08 07:54:39 +02:00
return ( ! _read & & ! _write ) ;
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
std : : set < nonneg int > _aliases ;
2012-05-14 20:46:23 +02:00
std : : set < const Scope * > _assignments ;
2012-09-04 14:53:24 +02:00
const Variable * _var ;
const Token * _lastAccess ;
2018-06-16 20:25:54 +02:00
VariableType mType ;
2011-08-19 20:35:25 +02:00
bool _read ;
bool _write ;
bool _modified ; // read/modify/write
bool _allocateMemory ;
} ;
2014-11-20 14:20:09 +01:00
void clear ( ) {
2018-06-17 18:55:41 +02:00
mVarUsage . clear ( ) ;
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
const std : : map < nonneg int , VariableUsage > & varUsage ( ) const {
2018-06-17 18:55:41 +02:00
return mVarUsage ;
2011-08-19 20:35:25 +02:00
}
2012-09-04 14:53:24 +02:00
void addVar ( const Variable * var , VariableType type , bool write_ ) ;
2021-01-27 19:49:13 +01:00
void allocateMemory ( nonneg int varid , const Token * tok ) ;
void read ( nonneg int varid , const Token * tok ) ;
void readAliases ( nonneg int varid , const Token * tok ) ;
void readAll ( nonneg int varid , const Token * tok ) ;
void write ( nonneg int varid , const Token * tok ) ;
void writeAliases ( nonneg int varid , const Token * tok ) ;
void writeAll ( nonneg int varid , const Token * tok ) ;
void use ( nonneg int varid , const Token * tok ) ;
void modified ( nonneg int varid , const Token * tok ) ;
VariableUsage * find ( nonneg int varid ) ;
void alias ( nonneg int varid1 , nonneg int varid2 , bool replace ) ;
void erase ( nonneg int varid ) {
2018-06-17 18:55:41 +02:00
mVarUsage . erase ( varid ) ;
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void eraseAliases ( nonneg int varid ) ;
void eraseAll ( nonneg int varid ) ;
void clearAliases ( nonneg int varid ) ;
2011-08-19 20:35:25 +02:00
private :
2012-12-04 21:39:51 +01:00
2021-01-27 19:49:13 +01:00
std : : map < nonneg int , VariableUsage > mVarUsage ;
2011-08-19 20:35:25 +02:00
} ;
2011-12-18 20:15:41 +01:00
2011-08-19 20:35:25 +02:00
/**
* Alias the 2 given variables . Either replace the existing aliases if
* they exist or merge them . You would replace an existing alias when this
* assignment is in the same scope as the previous assignment . You might
* merge the aliases when this assignment is in a different scope from the
* previous assignment depending on the relationship of the 2 scopes .
*/
2021-01-27 19:49:13 +01:00
void Variables : : alias ( nonneg int varid1 , nonneg int varid2 , bool replace )
2011-08-19 20:35:25 +02:00
{
VariableUsage * var1 = find ( varid1 ) ;
VariableUsage * var2 = find ( varid2 ) ;
2014-08-14 16:10:12 +02:00
if ( ! var1 | | ! var2 )
return ;
2011-08-19 20:35:25 +02:00
// alias to self
2011-10-13 20:53:06 +02:00
if ( varid1 = = varid2 ) {
2018-12-17 17:48:45 +01:00
var1 - > use ( ) ;
2011-08-19 20:35:25 +02:00
return ;
}
2011-10-13 20:53:06 +02:00
if ( replace ) {
2011-08-19 20:35:25 +02:00
// remove var1 from all aliases
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator i = var1 - > _aliases . cbegin ( ) ; i ! = var1 - > _aliases . cend ( ) ; + + i ) {
2011-08-19 20:35:25 +02:00
VariableUsage * temp = find ( * i ) ;
if ( temp )
2013-07-20 12:31:04 +02:00
temp - > _aliases . erase ( var1 - > _var - > declarationId ( ) ) ;
2011-08-19 20:35:25 +02:00
}
// remove all aliases from var1
var1 - > _aliases . clear ( ) ;
}
// var1 gets all var2s aliases
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator i = var2 - > _aliases . cbegin ( ) ; i ! = var2 - > _aliases . cend ( ) ; + + i ) {
2011-08-19 20:35:25 +02:00
if ( * i ! = varid1 )
var1 - > _aliases . insert ( * i ) ;
}
// var2 is an alias of var1
var2 - > _aliases . insert ( varid1 ) ;
var1 - > _aliases . insert ( varid2 ) ;
2018-06-16 20:25:54 +02:00
if ( var2 - > mType = = Variables : : pointer ) {
2011-08-19 20:35:25 +02:00
var2 - > _read = true ;
2012-12-04 21:39:51 +01:00
}
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : clearAliases ( nonneg int varid )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2011-10-13 20:53:06 +02:00
if ( usage ) {
2011-08-19 20:35:25 +02:00
// remove usage from all aliases
2021-01-27 19:49:13 +01:00
std : : set < nonneg int > : : const_iterator i ;
2011-08-19 20:35:25 +02:00
2022-12-30 15:13:47 +01:00
for ( i = usage - > _aliases . cbegin ( ) ; i ! = usage - > _aliases . cend ( ) ; + + i ) {
2011-08-19 20:35:25 +02:00
VariableUsage * temp = find ( * i ) ;
if ( temp )
2013-07-20 12:31:04 +02:00
temp - > _aliases . erase ( usage - > _var - > declarationId ( ) ) ;
2011-08-19 20:35:25 +02:00
}
// remove all aliases from usage
usage - > _aliases . clear ( ) ;
}
}
2021-01-27 19:49:13 +01:00
void Variables : : eraseAliases ( nonneg int varid )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2011-10-13 20:53:06 +02:00
if ( usage ) {
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator aliases = usage - > _aliases . cbegin ( ) ; aliases ! = usage - > _aliases . cend ( ) ; + + aliases )
2011-08-19 20:35:25 +02:00
erase ( * aliases ) ;
}
}
2021-01-27 19:49:13 +01:00
void Variables : : eraseAll ( nonneg int varid )
2011-08-19 20:35:25 +02:00
{
eraseAliases ( varid ) ;
erase ( varid ) ;
}
2012-09-04 14:53:24 +02:00
void Variables : : addVar ( const Variable * var ,
2011-08-19 20:35:25 +02:00
VariableType type ,
bool write_ )
{
2013-07-20 12:31:04 +02:00
if ( var - > declarationId ( ) > 0 ) {
2018-06-17 18:55:41 +02:00
mVarUsage . insert ( std : : make_pair ( var - > declarationId ( ) , VariableUsage ( var , type , false , write_ , false ) ) ) ;
2012-12-04 21:39:51 +01:00
}
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : allocateMemory ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2012-09-04 14:53:24 +02:00
if ( usage ) {
2011-08-19 20:35:25 +02:00
usage - > _allocateMemory = true ;
2012-09-04 14:53:24 +02:00
usage - > _lastAccess = tok ;
}
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : read ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2012-09-04 14:53:24 +02:00
if ( usage ) {
2011-08-19 20:35:25 +02:00
usage - > _read = true ;
2012-12-04 21:39:51 +01:00
if ( tok )
usage - > _lastAccess = tok ;
2012-09-04 14:53:24 +02:00
}
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : readAliases ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
2023-05-22 19:53:51 +02:00
const VariableUsage * usage = find ( varid ) ;
2011-08-19 20:35:25 +02:00
2011-10-13 20:53:06 +02:00
if ( usage ) {
2022-10-02 07:12:40 +02:00
for ( nonneg int const aliases : usage - > _aliases ) {
2020-09-21 19:30:47 +02:00
VariableUsage * aliased = find ( aliases ) ;
2011-08-19 20:35:25 +02:00
2012-09-04 14:53:24 +02:00
if ( aliased ) {
2011-08-19 20:35:25 +02:00
aliased - > _read = true ;
2012-09-04 14:53:24 +02:00
aliased - > _lastAccess = tok ;
}
2011-08-19 20:35:25 +02:00
}
}
}
2021-01-27 19:49:13 +01:00
void Variables : : readAll ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
2012-09-11 14:24:12 +02:00
read ( varid , tok ) ;
readAliases ( varid , tok ) ;
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : write ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2012-09-02 18:50:17 +02:00
if ( usage ) {
2011-08-19 20:35:25 +02:00
usage - > _write = true ;
2012-09-30 17:22:35 +02:00
if ( ! usage - > _var - > isStatic ( ) & & ! Token : : simpleMatch ( tok - > next ( ) , " = 0 ; " ) )
2012-09-11 14:14:35 +02:00
usage - > _read = false ;
2012-09-04 14:53:24 +02:00
usage - > _lastAccess = tok ;
2012-09-02 18:50:17 +02:00
}
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : writeAliases ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2011-10-13 20:53:06 +02:00
if ( usage ) {
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator aliases = usage - > _aliases . cbegin ( ) ; aliases ! = usage - > _aliases . cend ( ) ; + + aliases ) {
2011-08-19 20:35:25 +02:00
VariableUsage * aliased = find ( * aliases ) ;
2012-09-04 14:53:24 +02:00
if ( aliased ) {
2011-08-19 20:35:25 +02:00
aliased - > _write = true ;
2012-09-04 14:53:24 +02:00
aliased - > _lastAccess = tok ;
}
2011-08-19 20:35:25 +02:00
}
}
}
2021-01-27 19:49:13 +01:00
void Variables : : writeAll ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
2012-09-11 14:24:12 +02:00
write ( varid , tok ) ;
writeAliases ( varid , tok ) ;
2011-08-19 20:35:25 +02:00
}
2021-01-27 19:49:13 +01:00
void Variables : : use ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2011-10-13 20:53:06 +02:00
if ( usage ) {
2018-12-17 17:48:45 +01:00
usage - > use ( ) ;
2012-09-04 14:53:24 +02:00
usage - > _lastAccess = tok ;
2011-08-19 20:35:25 +02:00
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator aliases = usage - > _aliases . cbegin ( ) ; aliases ! = usage - > _aliases . cend ( ) ; + + aliases ) {
2011-08-19 20:35:25 +02:00
VariableUsage * aliased = find ( * aliases ) ;
2012-09-04 14:53:24 +02:00
if ( aliased ) {
2018-12-17 17:48:45 +01:00
aliased - > use ( ) ;
2012-09-04 14:53:24 +02:00
aliased - > _lastAccess = tok ;
}
2011-08-19 20:35:25 +02:00
}
}
}
2021-01-27 19:49:13 +01:00
void Variables : : modified ( nonneg int varid , const Token * tok )
2011-08-19 20:35:25 +02:00
{
VariableUsage * usage = find ( varid ) ;
2011-10-13 20:53:06 +02:00
if ( usage ) {
2016-10-10 21:27:40 +02:00
if ( ! usage - > _var - > isStatic ( ) )
usage - > _read = false ;
2011-08-19 20:35:25 +02:00
usage - > _modified = true ;
2012-09-04 14:53:24 +02:00
usage - > _lastAccess = tok ;
2011-08-19 20:35:25 +02:00
2022-12-20 20:32:16 +01:00
for ( std : : set < nonneg int > : : const_iterator aliases = usage - > _aliases . cbegin ( ) ; aliases ! = usage - > _aliases . cend ( ) ; + + aliases ) {
2011-08-19 20:35:25 +02:00
VariableUsage * aliased = find ( * aliases ) ;
2012-09-04 14:53:24 +02:00
if ( aliased ) {
2011-08-19 20:35:25 +02:00
aliased - > _modified = true ;
2012-09-04 14:53:24 +02:00
aliased - > _lastAccess = tok ;
}
2011-08-19 20:35:25 +02:00
}
}
}
2021-01-27 19:49:13 +01:00
Variables : : VariableUsage * Variables : : find ( nonneg int varid )
2011-08-19 20:35:25 +02:00
{
2011-10-13 20:53:06 +02:00
if ( varid ) {
2022-10-02 07:12:40 +02:00
const std : : map < nonneg int , VariableUsage > : : iterator i = mVarUsage . find ( varid ) ;
2018-06-17 18:55:41 +02:00
if ( i ! = mVarUsage . end ( ) )
2011-08-19 20:35:25 +02:00
return & i - > second ;
}
2017-08-09 20:00:26 +02:00
return nullptr ;
2011-08-19 20:35:25 +02:00
}
2012-02-29 20:57:48 +01:00
static const Token * doAssignment ( Variables & variables , const Token * tok , bool dereference , const Scope * scope )
2011-08-19 20:35:25 +02:00
{
// a = a + b;
2017-09-26 23:51:04 +02:00
if ( Token : : Match ( tok , " %var% = %var% !!; " ) ) {
const Token * rhsVarTok = tok - > tokAt ( 2 ) ;
if ( tok - > varId ( ) = = rhsVarTok - > varId ( ) ) {
return rhsVarTok ;
}
2011-08-19 20:35:25 +02:00
}
2015-12-31 01:15:49 +01:00
if ( Token : : Match ( tok , " %var% %assign% " ) & & tok - > strAt ( 1 ) ! = " = " )
return tok - > next ( ) ;
2012-02-29 20:57:48 +01:00
const Token * const tokOld = tok ;
2011-12-18 20:15:41 +01:00
2011-08-19 20:35:25 +02:00
// check for aliased variable
2021-01-27 19:49:13 +01:00
const nonneg int varid1 = tok - > varId ( ) ;
2011-08-19 20:35:25 +02:00
Variables : : VariableUsage * var1 = variables . find ( varid1 ) ;
2011-10-13 20:53:06 +02:00
if ( var1 ) {
2012-02-29 20:57:48 +01:00
// jump behind '='
tok = tok - > next ( ) ;
2015-12-31 01:15:49 +01:00
while ( ! tok - > isAssignmentOp ( ) ) {
2012-08-22 19:47:46 +02:00
if ( tok - > varId ( ) )
2012-09-04 14:53:24 +02:00
variables . read ( tok - > varId ( ) , tok ) ;
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
2012-08-22 19:47:46 +02:00
}
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
2013-02-20 17:43:16 +01:00
if ( Token : : Match ( tok , " ( const| struct|union| %type% * ) ( ( " ) )
tok = tok - > link ( ) - > next ( ) ;
if ( Token : : Match ( tok , " ( [(<] const| struct|union| %type% *| [>)] " ) )
tok = tok - > next ( ) ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " (| &| %name% " ) | |
2016-11-26 17:08:36 +01:00
( Token : : Match ( tok - > next ( ) , " < const| struct|union| %type% *| > ( &| %name% " ) ) ) {
2011-08-19 20:35:25 +02:00
bool addressOf = false ;
2012-02-29 20:57:48 +01:00
if ( Token : : Match ( tok , " %var% . " ) )
2012-09-04 14:53:24 +02:00
variables . use ( tok - > varId ( ) , tok ) ; // use = read + write
2011-08-19 20:35:25 +02:00
// check for C style cast
2012-02-29 20:57:48 +01:00
if ( tok - > str ( ) = = " ( " ) {
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2012-02-29 20:57:48 +01:00
if ( Token : : Match ( tok , " struct|union " ) )
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2013-03-04 19:13:49 +01:00
while ( ( tok - > isName ( ) & & tok - > varId ( ) = = 0 ) | | ( tok - > str ( ) = = " * " ) | | ( tok - > str ( ) = = " ) " ) )
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2012-02-29 20:57:48 +01:00
if ( tok - > str ( ) = = " & " ) {
2011-08-19 20:35:25 +02:00
addressOf = true ;
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
} else if ( tok - > str ( ) = = " ( " ) {
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " & " ) {
2011-08-19 20:35:25 +02:00
addressOf = true ;
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
}
2013-09-03 17:02:46 +02:00
} else if ( Token : : Match ( tok , " %cop% %var% " ) ) {
variables . read ( tok - > next ( ) - > varId ( ) , tok ) ;
2012-02-29 20:57:48 +01:00
}
2011-08-19 20:35:25 +02:00
}
// check for C++ style cast
2012-02-29 20:57:48 +01:00
else if ( tok - > str ( ) . find ( " cast " ) ! = std : : string : : npos & &
tok - > strAt ( 1 ) = = " < " ) {
tok = tok - > tokAt ( 2 ) ;
if ( tok - > str ( ) = = " const " )
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2012-02-29 20:57:48 +01:00
if ( Token : : Match ( tok , " struct|union " ) )
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " * " )
tok = tok - > next ( ) ;
2011-08-19 20:35:25 +02:00
2012-02-29 20:57:48 +01:00
tok = tok - > tokAt ( 2 ) ;
2016-01-31 10:25:09 +01:00
if ( ! tok )
return tokOld ;
2012-02-29 20:57:48 +01:00
if ( tok - > str ( ) = = " & " ) {
2011-08-19 20:35:25 +02:00
addressOf = true ;
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
}
2011-08-19 20:35:25 +02:00
}
2012-02-29 20:57:48 +01:00
// no cast, no ?
2015-01-31 10:50:39 +01:00
else if ( ! Token : : Match ( tok , " %name% ? " ) ) {
2012-02-29 20:57:48 +01:00
if ( tok - > str ( ) = = " & " ) {
2011-08-19 20:35:25 +02:00
addressOf = true ;
2012-02-29 20:57:48 +01:00
tok = tok - > next ( ) ;
} else if ( tok - > str ( ) = = " new " )
return tokOld ;
2011-08-19 20:35:25 +02:00
}
// check if variable is local
2021-01-27 19:49:13 +01:00
const nonneg int varid2 = tok - > varId ( ) ;
2015-06-03 17:17:53 +02:00
const Variables : : VariableUsage * var2 = variables . find ( varid2 ) ;
2011-08-19 20:35:25 +02:00
2011-10-13 20:53:06 +02:00
if ( var2 ) { // local variable (alias or read it)
2018-06-16 20:25:54 +02:00
if ( var1 - > mType = = Variables : : pointer | | var1 - > mType = = Variables : : pointerArray ) {
2011-08-19 20:35:25 +02:00
if ( dereference )
2012-09-04 14:53:24 +02:00
variables . read ( varid2 , tok ) ;
2011-10-13 20:53:06 +02:00
else {
2011-08-19 20:35:25 +02:00
if ( addressOf | |
2018-06-16 20:25:54 +02:00
var2 - > mType = = Variables : : array | |
var2 - > mType = = Variables : : pointer ) {
2012-02-29 20:57:48 +01:00
bool replace = true ;
2011-08-19 20:35:25 +02:00
2012-06-24 16:54:37 +02:00
// pointerArray => don't replace
2018-06-16 20:25:54 +02:00
if ( var1 - > mType = = Variables : : pointerArray )
2012-06-24 16:54:37 +02:00
replace = false ;
2011-08-19 20:35:25 +02:00
// check if variable declared in same scope
2012-09-04 14:53:24 +02:00
else if ( scope = = var1 - > _var - > scope ( ) )
2011-08-19 20:35:25 +02:00
replace = true ;
// not in same scope as declaration
2011-10-13 20:53:06 +02:00
else {
2011-08-19 20:35:25 +02:00
// no other assignment in this scope
2012-04-28 15:43:42 +02:00
if ( var1 - > _assignments . find ( scope ) = = var1 - > _assignments . end ( ) | |
scope - > type = = Scope : : eSwitch ) {
2011-08-19 20:35:25 +02:00
// nothing to replace
2021-01-09 20:32:38 +01:00
// cppcheck-suppress duplicateBranch - remove when TODO below is address
2011-08-19 20:35:25 +02:00
if ( var1 - > _assignments . empty ( ) )
replace = false ;
// this variable has previous assignments
2011-10-13 20:53:06 +02:00
else {
2021-01-09 20:32:38 +01:00
// TODO: determine if existing aliases should be replaced or merged
2011-08-19 20:35:25 +02:00
replace = false ;
}
}
// assignment in this scope
2011-10-13 20:53:06 +02:00
else {
2012-02-29 20:57:48 +01:00
// replace when only one other assignment, merge them otherwise
replace = ( var1 - > _assignments . size ( ) = = 1 ) ;
2011-08-19 20:35:25 +02:00
}
}
variables . alias ( varid1 , varid2 , replace ) ;
2012-02-29 20:57:48 +01:00
} else if ( tok - > strAt ( 1 ) = = " ? " ) {
2018-06-16 20:25:54 +02:00
if ( var2 - > mType = = Variables : : reference )
2012-09-04 14:53:24 +02:00
variables . readAliases ( varid2 , tok ) ;
2011-08-19 20:35:25 +02:00
else
2012-09-04 14:53:24 +02:00
variables . read ( varid2 , tok ) ;
2012-08-22 19:47:46 +02:00
} else {
2012-12-28 18:18:36 +01:00
variables . readAll ( varid2 , tok ) ;
2011-08-19 20:35:25 +02:00
}
}
2018-06-16 20:25:54 +02:00
} else if ( var1 - > mType = = Variables : : reference ) {
2011-08-19 20:35:25 +02:00
variables . alias ( varid1 , varid2 , true ) ;
2018-12-30 20:20:20 +01:00
} else if ( var1 - > mType = = Variables : : standard & & addressOf ) {
variables . alias ( varid1 , varid2 , true ) ;
2011-10-13 20:53:06 +02:00
} else {
2018-06-16 20:25:54 +02:00
if ( ( var2 - > mType = = Variables : : pointer | | var2 - > mType = = Variables : : pointerArray ) & & tok - > strAt ( 1 ) = = " [ " )
2012-09-04 14:53:24 +02:00
variables . readAliases ( varid2 , tok ) ;
2011-08-19 20:35:25 +02:00
2012-09-04 14:53:24 +02:00
variables . read ( varid2 , tok ) ;
2011-08-19 20:35:25 +02:00
}
2011-10-13 20:53:06 +02:00
} else { // not a local variable (or an unsupported local variable)
2018-06-16 20:25:54 +02:00
if ( var1 - > mType = = Variables : : pointer & & ! dereference ) {
2011-08-19 20:35:25 +02:00
// check if variable declaration is in this scope
2017-07-09 11:19:00 +02:00
if ( var1 - > _var - > scope ( ) = = scope ) {
// If variable is used in RHS then "use" variable
for ( const Token * rhs = tok ; rhs & & rhs - > str ( ) ! = " ; " ; rhs = rhs - > next ( ) ) {
if ( rhs - > varId ( ) = = varid1 ) {
variables . use ( varid1 , tok ) ;
break ;
}
}
2011-08-19 20:35:25 +02:00
variables . clearAliases ( varid1 ) ;
2017-07-09 11:19:00 +02:00
} else {
2011-08-19 20:35:25 +02:00
// no other assignment in this scope
2011-12-18 20:15:41 +01:00
if ( var1 - > _assignments . find ( scope ) = = var1 - > _assignments . end ( ) ) {
2011-08-19 20:35:25 +02:00
/**
* @ todo determine if existing aliases should be discarded
*/
}
// this assignment replaces the last assignment in this scope
2011-10-13 20:53:06 +02:00
else {
2011-08-19 20:35:25 +02:00
// aliased variables in a larger scope are not supported
// remove all aliases
variables . clearAliases ( varid1 ) ;
}
}
}
}
2012-02-29 20:57:48 +01:00
} else
tok = tokOld ;
2011-08-19 20:35:25 +02:00
var1 - > _assignments . insert ( scope ) ;
}
// check for alias to struct member
// char c[10]; a.b = c;
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %name% . " ) ) {
2017-09-26 23:51:04 +02:00
const Token * rhsVarTok = tok - > tokAt ( 2 ) ;
if ( rhsVarTok & & rhsVarTok - > varId ( ) ) {
2021-01-27 19:49:13 +01:00
const nonneg int varid2 = rhsVarTok - > varId ( ) ;
2015-06-03 17:17:53 +02:00
const Variables : : VariableUsage * var2 = variables . find ( varid2 ) ;
2011-08-19 20:35:25 +02:00
// struct member aliased to local variable
2018-06-16 20:25:54 +02:00
if ( var2 & & ( var2 - > mType = = Variables : : array | |
var2 - > mType = = Variables : : pointer ) ) {
2011-08-19 20:35:25 +02:00
// erase aliased variable and all variables that alias it
// to prevent false positives
variables . eraseAll ( varid2 ) ;
}
}
}
2013-03-20 06:38:53 +01:00
// Possible pointer alias
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok , " %name% = %name% ; " ) ) {
2021-01-27 19:49:13 +01:00
const nonneg int varid2 = tok - > tokAt ( 2 ) - > varId ( ) ;
2015-06-03 17:17:53 +02:00
const Variables : : VariableUsage * var2 = variables . find ( varid2 ) ;
2018-06-16 20:25:54 +02:00
if ( var2 & & ( var2 - > mType = = Variables : : array | |
var2 - > mType = = Variables : : pointer ) ) {
2013-03-20 06:38:53 +01:00
variables . use ( varid2 , tok ) ;
}
}
2012-02-29 20:57:48 +01:00
return tok ;
2011-08-19 20:35:25 +02:00
}
2011-12-18 20:15:41 +01:00
static bool isPartOfClassStructUnion ( const Token * tok )
{
for ( ; tok ; tok = tok - > previous ( ) ) {
if ( tok - > str ( ) = = " } " | | tok - > str ( ) = = " ) " )
tok = tok - > link ( ) ;
else if ( tok - > str ( ) = = " ( " )
2023-08-08 11:05:02 +02:00
return false ;
2011-12-18 20:15:41 +01:00
else if ( tok - > str ( ) = = " { " ) {
2013-08-07 16:27:37 +02:00
return ( tok - > strAt ( - 1 ) = = " struct " | | tok - > strAt ( - 2 ) = = " struct " | | tok - > strAt ( - 1 ) = = " class " | | tok - > strAt ( - 2 ) = = " class " | | tok - > strAt ( - 1 ) = = " union " | | tok - > strAt ( - 2 ) = = " union " ) ;
2011-12-18 20:15:41 +01:00
}
}
return false ;
}
2020-04-10 11:53:32 +02:00
static bool isVarDecl ( const Token * tok )
{
return tok & & tok - > variable ( ) & & tok - > variable ( ) - > nameToken ( ) = = tok ;
}
2011-12-26 08:12:23 +01:00
// Skip [ .. ]
static const Token * skipBrackets ( const Token * tok )
{
while ( tok & & tok - > str ( ) = = " [ " )
tok = tok - > link ( ) - > next ( ) ;
return tok ;
}
2012-02-26 08:29:02 +01:00
// Skip [ .. ] . x
static const Token * skipBracketsAndMembers ( const Token * tok )
{
while ( tok ) {
if ( tok - > str ( ) = = " [ " )
tok = tok - > link ( ) - > next ( ) ;
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok , " . %name% " ) )
2012-02-26 08:29:02 +01:00
tok = tok - > tokAt ( 2 ) ;
else
break ;
}
return tok ;
}
2017-02-28 22:04:05 +01:00
static void useFunctionArgs ( const Token * tok , Variables & variables )
{
// TODO: Match function args to see if they are const or not. Assume that const data is not written.
if ( ! tok )
return ;
2017-07-01 22:45:51 +02:00
if ( tok - > str ( ) = = " , " ) {
useFunctionArgs ( tok - > astOperand1 ( ) , variables ) ;
useFunctionArgs ( tok - > astOperand2 ( ) , variables ) ;
} else if ( Token : : Match ( tok , " [+:] " ) & & ( ! tok - > valueType ( ) | | tok - > valueType ( ) - > pointer ) ) {
2017-02-28 22:04:05 +01:00
useFunctionArgs ( tok - > astOperand1 ( ) , variables ) ;
useFunctionArgs ( tok - > astOperand2 ( ) , variables ) ;
} else if ( tok - > variable ( ) & & tok - > variable ( ) - > isArray ( ) ) {
variables . use ( tok - > varId ( ) , tok ) ;
}
}
2012-02-26 08:29:02 +01:00
2011-08-19 20:35:25 +02:00
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
2018-12-17 17:48:45 +01:00
void CheckUnusedVar : : checkFunctionVariableUsage_iterateScopes ( const Scope * const scope , Variables & variables )
2011-08-19 20:35:25 +02:00
{
2012-02-25 12:56:33 +01:00
// Find declarations if the scope is executable..
2012-09-04 14:53:24 +02:00
if ( scope - > isExecutable ( ) ) {
2012-02-25 12:56:33 +01:00
// Find declarations
2022-12-20 20:32:16 +01:00
for ( std : : list < Variable > : : const_iterator i = scope - > varlist . cbegin ( ) ; i ! = scope - > varlist . cend ( ) ; + + i ) {
2012-06-28 17:22:56 +02:00
if ( i - > isThrow ( ) | | i - > isExtern ( ) )
2012-03-26 21:19:42 +02:00
continue ;
2012-02-25 12:56:33 +01:00
Variables : : VariableType type = Variables : : none ;
if ( i - > isArray ( ) & & ( i - > nameToken ( ) - > previous ( ) - > str ( ) = = " * " | | i - > nameToken ( ) - > strAt ( - 2 ) = = " * " ) )
type = Variables : : pointerArray ;
else if ( i - > isArray ( ) & & i - > nameToken ( ) - > previous ( ) - > str ( ) = = " & " )
type = Variables : : referenceArray ;
else if ( i - > isArray ( ) )
2023-08-20 11:08:17 +02:00
type = Variables : : array ;
2022-04-09 14:50:30 +02:00
else if ( i - > isReference ( ) & & ! ( i - > valueType ( ) & & i - > valueType ( ) - > type = = ValueType : : UNKNOWN_TYPE & & Token : : simpleMatch ( i - > typeStartToken ( ) , " auto " ) ) )
2012-02-25 12:56:33 +01:00
type = Variables : : reference ;
else if ( i - > nameToken ( ) - > previous ( ) - > str ( ) = = " * " & & i - > nameToken ( ) - > strAt ( - 2 ) = = " * " )
type = Variables : : pointerPointer ;
2015-08-27 23:56:26 +02:00
else if ( i - > isPointerToArray ( ) )
type = Variables : : pointerPointer ;
2012-02-25 12:56:33 +01:00
else if ( i - > isPointer ( ) )
type = Variables : : pointer ;
2018-06-16 16:10:28 +02:00
else if ( mTokenizer - > isC ( ) | |
2013-01-07 20:28:43 +01:00
i - > typeEndToken ( ) - > isStandardType ( ) | |
2013-03-05 15:28:40 +01:00
isRecordTypeWithoutSideEffects ( i - > type ( ) ) | |
2022-08-20 12:14:55 +02:00
mSettings - > library . detectContainer ( i - > typeStartToken ( ) ) | |
2022-01-12 22:25:37 +01:00
i - > isStlType ( ) )
2012-02-25 12:56:33 +01:00
type = Variables : : standard ;
if ( type = = Variables : : none | | isPartOfClassStructUnion ( i - > typeStartToken ( ) ) )
continue ;
const Token * defValTok = i - > nameToken ( ) - > next ( ) ;
2016-01-30 20:59:32 +01:00
if ( Token : : Match ( i - > nameToken ( ) - > previous ( ) , " * %var% ) ( " ) ) // function pointer. Jump behind parameter list.
defValTok = defValTok - > linkAt ( 1 ) - > next ( ) ;
2012-02-25 12:56:33 +01:00
for ( ; defValTok ; defValTok = defValTok - > next ( ) ) {
if ( defValTok - > str ( ) = = " [ " )
defValTok = defValTok - > link ( ) ;
2015-10-27 14:46:58 +01:00
else if ( defValTok - > str ( ) = = " ( " | | defValTok - > str ( ) = = " { " || defValTok->str() == " = " || defValTok->str() == " : " ) {
2012-09-04 14:53:24 +02:00
variables . addVar ( & * i , type , true ) ;
2012-02-25 12:56:33 +01:00
break ;
} else if ( defValTok - > str ( ) = = " ; " || defValTok->str() == " , " || defValTok->str() == " ) " ) {
2022-03-13 06:26:21 +01:00
variables . addVar ( & * i , type , i - > isStatic ( ) & & i - > scope ( ) - > type ! = Scope : : eFunction ) ;
2012-02-25 12:56:33 +01:00
break ;
}
2011-08-19 20:35:25 +02:00
}
2022-01-10 07:36:49 +01:00
if ( i - > isArray ( ) & & i - > isClass ( ) & & // Array of class/struct members. Initialized by ctor except for std::array
! ( i - > isStlType ( ) & & i - > valueType ( ) & & i - > valueType ( ) - > containerTypeToken & & i - > valueType ( ) - > containerTypeToken - > isStandardType ( ) ) )
2013-07-20 12:31:04 +02:00
variables . write ( i - > declarationId ( ) , i - > nameToken ( ) ) ;
2015-01-31 10:50:39 +01:00
if ( i - > isArray ( ) & & Token : : Match ( i - > nameToken ( ) , " %name% [ %var% ] " ) ) // Array index variable read.
2012-09-04 14:53:24 +02:00
variables . read ( i - > nameToken ( ) - > tokAt ( 2 ) - > varId ( ) , i - > nameToken ( ) ) ;
2012-02-25 12:56:33 +01:00
2017-01-22 10:16:40 +01:00
if ( defValTok & & defValTok - > next ( ) ) {
// simple assignment "var = 123"
if ( defValTok - > str ( ) = = " = " & & defValTok - > next ( ) - > str ( ) ! = " { " ) {
2012-02-25 12:56:33 +01:00
doAssignment ( variables , i - > nameToken ( ) , false , scope ) ;
2017-01-22 10:16:40 +01:00
} else {
// could be "var = {...}" OR "var{...}" (since C++11)
2017-07-23 23:32:14 +02:00
const Token * tokBraceStart = nullptr ;
if ( Token : : simpleMatch ( defValTok , " = { " ) ) {
2017-01-22 10:16:40 +01:00
// "var = {...}"
tokBraceStart = defValTok - > next ( ) ;
} else if ( defValTok - > str ( ) = = " { " ) {
// "var{...}"
tokBraceStart = defValTok ;
}
if ( tokBraceStart ) {
for ( const Token * tok = tokBraceStart - > next ( ) ; tok & & tok ! = tokBraceStart - > link ( ) ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) ) {
// Variables used to initialize the array read.
variables . read ( tok - > varId ( ) , i - > nameToken ( ) ) ;
}
}
}
}
2014-08-05 15:33:57 +02:00
}
2011-12-18 20:15:41 +01:00
}
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
// Check variable usage
2014-08-03 19:13:37 +02:00
const Token * tok ;
if ( scope - > type = = Scope : : eFunction )
2018-04-27 22:36:30 +02:00
tok = scope - > bodyStart - > next ( ) ;
2014-08-03 19:13:37 +02:00
else
tok = scope - > classDef - > next ( ) ;
2018-04-27 22:36:30 +02:00
for ( ; tok & & tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " & & tok ! = scope - > bodyStart & & ! tok - > previous ( ) - > varId ( ) ) {
2022-12-30 15:13:47 +01:00
if ( std : : any_of ( scope - > nestedList . cbegin ( ) , scope - > nestedList . cend ( ) , [ & ] ( const Scope * s ) {
2022-10-16 13:46:26 +02:00
return s - > bodyStart = = tok ;
} ) ) {
checkFunctionVariableUsage_iterateScopes ( tok - > scope ( ) , variables ) ; // Scan child scope
tok = tok - > link ( ) ;
2011-08-19 20:35:25 +02:00
}
2011-12-18 20:15:41 +01:00
if ( ! tok )
break ;
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
if ( Token : : Match ( tok , " asm ( %str% ) " ) ) {
variables . clear ( ) ;
break ;
}
2016-01-31 12:39:43 +01:00
// templates
2018-03-29 22:00:04 +02:00
if ( tok - > isName ( ) & & endsWith ( tok - > str ( ) , ' > ' ) ) {
2016-01-31 09:11:52 +01:00
// TODO: This is a quick fix to handle when constants are used
// as template parameters. Try to handle this better, perhaps
// only remove constants.
2016-01-30 16:49:39 +01:00
variables . clear ( ) ;
}
2013-03-28 06:44:37 +01:00
2014-07-02 00:17:35 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } ] " )) {
2012-07-24 20:47:29 +02:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) ) {
2016-01-31 12:39:43 +01:00
// Is this a variable declaration?
2013-02-06 06:39:58 +01:00
const Variable * var = tok2 - > variable ( ) ;
2016-01-31 12:39:43 +01:00
if ( ! var | | var - > nameToken ( ) ! = tok2 )
continue ;
// Mark template parameters used in declaration as use..
if ( tok2 - > strAt ( - 1 ) = = " > " ) {
for ( const Token * tok3 = tok ; tok3 ! = tok2 ; tok3 = tok3 - > next ( ) ) {
2021-01-27 19:49:13 +01:00
if ( tok3 - > varId ( ) )
2016-01-31 12:39:43 +01:00
variables . use ( tok3 - > varId ( ) , tok3 ) ;
}
2012-07-24 20:47:29 +02:00
}
2016-01-31 12:39:43 +01:00
// Skip variable declaration..
tok = tok2 - > next ( ) ;
if ( Token : : Match ( tok , " ( %name% ) " ) ) // Simple initialization through copy ctor
tok = tok - > next ( ) ;
else if ( Token : : Match ( tok , " = %var% ; " ) ) { // Simple initialization
tok = tok - > next ( ) ;
if ( ! var - > isReference ( ) )
variables . read ( tok - > varId ( ) , tok ) ;
2017-07-23 23:32:14 +02:00
} else if ( tok - > str ( ) = = " [ " & & Token : : simpleMatch ( skipBrackets ( tok ) , " = { " )) {
const Token * const rhs1 = skipBrackets ( tok ) - > next ( ) ;
for ( const Token * rhs = rhs1 - > link ( ) ; rhs ! = rhs1 ; rhs = rhs - > previous ( ) ) {
if ( rhs - > varId ( ) )
variables . readAll ( rhs - > varId ( ) , rhs ) ;
}
2016-01-31 12:39:43 +01:00
} else if ( var - > typeEndToken ( ) - > str ( ) = = " > " ) // Be careful with types like std::vector
tok = tok - > previous ( ) ;
break ;
2023-06-20 18:43:21 +02:00
}
if ( Token : : Match ( tok2 , " [;({=] " ) )
2012-02-19 15:25:46 +01:00
break ;
}
2011-12-18 20:15:41 +01:00
}
// Freeing memory (not considered "using" the pointer if it was also allocated in this function)
2023-05-21 14:01:14 +02:00
if ( ( Token : : Match ( tok , " %name% ( %var% ) " ) & & mSettings - > library . getDeallocFuncInfo ( tok ) ) | |
2018-06-16 16:10:28 +02:00
( mTokenizer - > isCPP ( ) & & ( Token : : Match ( tok , " delete %var% ; " ) | | Token : : Match ( tok , " delete [ ] %var% ; " ) ) ) ) {
2021-01-27 19:49:13 +01:00
nonneg int varid = 0 ;
2011-12-18 20:15:41 +01:00
if ( tok - > str ( ) ! = " delete " ) {
2017-09-26 23:51:04 +02:00
const Token * varTok = tok - > tokAt ( 2 ) ;
varid = varTok - > varId ( ) ;
tok = varTok - > next ( ) ;
2011-12-18 20:15:41 +01:00
} else if ( tok - > strAt ( 1 ) = = " [ " ) {
2017-09-26 23:51:04 +02:00
const Token * varTok = tok - > tokAt ( 3 ) ;
varid = varTok - > varId ( ) ;
tok = varTok ;
2011-12-18 20:15:41 +01:00
} else {
varid = tok - > next ( ) - > varId ( ) ;
2011-08-19 20:35:25 +02:00
tok = tok - > next ( ) ;
}
2018-09-23 20:24:51 +02:00
const Variables : : VariableUsage * const var = variables . find ( varid ) ;
2018-11-14 17:04:14 +01:00
if ( var ) {
if ( ! var - > _aliases . empty ( ) )
variables . use ( varid , tok ) ;
else if ( ! var - > _allocateMemory )
variables . readAll ( varid , tok ) ;
2011-08-19 20:35:25 +02:00
}
2011-12-18 20:15:41 +01:00
}
2011-08-19 20:35:25 +02:00
2012-03-20 19:00:16 +01:00
else if ( Token : : Match ( tok , " return|throw " ) ) {
2012-01-08 08:44:18 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) )
2012-09-04 14:53:24 +02:00
variables . readAll ( tok2 - > varId ( ) , tok ) ;
2012-01-08 08:44:18 +01:00
else if ( tok2 - > str ( ) = = " ; " )
break ;
}
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
// assignment
2015-12-31 01:15:49 +01:00
else if ( Token : : Match ( tok , " *| ++|--| %name% ++|--| %assign% " ) | |
Token : : Match ( tok , " *| ( const| %type% *| ) %name% %assign% " ) ) {
2011-12-18 20:15:41 +01:00
bool dereference = false ;
bool pre = false ;
bool post = false ;
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
if ( tok - > str ( ) = = " * " ) {
dereference = true ;
2011-08-19 20:35:25 +02:00
tok = tok - > next ( ) ;
}
2015-12-31 01:15:49 +01:00
if ( Token : : Match ( tok , " ( const| %type% *| ) %name% %assign% " ) )
2011-12-18 20:15:41 +01:00
tok = tok - > link ( ) - > next ( ) ;
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
else if ( tok - > str ( ) = = " ( " )
2011-08-19 20:35:25 +02:00
tok = tok - > next ( ) ;
2015-08-14 20:46:13 +02:00
if ( tok - > tokType ( ) = = Token : : eIncDecOp ) {
2011-12-18 20:15:41 +01:00
pre = true ;
2011-08-19 20:35:25 +02:00
tok = tok - > next ( ) ;
}
2015-08-14 20:46:13 +02:00
if ( tok - > next ( ) - > tokType ( ) = = Token : : eIncDecOp )
2011-12-18 20:15:41 +01:00
post = true ;
2011-08-19 20:35:25 +02:00
2021-01-27 19:49:13 +01:00
const nonneg int varid1 = tok - > varId ( ) ;
2012-11-15 08:36:43 +01:00
const Token * const start = tok ;
2011-08-19 20:35:25 +02:00
2016-01-01 12:14:18 +01:00
// assignment in while head..
bool inwhile = false ;
{
const Token * parent = tok - > astParent ( ) ;
while ( parent ) {
2017-08-24 17:10:33 +02:00
if ( Token : : simpleMatch ( parent - > previous ( ) , " while ( " ) ) {
2016-01-01 12:14:18 +01:00
inwhile = true ;
2017-08-24 17:10:33 +02:00
break ;
}
2016-01-01 12:14:18 +01:00
parent = parent - > astParent ( ) ;
}
}
2012-02-29 20:57:48 +01:00
tok = doAssignment ( variables , tok , dereference , scope ) ;
2011-08-19 20:35:25 +02:00
2015-12-31 01:15:49 +01:00
if ( tok & & tok - > isAssignmentOp ( ) & & tok - > str ( ) ! = " = " ) {
variables . use ( varid1 , tok ) ;
2015-12-31 15:30:33 +01:00
if ( Token : : Match ( tok , " %assign% %name% " ) ) {
2015-12-31 01:15:49 +01:00
tok = tok - > next ( ) ;
2015-12-31 15:30:33 +01:00
variables . read ( tok - > varId ( ) , tok ) ;
}
2015-12-31 01:15:49 +01:00
}
2011-12-18 20:15:41 +01:00
if ( pre | | post )
2012-09-04 14:53:24 +02:00
variables . use ( varid1 , tok ) ;
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
if ( dereference ) {
2018-09-23 20:24:51 +02:00
const Variables : : VariableUsage * const var = variables . find ( varid1 ) ;
2018-06-16 20:25:54 +02:00
if ( var & & var - > mType = = Variables : : array )
2012-09-04 14:53:24 +02:00
variables . write ( varid1 , tok ) ;
variables . writeAliases ( varid1 , tok ) ;
variables . read ( varid1 , tok ) ;
2011-12-18 20:15:41 +01:00
} else {
2018-09-23 20:24:51 +02:00
const Variables : : VariableUsage * const var = variables . find ( varid1 ) ;
2016-01-01 12:14:18 +01:00
if ( var & & ( inwhile | | start - > strAt ( - 1 ) = = " , " ) ) {
2012-11-15 08:36:43 +01:00
variables . use ( varid1 , tok ) ;
2018-06-16 20:25:54 +02:00
} else if ( var & & var - > mType = = Variables : : reference ) {
2012-09-04 14:53:24 +02:00
variables . writeAliases ( varid1 , tok ) ;
variables . read ( varid1 , tok ) ;
2011-08-19 20:35:25 +02:00
}
2011-12-18 20:15:41 +01:00
// Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
2018-06-16 20:25:54 +02:00
else if ( var & & var - > mType = = Variables : : pointer & &
2021-05-13 20:21:02 +02:00
Token : : Match ( start , " %name% = " ) & &
findAllocFuncCallToken ( start - > next ( ) - > astOperand2 ( ) , mSettings - > library ) ) {
2011-12-18 20:15:41 +01:00
2021-05-13 20:21:02 +02:00
const Token * allocFuncCallToken = findAllocFuncCallToken ( start - > next ( ) - > astOperand2 ( ) , mSettings - > library ) ;
2021-05-13 23:08:58 +02:00
const Library : : AllocFunc * allocFunc = mSettings - > library . getAllocFuncInfo ( allocFuncCallToken ) ;
bool allocateMemory = ! allocFunc | | Library : : ismemory ( allocFunc - > groupId ) ;
2021-05-13 20:21:02 +02:00
if ( allocFuncCallToken - > str ( ) = = " new " ) {
const Token * type = allocFuncCallToken - > next ( ) ;
2011-12-18 20:15:41 +01:00
// skip nothrow
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isCPP ( ) & & ( Token : : simpleMatch ( type , " ( nothrow ) " ) | |
2015-07-01 07:50:13 +02:00
Token : : simpleMatch ( type , " ( std :: nothrow ) " ) ) )
2011-12-18 20:15:41 +01:00
type = type - > link ( ) - > next ( ) ;
// is it a user defined type?
if ( ! type - > isStandardType ( ) ) {
2013-02-06 06:39:58 +01:00
const Variable * variable = start - > variable ( ) ;
2013-03-05 15:28:40 +01:00
if ( ! variable | | ! isRecordTypeWithoutSideEffects ( variable - > type ( ) ) )
2021-05-13 23:08:58 +02:00
allocateMemory = false ;
2011-12-18 20:15:41 +01:00
}
}
2011-08-19 20:35:25 +02:00
2021-05-13 23:08:58 +02:00
if ( allocateMemory )
2012-09-04 14:53:24 +02:00
variables . allocateMemory ( varid1 , tok ) ;
2011-12-18 20:15:41 +01:00
else
2012-09-04 14:53:24 +02:00
variables . write ( varid1 , tok ) ;
2011-12-18 20:15:41 +01:00
} else if ( varid1 & & Token : : Match ( tok , " %varid% . " , varid1 ) ) {
2017-08-01 14:56:53 +02:00
variables . read ( varid1 , tok ) ;
variables . write ( varid1 , start ) ;
2011-10-13 20:53:06 +02:00
} else {
2012-09-04 14:53:24 +02:00
variables . write ( varid1 , tok ) ;
2011-08-19 20:35:25 +02:00
}
2015-12-31 01:15:49 +01:00
}
2011-08-19 20:35:25 +02:00
2018-09-23 20:24:51 +02:00
const Variables : : VariableUsage * const var2 = variables . find ( tok - > varId ( ) ) ;
2015-12-31 01:15:49 +01:00
if ( var2 ) {
2018-06-16 20:25:54 +02:00
if ( var2 - > mType = = Variables : : reference ) {
2015-12-31 01:15:49 +01:00
variables . writeAliases ( tok - > varId ( ) , tok ) ;
variables . read ( tok - > varId ( ) , tok ) ;
} else if ( tok - > varId ( ) ! = varid1 & & Token : : Match ( tok , " %name% .|[ " ) )
variables . read ( tok - > varId ( ) , tok ) ;
else if ( tok - > varId ( ) ! = varid1 & &
2018-06-16 20:25:54 +02:00
var2 - > mType = = Variables : : standard & &
2015-12-31 01:15:49 +01:00
tok - > strAt ( - 1 ) ! = " & " )
variables . use ( tok - > varId ( ) , tok ) ;
2011-08-19 20:35:25 +02:00
}
2012-02-26 08:29:02 +01:00
const Token * const equal = skipBracketsAndMembers ( tok - > next ( ) ) ;
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
// checked for chained assignments
2011-12-26 08:12:23 +01:00
if ( tok ! = start & & equal & & equal - > str ( ) = = " = " ) {
2021-01-27 19:49:13 +01:00
const nonneg int varId = tok - > varId ( ) ;
2018-09-23 20:24:51 +02:00
const Variables : : VariableUsage * const var = variables . find ( varId ) ;
2011-08-19 20:35:25 +02:00
2018-06-16 20:25:54 +02:00
if ( var & & var - > mType ! = Variables : : reference ) {
2012-12-04 21:39:51 +01:00
variables . read ( varId , tok ) ;
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
tok = tok - > previous ( ) ;
}
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
// assignment
2015-01-31 10:50:39 +01:00
else if ( ( Token : : Match ( tok , " %name% [ " ) & & Token : : simpleMatch ( skipBracketsAndMembers ( tok - > next ( ) ) , " = " ) ) | |
2023-07-14 19:14:33 +02:00
( tok - > isUnaryOp ( " * " ) & & Token : : simpleMatch ( tok - > astParent ( ) , " = " ) & & Token : : simpleMatch ( tok - > astOperand1 ( ) , " + " ) ) ) {
2016-05-17 16:03:55 +02:00
const Token * eq = tok ;
while ( eq & & ! eq - > isAssignmentOp ( ) )
eq = eq - > astParent ( ) ;
const bool deref = eq & & eq - > astOperand1 ( ) & & eq - > astOperand1 ( ) - > valueType ( ) & & eq - > astOperand1 ( ) - > valueType ( ) - > pointer = = 0U ;
2012-08-25 13:07:33 +02:00
if ( tok - > str ( ) = = " * " ) {
tok = tok - > tokAt ( 2 ) ;
if ( tok - > str ( ) = = " ( " )
tok = tok - > link ( ) - > next ( ) ;
}
2021-01-27 19:49:13 +01:00
const nonneg int varid = tok - > varId ( ) ;
2011-12-18 20:15:41 +01:00
const Variables : : VariableUsage * var = variables . find ( varid ) ;
if ( var ) {
// Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
2018-06-16 20:25:54 +02:00
if ( var - > mType = = Variables : : pointer & &
2023-06-21 17:35:15 +02:00
( ( mTokenizer - > isCPP ( ) & & Token : : simpleMatch ( skipBrackets ( tok - > next ( ) ) , " = new " ) ) | |
( Token : : Match ( skipBrackets ( tok - > next ( ) ) , " = %name% ( " ) & & mSettings - > library . getAllocFuncInfo ( tok - > tokAt ( 2 ) ) ) ) ) {
2012-09-04 14:53:24 +02:00
variables . allocateMemory ( varid , tok ) ;
2018-06-16 20:25:54 +02:00
} else if ( var - > mType = = Variables : : pointer | | var - > mType = = Variables : : reference ) {
2012-09-04 14:53:24 +02:00
variables . read ( varid , tok ) ;
variables . writeAliases ( varid , tok ) ;
2018-06-16 20:25:54 +02:00
} else if ( var - > mType = = Variables : : pointerArray ) {
2016-05-17 16:03:55 +02:00
tok = doAssignment ( variables , tok , deref , scope ) ;
2011-12-18 20:15:41 +01:00
} else
2012-09-04 14:53:24 +02:00
variables . writeAll ( varid , tok ) ;
2011-12-18 20:15:41 +01:00
}
}
2011-08-19 20:35:25 +02:00
2018-06-16 16:10:28 +02:00
else if ( mTokenizer - > isCPP ( ) & & Token : : Match ( tok , " [ ; { } ] % var % < < " )) {
2012-12-18 19:02:30 +01:00
variables . erase ( tok - > next ( ) - > varId ( ) ) ;
}
2012-03-20 19:00:16 +01:00
else if ( Token : : Match ( tok , " & %var% " ) ) {
2014-07-02 00:17:35 +02:00
if ( tok - > astOperand2 ( ) ) { // bitop
2012-09-04 14:53:24 +02:00
variables . read ( tok - > next ( ) - > varId ( ) , tok ) ;
2012-03-20 19:00:16 +01:00
} else // addressof
2012-09-04 14:53:24 +02:00
variables . use ( tok - > next ( ) - > varId ( ) , tok ) ; // use = read + write
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok , " >>|>>= %name% " ) ) {
2018-06-16 16:10:28 +02:00
if ( isLikelyStreamRead ( mTokenizer - > isCPP ( ) , tok ) )
2013-08-27 15:46:51 +02:00
variables . use ( tok - > next ( ) - > varId ( ) , tok ) ; // use = read + write
2018-04-22 17:08:23 +02:00
else
variables . read ( tok - > next ( ) - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
} else if ( Token : : Match ( tok , " %var% >>|& " ) & & Token : : Match ( tok - > previous ( ) , " [ { } ; : ] " )) {
2012-09-04 14:53:24 +02:00
variables . read ( tok - > varId ( ) , tok ) ;
2018-06-16 16:10:28 +02:00
} else if ( isLikelyStreamRead ( mTokenizer - > isCPP ( ) , tok - > previous ( ) ) ) {
2018-04-17 14:23:04 +02:00
variables . use ( tok - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
}
2011-12-18 20:15:41 +01:00
// function parameter
2012-09-04 13:06:04 +02:00
else if ( Token : : Match ( tok , " [(,] %var% [ " ) ) {
2012-09-04 14:53:24 +02:00
variables . use ( tok - > next ( ) - > varId ( ) , tok ) ; // use = read + write
2012-09-04 13:06:04 +02:00
} else if ( Token : : Match ( tok , " [(,] %var% [,) ] " ) && tok->previous()->str() != " * " ) {
2012-09-04 14:53:24 +02:00
variables . use ( tok - > next ( ) - > varId ( ) , tok ) ; // use = read + write
2016-09-03 20:38:36 +02:00
} else if ( Token : : Match ( tok , " [(,] & %var% [,) ] " )) {
variables . eraseAll ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
2011-12-18 20:15:41 +01:00
} else if ( Token : : Match ( tok , " [(,] ( " ) & &
2023-08-20 11:08:17 +02:00
Token : : Match ( tok - > next ( ) - > link ( ) , " ) %var% [,)[] " ) ) {
2012-09-04 14:53:24 +02:00
variables . use ( tok - > next ( ) - > link ( ) - > next ( ) - > varId ( ) , tok ) ; // use = read + write
2023-08-20 11:08:17 +02:00
} else if ( Token : : Match ( tok , " [(,] *| *| %var% " ) ) {
const Token * vartok = tok - > next ( ) ;
while ( vartok - > str ( ) = = " * " )
vartok = vartok - > next ( ) ;
if ( ! ( vartok - > variable ( ) & & vartok = = vartok - > variable ( ) - > nameToken ( ) ) & &
! ( tok - > str ( ) = = " ( " & & ! Token : : Match ( tok - > previous ( ) , " %name% " ) ) )
variables . use ( vartok - > varId ( ) , vartok ) ;
2012-09-04 13:06:04 +02:00
}
2011-12-18 20:15:41 +01:00
// function
2017-02-28 22:04:05 +01:00
else if ( Token : : Match ( tok , " %name% ( " ) ) {
2022-07-24 17:52:14 +02:00
if ( tok - > varId ( ) & & ! tok - > function ( ) ) // operator()
variables . use ( tok - > varId ( ) , tok ) ;
else
variables . read ( tok - > varId ( ) , tok ) ;
2017-02-28 22:04:05 +01:00
useFunctionArgs ( tok - > next ( ) - > astOperand2 ( ) , variables ) ;
2016-09-03 20:38:36 +02:00
} else if ( Token : : Match ( tok , " std :: ref ( %var% ) " )) {
variables . eraseAll ( tok - > tokAt ( 4 ) - > varId ( ) ) ;
2011-12-18 20:15:41 +01:00
}
2011-08-19 20:35:25 +02:00
2014-09-30 12:39:27 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " [ { , ] % var % [ , } ] " )) {
variables . read ( tok - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
}
2011-08-19 20:35:25 +02:00
2014-07-02 00:17:35 +02:00
else if ( tok - > varId ( ) & & Token : : Match ( tok , " %var% . " ) ) {
2012-09-04 14:53:24 +02:00
variables . use ( tok - > varId ( ) , tok ) ; // use = read + write
2012-09-04 13:06:04 +02:00
}
2011-08-19 20:35:25 +02:00
2017-07-01 22:45:51 +02:00
else if ( tok - > str ( ) = = " : " & & ( ! tok - > valueType ( ) | | tok - > valueType ( ) - > pointer ) ) {
2017-07-01 11:31:51 +02:00
if ( tok - > astOperand1 ( ) )
variables . use ( tok - > astOperand1 ( ) - > varId ( ) , tok - > astOperand1 ( ) ) ;
if ( tok - > astOperand2 ( ) )
variables . use ( tok - > astOperand2 ( ) - > varId ( ) , tok - > astOperand2 ( ) ) ;
}
2020-04-10 11:53:32 +02:00
else if ( tok - > isExtendedOp ( ) & & tok - > next ( ) & & tok - > next ( ) - > varId ( ) & & tok - > strAt ( 2 ) ! = " = " & & ! isVarDecl ( tok - > next ( ) ) ) {
2012-09-04 14:53:24 +02:00
variables . readAll ( tok - > next ( ) - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
}
2011-08-19 20:35:25 +02:00
2020-04-10 11:53:32 +02:00
else if ( tok - > varId ( ) & & ! isVarDecl ( tok ) & & tok - > next ( ) & & ( tok - > next ( ) - > str ( ) = = " ) " | | tok - > next ( ) - > isExtendedOp ( ) ) ) {
2016-01-01 16:04:13 +01:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %name% ( %var% [,)] " ) & &
! ( tok - > tokAt ( - 2 ) - > variable ( ) & & tok - > tokAt ( - 2 ) - > variable ( ) - > isReference ( ) ) )
variables . use ( tok - > varId ( ) , tok ) ;
else
variables . readAll ( tok - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
}
2011-08-19 20:35:25 +02:00
2012-09-04 13:06:04 +02:00
else if ( Token : : Match ( tok , " %var% ; " ) & & Token : : Match ( tok - > previous ( ) , " [;{}:] " ) ) {
2012-09-04 14:53:24 +02:00
variables . readAll ( tok - > varId ( ) , tok ) ;
2012-09-04 13:06:04 +02:00
}
2011-08-19 20:35:25 +02:00
2014-07-02 00:17:35 +02:00
// ++|--
2015-08-14 20:46:13 +02:00
else if ( tok - > next ( ) & & tok - > next ( ) - > tokType ( ) = = Token : : eIncDecOp & & tok - > next ( ) - > astOperand1 ( ) & & tok - > next ( ) - > astOperand1 ( ) - > varId ( ) ) {
2014-07-02 00:17:35 +02:00
if ( tok - > next ( ) - > astParent ( ) )
variables . use ( tok - > next ( ) - > astOperand1 ( ) - > varId ( ) , tok ) ;
2011-12-18 20:15:41 +01:00
else
2014-07-02 00:17:35 +02:00
variables . modified ( tok - > next ( ) - > astOperand1 ( ) - > varId ( ) , tok ) ;
2011-12-18 20:15:41 +01:00
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
else if ( tok - > isAssignmentOp ( ) ) {
for ( const Token * tok2 = tok - > next ( ) ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) ) {
2014-08-31 19:46:30 +02:00
if ( tok2 - > strAt ( 1 ) = = " = " )
2012-09-04 14:53:24 +02:00
variables . write ( tok2 - > varId ( ) , tok ) ;
2015-06-04 17:45:12 +02:00
else if ( tok2 - > next ( ) & & tok2 - > next ( ) - > isAssignmentOp ( ) )
2014-08-31 19:46:30 +02:00
variables . use ( tok2 - > varId ( ) , tok ) ;
2012-08-10 12:36:08 +02:00
else
2012-09-04 14:53:24 +02:00
variables . read ( tok2 - > varId ( ) , tok ) ;
2011-08-19 20:35:25 +02:00
}
}
2020-10-25 07:12:30 +01:00
} else if ( tok - > variable ( ) & & tok - > variable ( ) - > isClass ( ) & & tok - > variable ( ) - > type ( ) & &
( tok - > variable ( ) - > type ( ) - > needInitialization = = Type : : NeedInitialization : : False ) & &
tok - > next ( ) - > str ( ) = = " ; " ) {
2020-10-25 07:11:45 +01:00
variables . write ( tok - > varId ( ) , tok ) ;
}
2011-12-18 20:15:41 +01:00
}
}
2011-08-19 20:35:25 +02:00
2011-12-18 20:15:41 +01:00
void CheckUnusedVar : : checkFunctionVariableUsage ( )
{
2023-01-26 22:28:04 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) & & ! mSettings - > checkLibrary )
2011-12-18 20:15:41 +01:00
return ;
2011-08-19 20:35:25 +02:00
2023-08-29 12:00:52 +02:00
logChecker ( " CheckUnusedVar::checkFunctionVariableUsage " ) ; // style
2011-12-18 20:15:41 +01:00
// Parse all executing scopes..
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2011-08-19 20:35:25 +02:00
2022-03-02 11:11:44 +01:00
auto reportLibraryCfgError = [ this ] ( const Token * tok , const std : : string & typeName ) {
2023-01-26 22:28:04 +01:00
if ( mSettings - > checkLibrary ) {
2022-03-02 11:11:44 +01:00
reportError ( tok ,
Severity : : information ,
" checkLibraryCheckType " ,
" --check-library: Provide <type-checks><unusedvar> configuration for " + typeName ) ;
}
} ;
2012-11-16 06:50:49 +01:00
// only check functions
2018-11-14 06:58:21 +01:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2016-05-26 18:07:56 +02:00
// Bailout when there are lambdas or inline functions
// TODO: Handle lambdas and inline functions properly
if ( scope - > hasInlineOrLambdaFunction ( ) )
continue ;
2018-12-13 18:52:56 +01:00
for ( const Token * tok = scope - > bodyStart ; tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
2019-01-26 21:43:44 +01:00
if ( findLambdaEndToken ( tok ) )
2018-12-13 18:52:56 +01:00
// todo: handle lambdas
break ;
if ( Token : : simpleMatch ( tok , " try { " ) )
// todo: check try blocks
tok = tok - > linkAt ( 1 ) ;
2018-12-16 19:01:05 +01:00
const Token * varDecl = nullptr ;
if ( tok - > variable ( ) & & tok - > variable ( ) - > nameToken ( ) = = tok ) {
const Token * eq = tok - > next ( ) ;
while ( Token : : simpleMatch ( eq , " [ " ) )
eq = eq - > link ( ) - > next ( ) ;
2023-02-26 18:03:24 +01:00
if ( Token : : simpleMatch ( eq , " ) ( " ) & & Token : : simpleMatch ( eq - > linkAt ( 1 ) , " ) = " ) )
eq = eq - > linkAt ( 1 ) - > next ( ) ;
2018-12-16 19:01:05 +01:00
if ( Token : : simpleMatch ( eq , " = " ) ) {
varDecl = tok ;
tok = eq ;
}
}
2019-07-29 08:49:19 +02:00
// not assignment/initialization/increment => continue
const bool isAssignment = tok - > isAssignmentOp ( ) & & tok - > astOperand1 ( ) ;
2022-01-10 07:36:49 +01:00
const bool isInitialization = ( Token : : Match ( tok , " %var% (|{ " ) & & tok - > variable ( ) & & tok - > variable ( ) - > nameToken ( ) = = tok ) ;
2019-07-29 08:49:19 +02:00
const bool isIncrementOrDecrement = ( tok - > tokType ( ) = = Token : : Type : : eIncDecOp ) ;
if ( ! isAssignment & & ! isInitialization & & ! isIncrementOrDecrement )
2018-12-13 18:52:56 +01:00
continue ;
2020-09-26 22:13:05 +02:00
2022-01-12 22:06:03 +01:00
if ( isInitialization & & Token : : Match ( tok , " %var% { } " ) ) // don't warn for trivial initialization
continue ;
2020-09-26 22:13:05 +02:00
if ( isIncrementOrDecrement & & tok - > astParent ( ) & & precedes ( tok , tok - > astOperand1 ( ) ) )
continue ;
2022-06-07 21:20:33 +02:00
if ( tok - > str ( ) = = " = " & & ! ( tok - > valueType ( ) & & tok - > valueType ( ) - > pointer ) & & isRaiiClass ( tok - > valueType ( ) , mTokenizer - > isCPP ( ) , false ) )
2020-09-27 19:15:15 +02:00
continue ;
2022-07-16 23:46:55 +02:00
const bool isPointer = tok - > valueType ( ) & & ( tok - > valueType ( ) - > pointer | | tok - > valueType ( ) - > type = = ValueType : : SMART_POINTER ) ;
2022-05-18 13:52:44 +02:00
2018-12-13 18:52:56 +01:00
if ( tok - > isName ( ) ) {
2022-01-13 08:05:05 +01:00
if ( isRaiiClass ( tok - > valueType ( ) , mTokenizer - > isCPP ( ) , false ) )
2020-09-27 19:15:15 +02:00
continue ;
2018-12-13 18:52:56 +01:00
tok = tok - > next ( ) ;
}
2023-06-27 14:28:14 +02:00
if ( ! isInitialization & & tok - > astParent ( ) & & ! tok - > astParent ( ) - > isAssignmentOp ( ) & & tok - > str ( ) ! = " ( " ) {
2018-12-13 18:52:56 +01:00
const Token * parent = tok - > astParent ( ) ;
while ( Token : : Match ( parent , " %oror%|%comp%|!|&& " ) )
parent = parent - > astParent ( ) ;
if ( ! parent )
continue ;
if ( ! Token : : simpleMatch ( parent - > previous ( ) , " if ( " ) )
continue ;
}
// Do not warn about assignment with NULL
2022-05-18 13:52:44 +02:00
if ( isPointer & & isNullOperand ( tok - > astOperand2 ( ) ) )
2018-12-13 18:52:56 +01:00
continue ;
2019-07-29 19:05:36 +02:00
if ( ! tok - > astOperand1 ( ) )
continue ;
2019-08-04 10:21:16 +02:00
const Token * iteratorToken = tok - > astOperand1 ( ) ;
while ( Token : : Match ( iteratorToken , " [.*] " ) )
iteratorToken = iteratorToken - > astOperand1 ( ) ;
if ( iteratorToken & & iteratorToken - > variable ( ) & & iteratorToken - > variable ( ) - > typeEndToken ( ) - > str ( ) . find ( " iterator " ) ! = std : : string : : npos )
continue ;
2019-11-04 17:59:16 +01:00
const Token * op1tok = tok - > astOperand1 ( ) ;
while ( Token : : Match ( op1tok , " .|[|* " ) )
op1tok = op1tok - > astOperand1 ( ) ;
2023-03-05 15:31:53 +01:00
// Assignment in macro => do not warn
if ( isAssignment & & tok - > isExpandedMacro ( ) & & op1tok & & op1tok - > isExpandedMacro ( ) )
continue ;
2019-11-04 17:59:16 +01:00
const Variable * op1Var = op1tok ? op1tok - > variable ( ) : nullptr ;
2022-01-13 08:05:05 +01:00
if ( ! op1Var & & Token : : Match ( tok , " (|{ " ) & & tok - > previous ( ) & & tok - > previous ( ) - > variable ( ) )
op1Var = tok - > previous ( ) - > variable ( ) ;
2019-11-17 12:08:21 +01:00
std : : string bailoutTypeName ;
2019-11-16 19:49:43 +01:00
if ( op1Var ) {
if ( op1Var - > isReference ( ) & & op1Var - > nameToken ( ) ! = tok - > astOperand1 ( ) )
// todo: check references
continue ;
2018-12-13 18:52:56 +01:00
2019-11-16 19:49:43 +01:00
if ( op1Var - > isStatic ( ) )
// todo: check static variables
continue ;
2018-12-13 18:52:56 +01:00
2019-11-16 19:49:43 +01:00
if ( op1Var - > nameToken ( ) - > isAttributeUnused ( ) )
continue ;
2020-10-02 20:22:09 +02:00
// Avoid FP for union..
if ( op1Var - > type ( ) & & op1Var - > type ( ) - > isUnionType ( ) )
continue ;
2019-11-16 19:49:43 +01:00
// Bailout for unknown template classes, we have no idea what side effects such assignments have
if ( mTokenizer - > isCPP ( ) & &
op1Var - > isClass ( ) & &
2019-11-17 12:08:21 +01:00
( ! op1Var - > valueType ( ) | | op1Var - > valueType ( ) - > type = = ValueType : : Type : : UNKNOWN_TYPE ) ) {
// Check in the library if we should bailout or not..
2023-06-27 14:28:14 +02:00
std : : string typeName = op1Var - > getTypeName ( ) ;
2023-09-08 19:30:25 +02:00
if ( startsWith ( typeName , " :: " ) )
2023-06-27 14:28:14 +02:00
typeName . erase ( typeName . begin ( ) , typeName . begin ( ) + 2 ) ;
2019-11-17 12:08:21 +01:00
switch ( mSettings - > library . getTypeCheck ( " unusedvar " , typeName ) ) {
case Library : : TypeCheck : : def :
bailoutTypeName = typeName ;
break ;
case Library : : TypeCheck : : check :
break ;
case Library : : TypeCheck : : suppress :
2022-09-30 07:25:33 +02:00
case Library : : TypeCheck : : checkFiniteLifetime :
2019-11-17 12:08:21 +01:00
continue ;
2020-04-21 17:27:51 +02:00
}
2019-11-17 12:08:21 +01:00
}
2019-11-16 19:49:43 +01:00
}
2018-12-13 18:52:56 +01:00
// Is there a redundant assignment?
const Token * start = tok - > findExpressionStartEndTokens ( ) . second - > next ( ) ;
2018-12-16 19:01:05 +01:00
const Token * expr = varDecl ? varDecl : tok - > astOperand1 ( ) ;
2018-12-13 18:52:56 +01:00
2020-09-14 18:44:50 +02:00
if ( isInitialization )
expr = tok - > previous ( ) ;
2019-12-20 18:31:44 +01:00
// Is variable in lhs a union member?
if ( tok - > previous ( ) & & tok - > previous ( ) - > variable ( ) & & tok - > previous ( ) - > variable ( ) - > nameToken ( ) - > scope ( ) - > type = = Scope : : eUnion )
continue ;
2018-12-31 18:00:47 +01:00
FwdAnalysis fwdAnalysis ( mTokenizer - > isCPP ( ) , mSettings - > library ) ;
2023-01-28 10:20:47 +01:00
const Token * scopeEnd = ValueFlow : : getEndOfExprScope ( expr , scope , /*smallest*/ false ) ;
2022-02-22 09:51:44 +01:00
if ( fwdAnalysis . unusedValue ( expr , start , scopeEnd ) ) {
2022-03-28 21:45:49 +02:00
if ( ! bailoutTypeName . empty ( ) ) {
if ( bailoutTypeName ! = " auto " )
reportLibraryCfgError ( tok , bailoutTypeName ) ;
2022-01-13 08:05:05 +01:00
continue ;
2019-11-17 12:08:21 +01:00
}
2018-12-13 18:52:56 +01:00
// warn
2020-04-13 12:52:00 +02:00
if ( ! expr - > variable ( ) | | ! expr - > variable ( ) - > isMaybeUnused ( ) )
2020-04-12 20:35:54 +02:00
unreadVariableError ( tok , expr - > expressionString ( ) , false ) ;
2019-11-17 12:08:21 +01:00
}
2018-12-13 18:52:56 +01:00
}
2011-12-18 20:15:41 +01:00
// varId, usage {read, write, modified}
Variables variables ;
2011-08-19 20:35:25 +02:00
2018-12-17 17:48:45 +01:00
checkFunctionVariableUsage_iterateScopes ( scope , variables ) ;
2011-08-19 20:35:25 +02:00
// Check usage of all variables in the current scope..
2022-12-20 20:32:16 +01:00
for ( std : : map < nonneg int , Variables : : VariableUsage > : : const_iterator it = variables . varUsage ( ) . cbegin ( ) ;
it ! = variables . varUsage ( ) . cend ( ) ;
2012-12-05 20:18:14 +01:00
+ + it ) {
2011-08-19 20:35:25 +02:00
const Variables : : VariableUsage & usage = it - > second ;
// variable has been marked as unused so ignore it
2014-08-06 11:13:58 +02:00
if ( usage . _var - > nameToken ( ) - > isAttributeUnused ( ) | | usage . _var - > nameToken ( ) - > isAttributeUsed ( ) )
2011-08-19 20:35:25 +02:00
continue ;
// skip things that are only partially implemented to prevent false positives
2018-06-16 20:25:54 +02:00
if ( usage . mType = = Variables : : pointerPointer | |
usage . mType = = Variables : : pointerArray | |
usage . mType = = Variables : : referenceArray )
2011-08-19 20:35:25 +02:00
continue ;
2014-09-16 11:34:16 +02:00
const std : : string & varname = usage . _var - > name ( ) ;
const Variable * var = symbolDatabase - > getVariableFromVarId ( it - > first ) ;
2011-08-19 20:35:25 +02:00
// variable has had memory allocated for it, but hasn't done
// anything with that memory other than, perhaps, freeing it
if ( usage . unused ( ) & & ! usage . _modified & & usage . _allocateMemory )
2012-09-04 14:53:24 +02:00
allocatedButUnusedVariableError ( usage . _lastAccess , varname ) ;
2011-08-19 20:35:25 +02:00
// variable has not been written, read, or modified
2020-04-12 20:35:54 +02:00
else if ( usage . unused ( ) & & ! usage . _modified ) {
if ( ! usage . _var - > isMaybeUnused ( ) ) {
unusedVariableError ( usage . _var - > nameToken ( ) , varname ) ;
}
}
2011-08-19 20:35:25 +02:00
// variable has not been written but has been modified
2022-09-17 18:50:07 +02:00
else if ( usage . _modified & & ! usage . _write & & ! usage . _allocateMemory & & var & & ! var - > isStlType ( ) ) {
if ( var - > isStatic ( ) ) // static variables are initialized by default
continue ;
2012-09-04 14:53:24 +02:00
unassignedVariableError ( usage . _var - > nameToken ( ) , varname ) ;
2022-09-17 18:50:07 +02:00
}
2011-08-19 20:35:25 +02:00
// variable has been read but not written
2015-01-18 13:02:09 +01:00
else if ( ! usage . _write & & ! usage . _allocateMemory & & var & & ! var - > isStlType ( ) & & ! isEmptyType ( var - > type ( ) ) )
2012-09-04 14:53:24 +02:00
unassignedVariableError ( usage . _var - > nameToken ( ) , varname ) ;
2022-03-02 11:11:44 +01:00
else if ( ! usage . _var - > isMaybeUnused ( ) & & ! usage . _modified & & ! usage . _read & & var ) {
2022-03-05 08:14:57 +01:00
const Token * vnt = var - > nameToken ( ) ;
bool error = false ;
2023-08-21 10:44:17 +02:00
if ( vnt - > next ( ) - > isSplittedVarDeclEq ( ) | | ( ! var - > isReference ( ) & & vnt - > next ( ) - > str ( ) = = " = " ) ) {
2022-03-05 08:14:57 +01:00
const Token * nextStmt = vnt - > tokAt ( 2 ) ;
2023-03-05 15:31:53 +01:00
if ( nextStmt - > isExpandedMacro ( ) ) {
const Token * parent = nextStmt ;
while ( parent - > astParent ( ) & & parent = = parent - > astParent ( ) - > astOperand1 ( ) )
parent = parent - > astParent ( ) ;
if ( parent - > isAssignmentOp ( ) & & parent - > isExpandedMacro ( ) )
continue ;
}
2022-03-05 08:14:57 +01:00
while ( nextStmt & & nextStmt - > str ( ) ! = " ; " )
nextStmt = nextStmt - > next ( ) ;
error = precedes ( usage . _lastAccess , nextStmt ) ;
}
if ( error ) {
2022-03-02 11:11:44 +01:00
if ( mTokenizer - > isCPP ( ) & & var - > isClass ( ) & &
( ! var - > valueType ( ) | | var - > valueType ( ) - > type = = ValueType : : Type : : UNKNOWN_TYPE ) ) {
const std : : string typeName = var - > getTypeName ( ) ;
switch ( mSettings - > library . getTypeCheck ( " unusedvar " , typeName ) ) {
case Library : : TypeCheck : : def :
2022-03-05 08:14:57 +01:00
reportLibraryCfgError ( vnt , typeName ) ;
2022-03-02 11:11:44 +01:00
break ;
case Library : : TypeCheck : : check :
break ;
case Library : : TypeCheck : : suppress :
2022-09-30 07:25:33 +02:00
case Library : : TypeCheck : : checkFiniteLifetime :
2022-03-02 11:11:44 +01:00
error = false ;
}
}
if ( error )
2022-03-05 08:14:57 +01:00
unreadVariableError ( vnt , varname , false ) ;
2022-03-02 11:11:44 +01:00
}
}
2011-08-19 20:35:25 +02:00
}
}
}
void CheckUnusedVar : : unusedVariableError ( const Token * tok , const std : : string & varname )
{
2023-01-26 22:28:04 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
return ;
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unusedVariable " , " $symbol: " + varname + " \n Unused variable: $symbol " , CWE563 , Certainty : : normal ) ;
2011-08-19 20:35:25 +02:00
}
void CheckUnusedVar : : allocatedButUnusedVariableError ( const Token * tok , const std : : string & varname )
{
2023-01-26 22:28:04 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
return ;
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unusedAllocatedMemory " , " $symbol: " + varname + " \n Variable '$symbol' is allocated memory that is never used. " , CWE563 , Certainty : : normal ) ;
2011-08-19 20:35:25 +02:00
}
2016-10-10 21:27:40 +02:00
void CheckUnusedVar : : unreadVariableError ( const Token * tok , const std : : string & varname , bool modified )
2011-08-19 20:35:25 +02:00
{
2023-01-26 22:28:04 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
return ;
2016-10-10 21:27:40 +02:00
if ( modified )
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unreadVariable " , " $symbol: " + varname + " \n Variable '$symbol' is modified but its new value is never used. " , CWE563 , Certainty : : normal ) ;
2016-10-10 21:27:40 +02:00
else
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unreadVariable " , " $symbol: " + varname + " \n Variable '$symbol' is assigned a value that is never used. " , CWE563 , Certainty : : normal ) ;
2011-08-19 20:35:25 +02:00
}
void CheckUnusedVar : : unassignedVariableError ( const Token * tok , const std : : string & varname )
{
2023-01-26 22:28:04 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
return ;
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unassignedVariable " , " $symbol: " + varname + " \n Variable '$symbol' is not assigned a value. " , CWE665 , Certainty : : normal ) ;
2011-08-19 20:35:25 +02:00
}
//---------------------------------------------------------------------------
// Check that all struct members are used
//---------------------------------------------------------------------------
void CheckUnusedVar : : checkStructMemberUsage ( )
{
2021-02-24 22:00:06 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
2011-08-19 20:35:25 +02:00
return ;
2023-08-29 12:00:52 +02:00
logChecker ( " CheckUnusedVar::checkStructMemberUsage " ) ; // style
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2016-05-24 23:10:39 +02:00
2018-11-14 06:58:21 +01:00
for ( const Scope & scope : symbolDatabase - > scopeList ) {
2023-04-17 20:34:39 +02:00
if ( scope . type ! = Scope : : eStruct & & scope . type ! = Scope : : eClass & & scope . type ! = Scope : : eUnion )
2011-08-19 20:35:25 +02:00
continue ;
2018-11-14 06:58:21 +01:00
if ( scope . bodyStart - > fileIndex ( ) ! = 0 | | scope . className . empty ( ) )
2016-05-25 11:13:31 +02:00
continue ;
2011-08-19 20:35:25 +02:00
2023-05-26 17:48:49 +02:00
if ( scope . classDef - > isExpandedMacro ( ) )
continue ;
2016-09-05 17:27:12 +02:00
// Packed struct => possibly used by lowlevel code. Struct members might be required by hardware.
2018-11-14 06:58:21 +01:00
if ( scope . bodyEnd - > isAttributePacked ( ) )
2016-09-05 17:27:12 +02:00
continue ;
2020-06-30 10:59:57 +02:00
if ( const Preprocessor * preprocessor = mTokenizer - > getPreprocessor ( ) ) {
2022-10-16 13:46:26 +02:00
const auto & directives = preprocessor - > getDirectives ( ) ;
2022-12-30 15:13:47 +01:00
const bool isPacked = std : : any_of ( directives . cbegin ( ) , directives . cend ( ) , [ & ] ( const Directive & d ) {
2022-10-16 13:46:26 +02:00
return d . linenr < scope . bodyStart - > linenr ( ) & & d . str = = " #pragma pack(1) " & & d . file = = mTokenizer - > list . getFiles ( ) . front ( ) ;
} ) ;
2020-06-30 10:59:57 +02:00
if ( isPacked )
continue ;
}
2016-09-05 17:27:12 +02:00
2019-03-06 20:51:48 +01:00
// Bail out for template struct, members might be used in non-matching instantiations
2023-02-08 21:01:51 +01:00
if ( scope . className . find ( ' < ' ) ! = std : : string : : npos )
2019-03-06 20:51:48 +01:00
continue ;
2016-05-25 11:13:31 +02:00
// bail out if struct is inherited
2023-04-18 22:30:08 +02:00
const bool isInherited = std : : any_of ( symbolDatabase - > scopeList . cbegin ( ) , symbolDatabase - > scopeList . cend ( ) , [ & ] ( const Scope & derivedScope ) {
2022-10-16 13:46:26 +02:00
const Type * dType = derivedScope . definedType ;
2022-12-30 15:13:47 +01:00
return dType & & std : : any_of ( dType - > derivedFrom . cbegin ( ) , dType - > derivedFrom . cend ( ) , [ & ] ( const Type : : BaseInfo & derivedFrom ) {
2023-04-18 22:30:08 +02:00
return derivedFrom . type = = scope . definedType & & derivedFrom . access ! = AccessControl : : Private ;
2022-10-16 13:46:26 +02:00
} ) ;
} ) ;
2015-09-22 15:38:49 +02:00
2016-05-25 11:13:31 +02:00
// bail out for extern/global struct
2023-04-18 22:30:08 +02:00
bool bailout = false ;
2018-04-28 09:38:33 +02:00
for ( const Variable * var : symbolDatabase - > variableList ( ) ) {
2018-11-14 06:58:21 +01:00
if ( var & & ( var - > isExtern ( ) | | ( var - > isGlobal ( ) & & ! var - > isStatic ( ) ) ) & & var - > typeEndToken ( ) - > str ( ) = = scope . className ) {
2016-05-25 11:13:31 +02:00
bailout = true ;
break ;
2013-01-07 19:20:15 +01:00
}
2022-08-18 23:36:21 +02:00
if ( bailout )
break ;
2011-08-19 20:35:25 +02:00
}
2016-05-25 11:13:31 +02:00
if ( bailout )
continue ;
2011-08-19 20:35:25 +02:00
2016-05-25 11:13:31 +02:00
// Bail out if some data is casted to struct..
2022-02-26 18:53:00 +01:00
const std : : string castPattern ( " ( struct| " + scope . className + " * ) &| %name% " ) ;
2018-11-14 06:58:21 +01:00
if ( Token : : findmatch ( scope . bodyEnd , castPattern . c_str ( ) ) )
2016-05-25 11:13:31 +02:00
continue ;
2011-08-19 20:35:25 +02:00
2017-11-12 22:33:17 +01:00
// (struct S){..}
2018-11-14 06:58:21 +01:00
const std : : string initPattern ( " ( struct| " + scope . className + " ) { " ) ;
if ( Token : : findmatch ( scope . bodyEnd , initPattern . c_str ( ) ) )
2017-11-12 22:33:17 +01:00
continue ;
2016-08-02 18:50:04 +02:00
// Bail out if struct is used in sizeof..
2018-11-14 06:58:21 +01:00
for ( const Token * tok = scope . bodyEnd ; nullptr ! = ( tok = Token : : findsimplematch ( tok , " sizeof ( " ) ) ; ) {
2016-08-02 19:23:45 +02:00
tok = tok - > tokAt ( 2 ) ;
2018-11-14 06:58:21 +01:00
if ( Token : : Match ( tok , ( " struct| " + scope . className ) . c_str ( ) ) ) {
2016-08-02 18:50:04 +02:00
bailout = true ;
break ;
}
}
if ( bailout )
continue ;
2018-11-14 06:58:21 +01:00
for ( const Variable & var : scope . varlist ) {
2022-02-26 18:53:00 +01:00
// only warn for variables without side effects
if ( ! var . typeStartToken ( ) - > isStandardType ( ) & & ! var . isPointer ( ) & & ! astIsContainer ( var . nameToken ( ) ) & & ! isRecordTypeWithoutSideEffects ( var . type ( ) ) )
2011-08-19 20:35:25 +02:00
continue ;
2023-04-18 22:30:08 +02:00
if ( isInherited & & ! var . isPrivate ( ) )
continue ;
2011-08-19 20:35:25 +02:00
2015-09-24 18:29:08 +02:00
// Check if the struct member variable is used anywhere in the file
2021-10-30 19:34:46 +02:00
bool use = false ;
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2023-06-20 22:34:54 +02:00
if ( Token : : Match ( tok , " . %name% " ) & & ! tok - > next ( ) - > variable ( ) & & ! tok - > next ( ) - > function ( ) & & tok - > next ( ) - > str ( ) = = var . name ( ) ) {
// not known => assume variable is used
use = true ;
break ;
}
2021-10-30 19:34:46 +02:00
if ( tok - > variable ( ) ! = & var )
continue ;
if ( tok ! = var . nameToken ( ) ) {
use = true ;
break ;
}
}
2023-04-17 20:34:39 +02:00
if ( ! use ) {
std : : string prefix = " struct " ;
if ( scope . type = = Scope : : ScopeType : : eClass )
prefix = " class " ;
else if ( scope . type = = Scope : : ScopeType : : eUnion )
prefix = " union " ;
unusedStructMemberError ( var . nameToken ( ) , scope . className , var . name ( ) , prefix ) ;
}
2011-08-19 20:35:25 +02:00
}
}
}
2023-04-17 20:34:39 +02:00
void CheckUnusedVar : : unusedStructMemberError ( const Token * tok , const std : : string & structname , const std : : string & varname , const std : : string & prefix )
2011-08-19 20:35:25 +02:00
{
2023-04-17 20:34:39 +02:00
reportError ( tok , Severity : : style , " unusedStructMember " , " $symbol: " + structname + " :: " + varname + ' \n ' + prefix + " member '$symbol' is never used. " , CWE563 , Certainty : : normal ) ;
2011-08-19 20:35:25 +02:00
}
2013-04-01 12:41:14 +02:00
bool CheckUnusedVar : : isRecordTypeWithoutSideEffects ( const Type * type )
{
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check constructors for side effects */
2018-06-17 19:04:06 +02:00
const std : : pair < std : : map < const Type * , bool > : : iterator , bool > found = mIsRecordTypeWithoutSideEffectsMap . insert (
2021-08-07 20:51:18 +02:00
std : : pair < const Type * , bool > ( type , false ) ) ; //Initialize with side effects for possible recursions
2020-07-23 11:10:08 +02:00
bool & withoutSideEffects = found . first - > second ;
2013-04-01 12:41:14 +02:00
if ( ! found . second )
return withoutSideEffects ;
2020-07-23 11:10:08 +02:00
// unknown types are assumed to have side effects
if ( ! type | | ! type - > classScope )
return ( withoutSideEffects = false ) ;
// Non-empty constructors => possible side effects
for ( const Function & f : type - > classScope - > functionList ) {
2022-06-14 09:55:22 +02:00
if ( ! f . isConstructor ( ) & & ! f . isDestructor ( ) )
2020-07-23 11:10:08 +02:00
continue ;
2020-07-23 18:54:40 +02:00
if ( f . argDef & & Token : : simpleMatch ( f . argDef - > link ( ) , " ) = " ) )
2020-07-23 11:10:08 +02:00
continue ; // ignore default/deleted constructors
const bool emptyBody = ( f . functionScope & & Token : : simpleMatch ( f . functionScope - > bodyStart , " { } " ) ) ;
2020-10-25 07:11:45 +01:00
2023-02-08 21:07:16 +01:00
const Token * nextToken = f . argDef - > link ( ) ;
2020-10-25 07:11:45 +01:00
if ( Token : : simpleMatch ( nextToken , " ) : " ) ) {
// validating initialization list
nextToken = nextToken - > next ( ) ; // goto ":"
2020-10-25 07:12:30 +01:00
for ( const Token * initListToken = nextToken ; Token : : Match ( initListToken , " [:,] %var% [({] " ) ; initListToken = initListToken - > linkAt ( 2 ) - > next ( ) ) {
2020-10-25 07:11:45 +01:00
const Token * varToken = initListToken - > next ( ) ;
const Variable * variable = varToken - > variable ( ) ;
2020-10-25 07:12:30 +01:00
if ( variable & & ! isVariableWithoutSideEffects ( * variable ) ) {
2020-10-25 07:11:45 +01:00
return withoutSideEffects = false ;
}
const Token * valueEnd = initListToken - > linkAt ( 2 ) ;
for ( const Token * valueToken = initListToken - > tokAt ( 3 ) ; valueToken ! = valueEnd ; valueToken = valueToken - > next ( ) ) {
const Variable * initValueVar = valueToken - > variable ( ) ;
2020-10-25 07:12:30 +01:00
if ( initValueVar & & ! isVariableWithoutSideEffects ( * initValueVar ) ) {
2020-10-25 07:11:45 +01:00
return withoutSideEffects = false ;
}
2020-11-26 17:34:42 +01:00
if ( ( valueToken - > tokType ( ) = = Token : : Type : : eName ) | |
2020-10-25 07:11:45 +01:00
( valueToken - > tokType ( ) = = Token : : Type : : eLambda ) | |
2020-10-25 07:12:30 +01:00
( valueToken - > tokType ( ) = = Token : : Type : : eOther ) ) {
2020-10-25 07:11:45 +01:00
return withoutSideEffects = false ;
}
2020-11-26 17:34:42 +01:00
const Function * initValueFunc = valueToken - > function ( ) ;
2020-11-28 05:52:35 +01:00
if ( initValueFunc & & ! isFunctionWithoutSideEffects ( * initValueFunc , valueToken ,
2021-08-07 20:51:18 +02:00
std : : list < const Function * > { } ) ) {
2020-11-26 17:34:42 +01:00
return withoutSideEffects = false ;
}
2020-10-25 07:11:45 +01:00
}
}
}
if ( ! emptyBody )
2020-07-23 11:10:08 +02:00
return ( withoutSideEffects = false ) ;
}
// Derived from type that has side effects?
2022-12-30 15:13:47 +01:00
if ( std : : any_of ( type - > derivedFrom . cbegin ( ) , type - > derivedFrom . cend ( ) , [ this ] ( const Type : : BaseInfo & derivedFrom ) {
2022-10-16 13:46:26 +02:00
return ! isRecordTypeWithoutSideEffects ( derivedFrom . type ) ;
} ) )
return ( withoutSideEffects = false ) ;
2020-07-23 11:10:08 +02:00
// Is there a member variable with possible side effects
for ( const Variable & var : type - > classScope - > varlist ) {
2020-10-25 07:11:45 +01:00
withoutSideEffects = isVariableWithoutSideEffects ( var ) ;
2020-10-25 07:12:30 +01:00
if ( ! withoutSideEffects ) {
2020-10-25 07:11:45 +01:00
return withoutSideEffects ;
2013-04-01 12:41:14 +02:00
}
}
2020-07-23 11:10:08 +02:00
return ( withoutSideEffects = true ) ;
2013-04-01 12:41:14 +02:00
}
2014-02-01 22:40:35 +01:00
2020-10-25 07:11:45 +01:00
bool CheckUnusedVar : : isVariableWithoutSideEffects ( const Variable & var )
{
if ( var . isPointer ( ) )
return true ;
const Type * variableType = var . type ( ) ;
if ( variableType ) {
if ( ! isRecordTypeWithoutSideEffects ( variableType ) )
return false ;
} else {
2020-11-27 16:45:26 +01:00
if ( WRONG_DATA ( ! var . valueType ( ) , var . typeStartToken ( ) ) )
return false ;
2022-10-02 07:12:40 +02:00
const ValueType : : Type valueType = var . valueType ( ) - > type ;
2020-10-25 07:11:45 +01:00
if ( ( valueType = = ValueType : : Type : : UNKNOWN_TYPE ) | | ( valueType = = ValueType : : Type : : NONSTD ) )
return false ;
}
return true ;
}
2014-02-01 22:40:35 +01:00
bool CheckUnusedVar : : isEmptyType ( const Type * type )
{
// a type that has no variables and no constructor
2018-06-17 19:04:06 +02:00
const std : : pair < std : : map < const Type * , bool > : : iterator , bool > found = mIsEmptyTypeMap . insert (
2021-08-07 20:51:18 +02:00
std : : pair < const Type * , bool > ( type , false ) ) ;
2014-02-01 22:40:35 +01:00
bool & emptyType = found . first - > second ;
if ( ! found . second )
return emptyType ;
if ( type & & type - > classScope & & type - > classScope - > numConstructors = = 0 & &
( type - > classScope - > varlist . empty ( ) ) ) {
2022-12-30 15:13:47 +01:00
return ( emptyType = std : : all_of ( type - > derivedFrom . cbegin ( ) , type - > derivedFrom . cend ( ) , [ this ] ( const Type : : BaseInfo & bi ) {
2022-10-16 13:46:26 +02:00
return isEmptyType ( bi . type ) ;
} ) ) ;
2014-02-01 22:40:35 +01:00
}
2022-10-16 13:46:26 +02:00
// unknown types are assumed to be nonempty
return ( emptyType = false ) ;
2014-02-01 22:40:35 +01:00
}
2020-11-26 17:34:42 +01:00
bool CheckUnusedVar : : isFunctionWithoutSideEffects ( const Function & func , const Token * functionUsageToken ,
2021-08-07 20:51:18 +02:00
std : : list < const Function * > checkedFuncs )
2020-11-28 05:52:35 +01:00
{
2020-11-26 17:34:42 +01:00
// no body to analyze
if ( ! func . hasBody ( ) ) {
return false ;
}
for ( const Token * argsToken = functionUsageToken - > next ( ) ; ! Token : : simpleMatch ( argsToken , " ) " ) ; argsToken = argsToken - > next ( ) ) {
const Variable * argVar = argsToken - > variable ( ) ;
if ( argVar & & argVar - > isGlobal ( ) ) {
return false ; // TODO: analyze global variable usage
}
}
bool sideEffectReturnFound = false ;
2020-12-19 08:55:19 +01:00
std : : set < const Variable * > pointersToGlobals ;
2023-02-08 21:07:16 +01:00
for ( const Token * bodyToken = func . functionScope - > bodyStart - > next ( ) ; bodyToken ! = func . functionScope - > bodyEnd ;
2020-12-19 08:56:46 +01:00
bodyToken = bodyToken - > next ( ) ) {
2020-12-19 08:55:19 +01:00
// check variable inside function body
2020-11-26 17:34:42 +01:00
const Variable * bodyVariable = bodyToken - > variable ( ) ;
if ( bodyVariable ) {
if ( ! isVariableWithoutSideEffects ( * bodyVariable ) ) {
return false ;
}
// check if global variable is changed
2020-12-19 08:56:46 +01:00
if ( bodyVariable - > isGlobal ( ) | | ( pointersToGlobals . find ( bodyVariable ) ! = pointersToGlobals . end ( ) ) ) {
2023-08-08 10:38:03 +02:00
const int indirect = bodyVariable - > isArray ( ) ? bodyVariable - > dimensions ( ) . size ( ) : bodyVariable - > isPointer ( ) ;
if ( isVariableChanged ( bodyToken , indirect , mSettings , mTokenizer - > isCPP ( ) ) ) {
2020-12-19 08:55:19 +01:00
return false ;
}
// check if pointer to global variable assigned to another variable (another_var = &global_var)
if ( Token : : simpleMatch ( bodyToken - > tokAt ( - 1 ) , " & " ) & & Token : : simpleMatch ( bodyToken - > tokAt ( - 2 ) , " = " ) ) {
const Token * assigned_var_token = bodyToken - > tokAt ( - 3 ) ;
2020-12-19 08:56:46 +01:00
if ( assigned_var_token & & assigned_var_token - > variable ( ) ) {
2020-12-19 08:55:19 +01:00
pointersToGlobals . insert ( assigned_var_token - > variable ( ) ) ;
}
}
2020-11-26 17:34:42 +01:00
}
}
// check nested function
const Function * bodyFunction = bodyToken - > function ( ) ;
if ( bodyFunction ) {
2022-12-30 15:13:47 +01:00
if ( std : : find ( checkedFuncs . cbegin ( ) , checkedFuncs . cend ( ) , bodyFunction ) ! = checkedFuncs . cend ( ) ) { // recursion found
2020-11-26 17:34:42 +01:00
continue ;
}
checkedFuncs . push_back ( bodyFunction ) ;
if ( ! isFunctionWithoutSideEffects ( * bodyFunction , bodyToken , checkedFuncs ) ) {
return false ;
}
}
// check returned value
if ( Token : : simpleMatch ( bodyToken , " return " ) ) {
const Token * returnValueToken = bodyToken - > next ( ) ;
// TODO: handle complex return expressions
if ( ! Token : : simpleMatch ( returnValueToken - > next ( ) , " ; " ) ) {
sideEffectReturnFound = true ;
continue ;
}
// simple one-token return
const Variable * returnVariable = returnValueToken - > variable ( ) ;
2020-11-28 05:52:35 +01:00
if ( returnValueToken - > isLiteral ( ) | |
2020-11-26 17:34:42 +01:00
( returnVariable & & isVariableWithoutSideEffects ( * returnVariable ) ) ) {
continue ;
}
sideEffectReturnFound = true ;
}
// unknown name
if ( bodyToken - > isNameOnly ( ) ) {
return false ;
}
}
return ! sideEffectReturnFound ;
}