| 2450 | } |
| 2451 | |
| 2452 | static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) |
| 2453 | { |
| 2454 | if (!Token::Match(tok, "%name% (")) |
| 2455 | return; |
| 2456 | Token* memtok = nullptr; |
| 2457 | if (Token::Match(tok->astParent(), ". %name% (") && astIsRHS(tok)) |
| 2458 | memtok = tok->astParent()->astOperand1(); |
| 2459 | const int returnContainer = settings.library.returnValueContainer(tok); |
| 2460 | if (returnContainer >= 0) { |
| 2461 | std::vector<const Token *> args = getArguments(tok); |
| 2462 | for (int argnr = 1; argnr <= args.size(); ++argnr) { |
| 2463 | const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr); |
| 2464 | if (!i) |
| 2465 | continue; |
| 2466 | if (i->container != returnContainer) |
| 2467 | continue; |
| 2468 | const Token * const argTok = args[argnr - 1]; |
| 2469 | bool forward = false; |
| 2470 | for (ValueFlow::Value val : argTok->values()) { |
| 2471 | if (!val.isLifetimeValue()) |
| 2472 | continue; |
| 2473 | val.errorPath.emplace_back(argTok, "Passed to '" + tok->str() + "'."); |
| 2474 | setTokenValue(tok->next(), std::move(val), settings); |
| 2475 | forward = true; |
| 2476 | } |
| 2477 | // Check if lifetime is available to avoid adding the lifetime twice |
| 2478 | if (forward) { |
| 2479 | valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); |
| 2480 | break; |
| 2481 | } |
| 2482 | } |
| 2483 | } else if (Token::Match(tok->tokAt(-2), "std :: ref|cref|tie|front_inserter|back_inserter")) { |
| 2484 | for (const Token *argtok : getArguments(tok)) { |
| 2485 | LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byRef( |
| 2486 | tok->next(), tokenlist, errorLogger, settings); |
| 2487 | } |
| 2488 | } else if (Token::Match(tok->tokAt(-2), "std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind")) { |
| 2489 | for (const Token *argtok : getArguments(tok)) { |
| 2490 | LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal( |
| 2491 | tok->next(), tokenlist, errorLogger, settings); |
| 2492 | } |
| 2493 | } else if (memtok && Token::Match(tok->astParent(), ". push_back|push_front|insert|push|assign") && |
| 2494 | astIsNonStringContainer(memtok)) { |
| 2495 | std::vector<const Token *> args = getArguments(tok); |
| 2496 | const std::size_t n = args.size(); |
| 2497 | if (n > 1 && Token::typeStr(args[n - 2]) == Token::typeStr(args[n - 1]) && |
| 2498 | ((astIsIterator(args[n - 2]) && astIsIterator(args[n - 1])) || |
| 2499 | (astIsPointer(args[n - 2]) && astIsPointer(args[n - 1])))) { |
| 2500 | LifetimeStore{ |
| 2501 | args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} |
| 2502 | .byDerefCopy(memtok, tokenlist, errorLogger, settings); |
| 2503 | } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) { |
| 2504 | LifetimeStore{ |
| 2505 | args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} |
| 2506 | .byVal(memtok, tokenlist, errorLogger, settings); |
| 2507 | } |
| 2508 | } else if (tok->function()) { |
| 2509 | const Function *f = tok->function(); |
no test coverage detected