fn walk_guards<'hir>(
gcx: Gcx<'hir>,
hir: &'hir Hir<'hir>,
stmts: &'hir [Stmt<'hir>],
recipient: VariableId,
token: VariableId,
delegations: &[FunctionId],
unstable_code_delegations: &[FunctionId],
bypass: bool,
seen: &mut Vec<FunctionId>,
walk: &mut GuardWalk,
)Expand description
Reads a body in statement order and judges the delegated mints against the guards. A code-less
proof may cover a later delegation, but a callback must run after ownership is established to
match _safeMint: the receiver can inspect ownerOf, balances, or reenter during the hook.
Such a callback covers delegations still pending, the revert undoing them, unless a statement
in between may leave the function successfully, keeping the unacknowledged token:
super._mint(to, id); if (id == 0) return; require(hook...) walks out with token zero standing.
The recognized guard shapes are a closed set, because a hook call that merely appears inside
a condition proves nothing about whether the revert depends on its answer. They are:
require/assert on an acceptance condition, if (hook != selector) <exits>,
if (hook == selector) {} else <exits>, and any of those reached through a function or
modifier. A callback helper receives both identities, the way OpenZeppelin factors
_checkOnERC721Received out of _safeMint; a code-less proof needs only the recipient.
Branches are read separately and merged: coverage holds only when every path checked, while
a pending or escaping path taints the whole. The branch a to.code.length test dedicates to
accounts starts covered, an account always accepting the token. A loop body may run zero
times, so nothing in one is credited, while the delegations and escapes it may hold still
count.
Everything else reports, a try whose catch may swallow the refusal included, and so are
an answer stored in a local and a helper returning it as a bool. Following the value
across statements would take a dataflow analysis this detector does not run.