Expand description
Structural-mode candidate generation from the control-flow skeleton.
The other two candidate stages both describe a unit by the pieces it is
made of: crate::candidate indexes statement windows and subtrees and
pairs units that share one exactly, and crate::near_match treats those
same pieces as a set and pairs units whose sets overlap. Both lose the same
edit, and lose it hardest where code is smallest.
Inserting a statement rewrites every piece that encloses it. In a short function almost every piece encloses almost everything: the body block, the loop, the whole unit. A copy with two statements added can therefore share no window and no subtree with its original, so the exact stage proposes nothing and the set stage sees two disjoint sets — while a reader would call them the same function. The loss is not a threshold that could be relaxed; there is no overlap left to find.
What such an edit does leave untouched is the shape of the control flow. A
statement that is not a loop, a branch, a match or a jump does not appear in
crate::features::CfgFeature::skeleton_hash at all, so a unit and its
gapped copy hash to the same skeleton. This stage indexes that hash and
pairs the units that share one. It is an exact-match index like the seed
layer, not an approximation: units either have the same skeleton or they do
not.
A skeleton says much less than a subtree does — it is why this stage
proposes rather than concludes, and every pair it emits is judged by
crate::verify like any other. Three controls keep what it proposes
bounded (AGENTS.md invariant 10), and each counts what it drops:
- a minimum skeleton size — a unit with fewer than
ControlFlowConfig::min_opscontrol operations has a skeleton so common that sharing it is no evidence at all, and is not indexed; - high-frequency suppression — a skeleton shared by more than
ControlFlowConfig::posting_capunits is common structure rather than a family of copies, and its whole posting list is dropped; - a length-ratio gate and a global pair budget — as in the near-match stage, a pair spanning too great a size difference is not a gapped copy, and posting lists are paired rarest-first so exhaustion sacrifices the lowest-signal candidates.
As in crate::candidate, the budget stops between posting lists and never
inside one: a list compared only in part reaches grouping as a family whose
members disagree, and comes back out as the stray pairs the ceiling allowed
rather than as the one group it is. What a list costs is counted after the
length-ratio gate, so a list of widely differing sizes is charged for the
few pairs it really contributes.
Output is a pure function of the input: the index is ordered, pairing is deterministic, and the emitted pairs are sorted.
Structs§
- Control
Flow Config - Tuning for control-flow candidate generation.
- Control
Flow Pair - A control-flow candidate: two units with the same control-flow skeleton.
Canonical:
a < b. - Control
Flow Set - The control-flow stage’s output: candidate unit pairs plus funnel counters.
- Control
Flow Stats - Counters describing what control-flow generation saw and dropped.
Constants§
- DEFAULT_
MAX_ LENGTH_ RATIO - Default largest unit-size ratio a pair may span.
- DEFAULT_
MIN_ OPS - Default smallest skeleton size, in control operations, for a unit to be indexed.
- DEFAULT_
PAIR_ BUDGET - Default global candidate-pair upper bound.
- DEFAULT_
POSTING_ CAP - Default posting-list cap; longer lists are common structure and dropped.
Functions§
- generate
- Generate control-flow candidate unit pairs across
files.