diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index cf3cdb56187..eb5dc9e0f7a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -4243,28 +4243,33 @@ struct LifetimeStore { } }; -static bool isOwningVariables(const std::list& vars, int depth = 10) +static bool hasBorrowingVariables(const std::list& vars, const std::vector& args, int depth = 10) { if (depth < 0) return false; - return vars.empty() || std::all_of(vars.cbegin(), vars.cend(), [&](const Variable& var) { - if (var.isReference() || var.isPointer()) - return false; + return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) { const ValueType* vt = var.valueType(); if (vt) { - if (vt->pointer > 0) + if (vt->pointer > 0 && + std::none_of(args.begin(), args.end(), [vt](const Token* arg) { + return arg->valueType() && arg->valueType()->type == vt->type; + })) return false; - if (vt->isPrimitive()) + if (vt->pointer > 0) return true; - if (vt->isEnum()) + if (vt->reference != Reference::None) return true; + if (vt->isPrimitive()) + return false; + if (vt->isEnum()) + return false; // TODO: Check container inner type if (vt->type == ValueType::CONTAINER && vt->container) - return !vt->container->view; + return vt->container->view; if (vt->typeScope) - return isOwningVariables(vt->typeScope->varlist, depth - 1); + return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1); } - return false; + return true; }); } @@ -4341,7 +4346,7 @@ static void valueFlowLifetimeUserConstructor(Token* tok, else ls.byVal(tok, tokenlist, errorLogger, settings); }); - } else if (!isOwningVariables(constructor->nestedIn->varlist)) { + } else if (hasBorrowingVariables(constructor->nestedIn->varlist, args)) { LifetimeStore::forEach(args, "Passed to constructor of '" + name + "'.", ValueFlow::Value::LifetimeKind::SubObject, diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 0ee1d84132a..159782782d3 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -3647,6 +3647,19 @@ class TestAutoVariables : public TestFixture { "}\n", true); ASSERT_EQUALS("", errout.str()); + + check("struct S {\n" + " explicit S(const char* p) { m = p; }\n" + " void g();\n" + " std::string m;\n" + " int* t{};\n" + "};\n" + "void f(const std::stringstream& buffer) {\n" + " S s(buffer.str().c_str());\n" + " s.g();\n" + "}\n", + true); + ASSERT_EQUALS("", errout.str()); } void danglingLifetimeAggegrateConstructor() {