fix(lint): stop 109 autofixes rewriting hard-quoted data - #128
Merged
Conversation
Seventeen `Fixable` rules in `lint-conditional` fired inside hard-quoted data and rewrote a data literal as if it were code. `--fix` then corrupted the file silently: every round-trip property still passed, because a consistently wrong parse is a fixed point of its own round-trip. Measured over 6,474 SHA-256-deduplicated Common Lisp files, with 91.5% of emitted fixes classified by quote state: hard-quoted fixes 332 -> 223 (109 eliminated) unquoted-code fixes 9,112 -> 9,112 (not one lost) quasiquote-template 707 -> 707 (not one lost) The two unmoved counters are the point. Over-suppression is the default failure mode when fixing false positives, so each guarded rule carries a `still_fires_inside_a_quasiquote_template` test asserting the rewritten source, generated from an oracle binary running the real dispatch rather than guessed. A quasiquote template is code: `(if ,c nil ,e)` in a macro body must still be fixed. The guard therefore tests `hard` only, never a combined is-data predicate -- a mutation harness kills exactly that mutant, along with five others (guard always true, always false, inverted, skipping the target's own prefixes, ignoring long-hand `(quote ...)`). `one-armed-if` is deliberately left unguarded: 6 of its 16 hard-quoted findings sit under a `#.` read-eval ancestor or inside an SBCL `deftransform`/`defoptimizer` template, where the "quoted" text is spliced back as live code. Every rule guarded here measured zero such exposure. Four of the seventeen guards -- `cond-t-clause`, `negated-if`, `nested-when`, `nested-unless` -- had no measured misfires and are preventive rather than evidence-driven. No rule count changes; no registry, presentation, docs or bench file is touched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Seventeen
Fixablerules inlint-conditionalfired inside hard-quoted data and rewrote a data literal as if it were code.Measured over 6,474 SHA-256-deduplicated Common Lisp files
91.5% of emitted fixes classified by quote state.
The two unmoved counters are the point — over-suppression is the default failure mode when fixing false positives.
Why the guard tests
hardonlyA quasiquote template is code:
(if ,c nil ,e)in a macro body must still be fixed. Every guarded rule carries astill_fires_inside_a_quasiquote_templatetest asserting the rewritten source, generated from an oracle binary running the real dispatch rather than guessed.A mutation harness kills 6 mutants, including
state.hard→state.is_data()— the obvious wrong fix.Exclusion
one-armed-ifis deliberately left unguarded: 6 of its 16 hard-quoted findings sit under a#.read-eval ancestor or inside an SBCLdeftransform/defoptimizertemplate, where the quoted text is spliced back as live code. Every rule guarded here measured zero such exposure.Four guards (
cond-t-clause,negated-if,nested-when,nested-unless) had no measured misfires and are preventive, not evidence-driven.Verification
cargo fmt --all --check0 ·cargo clippy --workspace --all-targets -D warnings0 ·cargo test --workspace0 (178 suites)No rule count changes; no registry, presentation, docs or bench file touched.