diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6e873333d..1b3451b36 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6307,25 +6307,60 @@ static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *setting } } -static std::vector getInitListSize(const Token* tok, - const Library::Container* container, - bool known = true) +static std::vector getContainerValues(const Token* tok) { - std::vector args = getArguments(tok); - if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) || - (args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) { - std::vector values; - std::copy_if(args[0]->values().begin(), - args[0]->values().end(), + std::vector values; + if (tok) { + std::copy_if(tok->values().begin(), + tok->values().end(), std::back_inserter(values), std::mem_fn(&ValueFlow::Value::isContainerSizeValue)); - return values; } - ValueFlow::Value value(args.size()); + return values; +} + +static ValueFlow::Value makeContainerSizeValue(std::size_t s, bool known = true) +{ + ValueFlow::Value value(s); value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; if (known) value.setKnown(); - return {value}; + return value; +} + +static std::vector makeContainerSizeValue(const Token* tok, bool known = true) +{ + if (tok->hasKnownIntValue()) + return {makeContainerSizeValue(tok->values().front().intvalue, known)}; + return {}; +} + +static std::vector getInitListSize(const Token* tok, + const Library::Container* container, + bool known = true) +{ + std::vector args = getArguments(tok); + // Strings dont use an init list + if (!args.empty() && container->stdStringLike) { + if (astIsIntegral(args[0], false)) { + if (args.size() > 1) + return {makeContainerSizeValue(args[0], known)}; + } else if (astIsPointer(args[0])) { + // TODO: Try to read size of string literal + if (args.size() == 2 && astIsIntegral(args[1], false)) + return {makeContainerSizeValue(args[1], known)}; + } else if (astIsContainer(args[0])) { + if (args.size() == 1) + return getContainerValues(args[0]); + if (args.size() == 3) + return {makeContainerSizeValue(args[2], known)}; + } + return {}; + } else if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) || + (args.size() == 2 && astIsIterator(args[0]) && astIsIterator(args[1]))) { + return getContainerValues(args[0]); + } + return {makeContainerSizeValue(args.size(), known)}; } static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger * /*errorLogger*/, const Settings *settings) diff --git a/test/teststl.cpp b/test/teststl.cpp index e9579bc72..39bacbb4d 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -527,6 +527,16 @@ private: " return (*pv).at(42);\n" "}\n"); ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in expression '(*pv).at(42)' because '*pv' is empty and 'at' may be non-zero.\n", errout.str()); + + checkNormal("std::string f(const char* DirName) {\n" + " if (DirName == nullptr)\n" + " return {};\n" + " std::string Name{ DirName };\n" + " if (!Name.empty() && Name.back() != '\\')\n" + " Name += '\\';\n" + " return Name;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void outOfBoundsIndexExpression() {