CheckIO: Handle classes derived from STL

This commit is contained in:
Daniel Marjamäki 2013-09-07 07:20:06 +02:00
parent 489a3a6e53
commit 40c5924292
3 changed files with 52 additions and 9 deletions

View File

@ -833,9 +833,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
tok1 = tok1->link();
// check for some common well known functions
else if (Token::Match(tok1->previous(), "%var% . size|empty|c_str ( )") && tok1->previous()->variable() &&
(Token::Match(tok1->previous()->variable()->typeStartToken(), "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <") ||
Token::Match(tok1->previous()->variable()->typeStartToken(), "std :: string|wstring"))) {
else if (Token::Match(tok1->previous(), "%var% . size|empty|c_str ( )") && isStdContainer(tok1->previous())) {
tempToken = new Token(0);
tempToken->fileIndex(tok1->fileIndex());
tempToken->linenr(tok1->linenr());
@ -874,8 +872,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
// look for std::vector operator [] and use template type as return type
if (variableInfo) {
if (element && Token::Match(variableInfo->typeStartToken(), "std :: vector|array <")) {
typeToken = variableInfo->typeStartToken()->tokAt(4);
if (element && isStdVector()) { // isStdVector sets type token if true
element = false; // not really an array element
} else
typeToken = variableInfo->typeStartToken();
@ -887,6 +884,42 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
}
}
bool CheckIO::ArgumentInfo::isStdVector()
{
if (Token::Match(variableInfo->typeStartToken(), "std :: vector|array <")) {
typeToken = variableInfo->typeStartToken()->tokAt(4);
return true;
} else if (variableInfo->type() && !variableInfo->type()->derivedFrom.empty()) {
for (std::size_t i = 0, e = variableInfo->type()->derivedFrom.size(); i != e; ++i) {
if (Token::Match(variableInfo->type()->derivedFrom[i].nameTok, "std :: vector|array <")) {
typeToken = variableInfo->type()->derivedFrom[i].nameTok->tokAt(4);
return true;
}
}
}
return false;
}
bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
{
if (tok && tok->variable()) {
if (Token::Match(tok->variable()->typeStartToken(), "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <") ||
Token::Match(tok->variable()->typeStartToken(), "std :: string|wstring")) {
return true;
} else if (tok->variable()->type() && !tok->variable()->type()->derivedFrom.empty()) {
for (std::size_t i = 0, e = tok->variable()->type()->derivedFrom.size(); i != e; ++i) {
if (Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <") ||
Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: string|wstring")) {
return true;
}
}
}
}
return false;
}
bool CheckIO::ArgumentInfo::isComplexType() const
{
if (variableInfo->type())

View File

@ -84,6 +84,8 @@ private:
}
bool isComplexType() const;
bool isKnownType() const;
bool isStdVector();
bool isStdContainer(const Token *tok);
const Variable *variableInfo;
const Token *typeToken;

View File

@ -1130,14 +1130,22 @@ private:
"[test.cpp:5]: (warning) %f in format string (no. 4) requires a floating point number but the argument type is 'size_t {aka unsigned long}'.\n", errout.str());
check("class Fred : public std::vector<int> {} v;\n"
"std::string s;\n"
"void foo() {\n"
" printf(\"%zu %Iu %d %f\", v.size(), v.size(), v.size(), v.size());\n"
" printf(\"%zu %Iu %d %f\", s.size(), s.size(), s.size(), s.size());\n"
"}\n", false, false, Settings::Unix64);
TODO_ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 3) requires a signed integer but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:4]: (warning) %f in format string (no. 4) requires a floating point number but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:5]: (warning) %d in format string (no. 3) requires a signed integer but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:5]: (warning) %f in format string (no. 4) requires a floating point number but the argument type is 'size_t {aka unsigned long}'.\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (warning) %d in format string (no. 3) requires a signed integer but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:4]: (warning) %f in format string (no. 4) requires a floating point number but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:5]: (warning) %d in format string (no. 3) requires a signed integer but the argument type is 'size_t {aka unsigned long}'.\n"
"[test.cpp:5]: (warning) %f in format string (no. 4) requires a floating point number but the argument type is 'size_t {aka unsigned long}'.\n", errout.str());
check("class Fred : public std::vector<int> {} v;\n"
"void foo() {\n"
" printf(\"%d %u %f\", v[0], v[0], v[0]);\n"
"}\n", false, false, Settings::Unix64);
ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer but the argument type is 'int'.\n"
"[test.cpp:3]: (warning) %f in format string (no. 3) requires a floating point number but the argument type is 'int'.\n", errout.str());
check("std::string s;\n"
"void foo() {\n"