2019-09-17 21:00:59 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2020-05-10 11:16:32 +02:00
* Copyright ( C ) 2007 - 2020 Cppcheck team .
2019-09-17 21:00:59 +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/>.
*/
//---------------------------------------------------------------------------
# ifndef exprengineH
# define exprengineH
//---------------------------------------------------------------------------
2019-09-19 19:40:00 +02:00
# include "config.h"
2019-09-17 21:00:59 +02:00
# include <functional>
# include <map>
# include <memory>
# include <string>
# include <vector>
2020-04-13 13:44:48 +02:00
# include <cstdint>
2019-09-17 21:00:59 +02:00
class ErrorLogger ;
class Tokenizer ;
class Scope ;
class Settings ;
class Token ;
2019-09-25 18:33:21 +02:00
class Variable ;
2019-09-17 21:00:59 +02:00
2019-10-09 10:25:21 +02:00
# if defined(__GNUC__) && defined (__SIZEOF_INT128__)
2019-09-17 21:00:59 +02:00
typedef __int128_t int128_t ;
# else
typedef long long int128_t ;
2019-09-18 21:50:23 +02:00
# ifdef _MSC_VER
# pragma message(__FILE__ "(" _CRT_STRINGIZE(__LINE__) ")" ": warning: TODO No 128-bit integer type is available => Limited analysis of large integers...")
# else
2019-09-17 21:00:59 +02:00
# warning TODO No 128-bit integer type is available => Limited analysis of large integers
# endif
2019-09-18 21:50:23 +02:00
# endif
2019-09-17 21:00:59 +02:00
namespace ExprEngine {
std : : string str ( int128_t ) ;
// TODO we need to handle floats, containers, pointers, aliases and structs and stuff
2019-09-23 20:27:13 +02:00
enum class ValueType {
UninitValue ,
IntRange ,
FloatRange ,
2019-09-26 10:03:58 +02:00
ConditionalValue ,
2019-09-23 20:27:13 +02:00
ArrayValue ,
StringLiteralValue ,
StructValue ,
AddressOfValue ,
BinOpResult ,
2019-12-22 21:00:53 +01:00
IntegerTruncation ,
BailoutValue
2019-09-23 20:27:13 +02:00
} ;
2019-09-17 21:00:59 +02:00
class Value ;
typedef std : : shared_ptr < Value > ValuePtr ;
2019-09-29 15:00:54 +02:00
class DataBase {
public :
2020-04-27 09:08:50 +02:00
explicit DataBase ( const std : : string & currentFunction , const Settings * settings )
: currentFunction ( currentFunction )
, settings ( settings ) {
}
2019-09-29 15:00:54 +02:00
virtual std : : string getNewSymbolName ( ) = 0 ;
2020-04-27 09:08:50 +02:00
const std : : string currentFunction ;
2019-09-29 15:00:54 +02:00
const Settings * const settings ;
2019-12-22 21:00:53 +01:00
virtual void addError ( int linenr ) {
( void ) linenr ;
}
2019-09-29 15:00:54 +02:00
} ;
2019-09-17 21:00:59 +02:00
class Value {
public :
2019-09-26 10:03:58 +02:00
Value ( const std : : string & name , const ValueType type ) : name ( name ) , type ( type ) { }
2019-09-17 21:00:59 +02:00
virtual ~ Value ( ) { }
2019-09-26 10:03:58 +02:00
virtual std : : string getRange ( ) const {
return name ;
}
virtual std : : string getSymbolicExpression ( ) const {
return name ;
}
2019-10-08 20:13:25 +02:00
virtual bool isEqual ( DataBase * dataBase , int value ) const {
2019-10-02 21:47:00 +02:00
( void ) dataBase ;
2019-09-17 21:00:59 +02:00
( void ) value ;
return false ;
}
2019-10-08 20:13:25 +02:00
virtual bool isGreaterThan ( DataBase * dataBase , int value ) const {
( void ) dataBase ;
( void ) value ;
return false ;
}
virtual bool isLessThan ( DataBase * dataBase , int value ) const {
( void ) dataBase ;
( void ) value ;
return false ;
}
2019-12-30 18:55:16 +01:00
virtual bool isUninit ( ) const {
return false ;
}
2019-10-08 20:13:25 +02:00
2019-09-17 21:00:59 +02:00
const std : : string name ;
2019-09-26 10:03:58 +02:00
ValueType type ;
2019-09-17 21:00:59 +02:00
} ;
class UninitValue : public Value {
public :
2019-09-26 10:03:58 +02:00
UninitValue ( ) : Value ( " ? " , ValueType : : UninitValue ) { }
2020-01-10 15:08:53 +01:00
bool isEqual ( DataBase * dataBase , int value ) const OVERRIDE {
2020-01-09 19:40:03 +01:00
( void ) dataBase ;
( void ) value ;
return true ;
}
2019-12-30 18:55:16 +01:00
bool isUninit ( ) const OVERRIDE {
return true ;
}
2019-09-17 21:00:59 +02:00
} ;
class IntRange : public Value {
public :
IntRange ( const std : : string & name , int128_t minValue , int128_t maxValue )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : IntRange )
2019-09-17 21:00:59 +02:00
, minValue ( minValue )
, maxValue ( maxValue ) {
}
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-21 14:17:16 +02:00
if ( minValue = = maxValue )
return str ( minValue ) ;
return str ( minValue ) + " : " + str ( maxValue ) ;
2019-09-17 21:00:59 +02:00
}
2019-12-27 16:26:44 +01:00
bool isEqual ( DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( DataBase * dataBase , int value ) const OVERRIDE ;
bool isLessThan ( DataBase * dataBase , int value ) const OVERRIDE ;
2019-09-17 21:00:59 +02:00
int128_t minValue ;
int128_t maxValue ;
} ;
2019-09-22 21:14:20 +02:00
class FloatRange : public Value {
public :
FloatRange ( const std : : string & name , long double minValue , long double maxValue )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : FloatRange )
2019-09-22 21:14:20 +02:00
, minValue ( minValue )
, maxValue ( maxValue ) {
}
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-22 21:14:20 +02:00
return std : : to_string ( minValue ) + " : " + std : : to_string ( maxValue ) ;
}
2019-12-30 19:47:18 +01:00
bool isEqual ( DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( DataBase * dataBase , int value ) const OVERRIDE ;
bool isLessThan ( DataBase * dataBase , int value ) const OVERRIDE ;
2019-09-22 21:14:20 +02:00
long double minValue ;
long double maxValue ;
} ;
2019-09-26 10:03:58 +02:00
class ConditionalValue : public Value {
public :
typedef std : : vector < std : : pair < ValuePtr , ValuePtr > > Vector ;
ConditionalValue ( const std : : string & name , const Vector & values ) : Value ( name , ValueType : : ConditionalValue ) , values ( values ) { }
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-26 10:03:58 +02:00
Vector values ;
} ;
2019-12-29 16:26:11 +01:00
// Array or pointer
2019-09-17 21:00:59 +02:00
class ArrayValue : public Value {
public :
const int MAXSIZE = 0x100000 ;
2019-12-29 16:26:11 +01:00
ArrayValue ( const std : : string & name , ValuePtr size , ValuePtr value , bool pointer , bool nullPointer , bool uninitPointer ) ;
2019-09-29 15:00:54 +02:00
ArrayValue ( DataBase * data , const Variable * var ) ;
2019-09-17 21:00:59 +02:00
2019-12-29 21:22:20 +01:00
std : : string getRange ( ) const OVERRIDE ;
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-17 21:00:59 +02:00
void assign ( ValuePtr index , ValuePtr value ) ;
2019-09-24 22:22:16 +02:00
void clear ( ) ;
2019-09-26 10:03:58 +02:00
ConditionalValue : : Vector read ( ValuePtr index ) const ;
2019-09-25 18:33:21 +02:00
2019-12-29 16:26:11 +01:00
bool pointer ;
bool nullPointer ;
bool uninitPointer ;
2019-09-25 18:33:21 +02:00
struct IndexAndValue {
ValuePtr index ;
ValuePtr value ;
} ;
std : : vector < IndexAndValue > data ;
ValuePtr size ;
2019-09-17 21:00:59 +02:00
} ;
2019-09-21 11:36:34 +02:00
class StringLiteralValue : public Value {
public :
2019-09-26 10:03:58 +02:00
StringLiteralValue ( const std : : string & name , const std : : string & s ) : Value ( name , ValueType : : StringLiteralValue ) , string ( s ) { }
2019-09-21 11:36:34 +02:00
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-21 11:36:34 +02:00
return " \" " + string + " \" " ;
}
int size ( ) const {
return string . size ( ) ;
}
const std : : string string ;
} ;
2019-09-17 21:00:59 +02:00
class StructValue : public Value {
public :
2019-09-26 10:03:58 +02:00
explicit StructValue ( const std : : string & name ) : Value ( name , ValueType : : StructValue ) { }
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-26 19:39:12 +02:00
2020-05-10 22:16:58 +02:00
ValuePtr getValueOfMember ( const std : : string & n ) const {
auto it = member . find ( n ) ;
2019-09-17 21:00:59 +02:00
return ( it = = member . end ( ) ) ? ValuePtr ( ) : it - > second ;
}
std : : map < std : : string , ValuePtr > member ;
} ;
class AddressOfValue : public Value {
public :
AddressOfValue ( const std : : string & name , int varId )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : AddressOfValue )
2019-09-17 21:00:59 +02:00
, varId ( varId )
{ }
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-26 10:03:58 +02:00
return " &@ " + std : : to_string ( varId ) ;
2019-09-17 21:00:59 +02:00
}
int varId ;
} ;
class BinOpResult : public Value {
public :
BinOpResult ( const std : : string & binop , ValuePtr op1 , ValuePtr op2 )
2019-09-27 14:20:17 +02:00
: Value ( getName ( binop , op1 , op2 ) , ValueType : : BinOpResult )
2019-09-17 21:00:59 +02:00
, binop ( binop )
, op1 ( op1 )
, op2 ( op2 ) {
}
2019-12-27 16:26:44 +01:00
bool isEqual ( DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( DataBase * dataBase , int value ) const OVERRIDE ;
virtual bool isLessThan ( DataBase * dataBase , int value ) const OVERRIDE ;
2019-10-08 20:13:25 +02:00
2019-10-02 21:47:00 +02:00
std : : string getExpr ( DataBase * dataBase ) const ;
2019-09-17 21:00:59 +02:00
std : : string binop ;
ValuePtr op1 ;
ValuePtr op2 ;
private :
2019-09-27 14:20:17 +02:00
std : : string getName ( const std : : string & binop , ValuePtr op1 , ValuePtr op2 ) const {
std : : string name1 = op1 ? op1 - > name : std : : string ( " null " ) ;
std : : string name2 = op2 ? op2 - > name : std : : string ( " null " ) ;
return " ( " + name1 + " ) " + binop + " ( " + name2 + " ) " ;
}
2019-09-17 21:00:59 +02:00
} ;
2019-09-23 20:27:13 +02:00
class IntegerTruncation : public Value {
public :
IntegerTruncation ( const std : : string & name , ValuePtr inputValue , int bits , char sign )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : IntegerTruncation )
2019-09-23 20:27:13 +02:00
, inputValue ( inputValue )
, bits ( bits )
, sign ( sign ) {
}
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-23 20:27:13 +02:00
ExprEngine : : ValuePtr inputValue ;
int bits ;
char sign ;
} ;
2019-12-22 21:00:53 +01:00
class BailoutValue : public Value {
public :
BailoutValue ( ) : Value ( " bailout " , ValueType : : BailoutValue ) { }
2020-01-12 10:42:20 +01:00
bool isEqual ( DataBase * /*dataBase*/ , int /*value*/ ) const OVERRIDE {
return true ;
}
2020-01-12 14:52:15 +01:00
/* FIXME: This is too noisy
2020-01-12 10:42:20 +01:00
bool isUninit ( ) const OVERRIDE {
2019-12-22 21:00:53 +01:00
return true ;
}
2020-01-12 14:52:15 +01:00
*/
2019-12-22 21:00:53 +01:00
} ;
2019-10-02 21:47:00 +02:00
typedef std : : function < void ( const Token * , const ExprEngine : : Value & , ExprEngine : : DataBase * ) > Callback ;
2019-09-17 21:00:59 +02:00
/** Execute all functions */
2020-04-28 17:16:13 +02:00
void CPPCHECKLIB executeAllFunctions ( ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings , const std : : vector < Callback > & callbacks , std : : ostream & report ) ;
void executeFunction ( const Scope * functionScope , ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings , const std : : vector < Callback > & callbacks , std : : ostream & report ) ;
2019-09-17 21:00:59 +02:00
void runChecks ( ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings ) ;
2020-05-27 19:37:07 +02:00
void dump ( ExprEngine : : ValuePtr val ) ;
2019-09-17 21:00:59 +02:00
}
# endif // exprengineH