From 40c5924292af9f2682873c8af8410aac7ac1099c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 7 Sep 2013 07:20:06 +0200 Subject: [PATCH] CheckIO: Handle classes derived from STL --- lib/checkio.cpp | 43 ++++++++++++++++++++++++++++++++++++++----- lib/checkio.h | 2 ++ test/testio.cpp | 16 ++++++++++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 72f8ede6e..c6b2864c1 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -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()) diff --git a/lib/checkio.h b/lib/checkio.h index 890f56a80..e7b756786 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -84,6 +84,8 @@ private: } bool isComplexType() const; bool isKnownType() const; + bool isStdVector(); + bool isStdContainer(const Token *tok); const Variable *variableInfo; const Token *typeToken; diff --git a/test/testio.cpp b/test/testio.cpp index dc8b3c117..4d99fcc06 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -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 {} 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 {} 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"