Library: Support arguments with default value. Fixed default value handling for <container> tags broken in last commit.

This commit is contained in:
PKEuS 2016-07-09 12:42:46 +02:00
parent b5d3ecb942
commit ded8d80b23
5 changed files with 86 additions and 13 deletions

View File

@ -3597,7 +3597,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<arg nr="2" default="0">
<not-uninit/>
</arg>
</function>
@ -3990,7 +3990,10 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-null/>
<not-uninit/>
</arg>
<arg nr="2">
<arg nr="2" default="0">
<not-uninit/>
</arg>
<arg nr="3" default="">
<not-uninit/>
</arg>
</function>

View File

@ -336,7 +336,9 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
const char* const itEndPattern = node->Attribute("itEndPattern");
if (itEndPattern)
container.itEndPattern = itEndPattern;
container.opLessAllowed = (node->Attribute("opLessAllowed", "true") != nullptr);
const char* const opLessAllowed = node->Attribute("opLessAllowed");
if (opLessAllowed)
container.opLessAllowed = std::string(opLessAllowed) == "true";
for (const tinyxml2::XMLElement *containerNode = node->FirstChildElement(); containerNode; containerNode = containerNode->NextSiblingElement()) {
const std::string containerNodeName = containerNode->Name();
@ -414,14 +416,18 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
if (templateArg)
container.size_templateArgNo = atoi(templateArg);
} else if (containerNodeName == "access") {
container.arrayLike_indexOp = (containerNode->Attribute("indexOperator", "array-like") != nullptr);
const char* const indexArg = containerNode->Attribute("indexOperator");
if (indexArg)
container.arrayLike_indexOp = std::string(indexArg) == "array-like";
}
} else if (containerNodeName == "type") {
const char* const templateArg = containerNode->Attribute("templateParameter");
if (templateArg)
container.type_templateArgNo = atoi(templateArg);
container.stdStringLike = (containerNode->Attribute("string", "std-like") != nullptr);
const char* const string = containerNode->Attribute("string");
if (string)
container.stdStringLike = std::string(string) == "std-like";
} else
unknown_elements.insert(containerNodeName);
}
@ -530,9 +536,12 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
leakignore.insert(name);
else if (functionnodename == "use-retval")
_useretval.insert(name);
else if (functionnodename == "arg" && functionnode->Attribute("nr") != nullptr) {
const bool bAnyArg = strcmp(functionnode->Attribute("nr"),"any")==0;
const int nr = (bAnyArg) ? -1 : atoi(functionnode->Attribute("nr"));
else if (functionnodename == "arg") {
const char* argNrString = functionnode->Attribute("nr");
if (!argNrString)
return Error(MISSING_ATTRIBUTE, "nr");
const bool bAnyArg = strcmp(argNrString, "any")==0;
const int nr = (bAnyArg) ? -1 : atoi(argNrString);
bool notbool = false;
bool notnull = false;
bool notuninit = false;
@ -620,6 +629,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
argumentChecks[name][nr].notuninit = notuninit;
argumentChecks[name][nr].formatstr = formatstr;
argumentChecks[name][nr].strz = strz;
argumentChecks[name][nr].optional = functionnode->Attribute("default") != nullptr;
} else if (functionnodename == "ignorefunction") {
_ignorefunction.insert(name);
} else if (functionnodename == "formatstr") {
@ -894,13 +904,17 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
if (it == argumentChecks.end())
return (callargs != 0);
int args = 0;
int firstOptionalArg = -1;
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
if (it2->first > args)
args = it2->first;
if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first))
firstOptionalArg = it2->first;
if (it2->second.formatstr)
return args > callargs;
}
return args != callargs;
return (firstOptionalArg < 0) ? args != callargs : !(callargs >= firstOptionalArg-1 && callargs <= args);
}
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const

View File

@ -226,7 +226,8 @@ public:
notnull(false),
notuninit(false),
formatstr(false),
strz(false) {
strz(false),
optional(false) {
}
bool notbool;
@ -234,6 +235,7 @@ public:
bool notuninit;
bool formatstr;
bool strz;
bool optional;
std::string valid;
class MinSize {

View File

@ -34,6 +34,7 @@ private:
TEST_CASE(function);
TEST_CASE(function_match_scope);
TEST_CASE(function_match_args);
TEST_CASE(function_match_args_default);
TEST_CASE(function_match_var);
TEST_CASE(function_arg);
TEST_CASE(function_arg_any);
@ -126,13 +127,64 @@ private:
TokenList tokenList(nullptr);
std::istringstream istr("foo();"); // <- too few arguments, not library function
tokenList.createTokens(istr);
tokenList.front()->next()->astOperand1(tokenList.front());
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
tokenList.createAst();
Library library;
readLibrary(library, xmldata);
ASSERT(library.isNotLibraryFunction(tokenList.front()));
}
void function_match_args_default() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n"
" <function name=\"foo\">\n"
" <arg nr=\"1\"/>"
" <arg nr=\"2\" default=\"0\"/>"
" </function>\n"
"</def>";
Library library;
readLibrary(library, xmldata);
{
TokenList tokenList(nullptr);
std::istringstream istr("foo();"); // <- too few arguments, not library function
tokenList.createTokens(istr);
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
tokenList.createAst();
ASSERT(library.isNotLibraryFunction(tokenList.front()));
}
{
TokenList tokenList(nullptr);
std::istringstream istr("foo(a);"); // <- library function
tokenList.createTokens(istr);
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
tokenList.createAst();
ASSERT(!library.isNotLibraryFunction(tokenList.front()));
}
{
TokenList tokenList(nullptr);
std::istringstream istr("foo(a, b);"); // <- library function
tokenList.createTokens(istr);
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
tokenList.createAst();
ASSERT(!library.isNotLibraryFunction(tokenList.front()));
}
{
TokenList tokenList(nullptr);
std::istringstream istr("foo(a, b, c);"); // <- too much arguments, not library function
tokenList.createTokens(istr);
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
tokenList.createAst();
ASSERT(library.isNotLibraryFunction(tokenList.front()));
}
}
void function_match_var() const {
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
"<def>\n"
@ -160,7 +212,7 @@ private:
" <arg nr=\"2\"><not-null/></arg>\n"
" <arg nr=\"3\"><formatstr/></arg>\n"
" <arg nr=\"4\"><strz/></arg>\n"
" <arg nr=\"5\"><not-bool/></arg>\n"
" <arg nr=\"5\" default=\"0\"><not-bool/></arg>\n"
" </function>\n"
"</def>";
@ -170,7 +222,9 @@ private:
ASSERT_EQUALS(true, library.argumentChecks["foo"][2].notnull);
ASSERT_EQUALS(true, library.argumentChecks["foo"][3].formatstr);
ASSERT_EQUALS(true, library.argumentChecks["foo"][4].strz);
ASSERT_EQUALS(false, library.argumentChecks["foo"][4].optional);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].notbool);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].optional);
}
void function_arg_any() const {

View File

@ -1417,7 +1417,7 @@ private:
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Dangerous comparison using operator< on iterator.\n", errout.str());
ASSERT_EQUALS_MSG("[test.cpp:4]: (error) Dangerous comparison using operator< on iterator.\n", errout.str(), stlCont[i]);
}
check("void f() {\n"