| 1953 | } |
| 1954 | |
| 1955 | static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) |
| 1956 | { |
| 1957 | // Forward lifetimes to constructed variable |
| 1958 | if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) { |
| 1959 | std::list<ValueFlow::Value> values = tok->values(); |
| 1960 | values.remove_if(&isNotLifetimeValue); |
| 1961 | valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), std::move(values), tokenlist, errorLogger, settings); |
| 1962 | return; |
| 1963 | } |
| 1964 | Token *parent = tok->astParent(); |
| 1965 | while (parent && parent->str() == ",") |
| 1966 | parent = parent->astParent(); |
| 1967 | if (!parent) |
| 1968 | return; |
| 1969 | // Assignment |
| 1970 | if (parent->str() == "=" && (!parent->astParent() || Token::simpleMatch(parent->astParent(), ";"))) { |
| 1971 | // Rhs values.. |
| 1972 | if (!parent->astOperand2() || parent->astOperand2()->values().empty()) |
| 1973 | return; |
| 1974 | |
| 1975 | if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings)) |
| 1976 | return; |
| 1977 | |
| 1978 | const Token* expr = getLHSVariableToken(parent); |
| 1979 | if (!expr) |
| 1980 | return; |
| 1981 | |
| 1982 | if (expr->exprId() == 0) |
| 1983 | return; |
| 1984 | |
| 1985 | const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr); |
| 1986 | |
| 1987 | // Only forward lifetime values |
| 1988 | std::list<ValueFlow::Value> values = parent->astOperand2()->values(); |
| 1989 | values.remove_if(&isNotLifetimeValue); |
| 1990 | // Dont forward lifetimes that overlap |
| 1991 | values.remove_if([&](const ValueFlow::Value& value) { |
| 1992 | return findAstNode(value.tokvalue, [&](const Token* child) { |
| 1993 | return child->exprId() == expr->exprId(); |
| 1994 | }); |
| 1995 | }); |
| 1996 | |
| 1997 | // Skip RHS |
| 1998 | Token* nextExpression = nextAfterAstRightmostLeaf(parent); |
| 1999 | |
| 2000 | if (expr->exprId() > 0) { |
| 2001 | valueFlowForward(nextExpression, endOfVarScope->next(), expr, values, tokenlist, errorLogger, settings); |
| 2002 | |
| 2003 | for (ValueFlow::Value& val : values) { |
| 2004 | if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address) |
| 2005 | val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject; |
| 2006 | } |
| 2007 | // TODO: handle `[` |
| 2008 | if (Token::simpleMatch(parent->astOperand1(), ".")) { |
| 2009 | const Token* parentLifetime = |
| 2010 | getParentLifetime(parent->astOperand1()->astOperand2(), settings.library); |
| 2011 | if (parentLifetime && parentLifetime->exprId() > 0) { |
| 2012 | valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings); |
no test coverage detected