diff --git a/cfg/std.cfg b/cfg/std.cfg
index 4cd2a00a0..030a549e9 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -1975,6 +1975,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1989,6 +2001,7 @@
+
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index e36a581be..f1618ef97 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -759,6 +759,8 @@ static bool if_findCompare(const Token * const tokBack)
return true;
if (tok->isArithmeticalOp()) // result is used in some calculation
return true; // TODO: check if there is a comparison of the result somewhere
+ if (tok->str() == ".")
+ return true; // Dereferencing is OK, the programmer might know that the element exists - TODO: An inconclusive warning might be appropriate
if (tok->isAssignmentOp())
return if_findCompare(tok); // Go one step upwards in the AST
return false;
@@ -782,72 +784,48 @@ void CheckStl::if_find()
tok = tok->next();
for (const Token* const end = tok->link(); tok != end; tok = (tok == end) ? end : tok->next()) {
- if (Token::Match(tok, "%var% . find (")) {
- const Variable *var = tok->variable();
- if (var) {
- if (if_findCompare(tok->tokAt(3)))
- continue;
+ const Token* funcTok = nullptr;
+ const Library::Container* container = nullptr;
- // Is the variable a std::string or STL container?
- const Token * decl = var->typeStartToken();
- // stl container
- if (warning && Token::Match(decl, "std :: %var% <") && Token::Match(decl->linkAt(3), "> !!::"))
- if_findError(tok, false);
- else if (performance && var->isStlStringType())
- if_findError(tok, true);
- }
+ if (tok->variable() && Token::Match(tok, "%var% . %var% (")) {
+ container = _settings->library.detectContainer(tok->variable()->typeStartToken());
+ funcTok = tok->tokAt(2);
}
- //check also for vector-like or pointer containers
+ // check also for vector-like or pointer containers
else if (tok->variable() && tok->astParent() && (tok->astParent()->str() == "*" || tok->astParent()->str() == "[")) {
const Token *tok2 = tok->astParent();
- if (!Token::simpleMatch(tok2->astParent(), ". find ("))
+ if (!Token::Match(tok2->astParent(), ". %var% ("))
continue;
- if (if_findCompare(tok2->astParent()->tokAt(2)))
- continue;
+ funcTok = tok2->astParent()->next();
- const Variable *var = tok->variable();
- if (var) {
- //pretty bad limitation.. but it is there in order to avoid
- //own implementations of 'find' or any container
- if (!var->isStlType())
- continue;
+ if (tok->variable()->isArrayOrPointer())
+ container = _settings->library.detectContainer(tok->variable()->typeStartToken());
+ else { // Container of container - find the inner container
+ container = _settings->library.detectContainer(tok->variable()->typeStartToken()); // outer container
+ tok2 = Token::findsimplematch(tok->variable()->typeStartToken(), "<", tok->variable()->typeEndToken());
+ if (container && container->type_templateArgNo >= 0 && tok2) {
+ tok2 = tok2->next();
+ for (int i = 0; i < container->type_templateArgNo; i++)
+ tok2 = tok2->nextTemplateArgument();
- // Is the variable a std::string or STL container?
- const Token * decl = var->typeStartToken();
- const unsigned int varid = tok->varId();
-
- decl = decl->tokAt(2);
-
- if (Token::Match(decl, "%var% <")) {
- decl = decl->tokAt(2);
- //stl-like
- if (warning && Token::Match(decl, "std :: %var% < %type% > > &| %varid%", varid))
- if_findError(tok, false);
- //not stl-like, then let's hope it's a pointer or an array
- else if (Token::Match(decl, "%type% >")) {
- decl = decl->tokAt(2);
- if (warning && (Token::Match(decl, "* &| %varid%", varid) ||
- Token::Match(decl, "&| %varid% [ ]| %any% ]|", varid)))
- if_findError(tok, false);
- }
-
- else if (performance && Token::Match(decl, "std :: string|wstring > &| %varid%", varid))
- if_findError(tok, true);
- }
-
- else if (performance && var->isStlStringType()) {
- decl = decl->next();
- if (Token::Match(decl, "* &| %varid%", varid) ||
- Token::Match(decl, "&| %varid% [ ]| %any% ]|", varid))
- if_findError(tok, true);
- }
+ container = _settings->library.detectContainer(tok2); // innner container
+ } else
+ container = nullptr;
}
}
- else if (warning && Token::Match(tok, "std :: find|find_if (")) {
+ if (container && container->getAction(funcTok->str()) == Library::Container::FIND) {
+ if (if_findCompare(funcTok->next()))
+ continue;
+
+ if (warning && !container->stdStringLike)
+ if_findError(tok, false);
+ else if (performance && container->stdStringLike)
+ if_findError(tok, true);
+ } else if (warning && Token::Match(tok, "std :: find|find_if (")) {
// check that result is checked properly
if (!if_findCompare(tok->tokAt(3))) {
if_findError(tok, false);
diff --git a/lib/library.cpp b/lib/library.cpp
index ea900f631..2d0730b25 100644
--- a/lib/library.cpp
+++ b/lib/library.cpp
@@ -434,6 +434,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
action = Container::PUSH;
else if (actionName == "pop")
action = Container::POP;
+ else if (actionName == "find")
+ action = Container::FIND;
else
return Error(BAD_ATTRIBUTE_VALUE, actionName);
}
diff --git a/lib/library.h b/lib/library.h
index a1f787e02..a906fb90d 100644
--- a/lib/library.h
+++ b/lib/library.h
@@ -147,7 +147,7 @@ public:
}
enum Action {
- RESIZE, CLEAR, PUSH, POP,
+ RESIZE, CLEAR, PUSH, POP, FIND,
NO_ACTION
};
enum Yield {
diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp
index 7b35de41b..019f15007 100644
--- a/test/testlibrary.cpp
+++ b/test/testlibrary.cpp
@@ -297,6 +297,7 @@ private:
" \n"
" \n"
" \n"
+ " \n"
" \n"
" \n"
" \n"
@@ -336,6 +337,7 @@ private:
ASSERT_EQUALS(Library::Container::CLEAR, A.getAction("clear"));
ASSERT_EQUALS(Library::Container::PUSH, A.getAction("push_back"));
ASSERT_EQUALS(Library::Container::POP, A.getAction("pop_back"));
+ ASSERT_EQUALS(Library::Container::FIND, A.getAction("find"));
ASSERT_EQUALS(Library::Container::NO_ACTION, A.getAction("foo"));
ASSERT_EQUALS(B.type_templateArgNo, 1);
diff --git a/test/teststl.cpp b/test/teststl.cpp
index d9c5cfe2e..90159e1bf 100644
--- a/test/teststl.cpp
+++ b/test/teststl.cpp
@@ -1561,6 +1561,12 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
+ // ok (dereference, #6402)
+ check("void f(std::set s) {\n"
+ " if (s.find(12).member) { }\n"
+ "}");
+ ASSERT_EQUALS("", errout.str());
+
// ---------------------------
// std::find