Summary
The Checker trait (src/checker.rs:168-231) is a ~13-method mega-trait
with no default bodies for the trivial predicates, making "add a language"
a copy-paste ritual and embedding signature inconsistencies. 2.0 is the
natural window to reshape it (it is #[doc(hidden)] and already slated for
reconsideration per STABILITY.md). Three related cleanups:
(a) Default bodies for the "almost always false/empty" predicates
is_comment, is_useful_comment, is_func_space, is_func,
is_closure, is_call, is_non_arg, is_string, is_else_if,
is_primitive are all required (no defaults). Concretely this forces
pure-boilerplate stubs: PreprocCode (src/checker.rs:233-271) and
CcommentCode (:273-311) are almost entirely false-returning, and
BashCode::is_closure (:1407) is a forced stub. is_primitive,
is_closure, is_useful_comment, is_non_arg have an obviously-safe
false default — a new language can't be told by the compiler that false
is correct.
Fix: give those predicates -> false defaults (deletes hundreds of
stub lines). Optionally split into CommentClassifier / SpaceClassifier
/ OperandClassifier sub-traits.
(b) is_primitive(id: u16) breaks the &Node convention
src/checker.rs:178 — fn is_primitive(_id: u16) -> bool;. Every other
predicate takes &Node. The sole caller already has the &Node
(src/metrics/halstead.rs:382 does T::is_primitive(node.kind_id())).
Passing a bare u16 where the rest of the trait passes a domain type is
the "two same-typed primitives" footgun (AGENTS.md) and forecloses
primitive checks that need children/text.
Fix: fn is_primitive(_node: &Node) -> bool with default false.
(c) Narrow count_specific_ancestors from ParserTrait to Checker
src/node.rs:237 — count_specific_ancestors<T: ParserTrait> instantiates
the full 15-associated-type ParserTrait purely to call
T::Checker::is_else_if. Callers pass PythonParser etc.
(src/metrics/cognitive.rs:421, loc.rs:1014).
Fix: bound on <C: Checker> and call C::is_else_if; callers pass
PythonCode. Internal (pub(crate)), so fixable anytime, but belongs with
the trait reshape.
Why it matters for 2.x
Default bodies and the is_primitive signature change are best landed with
the #[doc(hidden)]-trait fate decision already on the 2.0 roadmap (#505).
Part of #505. Label: enhancement.
Summary
The
Checkertrait (src/checker.rs:168-231) is a ~13-method mega-traitwith no default bodies for the trivial predicates, making "add a language"
a copy-paste ritual and embedding signature inconsistencies.
2.0is thenatural window to reshape it (it is
#[doc(hidden)]and already slated forreconsideration per STABILITY.md). Three related cleanups:
(a) Default bodies for the "almost always false/empty" predicates
is_comment,is_useful_comment,is_func_space,is_func,is_closure,is_call,is_non_arg,is_string,is_else_if,is_primitiveare all required (no defaults). Concretely this forcespure-boilerplate stubs:
PreprocCode(src/checker.rs:233-271) andCcommentCode(:273-311) are almost entirelyfalse-returning, andBashCode::is_closure(:1407) is a forced stub.is_primitive,is_closure,is_useful_comment,is_non_arghave an obviously-safefalsedefault — a new language can't be told by the compiler thatfalseis correct.
Fix: give those predicates
-> falsedefaults (deletes hundreds ofstub lines). Optionally split into
CommentClassifier/SpaceClassifier/
OperandClassifiersub-traits.(b)
is_primitive(id: u16)breaks the&Nodeconventionsrc/checker.rs:178—fn is_primitive(_id: u16) -> bool;. Every otherpredicate takes
&Node. The sole caller already has the&Node(
src/metrics/halstead.rs:382doesT::is_primitive(node.kind_id())).Passing a bare
u16where the rest of the trait passes a domain type isthe "two same-typed primitives" footgun (AGENTS.md) and forecloses
primitive checks that need children/text.
Fix:
fn is_primitive(_node: &Node) -> boolwith defaultfalse.(c) Narrow
count_specific_ancestorsfromParserTraittoCheckersrc/node.rs:237—count_specific_ancestors<T: ParserTrait>instantiatesthe full 15-associated-type
ParserTraitpurely to callT::Checker::is_else_if. Callers passPythonParseretc.(
src/metrics/cognitive.rs:421,loc.rs:1014).Fix: bound on
<C: Checker>and callC::is_else_if; callers passPythonCode. Internal (pub(crate)), so fixable anytime, but belongs withthe trait reshape.
Why it matters for 2.x
Default bodies and the
is_primitivesignature change are best landed withthe
#[doc(hidden)]-trait fate decision already on the 2.0 roadmap (#505).Part of #505. Label: enhancement.