@@ -3031,22 +3031,32 @@ static bool isNotLifetimeValue(const ValueFlow::Value& val)
30313031 return !val.isLifetimeValue ();
30323032}
30333033
3034+ static bool isLifetimeOwned (const ValueType* vtParent)
3035+ {
3036+ if (vtParent->container )
3037+ return !vtParent->container ->view ;
3038+ return vtParent->type == ValueType::CONTAINER;
3039+ }
3040+
30343041static bool isLifetimeOwned (const ValueType *vt, const ValueType *vtParent)
30353042{
30363043 if (!vtParent)
30373044 return false ;
30383045 if (!vt) {
3039- if (vtParent-> type == ValueType::CONTAINER )
3046+ if (isLifetimeOwned ( vtParent) )
30403047 return true ;
30413048 return false ;
30423049 }
3050+ // If converted from iterator to pointer then the iterator is most likely a pointer
3051+ if (vtParent->pointer == 1 && vt->pointer == 0 && vt->type == ValueType::ITERATOR)
3052+ return false ;
30433053 if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE) {
30443054 if (vt->pointer != vtParent->pointer )
30453055 return true ;
30463056 if (vt->type != vtParent->type ) {
30473057 if (vtParent->type == ValueType::RECORD)
30483058 return true ;
3049- if (vtParent-> type == ValueType::CONTAINER )
3059+ if (isLifetimeOwned ( vtParent) )
30503060 return true ;
30513061 }
30523062 }
@@ -3062,6 +3072,8 @@ static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent)
30623072 return false ;
30633073 if (vt->pointer > 0 && vt->pointer == vtParent->pointer )
30643074 return true ;
3075+ if (vtParent->container && vtParent->container ->view )
3076+ return true ;
30653077 if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE && vtParent->container == vt->container ) {
30663078 if (vtParent->pointer > vt->pointer )
30673079 return true ;
@@ -3146,6 +3158,42 @@ static bool isDifferentType(const Token* src, const Token* dst)
31463158 return false ;
31473159}
31483160
3161+ static std::vector<ValueType> getParentValueTypes (const Token* tok, const Settings* settings = nullptr )
3162+ {
3163+ if (!tok)
3164+ return {};
3165+ if (!tok->astParent ())
3166+ return {};
3167+ if (Token::Match (tok->astParent (), " (|{|," )) {
3168+ int argn = -1 ;
3169+ const Token* ftok = getTokenArgumentFunction (tok, argn);
3170+ if (ftok && ftok->function ()) {
3171+ std::vector<ValueType> result;
3172+ std::vector<const Variable*> argsVars = getArgumentVars (ftok, argn);
3173+ for (const Variable* var : getArgumentVars (ftok, argn)) {
3174+ if (!var)
3175+ continue ;
3176+ if (!var->valueType ())
3177+ continue ;
3178+ result.push_back (*var->valueType ());
3179+ }
3180+ return result;
3181+ }
3182+ }
3183+ if (settings && Token::Match (tok->astParent ()->tokAt (-2 ), " . push_back|push_front|insert|push (" ) &&
3184+ astIsContainer (tok->astParent ()->tokAt (-2 )->astOperand1 ())) {
3185+ const Token* contTok = tok->astParent ()->tokAt (-2 )->astOperand1 ();
3186+ const ValueType* vtCont = contTok->valueType ();
3187+ if (!vtCont->containerTypeToken )
3188+ return {};
3189+ ValueType vtParent = ValueType::parseDecl (vtCont->containerTypeToken , settings);
3190+ return {std::move (vtParent)};
3191+ }
3192+ if (tok->astParent ()->valueType ())
3193+ return {*tok->astParent ()->valueType ()};
3194+ return {};
3195+ }
3196+
31493197bool isLifetimeBorrowed (const Token *tok, const Settings *settings)
31503198{
31513199 if (!tok)
@@ -3605,6 +3653,13 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
36053653 }
36063654 if (update)
36073655 valueFlowForwardLifetime (tok->next (), tokenlist, errorLogger, settings);
3656+ } else if (tok->valueType ()) {
3657+ // TODO: Propagate lifetimes with library functions
3658+ if (settings->library .getFunction (tok->previous ()))
3659+ return ;
3660+ // Assume constructing the valueType
3661+ valueFlowLifetimeConstructor (tok, tokenlist, errorLogger, settings);
3662+ valueFlowForwardLifetime (tok->next (), tokenlist, errorLogger, settings);
36083663 }
36093664}
36103665
@@ -3673,7 +3728,13 @@ static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, Error
36733728 Token* parent = tok->astParent ();
36743729 while (Token::simpleMatch (parent, " ," ))
36753730 parent = parent->astParent ();
3676- if (Token::simpleMatch (parent, " {" ) && hasInitList (parent->astParent ())) {
3731+ if (Token::Match (tok, " {|(" ) && astIsContainerView (tok) && !tok->function ()) {
3732+ std::vector<const Token*> args = getArguments (tok);
3733+ if (args.size () == 1 && astIsContainerOwned (args.front ())) {
3734+ LifetimeStore{args.front (), " Passed to container view." , ValueFlow::Value::LifetimeKind::SubObject}.byRef (
3735+ tok, tokenlist, errorLogger, settings);
3736+ }
3737+ } else if (Token::simpleMatch (parent, " {" ) && hasInitList (parent->astParent ())) {
36773738 valueFlowLifetimeConstructor (tok, Token::typeOf (parent->previous ()), tokenlist, errorLogger, settings);
36783739 } else if (Token::simpleMatch (tok, " {" ) && hasInitList (parent)) {
36793740 std::vector<const Token *> args = getArguments (tok);
@@ -3764,6 +3825,16 @@ static bool isDecayedPointer(const Token *tok)
37643825 return astIsPointer (tok->astParent ());
37653826}
37663827
3828+ static bool isConvertedToView (const Token* tok, const Settings* settings)
3829+ {
3830+ std::vector<ValueType> vtParents = getParentValueTypes (tok, settings);
3831+ return std::any_of (vtParents.begin (), vtParents.end (), [&](const ValueType& vt) {
3832+ if (!vt.container )
3833+ return false ;
3834+ return vt.container ->view ;
3835+ });
3836+ }
3837+
37673838static void valueFlowLifetime (TokenList *tokenlist, SymbolDatabase*, ErrorLogger *errorLogger, const Settings *settings)
37683839{
37693840 for (Token *tok = tokenlist->front (); tok; tok = tok->next ()) {
@@ -3861,6 +3932,13 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
38613932 valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings);
38623933 }
38633934 }
3935+ // Converting to container view
3936+ else if (astIsContainerOwned (tok) && isConvertedToView (tok, settings)) {
3937+ LifetimeStore ls =
3938+ LifetimeStore{tok, " Converted to container view" , ValueFlow::Value::LifetimeKind::SubObject};
3939+ ls.byRef (tok, tokenlist, errorLogger, settings);
3940+ valueFlowForwardLifetime (tok, tokenlist, errorLogger, settings);
3941+ }
38643942 // container lifetimes
38653943 else if (astIsContainer (tok)) {
38663944 Token * parent = astParentSkipParens (tok);
@@ -3902,6 +3980,16 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
39023980 continue ;
39033981 toks.push_back (v.tokvalue );
39043982 }
3983+ } else if (astIsContainerView (tok)) {
3984+ for (const ValueFlow::Value& v : tok->values ()) {
3985+ if (!v.isLifetimeValue ())
3986+ continue ;
3987+ if (!v.tokvalue )
3988+ continue ;
3989+ if (!astIsContainerOwned (v.tokvalue ))
3990+ continue ;
3991+ toks.push_back (v.tokvalue );
3992+ }
39053993 } else {
39063994 toks = {tok};
39073995 }
0 commit comments