mirror of
https://github.com/github/codeql.git
synced 2026-05-14 19:29:28 +02:00
Previously, apply_rules_inner snapshotted a node's fields by cloning the BTreeMap into a Vec<(FieldId, Vec<Id>)>, then built a fresh BTreeMap of new_fields for the rewritten Ids. For a node with N fields, this allocated 2N+1 things per visit (the snapshot Vec, N cloned children Vecs, the new BTreeMap entries) — even when nothing in the subtree was rewritten. Use std::mem::take to swap the parent's fields out by ownership: the recursion can mutate the AST (including pushing new nodes from rule firings) without any conflict, since we hold the owned BTreeMap locally. Iterate values_mut() and only allocate a fresh children Vec on the first divergence (lazy alloc): unchanged children stay in the existing slot. When done, swap the fields back. For a subtree with no rewrites, this is now zero allocations per node (modulo the recursion itself). For nodes with rewrites, it's one Vec allocation per field that contains a rewritten child, instead of two plus the BTreeMap rebuild.