CheckStl::mismatchingContainers: Refactoring, use Library instead of hardcoding

This commit is contained in:
Daniel Marjamäki 2016-10-27 10:25:45 +02:00
parent d95a4d83bc
commit f6a5f6bb61
3 changed files with 69 additions and 27 deletions

View File

@ -4021,7 +4021,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<arg nr="3"/> <arg nr="3"/>
</function> </function>
<!-- iterator std::find(iterator first, iterator last, T val) --> <!-- iterator std::find(iterator first, iterator last, T val) -->
<function name="std::find"> <function name="std::find,std::find_if,std::find_if_not,std::count,std::count_if">
<noreturn>false</noreturn> <noreturn>false</noreturn>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
@ -4035,6 +4035,40 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/> <not-uninit/>
</arg> </arg>
</function> </function>
<function name="std::find_end,std::find_first_of">
<noreturn>false</noreturn>
<arg nr="1">
<not-uninit/>
<iterator container="1" type="first"/>
</arg>
<arg nr="2">
<not-uninit/>
<iterator container="1" type="last"/>
</arg>
<arg nr="3">
<not-uninit/>
<iterator container="2" type="first"/>
</arg>
<arg nr="4">
<not-uninit/>
<iterator container="2" type="last"/>
</arg>
</function>
<function name="std::inplace_merge">
<noreturn>false</noreturn>
<arg nr="1">
<not-uninit/>
<iterator container="1" type="first"/>
</arg>
<arg nr="2">
<not-uninit/>
<iterator container="1" type="middle"/>
</arg>
<arg nr="3">
<not-uninit/>
<iterator container="1" type="last"/>
</arg>
</function>
<memory> <memory>
<alloc init="false">malloc</alloc> <alloc init="false">malloc</alloc>
<alloc init="true">calloc</alloc> <alloc init="true">calloc</alloc>

View File

@ -77,7 +77,6 @@ static const Token *skipMembers(const Token *tok)
bool CheckStl::isIterator(const Variable *var) const bool CheckStl::isIterator(const Variable *var) const
{ {
// Check that its an iterator // Check that its an iterator
if (!var || !var->isLocal() || !Token::Match(var->typeEndToken(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator|auto")) if (!var || !var->isLocal() || !Token::Match(var->typeEndToken(), "iterator|const_iterator|reverse_iterator|const_reverse_iterator|auto"))
return false; return false;
@ -299,6 +298,16 @@ namespace {
const std::string pattern2 = pattern1x1_1 + pattern1x1_2; const std::string pattern2 = pattern1x1_1 + pattern1x1_2;
} }
static const Variable *getContainer(const Token *argtok)
{
if (!Token::Match(argtok, "%var% . begin|end|rbegin|rend ( )")) // TODO: use Library yield
return nullptr;
const Variable *var = argtok->variable();
if (var && Token::Match(var->typeStartToken(), "std ::"))
return var;
return nullptr;
}
void CheckStl::mismatchingContainers() void CheckStl::mismatchingContainers()
{ {
// Check if different containers are used in various calls of standard functions // Check if different containers are used in various calls of standard functions
@ -307,34 +316,33 @@ void CheckStl::mismatchingContainers()
for (std::size_t ii = 0; ii < functions; ++ii) { for (std::size_t ii = 0; ii < functions; ++ii) {
const Scope * scope = symbolDatabase->functionScopes[ii]; const Scope * scope = symbolDatabase->functionScopes[ii];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (!Token::Match(tok, "std :: %type% ( !!)")) if (!Token::Match(tok, "%name% ( !!)"))
continue; continue;
const Token* arg1 = tok->tokAt(4); const Token * const ftok = tok;
const Token * const arg1 = tok->tokAt(2);
// TODO: If iterator variables are used instead then there are false negatives. int argnr = 1;
if (Token::Match(arg1, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) { std::map<const Variable *, unsigned int> containerNr;
if (arg1->str() != arg1->strAt(6)) { for (const Token *argTok = arg1; argTok; argTok = argTok->nextArgument()) {
mismatchingContainersError(arg1); const Library::ArgumentChecks::IteratorInfo *i = _settings->library.getArgIteratorInfo(ftok,argnr++);
} if (!i)
} else if (algorithm22.find(tok->strAt(2)) != algorithm22.end()) { continue;
if (Token::Match(arg1, pattern2.c_str()) && arg1->str() != arg1->strAt(6)) const Variable *c = getContainer(argTok);
mismatchingContainersError(arg1); if (!c)
// Find third parameter continue;
const Token* arg3 = arg1; std::map<const Variable *, unsigned int>::const_iterator it = containerNr.find(c);
for (unsigned int i = 0; i < 2 && arg3; i++) if (it == containerNr.end()) {
arg3 = arg3->nextArgument(); for (it = containerNr.begin(); it != containerNr.end(); ++it) {
if (Token::Match(arg3, pattern2.c_str()) && arg3->str() != arg3->strAt(6)) if (it->second == i->container) {
mismatchingContainersError(arg3); mismatchingContainersError(argTok);
} else if (Token::Match(arg1, pattern1x1_1.c_str()) && algorithm1x1.find(tok->strAt(2)) != algorithm1x1.end()) { break;
// Find third parameter
const Token *arg3 = arg1->tokAt(6)->nextArgument();
if (Token::Match(arg3, pattern1x1_2.c_str())) {
if (arg1->str() != arg3->str()) {
mismatchingContainersError(arg1);
} }
} }
containerNr[c] = i->container;
} else if (it->second != i->container) {
mismatchingContainersError(argTok);
}
} }
tok = arg1->linkAt(-1);
} }
} }
for (unsigned int varid = 0; varid < symbolDatabase->getVariableListSize(); varid++) { for (unsigned int varid = 0; varid < symbolDatabase->getVariableListSize(); varid++) {

View File

@ -342,8 +342,8 @@ private:
" const std::string fp1 = std::string(a.begin(), a.end());\n" " const std::string fp1 = std::string(a.begin(), a.end());\n"
" const std::string tp2(a.begin(), a.end());\n" " const std::string tp2(a.begin(), a.end());\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (error) Iterators of different containers are used together.\n" ASSERT_EQUALS(// TODO "[test.cpp:2]: (error) Iterators of different containers are used together.\n"
"[test.cpp:3]: (error) Iterators of different containers are used together.\n" // TODO "[test.cpp:3]: (error) Iterators of different containers are used together.\n"
"[test.cpp:4]: (error) Iterators of different containers are used together.\n" "[test.cpp:4]: (error) Iterators of different containers are used together.\n"
"[test.cpp:5]: (error) Iterators of different containers are used together.\n", errout.str()); "[test.cpp:5]: (error) Iterators of different containers are used together.\n", errout.str());
} }