2011-08-19 20:35:25 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2022-02-05 11:45:17 +01:00
* Copyright ( C ) 2007 - 2022 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
}
2016-07-16 21:21:24 +02:00
static const struct CWE CWE563 ( 563U ) ; // Assignment to Variable without Use ('Unused Variable')
CWE mapping of useAutoPointerMalloc, uselessCallsCompare, uselessCallsSwap, uselessCallsSubstr, uselessCallsEmpty, uselessCallsRemove, derefInvalidIterator, reademptycontainer, multiplySizeof, divideSizeof, stringLiteralWrite, incorrectStringCompare, literalWithCharPtrCompare, charLiteralWithCharPtrCompare, incorrectStringBooleanError, staticStringCompare, stringCompare, signConversion, truncLongCastAssignment, truncLongCastReturn, unusedFunction, unusedVariable, unusedAllocatedMemory, unreadVariable, unassignedVariable, unusedStructMember, postfixOperator, va_start_wrongParameter (#824)
Add an optional extended description…
2016-09-03 00:31:35 +02:00
static const struct 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
{
VariableUsage * usage = find ( varid ) ;
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 ( ) = = " ( " )
2013-08-07 16:27:37 +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 ( ) )
2017-06-03 15:31:29 +02:00
type = ( i - > dimensions ( ) . size ( ) = = 1U ) ? Variables : : array : Variables : : pointerArray ;
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 ;
2012-07-24 20:47:29 +02:00
} else 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)
if ( Token : : Match ( tok , " free|g_free|kfree|vfree ( %var% ) " ) | |
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 ( ) ) , " = " ) ) | |
2012-08-25 13:07:33 +02:00
( Token : : simpleMatch ( tok , " * ( " ) & & Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) = " ) ) ) {
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 & &
2012-02-29 20:57:48 +01:00
Token : : Match ( skipBrackets ( tok - > next ( ) ) , " = new|malloc|calloc|kmalloc|kzalloc|kcalloc|strdup|strndup|vmalloc|g_new0|g_try_new|g_new|g_malloc|g_malloc0|g_try_malloc|g_try_malloc0|g_strdup|g_strndup|g_strdup_printf " ) ) {
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 , " [(,] ( " ) & &
2012-09-04 13:06:04 +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
2016-08-02 08:50:04 +02:00
} else if ( Token : : Match ( tok , " [(,] *| %var% = " ) ) {
tok = tok - > next ( ) ;
if ( tok - > str ( ) = = " * " )
tok = tok - > next ( ) ;
variables . use ( tok - > varId ( ) , tok ) ;
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 ( )
{
2021-02-24 22:00:06 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
2011-12-18 20:15:41 +01:00
return ;
2011-08-19 20:35:25 +02:00
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 ) {
if ( mSettings - > checkLibrary & & mSettings - > severity . isEnabled ( Severity : : information ) ) {
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 ( ) ;
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 ( ) ;
}
2022-03-13 06:26:21 +01:00
if ( 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 ( ) ;
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..
const std : : string typeName = op1Var - > getTypeName ( ) ;
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 ) ;
2022-02-22 09:51:44 +01:00
const Token * scopeEnd = getEndOfExprScope ( expr , scope , /*smallest*/ false ) ;
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 ;
if ( vnt - > next ( ) - > isSplittedVarDeclEq ( ) ) {
const Token * nextStmt = vnt - > tokAt ( 2 ) ;
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 )
{
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 )
{
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
{
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 )
{
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 ;
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 ) {
if ( scope . type ! = Scope : : eStruct & & 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
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
2016-05-25 11:13:31 +02:00
// Bail out if struct/union contains any functions
2018-11-14 06:58:21 +01:00
if ( ! scope . functionList . empty ( ) )
2016-05-25 11:13:31 +02:00
continue ;
2011-08-19 20:35:25 +02:00
2019-03-06 20:51:48 +01:00
// Bail out for template struct, members might be used in non-matching instantiations
if ( scope . className . find ( " < " ) ! = std : : string : : npos )
continue ;
2016-05-25 11:13:31 +02:00
// bail out if struct is inherited
2022-12-30 15:13:47 +01:00
bool bailout = 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 ) {
2022-10-16 13:46:26 +02:00
return derivedFrom . type = = scope . definedType ;
} ) ;
} ) ;
2016-05-25 11:13:31 +02:00
if ( bailout )
continue ;
2015-09-22 15:38:49 +02:00
2016-05-25 11:13:31 +02:00
// bail out for extern/global struct
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-02-02 19:28:16 +01:00
if ( var & & ( var - > typeStartToken ( ) - > str ( ) = = scope . className | | var - > typeEndToken ( ) - > str ( ) = = scope . className ) ) {
const std : : string addressPattern ( " !! " + scope . className + " & " + var - > name ( ) ) ; // cast from struct
const Token * addrTok = scope . bodyEnd ;
do {
addrTok = Token : : findmatch ( addrTok , addressPattern . c_str ( ) ) ;
if ( ( addrTok & & addrTok - > str ( ) = = " ) " & & addrTok - > link ( ) - > isCast ( ) ) | | isCPPCast ( addrTok ) ) {
bailout = true ;
break ;
}
if ( addrTok )
addrTok = addrTok - > next ( ) ;
} while ( addrTok ) ;
}
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 ;
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 ( ) ) {
if ( tok - > variable ( ) ! = & var )
continue ;
if ( tok ! = var . nameToken ( ) ) {
use = true ;
break ;
}
}
if ( ! use )
unusedStructMemberError ( var . nameToken ( ) , scope . className , var . name ( ) , scope . type = = Scope : : eUnion ) ;
2011-08-19 20:35:25 +02:00
}
}
}
2015-09-22 16:38:23 +02:00
void CheckUnusedVar : : unusedStructMemberError ( const Token * tok , const std : : string & structname , const std : : string & varname , bool isUnion )
2011-08-19 20:35:25 +02:00
{
2018-04-09 06:43:48 +02:00
const std : : string prefix = isUnion ? " union member " : " struct member " ;
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : style , " unusedStructMember " , " $symbol: " + structname + " :: " + varname + ' \n ' + prefix + " '$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
Token * nextToken = f . argDef - > link ( ) ;
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 ;
2020-11-28 05:52:35 +01:00
for ( 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 ( ) ) ) {
2020-12-19 08:55:19 +01:00
const int depth = 20 ;
if ( isVariableChanged ( bodyToken , depth , mSettings , mTokenizer - > isCPP ( ) ) ) {
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 ;
}