Files
Skosh 17eeeb5367 fix(rules): recognize member hook state consumption (#1717)
* fix(rerender-state-only-in-handlers): recognize state consumed via member expression hook calls

State consumed by hook calls through member expressions (e.g. styles.useVariants({ state }))
was incorrectly flagged as unused. This commonly occurs with react-native-unistyles,
where state selects style variants via StyleSheet.useVariants().

The rule now checks both direct identifier calls (useX) and member expression calls
(obj.useX) when collecting custom hook arguments, following the existing pattern used
throughout the codebase.

Fixes #1716

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* chore: add changeset for member expression hook fix

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* test: add edge case for non-hook member expressions

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* fix(rules): preserve state setter bindings

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-08-29 22:13:41 -07:00
..

Fuzz corpus

The harness always loads this directory (no env needed) and fuzzes these programs plus mutated/crossed-over descendants — concentrating inputs on the detection logic that has historically been weakest.

Two seed families, split by expected rule verdict:

  • regressions/ — every file is a confirmed false positive: correct, idiomatic code that a rule once wrongly flagged.
  • true-positives/ — every file is a confirmed true positive: a genuine bug a rule must flag, kept as a mutation seed so its shape keeps applying pressure.

Seeds with // verdict: pass or // verdict: fail are replayed deterministically by both the smoke suite and targeted fuzzing. Seeds without a verdict remain mutation-only inputs. firedProgramCount is still a coverage stat rather than a correctness oracle for generated programs.

The evolving loop (see the fuzz skill): whenever a new false positive is confirmed — from a user report, an RDE eval, a react-bench run, review, or a fuzz invariant finding — add a minimal reproducer here as regressions/<rule-id>--<slug>.tsx with a header comment naming the rule and the weakness class. The next fuzz run picks it up automatically.

Header format:

// rule: <rule-id>
// weakness: <alias-guard | copy-tracking | name-heuristic | paren-shape |
//            framework-gating | test-gating | control-flow |
//            wrapper-transparency | library-idiom | cross-file | other>
// source: <PR/issue/session reference>
// react-major: <major, only when the false positive depends on React version>

Files may use .ts, .tsx, .js, or .jsx and must parse cleanly (pnpm test enforces it).

Exact audit corpora

react-bench-0.9.7-audit/ and dummy-threejs-v14-audit/ preserve complete source files from exhaustive production-corpus reviews. Their manifests pin the source-report hashes, audited callsites, source-line hashes, expected verdict counts, and fixture mappings. Regression files use // audit-verdict: pass because the exact source can contain unrelated valid findings; they remain mutation seeds instead of claiming the entire file must be diagnostic-free. True-positive files use // verdict: fail and are replayed deterministically.

Regenerate the Dummy corpus from its archived scan artifacts with:

node scripts/import-dummy-threejs-audit-corpus.mjs \
  <before-diagnostics.tsv> <after-diagnostics.tsv> <selected-roots.txt> \
  corpus/dummy-threejs-v14-audit corpus/dummy-threejs-v14-audit.json