@@ -517,6 +517,53 @@ static bool isAssignedToNonLocal(const Token* tok)
517517 return !var->isLocal () || var->isStatic ();
518518}
519519
520+ static std::vector<const Token*> getParentMembers (const Token* tok)
521+ {
522+ if (!tok)
523+ return {};
524+ if (!Token::simpleMatch (tok->astParent (), " ." ))
525+ return {tok};
526+ const Token* parent = tok;
527+ while (Token::simpleMatch (parent->astParent (), " ." ))
528+ parent = parent->astParent ();
529+ std::vector<const Token*> result;
530+ for (const Token* tok2 : astFlatten (parent, " ." )) {
531+ if (Token::simpleMatch (tok2, " (" ) && Token::simpleMatch (tok2->astOperand1 (), " ." )) {
532+ std::vector<const Token*> sub = getParentMembers (tok2->astOperand1 ());
533+ result.insert (result.end (), sub.begin (), sub.end ());
534+ }
535+ result.push_back (tok2);
536+ }
537+ return result;
538+ }
539+
540+ static const Token* getParentLifetime (bool cpp, const Token* tok, const Library* library)
541+ {
542+ std::vector<const Token*> members = getParentMembers (tok);
543+ if (members.size () < 2 )
544+ return tok;
545+ // Find the first local variable or temporary
546+ auto it = std::find_if (members.rbegin (), members.rend (), [&](const Token* tok2) {
547+ const Variable* var = tok2->variable ();
548+ if (var) {
549+ return var->isLocal () || var->isArgument ();
550+ } else {
551+ return isTemporary (cpp, tok2, library);
552+ }
553+ });
554+ if (it == members.rend ())
555+ return tok;
556+ // If any of the submembers are borrowed types then stop
557+ if (std::any_of (it.base () - 1 , members.end () - 1 , [&](const Token* tok2) {
558+ if (astIsPointer (tok2) || astIsContainerView (tok2) || astIsIterator (tok2))
559+ return true ;
560+ const Variable* var = tok2->variable ();
561+ return var && var->isReference ();
562+ }))
563+ return nullptr ;
564+ return *it;
565+ }
566+
520567void CheckAutoVariables::checkVarLifetimeScope (const Token * start, const Token * end)
521568{
522569 const bool printInconclusive = mSettings ->certainty .isEnabled (Certainty::inconclusive);
@@ -569,13 +616,16 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
569616 }
570617 }
571618 const bool escape = Token::Match (tok->astParent (), " return|throw" );
619+ std::unordered_set<const Token*> exprs;
572620 for (const ValueFlow::Value& val:tok->values ()) {
573621 if (!val.isLocalLifetimeValue () && !val.isSubFunctionLifetimeValue ())
574622 continue ;
575623 if (!printInconclusive && val.isInconclusive ())
576624 continue ;
577- for (const LifetimeToken& lt :
578- getLifetimeTokens (getParentLifetime (val.tokvalue ), escape || isAssignedToNonLocal (tok))) {
625+ const Token* parent = getParentLifetime (mTokenizer ->isCPP (), val.tokvalue , &mSettings ->library );
626+ if (!exprs.insert (parent).second )
627+ continue ;
628+ for (const LifetimeToken& lt : getLifetimeTokens (parent, escape || isAssignedToNonLocal (tok))) {
579629 const Token * tokvalue = lt.token ;
580630 if (val.isLocalLifetimeValue ()) {
581631 if (escape) {
0 commit comments