Library: Support variadic functions which are not a formatstr-function

This commit is contained in:
PKEuS 2017-03-14 17:41:34 +01:00
parent 263c3596d5
commit 92414b923a
4 changed files with 38 additions and 11 deletions

View File

@ -556,10 +556,12 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
const char* argNrString = functionnode->Attribute("nr"); const char* argNrString = functionnode->Attribute("nr");
if (!argNrString) if (!argNrString)
return Error(MISSING_ATTRIBUTE, "nr"); return Error(MISSING_ATTRIBUTE, "nr");
const bool bAnyArg = strcmp(argNrString, "any")==0; const bool bAnyArg = strcmp(argNrString, "any") == 0;
const int nr = bAnyArg ? -1 : std::atoi(argNrString); const bool bVariadicArg = strcmp(argNrString, "variadic") == 0;
const int nr = (bAnyArg || bVariadicArg) ? -1 : std::atoi(argNrString);
ArgumentChecks &ac = func.argumentChecks[nr]; ArgumentChecks &ac = func.argumentChecks[nr];
ac.optional = functionnode->Attribute("default") != nullptr; ac.optional = functionnode->Attribute("default") != nullptr;
ac.variadic = bVariadicArg;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) { for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
const std::string argnodename = argnode->Name(); const std::string argnodename = argnode->Name();
if (argnodename == "not-bool") if (argnodename == "not-bool")
@ -942,7 +944,7 @@ bool Library::matchArguments(const Token *ftok, const std::string &functionName)
if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first)) if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first))
firstOptionalArg = it2->first; firstOptionalArg = it2->first;
if (it2->second.formatstr) if (it2->second.formatstr || it2->second.variadic)
return args <= callargs; return args <= callargs;
} }
return (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args); return (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args);

View File

@ -223,6 +223,7 @@ public:
formatstr(false), formatstr(false),
strz(false), strz(false),
optional(false), optional(false),
variadic(false),
iteratorInfo() { iteratorInfo() {
} }
@ -232,14 +233,15 @@ public:
bool formatstr; bool formatstr;
bool strz; bool strz;
bool optional; bool optional;
bool variadic;
std::string valid; std::string valid;
class IteratorInfo { class IteratorInfo {
public: public:
IteratorInfo() : it(false), container(0), first(false), last(false) {} IteratorInfo() : container(0), it(false), first(false), last(false) {}
bool it;
int container; int container;
bool it;
bool first; bool first;
bool last; bool last;
}; };

View File

@ -5,7 +5,7 @@
<bookinfo> <bookinfo>
<title>Cppcheck 1.78 dev</title> <title>Cppcheck 1.78 dev</title>
<date>2016-08-13</date> <date>2017-03-14</date>
</bookinfo> </bookinfo>
<chapter> <chapter>
@ -918,11 +918,9 @@ Checking pen1.c...
<para>The arguments a function takes can be specified by <para>The arguments a function takes can be specified by
<literal>&lt;arg&gt;</literal> tags. Each of them takes the number of <literal>&lt;arg&gt;</literal> tags. Each of them takes the number of
the argument (starting from 1) in the <literal>nr</literal> attribute, the argument (starting from 1) in the <literal>nr</literal> attribute,
or <literal>nr="any"</literal> for variadic arguments. Optional <literal>nr="any"</literal> for arbitrary arguments, or <literal>nr="variadic"</literal> for variadic arguments.
arguments can be specified by providing a default value: Optional arguments can be specified by providing a default value:
<literal>default="value"</literal>. Specifying <literal>-1</literal> <literal>default="value"</literal>. The specifications for individual arguments override
as the argument number is going to apply a check to all arguments of
that function. The specifications for individual arguments override
this setting.</para> this setting.</para>
<section> <section>

View File

@ -41,6 +41,7 @@ private:
TEST_CASE(function_match_var); TEST_CASE(function_match_var);
TEST_CASE(function_arg); TEST_CASE(function_arg);
TEST_CASE(function_arg_any); TEST_CASE(function_arg_any);
TEST_CASE(function_arg_variadic);
TEST_CASE(function_arg_valid); TEST_CASE(function_arg_valid);
TEST_CASE(function_arg_minsize); TEST_CASE(function_arg_minsize);
TEST_CASE(function_namespace); TEST_CASE(function_namespace);
@ -242,6 +243,30 @@ private:
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[-1].notuninit); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[-1].notuninit);
} }
void function_arg_variadic() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n"
"<function name=\"foo\">\n"
" <arg nr=\"1\"></arg>\n"
" <arg nr=\"variadic\"><not-uninit/></arg>\n"
"</function>\n"
"</def>";
Library library;
readLibrary(library, xmldata);
ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[-1].notuninit);
TokenList tokenList(nullptr);
std::istringstream istr("foo(a,b,c,d,e);");
tokenList.createTokens(istr);
tokenList.front()->next()->astOperand1(tokenList.front());
ASSERT_EQUALS(false, library.isuninitargbad(tokenList.front(), 1));
ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 2));
ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 3));
ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 4));
}
void function_arg_valid() const { void function_arg_valid() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n" const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n" "<def>\n"