96adc66030
Adversarial review of the previous commit: scan() survived 16 literal-shape
attacks, and both HIGH findings were in the code that did NOT get rewritten.
The attribute handling still asked the RAW LINE the questions this commit's
whole argument says a raw line cannot answer.
- Bracket depth was counted over the raw line, so `#[cfg(feature = "[")]`
set attr_depth=1 with no reset path and exempted EVERY REMAINING LINE IN THE
FILE. The raw-string spelling of it is the exact defect class this rewrite
was for: scan() knew those bytes were string content and line 150 asked the
line instead. The tree has 14 `#[arg(...)]` and 3 `#[command(...)]` clap
attributes whose help strings are free text.
- `s.startswith("#[doc")` is an UNANCHORED PREFIX, so `#[doc(hidden)]` counted
as a comment and flagged correct code. Fourth instance of that class in this
campaign, eleven lines above the comment naming the previous three.
Also from the same review: `#![doc = "..."]` is the inner spelling of a doc
comment and was never counted (unlimited free crate doc); an inner attribute
between two `//!` blocks split one crate doc in half, where the rule exists to
separate a crate doc from an ITEM doc — so it now ends a run only where the doc
KIND changes; and a block comment closing on a line with code got one free line.
Attributes are now asked of the scanner: `scan()` returns the code-only text,
and depth is counted over that. `_is_attribute` is deleted — dead since the
logic moved inline, and an orphaned explanation is what --check-evidence exists
to catch one directory over.
The coverage finding was the important one. Two of scan()'s four literal
mechanisms had NO self-test case: reverting char-literal or plain-string
handling left the suite green. Both are load-bearing in opposite directions —
without char literals, `'"'` opens a string that eats the file (false negative);
without plain strings, a multi-line string holding `//` lines is a false
positive, the CI-breaking direction. Both now have cases, and so does every
shape above. The attribute-depth mechanism needed a fixture with code AFTER the
attribute, because comments inside one are counted either way: the first
fixture I wrote passed under its own injection.
Self-test: 17 violations caught, 9 legitimate shapes allowed. Every mechanism
proved discriminating by reverting it alone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>