| 563 | } |
| 564 | |
| 565 | void CheckAutoVariablesImpl::checkVarLifetimeScope(const Token * start, const Token * end) |
| 566 | { |
| 567 | const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); |
| 568 | if (!start) |
| 569 | return; |
| 570 | const Scope * scope = start->scope(); |
| 571 | if (!scope) |
| 572 | return; |
| 573 | // If the scope is not set correctly then skip checking it |
| 574 | if (scope->bodyStart != start) |
| 575 | return; |
| 576 | const bool returnRef = Function::returnsReference(scope->function); |
| 577 | for (const Token *tok = start; tok && tok != end; tok = tok->next()) { |
| 578 | // Return reference from function |
| 579 | if (returnRef && Token::simpleMatch(tok->astParent(), "return")) { |
| 580 | for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok, mSettings, true)) { |
| 581 | if (!printInconclusive && lt.inconclusive) |
| 582 | continue; |
| 583 | const Variable* var = lt.token->variable(); |
| 584 | if (var && !var->isGlobal() && !var->isStatic() && !var->isReference() && !var->isRValueReference() && |
| 585 | isInScope(var->nameToken(), tok->scope())) { |
| 586 | errorReturnReference(tok, lt.errorPath, lt.inconclusive); |
| 587 | break; |
| 588 | } |
| 589 | if (isDeadTemporary(lt.token, nullptr, mSettings.library)) { |
| 590 | errorReturnTempReference(tok, lt.errorPath, lt.inconclusive); |
| 591 | break; |
| 592 | } |
| 593 | } |
| 594 | // Assign reference to non-local variable |
| 595 | } else if (Token::Match(tok->previous(), "&|&& %var% =") && tok->astParent() == tok->next() && |
| 596 | tok->variable() && tok->variable()->nameToken() == tok && |
| 597 | tok->variable()->declarationId() == tok->varId() && tok->variable()->isStatic() && |
| 598 | !tok->variable()->isArgument()) { |
| 599 | ErrorPath errorPath; |
| 600 | const Variable *var = ValueFlow::getLifetimeVariable(tok, errorPath, mSettings); |
| 601 | if (var && isInScope(var->nameToken(), tok->scope())) { |
| 602 | errorDanglingReference(tok, var, std::move(errorPath)); |
| 603 | continue; |
| 604 | } |
| 605 | // Reference to temporary |
| 606 | } else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) { |
| 607 | for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(getParentLifetime(tok), mSettings)) { |
| 608 | if (!printInconclusive && lt.inconclusive) |
| 609 | continue; |
| 610 | const Token * tokvalue = lt.token; |
| 611 | if (isDeadTemporary(tokvalue, tok, mSettings.library)) { |
| 612 | errorDanglingTempReference(tok, lt.errorPath, lt.inconclusive); |
| 613 | break; |
| 614 | } |
| 615 | } |
| 616 | } |
| 617 | const bool escape = Token::simpleMatch(tok->astParent(), "throw") || |
| 618 | (Token::simpleMatch(tok->astParent(), "return") && !Function::returnsStandardType(scope->function)); |
| 619 | std::unordered_set<const Token*> exprs; |
| 620 | for (const ValueFlow::Value& val:tok->values()) { |
| 621 | if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue()) |
| 622 | continue; |
nothing calls this directly
no test coverage detected