Evaluate math library functions in valueflow (#4255)
* Evaluate math library functions in valueflow * Format
This commit is contained in:
parent
edebe746bc
commit
6b72274c67
90
cfg/std.cfg
90
cfg/std.cfg
|
@ -119,7 +119,7 @@
|
|||
<function name="acos,std::acos">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">acos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -131,7 +131,7 @@
|
|||
<function name="acosf,std::acosf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">acos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -143,7 +143,7 @@
|
|||
<function name="acosl,std::acosl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">acos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -231,7 +231,7 @@
|
|||
<function name="sqrt,std::sqrt">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">sqrt(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -243,7 +243,7 @@
|
|||
<function name="sqrtf,std::sqrtf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">sqrt(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -255,7 +255,7 @@
|
|||
<function name="sqrtl,std::sqrtl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">sqrt(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -279,7 +279,7 @@
|
|||
<function name="sinh,std::sinh">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">sinh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -290,7 +290,7 @@
|
|||
<function name="sinhf,std::sinhf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">sinh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -301,7 +301,7 @@
|
|||
<function name="sinhl,std::sinhl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">sinh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -312,7 +312,7 @@
|
|||
<function name="sin,std::sin">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">sin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -323,7 +323,7 @@
|
|||
<function name="sinf,std::sinf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">sin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -334,7 +334,7 @@
|
|||
<function name="sinl,std::sinl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">sin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -369,7 +369,7 @@
|
|||
<function name="asin,std::asin">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">asin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -381,7 +381,7 @@
|
|||
<function name="asinf,std::asinf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">asin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -393,7 +393,7 @@
|
|||
<function name="asinl,std::asinl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">asin(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -486,7 +486,7 @@
|
|||
<function name="tan,std::tan">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">tan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -497,7 +497,7 @@
|
|||
<function name="tanf,std::tanf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">tan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -508,7 +508,7 @@
|
|||
<function name="tanl,std::tanl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">tan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -531,7 +531,7 @@
|
|||
<function name="tanh,std::tanh">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">tanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -542,7 +542,7 @@
|
|||
<function name="tanhf,std::tanhf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">tanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -553,7 +553,7 @@
|
|||
<function name="tanhl,std::tanhl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">tanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -688,7 +688,7 @@
|
|||
<function name="atan,std::atan">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">atan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -699,7 +699,7 @@
|
|||
<function name="atanf,std::atanf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">atan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -710,7 +710,7 @@
|
|||
<function name="atanl,std::atanl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">atan(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -799,7 +799,7 @@
|
|||
<function name="atanh,std::atanh">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">atanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -811,7 +811,7 @@
|
|||
<function name="atanhf,std::atanhf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">atanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -823,7 +823,7 @@
|
|||
<function name="atanhl,std::atanhl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">atanh(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -847,7 +847,7 @@
|
|||
<function name="atan2,std::atan2">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">atan2(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -861,7 +861,7 @@
|
|||
<function name="atan2f,std::atan2f">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">atan2(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -875,7 +875,7 @@
|
|||
<function name="atan2l,std::atan2l">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">atan2(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1090,7 +1090,7 @@
|
|||
<function name="cos,std::cos">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">cos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1101,7 +1101,7 @@
|
|||
<function name="cosf,std::cosf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">cos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1112,7 +1112,7 @@
|
|||
<function name="cosl,std::cosl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">cos(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1357,7 +1357,7 @@
|
|||
<function name="exp,std::exp">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">exp(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1368,7 +1368,7 @@
|
|||
<function name="expf,std::expf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">exp(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -1379,7 +1379,7 @@
|
|||
<function name="expl,std::expl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">exp(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3217,7 +3217,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<!-- double log(double x); -->
|
||||
<function name="log,std::log">
|
||||
<use-retval/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">log(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3228,7 +3228,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<!-- float logf(float x); -->
|
||||
<function name="logf,std::logf">
|
||||
<use-retval/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">log(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3239,7 +3239,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<!-- long double logl(long double x);-->
|
||||
<function name="logl,std::logl">
|
||||
<use-retval/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">log(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3544,7 +3544,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="log10,std::log10">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">log10(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3556,7 +3556,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="log10f,std::log10f">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">log10(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -3568,7 +3568,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="log10l,std::log10l">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">log10(arg1)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -4126,7 +4126,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="pow,std::pow">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="double"/>
|
||||
<returnValue type="double">pow(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -4140,7 +4140,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="powf,std::powf">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="float"/>
|
||||
<returnValue type="float">pow(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
@ -4154,7 +4154,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<function name="powl,std::powl">
|
||||
<use-retval/>
|
||||
<pure/>
|
||||
<returnValue type="long double"/>
|
||||
<returnValue type="long double">pow(arg1, arg2)</returnValue>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in">
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
@ -615,6 +616,231 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value&
|
|||
return result;
|
||||
}
|
||||
|
||||
using BuiltinLibraryFunction = std::function<ValueFlow::Value(const std::vector<ValueFlow::Value>&)>;
|
||||
static std::unordered_map<std::string, BuiltinLibraryFunction> createBuiltinLibraryFunctions()
|
||||
{
|
||||
std::unordered_map<std::string, BuiltinLibraryFunction> functions;
|
||||
functions["strlen"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!(v.isTokValue() && v.tokvalue->tokType() == Token::eString))
|
||||
return ValueFlow::Value::unknown();
|
||||
v.valueType = ValueFlow::Value::ValueType::INT;
|
||||
v.intvalue = Token::getStrLength(v.tokvalue);
|
||||
v.tokvalue = nullptr;
|
||||
return v;
|
||||
};
|
||||
functions["sin"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::sin(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["cos"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::cos(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["tan"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::tan(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["asin"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::asin(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["acos"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::acos(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["atan"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::atan(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["atan2"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 2)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["pow"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 2)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["sqrt"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::sqrt(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["exp"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::exp(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["log"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::log(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["log10"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::log10(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["sinh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::sinh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["cosh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::cosh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["tanh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::tanh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["asinh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::asinh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["acosh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::acosh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
functions["atanh"] = [](const std::vector<ValueFlow::Value>& args) {
|
||||
if (args.size() != 1)
|
||||
return ValueFlow::Value::unknown();
|
||||
ValueFlow::Value v = args[0];
|
||||
if (!v.isFloatValue() && !v.isIntValue())
|
||||
return ValueFlow::Value::unknown();
|
||||
double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue;
|
||||
v.floatValue = std::atanh(value);
|
||||
v.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||
return v;
|
||||
};
|
||||
return functions;
|
||||
}
|
||||
|
||||
static BuiltinLibraryFunction getBuiltinLibraryFunction(const std::string& name)
|
||||
{
|
||||
static const std::unordered_map<std::string, BuiltinLibraryFunction> functions = createBuiltinLibraryFunctions();
|
||||
auto it = functions.find(name);
|
||||
if (it == functions.end())
|
||||
return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const Settings* settings)
|
||||
{
|
||||
ValueFlow::Value unknown = ValueFlow::Value::unknown();
|
||||
|
@ -787,29 +1013,26 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
|
|||
const Function* f = ftok->function();
|
||||
// TODO: Evaluate inline functions as well
|
||||
if (!f && settings && expr->str() == "(") {
|
||||
std::unordered_map<nonneg int, ValueFlow::Value> args;
|
||||
int argn = 0;
|
||||
for (const Token* tok : getArguments(expr)) {
|
||||
ValueFlow::Value result = execute(tok, pm, settings);
|
||||
if (!result.isUninitValue())
|
||||
args[argn] = result;
|
||||
argn++;
|
||||
}
|
||||
// strlen is a special builtin
|
||||
if (Token::simpleMatch(ftok, "strlen")) {
|
||||
if (args.count(0) > 0) {
|
||||
ValueFlow::Value v = args.at(0);
|
||||
if (v.isTokValue() && v.tokvalue->tokType() == Token::eString) {
|
||||
v.valueType = ValueFlow::Value::ValueType::INT;
|
||||
v.intvalue = Token::getStrLength(v.tokvalue);
|
||||
v.tokvalue = nullptr;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
std::vector<const Token*> tokArgs = getArguments(expr);
|
||||
std::vector<ValueFlow::Value> args(tokArgs.size());
|
||||
std::transform(tokArgs.begin(), tokArgs.end(), args.begin(), [&](const Token* tok) {
|
||||
return execute(tok, pm, settings);
|
||||
});
|
||||
BuiltinLibraryFunction lf = getBuiltinLibraryFunction(ftok->str());
|
||||
if (lf) {
|
||||
return lf(args);
|
||||
} else {
|
||||
const std::string& returnValue = settings->library.returnValue(ftok);
|
||||
if (!returnValue.empty())
|
||||
return evaluateLibraryFunction(args, returnValue, settings);
|
||||
if (!returnValue.empty()) {
|
||||
std::unordered_map<nonneg int, ValueFlow::Value> arg_map;
|
||||
int argn = 0;
|
||||
for (const ValueFlow::Value& result : args) {
|
||||
if (!result.isUninitValue())
|
||||
arg_map[argn] = result;
|
||||
argn++;
|
||||
}
|
||||
return evaluateLibraryFunction(arg_map, returnValue, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if functon modifies argument
|
||||
|
|
|
@ -36,6 +36,41 @@
|
|||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
int zerodiv_sqrt()
|
||||
{
|
||||
int i = std::sqrt(0);
|
||||
// cppcheck-suppress zerodiv
|
||||
return 42 / i;
|
||||
}
|
||||
|
||||
int zerodiv_sin()
|
||||
{
|
||||
int i = std::sin(0);
|
||||
// cppcheck-suppress zerodiv
|
||||
return 42 / i;
|
||||
}
|
||||
|
||||
int moduloofone_cos()
|
||||
{
|
||||
int i = std::cos(0);
|
||||
// cppcheck-suppress moduloofone
|
||||
return 42 % i;
|
||||
}
|
||||
|
||||
int moduloofone_exp()
|
||||
{
|
||||
int i = std::exp(0);
|
||||
// cppcheck-suppress moduloofone
|
||||
return 42 % i;
|
||||
}
|
||||
|
||||
int moduloofone_pow()
|
||||
{
|
||||
int i = std::pow(2, 0);
|
||||
// cppcheck-suppress moduloofone
|
||||
return 42 % i;
|
||||
}
|
||||
|
||||
char* invalidFunctionArgStr_strncpy(char * destination)
|
||||
{
|
||||
// Copies the first num characters of source to destination.
|
||||
|
|
Loading…
Reference in New Issue