| 1517 | |
| 1518 | template<class Predicate> |
| 1519 | static std::vector<ValueFlow::LifetimeToken> getLifetimeTokens(const Token* tok, |
| 1520 | bool escape, |
| 1521 | ErrorPath errorPath, |
| 1522 | Predicate pred, |
| 1523 | const Settings& settings, |
| 1524 | int depth = 20) |
| 1525 | { |
| 1526 | if (!tok) |
| 1527 | return std::vector<ValueFlow::LifetimeToken> {}; |
| 1528 | if (Token::simpleMatch(tok, "...")) |
| 1529 | return std::vector<ValueFlow::LifetimeToken>{}; |
| 1530 | const Variable *var = tok->variable(); |
| 1531 | if (pred(tok)) |
| 1532 | return {{tok, std::move(errorPath)}}; |
| 1533 | if (depth < 0) |
| 1534 | return {{tok, std::move(errorPath)}}; |
| 1535 | if (var && var->declarationId() == tok->varId()) { |
| 1536 | if (var->isReference() || var->isRValueReference()) { |
| 1537 | const Token * const varDeclEndToken = var->declEndToken(); |
| 1538 | if (!varDeclEndToken) |
| 1539 | return {{tok, true, std::move(errorPath)}}; |
| 1540 | if (var->isArgument()) { |
| 1541 | errorPath.emplace_back(varDeclEndToken, "Passed to reference."); |
| 1542 | return {{tok, true, std::move(errorPath)}}; |
| 1543 | } |
| 1544 | if (Token::Match(varDeclEndToken, "=|{")) { |
| 1545 | errorPath.emplace_back(varDeclEndToken, "Assigned to reference."); |
| 1546 | const Token *vartok = varDeclEndToken->astOperand2(); |
| 1547 | const bool temporary = isTemporary(vartok, nullptr, true); |
| 1548 | const bool nonlocal = var->isStatic() || var->isGlobal(); |
| 1549 | if (vartok == tok || (nonlocal && temporary) || |
| 1550 | (!escape && (var->isConst() || var->isRValueReference()) && temporary)) |
| 1551 | return {{tok, true, std::move(errorPath)}}; |
| 1552 | if (vartok) |
| 1553 | return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1); |
| 1554 | } else if (Token::simpleMatch(var->nameToken()->astParent(), ":") && |
| 1555 | var->nameToken()->astParent()->astParent() && |
| 1556 | Token::simpleMatch(var->nameToken()->astParent()->astParent()->previous(), "for (")) { |
| 1557 | errorPath.emplace_back(var->nameToken(), "Assigned to reference."); |
| 1558 | const Token* vartok = var->nameToken(); |
| 1559 | if (vartok == tok) |
| 1560 | return {{tok, true, std::move(errorPath)}}; |
| 1561 | const Token* contok = var->nameToken()->astParent()->astOperand2(); |
| 1562 | if (astIsContainer(contok)) |
| 1563 | return ValueFlow::LifetimeToken::setAddressOf( |
| 1564 | getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1), |
| 1565 | false); |
| 1566 | return std::vector<ValueFlow::LifetimeToken>{}; |
| 1567 | } else { |
| 1568 | return std::vector<ValueFlow::LifetimeToken> {}; |
| 1569 | } |
| 1570 | } |
| 1571 | } else if (Token::Match(tok->previous(), "%name% (")) { |
| 1572 | const Function *f = tok->previous()->function(); |
| 1573 | if (f) { |
| 1574 | if (!Function::returnsReference(f)) |
| 1575 | return {{tok, std::move(errorPath)}}; |
| 1576 | std::vector<ValueFlow::LifetimeToken> result; |
no test coverage detected