From fec2914700f00d67dc4f2e31cc6ad7ee7b7c3778 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 9 Aug 2020 22:52:03 -0500 Subject: [PATCH] Add tests for container changes --- lib/valueflow.cpp | 24 ++++++++++++++++++++++++ test/cfg/qt.cpp | 4 ++-- test/cfg/wxwidgets.cpp | 6 ++++-- test/testvalueflow.cpp | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c5c631671..8aedacfb6 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5640,6 +5640,11 @@ struct ContainerVariableForwardAnalyzer : VariableForwardAnalyzer { if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) { return rhsval.isKnown() && rhsval.isContainerSizeValue(); })) return Action::Read | Action::Write; } + } else if (Token::Match(tok, "%name% . %name% (")) { + Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); + if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) + return Action::Read | Action::Write; + const Token* arg = tok->tokAt(4); } return Action::None; } @@ -5664,6 +5669,12 @@ struct ContainerVariableForwardAnalyzer : VariableForwardAnalyzer { } } } + } else if (Token::Match(tok, "%name% . %name% (")) { + Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); + if (action == Library::Container::Action::PUSH) + value->intvalue++; + if (action == Library::Container::Action::POP) + value->intvalue--; } } @@ -5885,6 +5896,19 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold value.setKnown(); valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist); } + } else if (Token::Match(tok, "%var% . %name% (") && tok->valueType() && tok->valueType()->container) { + Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); + if (action == Library::Container::Action::CLEAR) { + ValueFlow::Value value(0); + value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; + value.setKnown(); + valueFlowContainerForward(tok->next(), tok->variable(), value, tokenlist); + } else if (action == Library::Container::Action::RESIZE && tok->tokAt(4)->hasKnownIntValue()) { + ValueFlow::Value value(tok->tokAt(4)->values().front()); + value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; + value.setKnown(); + valueFlowContainerForward(tok->next(), tok->variable(), value, tokenlist); + } } } } diff --git a/test/cfg/qt.cpp b/test/cfg/qt.cpp index 87d838c7a..59b5dde9f 100644 --- a/test/cfg/qt.cpp +++ b/test/cfg/qt.cpp @@ -88,7 +88,7 @@ void QList1(QList intListArg) QList qstringList2 = {"one", "two"}; (void)qstringList2[1]; qstringList2.clear(); - // TODO: cppcheck-suppress containerOutOfBounds #9243 + // cppcheck-suppress containerOutOfBounds (void)qstringList2[1]; QList qstringList3; @@ -117,7 +117,7 @@ void QList1(QList intListArg) qstringList4.append("a"); (void)qstringList4[0]; qstringList4.clear(); - // TODO: cppcheck-suppress containerOutOfBounds #9243 + // cppcheck-suppress containerOutOfBounds (void)qstringList4[0]; } diff --git a/test/cfg/wxwidgets.cpp b/test/cfg/wxwidgets.cpp index abe538612..435391642 100644 --- a/test/cfg/wxwidgets.cpp +++ b/test/cfg/wxwidgets.cpp @@ -33,7 +33,8 @@ wxString containerOutOfBounds_wxArrayString(void) wxArrayString a; a.Add("42"); a.Clear(); - // cppcheck-suppress containerOutOfBounds + // TODO: wxArrayString is defined to be a vector + // TODO: cppcheck-suppress containerOutOfBounds return a[0]; } @@ -42,7 +43,8 @@ int containerOutOfBounds_wxArrayInt(void) wxArrayInt a; a.Add(42); a.Clear(); - // cppcheck-suppress containerOutOfBounds + // TODO: wxArrayString is defined to be a vector + // TODO: cppcheck-suppress containerOutOfBounds return a[0]; } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 051def698..5220c9f2e 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -324,6 +324,12 @@ private: return tok ? tok->values() : std::list(); } + std::list tokenValues(const char code[], const char tokstr[], ValueFlow::Value::ValueType vt, const Settings *s = nullptr) { + std::list values = tokenValues(code, tokstr, s); + values.remove_if([&](const ValueFlow::Value& v) { return v.valueType != vt; }); + return values; + } + ValueFlow::Value valueOfTok(const char code[], const char tokstr[]) { std::list values = tokenValues(code, tokstr); return values.size() == 1U && !values.front().isTokValue() ? values.front() : ValueFlow::Value(); @@ -4439,6 +4445,32 @@ private: " x = s + s;\n" "}"; ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "+"), 8)); + + code = "void f(const std::vector &ints) {\n" + " ints.clear();\n" + " ints.front();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 0)); + + code = "void f(const std::vector &ints) {\n" + " ints.resize(3);\n" + " ints.front();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 3)); + + code = "void f(const std::vector &ints) {\n" + " ints.resize(3);\n" + " ints.push_back(3);\n" + " ints.front();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 4)); + + code = "void f(const std::vector &ints) {\n" + " ints.resize(3);\n" + " ints.pop_back();\n" + " ints.front();\n" + "}"; + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 2)); } void valueFlowDynamicBufferSize() {