Library: Support arguments with default value. Fixed default value handling for <container> tags broken in last commit.
This commit is contained in:
parent
b5d3ecb942
commit
ded8d80b23
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue