Skip to content

Commit ded8d80

Browse files
committed
Library: Support arguments with default value. Fixed default value handling for <container> tags broken in last commit.
1 parent b5d3ecb commit ded8d80

5 files changed

Lines changed: 86 additions & 13 deletions

File tree

cfg/std.cfg

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3597,7 +3597,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
35973597
<arg nr="1">
35983598
<not-uninit/>
35993599
</arg>
3600-
<arg nr="2">
3600+
<arg nr="2" default="0">
36013601
<not-uninit/>
36023602
</arg>
36033603
</function>
@@ -3990,7 +3990,10 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
39903990
<not-null/>
39913991
<not-uninit/>
39923992
</arg>
3993-
<arg nr="2">
3993+
<arg nr="2" default="0">
3994+
<not-uninit/>
3995+
</arg>
3996+
<arg nr="3" default="">
39943997
<not-uninit/>
39953998
</arg>
39963999
</function>

lib/library.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,9 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
336336
const char* const itEndPattern = node->Attribute("itEndPattern");
337337
if (itEndPattern)
338338
container.itEndPattern = itEndPattern;
339-
container.opLessAllowed = (node->Attribute("opLessAllowed", "true") != nullptr);
339+
const char* const opLessAllowed = node->Attribute("opLessAllowed");
340+
if (opLessAllowed)
341+
container.opLessAllowed = std::string(opLessAllowed) == "true";
340342

341343
for (const tinyxml2::XMLElement *containerNode = node->FirstChildElement(); containerNode; containerNode = containerNode->NextSiblingElement()) {
342344
const std::string containerNodeName = containerNode->Name();
@@ -414,14 +416,18 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
414416
if (templateArg)
415417
container.size_templateArgNo = atoi(templateArg);
416418
} else if (containerNodeName == "access") {
417-
container.arrayLike_indexOp = (containerNode->Attribute("indexOperator", "array-like") != nullptr);
419+
const char* const indexArg = containerNode->Attribute("indexOperator");
420+
if (indexArg)
421+
container.arrayLike_indexOp = std::string(indexArg) == "array-like";
418422
}
419423
} else if (containerNodeName == "type") {
420424
const char* const templateArg = containerNode->Attribute("templateParameter");
421425
if (templateArg)
422426
container.type_templateArgNo = atoi(templateArg);
423427

424-
container.stdStringLike = (containerNode->Attribute("string", "std-like") != nullptr);
428+
const char* const string = containerNode->Attribute("string");
429+
if (string)
430+
container.stdStringLike = std::string(string) == "std-like";
425431
} else
426432
unknown_elements.insert(containerNodeName);
427433
}
@@ -530,9 +536,12 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
530536
leakignore.insert(name);
531537
else if (functionnodename == "use-retval")
532538
_useretval.insert(name);
533-
else if (functionnodename == "arg" && functionnode->Attribute("nr") != nullptr) {
534-
const bool bAnyArg = strcmp(functionnode->Attribute("nr"),"any")==0;
535-
const int nr = (bAnyArg) ? -1 : atoi(functionnode->Attribute("nr"));
539+
else if (functionnodename == "arg") {
540+
const char* argNrString = functionnode->Attribute("nr");
541+
if (!argNrString)
542+
return Error(MISSING_ATTRIBUTE, "nr");
543+
const bool bAnyArg = strcmp(argNrString, "any")==0;
544+
const int nr = (bAnyArg) ? -1 : atoi(argNrString);
536545
bool notbool = false;
537546
bool notnull = false;
538547
bool notuninit = false;
@@ -620,6 +629,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
620629
argumentChecks[name][nr].notuninit = notuninit;
621630
argumentChecks[name][nr].formatstr = formatstr;
622631
argumentChecks[name][nr].strz = strz;
632+
argumentChecks[name][nr].optional = functionnode->Attribute("default") != nullptr;
623633
} else if (functionnodename == "ignorefunction") {
624634
_ignorefunction.insert(name);
625635
} else if (functionnodename == "formatstr") {
@@ -894,13 +904,17 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
894904
if (it == argumentChecks.end())
895905
return (callargs != 0);
896906
int args = 0;
907+
int firstOptionalArg = -1;
897908
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
898909
if (it2->first > args)
899910
args = it2->first;
911+
if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first))
912+
firstOptionalArg = it2->first;
913+
900914
if (it2->second.formatstr)
901915
return args > callargs;
902916
}
903-
return args != callargs;
917+
return (firstOptionalArg < 0) ? args != callargs : !(callargs >= firstOptionalArg-1 && callargs <= args);
904918
}
905919

906920
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const

lib/library.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,16 @@ class CPPCHECKLIB Library {
226226
notnull(false),
227227
notuninit(false),
228228
formatstr(false),
229-
strz(false) {
229+
strz(false),
230+
optional(false) {
230231
}
231232

232233
bool notbool;
233234
bool notnull;
234235
bool notuninit;
235236
bool formatstr;
236237
bool strz;
238+
bool optional;
237239
std::string valid;
238240

239241
class MinSize {

test/testlibrary.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class TestLibrary : public TestFixture {
3434
TEST_CASE(function);
3535
TEST_CASE(function_match_scope);
3636
TEST_CASE(function_match_args);
37+
TEST_CASE(function_match_args_default);
3738
TEST_CASE(function_match_var);
3839
TEST_CASE(function_arg);
3940
TEST_CASE(function_arg_any);
@@ -126,13 +127,64 @@ class TestLibrary : public TestFixture {
126127
TokenList tokenList(nullptr);
127128
std::istringstream istr("foo();"); // <- too few arguments, not library function
128129
tokenList.createTokens(istr);
129-
tokenList.front()->next()->astOperand1(tokenList.front());
130+
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
131+
tokenList.createAst();
130132

131133
Library library;
132134
readLibrary(library, xmldata);
133135
ASSERT(library.isNotLibraryFunction(tokenList.front()));
134136
}
135137

138+
void function_match_args_default() const {
139+
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
140+
"<def>\n"
141+
" <function name=\"foo\">\n"
142+
" <arg nr=\"1\"/>"
143+
" <arg nr=\"2\" default=\"0\"/>"
144+
" </function>\n"
145+
"</def>";
146+
147+
Library library;
148+
readLibrary(library, xmldata);
149+
150+
{
151+
TokenList tokenList(nullptr);
152+
std::istringstream istr("foo();"); // <- too few arguments, not library function
153+
tokenList.createTokens(istr);
154+
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
155+
tokenList.createAst();
156+
157+
ASSERT(library.isNotLibraryFunction(tokenList.front()));
158+
}
159+
{
160+
TokenList tokenList(nullptr);
161+
std::istringstream istr("foo(a);"); // <- library function
162+
tokenList.createTokens(istr);
163+
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
164+
tokenList.createAst();
165+
166+
ASSERT(!library.isNotLibraryFunction(tokenList.front()));
167+
}
168+
{
169+
TokenList tokenList(nullptr);
170+
std::istringstream istr("foo(a, b);"); // <- library function
171+
tokenList.createTokens(istr);
172+
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
173+
tokenList.createAst();
174+
175+
ASSERT(!library.isNotLibraryFunction(tokenList.front()));
176+
}
177+
{
178+
TokenList tokenList(nullptr);
179+
std::istringstream istr("foo(a, b, c);"); // <- too much arguments, not library function
180+
tokenList.createTokens(istr);
181+
Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
182+
tokenList.createAst();
183+
184+
ASSERT(library.isNotLibraryFunction(tokenList.front()));
185+
}
186+
}
187+
136188
void function_match_var() const {
137189
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
138190
"<def>\n"
@@ -160,7 +212,7 @@ class TestLibrary : public TestFixture {
160212
" <arg nr=\"2\"><not-null/></arg>\n"
161213
" <arg nr=\"3\"><formatstr/></arg>\n"
162214
" <arg nr=\"4\"><strz/></arg>\n"
163-
" <arg nr=\"5\"><not-bool/></arg>\n"
215+
" <arg nr=\"5\" default=\"0\"><not-bool/></arg>\n"
164216
" </function>\n"
165217
"</def>";
166218

@@ -170,7 +222,9 @@ class TestLibrary : public TestFixture {
170222
ASSERT_EQUALS(true, library.argumentChecks["foo"][2].notnull);
171223
ASSERT_EQUALS(true, library.argumentChecks["foo"][3].formatstr);
172224
ASSERT_EQUALS(true, library.argumentChecks["foo"][4].strz);
225+
ASSERT_EQUALS(false, library.argumentChecks["foo"][4].optional);
173226
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].notbool);
227+
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].optional);
174228
}
175229

176230
void function_arg_any() const {

test/teststl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ class TestStl : public TestFixture {
14171417
" ;\n"
14181418
"}");
14191419

1420-
ASSERT_EQUALS("[test.cpp:4]: (error) Dangerous comparison using operator< on iterator.\n", errout.str());
1420+
ASSERT_EQUALS_MSG("[test.cpp:4]: (error) Dangerous comparison using operator< on iterator.\n", errout.str(), stlCont[i]);
14211421
}
14221422

14231423
check("void f() {\n"

0 commit comments

Comments
 (0)