library: Improved argument <valid>-interface to defined values that are explicitly excluded. (#4111)
* library: Improved <valid>-interface to defined values that are explicitly excluded. * std.cfg: Improved configuration of remainder[fl](). * Fixed failing self check * Fixed failing self check * std.cfg: Added support for std::remquo().
This commit is contained in:
parent
fffb03a242
commit
4f410ffb79
|
@ -273,7 +273,7 @@
|
||||||
<optional>
|
<optional>
|
||||||
<element name="valid">
|
<element name="valid">
|
||||||
<data type="string"> <!-- regex test: https://regex101.com/r/LoRGVj/2/ -->
|
<data type="string"> <!-- regex test: https://regex101.com/r/LoRGVj/2/ -->
|
||||||
<param name="pattern">(-?[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?[,:])*([-]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?)?</param>
|
<param name="pattern">([-!]?[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?[,:])*([-!]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?)?</param>
|
||||||
</data>
|
</data>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
|
58
cfg/std.cfg
58
cfg/std.cfg
|
@ -4156,6 +4156,61 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
|
<!-- float remquo (float x , float y , int *quo); -->
|
||||||
|
<!-- double remquo (double x, double y, int *quo); -->
|
||||||
|
<!-- long double remquo (long double x, long double y, int *quo); -->
|
||||||
|
<function name="remquo,std::remquo">
|
||||||
|
<use-retval/>
|
||||||
|
<pure/>
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="out">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- float remquof (float x , float y , int *quo); -->
|
||||||
|
<function name="remquof,std::remquof">
|
||||||
|
<use-retval/>
|
||||||
|
<pure/>
|
||||||
|
<returnValue type="float"/>
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="out">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
|
<!-- long double remquol (long double x , long double y , int *quo); -->
|
||||||
|
<function name="remquol,std::remquol">
|
||||||
|
<use-retval/>
|
||||||
|
<pure/>
|
||||||
|
<returnValue type="long double"/>
|
||||||
|
<noreturn>false</noreturn>
|
||||||
|
<leak-ignore/>
|
||||||
|
<arg nr="1" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
</arg>
|
||||||
|
<arg nr="2" direction="in">
|
||||||
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
|
</arg>
|
||||||
|
<arg nr="3" direction="out">
|
||||||
|
<not-null/>
|
||||||
|
</arg>
|
||||||
|
</function>
|
||||||
<!-- double remainder(double x, double y); -->
|
<!-- double remainder(double x, double y); -->
|
||||||
<function name="remainder,std::remainder">
|
<function name="remainder,std::remainder">
|
||||||
<use-retval/>
|
<use-retval/>
|
||||||
|
@ -4168,6 +4223,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- float remainderf(float x, float y); -->
|
<!-- float remainderf(float x, float y); -->
|
||||||
|
@ -4182,6 +4238,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- long double remainderl(long double x, long double y); -->
|
<!-- long double remainderl(long double x, long double y); -->
|
||||||
|
@ -4196,6 +4253,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
||||||
</arg>
|
</arg>
|
||||||
<arg nr="2" direction="in">
|
<arg nr="2" direction="in">
|
||||||
<not-uninit/>
|
<not-uninit/>
|
||||||
|
<valid>!0.0</valid>
|
||||||
</arg>
|
</arg>
|
||||||
</function>
|
</function>
|
||||||
<!-- double remquo(double, x, double y, int *quo); -->
|
<!-- double remquo(double, x, double y, int *quo); -->
|
||||||
|
|
|
@ -748,7 +748,8 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
|
||||||
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : argnode->GetText()));
|
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, (!p ? "\"\"" : argnode->GetText()));
|
||||||
// Set validation expression
|
// Set validation expression
|
||||||
ac.valid = argnode->GetText();
|
ac.valid = argnode->GetText();
|
||||||
} else if (argnodename == "minsize") {
|
}
|
||||||
|
else if (argnodename == "minsize") {
|
||||||
const char *typeattr = argnode->Attribute("type");
|
const char *typeattr = argnode->Attribute("type");
|
||||||
if (!typeattr)
|
if (!typeattr)
|
||||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
|
return Error(ErrorCode::MISSING_ATTRIBUTE, "type");
|
||||||
|
@ -929,6 +930,10 @@ bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) con
|
||||||
return true;
|
return true;
|
||||||
if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1)))
|
if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1)))
|
||||||
return true;
|
return true;
|
||||||
|
if (Token::Match(tok, "%num%") && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue)))
|
||||||
|
return true;
|
||||||
|
if (Token::Match(tok, "! %num%") && MathLib::isFloat(tok->next()->str()))
|
||||||
|
return MathLib::isNotEqual(tok->next()->str(), MathLib::toString(argvalue));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1232,7 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
|
||||||
|
|
||||||
bool Library::isCompliantValidationExpression(const char* p)
|
bool Library::isCompliantValidationExpression(const char* p)
|
||||||
{
|
{
|
||||||
if (!p)
|
if (!p || !*p)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
@ -1237,15 +1242,18 @@ bool Library::isCompliantValidationExpression(const char* p)
|
||||||
|
|
||||||
error = *p == '.';
|
error = *p == '.';
|
||||||
for (; *p; p++) {
|
for (; *p; p++) {
|
||||||
if (std::isdigit(*p))
|
if (std::isdigit(*p)) {
|
||||||
error |= (*(p + 1) == '-');
|
error |= (*(p + 1) == '-');
|
||||||
|
}
|
||||||
else if (*p == ':') {
|
else if (*p == ':') {
|
||||||
error |= range | (*(p + 1) == '.');
|
error |= range | (*(p + 1) == '.');
|
||||||
range = true;
|
range = true;
|
||||||
has_dot = false;
|
has_dot = false;
|
||||||
has_E = false;
|
has_E = false;
|
||||||
} else if ((*p == '-') || (*p == '+'))
|
}
|
||||||
|
else if ((*p == '-') || (*p == '+')) {
|
||||||
error |= (!std::isdigit(*(p + 1)));
|
error |= (!std::isdigit(*(p + 1)));
|
||||||
|
}
|
||||||
else if (*p == ',') {
|
else if (*p == ',') {
|
||||||
range = false;
|
range = false;
|
||||||
error |= *(p + 1) == '.';
|
error |= *(p + 1) == '.';
|
||||||
|
@ -1257,6 +1265,8 @@ bool Library::isCompliantValidationExpression(const char* p)
|
||||||
} else if (*p == 'E' || *p == 'e') {
|
} else if (*p == 'E' || *p == 'e') {
|
||||||
error |= has_E;
|
error |= has_E;
|
||||||
has_E = true;
|
has_E = true;
|
||||||
|
} else if (*p == '!') {
|
||||||
|
error |= !((*(p+1) == '-') || (*(p+1) == '+') || (std::isdigit(*(p + 1))));
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,60 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
|
||||||
|
float invalidFunctionArg_float_remquo (float x, float y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquo(x,0.0f,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquof(x,0.0f,quo);
|
||||||
|
return remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
double invalidFunctionArg_double_remquo (double x, double y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquo(x,0.0,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquo(x,0.0f,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquo(x,0.0L,quo);
|
||||||
|
return remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
double invalidFunctionArg_long_double_remquo (long double x, long double y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquo(x,0.0L,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) remquol(x,0.0L,quo);
|
||||||
|
return remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainderl(long double f1, long double f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)remainderl(f1,0.0);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)remainderl(f1,0.0L);
|
||||||
|
(void)remainderl(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainder(double f1, double f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)remainder(f1,0.0);
|
||||||
|
(void)remainder(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainderf(float f1, float f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)remainderf(f1,0.0);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)remainderf(f1,0.0f);
|
||||||
|
(void)remainderf(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
int qsort_cmpfunc (const void * a, const void * b) {
|
int qsort_cmpfunc (const void * a, const void * b) {
|
||||||
return (*(int*)a - *(int*)b);
|
return (*(int*)a - *(int*)b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,60 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
float invalidFunctionArg_remquo (float x, float y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquo(x,0.0f,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquof(x,0.0f,quo);
|
||||||
|
return std::remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
double invalidFunctionArg_remquo (double x, double y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquo(x,0.0,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquo(x,0.0f,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquo(x,0.0L,quo);
|
||||||
|
return std::remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
double invalidFunctionArg_remquo (long double x, long double y, int* quo )
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquo(x,0.0L,quo);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void) std::remquol(x,0.0L,quo);
|
||||||
|
return std::remquo(x,y,quo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainderl(long double f1, long double f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)std::remainderl(f1,0.0);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)std::remainderl(f1,0.0L);
|
||||||
|
(void)std::remainderl(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainder(double f1, double f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)std::remainder(f1,0.0);
|
||||||
|
(void)std::remainder(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidFunctionArg_remainderf(float f1, float f2)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)std::remainderf(f1,0.0);
|
||||||
|
// cppcheck-suppress invalidFunctionArg
|
||||||
|
(void)std::remainderf(f1,0.0f);
|
||||||
|
(void)std::remainderf(f1,f2);
|
||||||
|
}
|
||||||
|
|
||||||
void uninitvar_std_fstream_open(std::fstream &fs, const std::string &strFileName, const char* filename, std::ios_base::openmode mode)
|
void uninitvar_std_fstream_open(std::fstream &fs, const std::string &strFileName, const char* filename, std::ios_base::openmode mode)
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
|
@ -89,10 +89,13 @@ private:
|
||||||
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:"));
|
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:"));
|
||||||
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38"));
|
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38"));
|
||||||
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0"));
|
ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0"));
|
||||||
|
ASSERT_EQUALS(true, Library::isCompliantValidationExpression("!42.0"));
|
||||||
|
|
||||||
// Robustness tests
|
// Robustness tests
|
||||||
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr));
|
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr));
|
||||||
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x"));
|
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x"));
|
||||||
|
ASSERT_EQUALS(false, Library::isCompliantValidationExpression("!"));
|
||||||
|
ASSERT_EQUALS(false, Library::isCompliantValidationExpression(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
void empty() const {
|
void empty() const {
|
||||||
|
@ -336,6 +339,7 @@ private:
|
||||||
" <arg nr=\"8\"><valid>0.0:</valid></arg>\n"
|
" <arg nr=\"8\"><valid>0.0:</valid></arg>\n"
|
||||||
" <arg nr=\"9\"><valid>:2.0</valid></arg>\n"
|
" <arg nr=\"9\"><valid>:2.0</valid></arg>\n"
|
||||||
" <arg nr=\"10\"><valid>0.0</valid></arg>\n"
|
" <arg nr=\"10\"><valid>0.0</valid></arg>\n"
|
||||||
|
" <arg nr=\"11\"><valid>!0.0</valid></arg>\n"
|
||||||
" </function>\n"
|
" </function>\n"
|
||||||
"</def>";
|
"</def>";
|
||||||
|
|
||||||
|
@ -343,7 +347,7 @@ private:
|
||||||
ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
|
ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
|
||||||
|
|
||||||
TokenList tokenList(nullptr);
|
TokenList tokenList(nullptr);
|
||||||
std::istringstream istr("foo(a,b,c,d,e,f,g,h,i,j);");
|
std::istringstream istr("foo(a,b,c,d,e,f,g,h,i,j,k);");
|
||||||
tokenList.createTokens(istr);
|
tokenList.createTokens(istr);
|
||||||
tokenList.front()->next()->astOperand1(tokenList.front());
|
tokenList.front()->next()->astOperand1(tokenList.front());
|
||||||
|
|
||||||
|
@ -460,8 +464,13 @@ private:
|
||||||
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 200.0));
|
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 200.0));
|
||||||
|
|
||||||
// 0.0
|
// 0.0
|
||||||
ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 10, 0));
|
ASSERT_EQUALS(true, library.isIntArgValid(tokenList.front(), 10, 0));
|
||||||
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 10, 0.0));
|
ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 10, 0.0));
|
||||||
|
|
||||||
|
// ! 0.0
|
||||||
|
ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 11, -0.42));
|
||||||
|
ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 11, 0.0));
|
||||||
|
ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 11, 0.42));
|
||||||
}
|
}
|
||||||
|
|
||||||
void function_arg_minsize() const {
|
void function_arg_minsize() const {
|
||||||
|
|
Loading…
Reference in New Issue