From ded8d80b2396389d87bd4e6505f36f97b285d69f Mon Sep 17 00:00:00 2001 From: PKEuS Date: Sat, 9 Jul 2016 12:42:46 +0200 Subject: [PATCH] Library: Support arguments with default value. Fixed default value handling for tags broken in last commit. --- cfg/std.cfg | 7 ++++-- lib/library.cpp | 28 +++++++++++++++------ lib/library.h | 4 ++- test/testlibrary.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++-- test/teststl.cpp | 2 +- 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/cfg/std.cfg b/cfg/std.cfg index b1397590f..e9c40a07f 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -3597,7 +3597,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + @@ -3990,7 +3990,10 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + + + + diff --git a/lib/library.cpp b/lib/library.cpp index 090c7d26a..25b5cdf9c 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -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::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 diff --git a/lib/library.h b/lib/library.h index 3fb8a7ddf..1cc07f8fd 100644 --- a/lib/library.h +++ b/lib/library.h @@ -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 { diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp index 0cf74ceff..a2052e8e6 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -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[] = "\n" + "\n" + " \n" + " " + " " + " \n" + ""; + + 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[] = "\n" "\n" @@ -160,7 +212,7 @@ private: " \n" " \n" " \n" - " \n" + " \n" " \n" ""; @@ -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 { diff --git a/test/teststl.cpp b/test/teststl.cpp index 459401a82..de56bb382 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -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"