feat: experimental tree-sitter dataflow engine (unused-assignment)#79
Draft
zmaril wants to merge 2 commits into
Draft
feat: experimental tree-sitter dataflow engine (unused-assignment)#79zmaril wants to merge 2 commits into
zmaril wants to merge 2 commits into
Conversation
An opt-in (--dataflow / config `dataflow`) language-generic dataflow analysis proving the per-language-binding-spec + one-generic-engine architecture. Each language (Rust, TypeScript/TSX/JS, Python) contributes one tree-sitter query in a fixed capture vocabulary (@def/@assign/@ref/ @scope/@loop/@branch/...); a single engine builds the scope tree, resolves names lexically, and runs a function-local def-use check. One check ships: unused-assignment (Warning) — a value assigned to a local variable that is never read before reassignment or scope end. Every approximation errs toward not flagging: unclassified identifiers stay reads, closure-touched variables are exempt, loops get a blanket back-edge exemption, branch kills are arm-granular, and unparseable files skip. Measured on powdermonkey/entl/disponent/straitjacket (752 files): the two FP classes the first build produced (whole-construct branch regions letting if/else arm writes kill each other; Rust match-arm guards extracted as bindings) are fixed and regression-tested; the final build reports zero findings on the fleet while catching all seeded dead stores. The oxc React rules are untouched; the flag is off by default so the dogfood self-scan is unaffected (and passes with the flag on too). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WauUMFGGuk9J2rFa5ahHgr
Records the design rationale for the experimental --dataflow engine: why oxc stays for JS/TS (portability audit of all six oxc-backed checks), the design space surveyed (stack-graphs, Semgrep's IL architecture, CodeQL/ Glean/SCIP/Joern) with the load-bearing facts, the binding-spec + generic- engine architecture and its degrade-to-read safety property, the measured fleet results (4 FPs found and fixed, 0 findings final, 4/4 seeded dead stores caught, 0.15s to 0.47s scan cost), the honest limits, and the follow-up path (Go, use-before-def, CFG-lite if taint is ever required). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WauUMFGGuk9J2rFa5ahHgr
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
straitjacket | 9278411 | Commit Preview URL Branch Preview URL |
Jul 09 2026, 11:44 PM |
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.
Before / After
Before: dataflow-grade checks (bindings, def-use) exist only for JS/TS, through oxc's React rules. Every other language straitjacket scans gets the non-parsing tiers: regex over lines, codepoint scans, indentation counting, cpd-finder tokens.
After: an opt-in
--dataflowflag (config keydataflow, off by default) runs a language-genericunused-assignmentcheck (Warning: a value assigned to a local variable that is never read before reassignment or scope end) over Rust, TypeScript/TSX/JS, and Python via tree-sitter binding specs.oxc is untouched. The React rules keep their parser — oxc is genuinely better for JS/TS, especially anything type-adjacent (see the portability audit in
notes/dataflow.md). The generic engine exists for reach into the languages oxc will never cover. The flag defaults off, so existing scans, the dogfood self-scan, and every current user are unaffected.How
Per-language binding spec + one generic engine. Each language contributes a single tree-sitter query file (
src/dataflow/queries/*.scm, 68–79 lines each) whose captures come from a fixed vocabulary (@def/@assign/@ref/@scope/@loop/@branch/...), plus a small quirks entry insrc/dataflow/spec.rs. One generic engine (src/dataflow/analysis.rs) parses, runs the query, builds the scope tree, resolves names lexically, and runs a function-local def-use pass. The load-bearing safety property: every ambiguity degrades to a read — an unclassified identifier stays a read, closure-touched variables are exempt, unparseable files skip — so a gap in a.scmfile can mask a real finding but can never invent a false one.Measured on the fleet
Ran
--no-config --only unused-assignment --dataflowover powdermonkey, entl, disponent, and straitjacket (752 files), inspecting every finding by hand:tests/dataflow.rsadditionally pins 8 true-positive patterns and ~30 tricky negatives.--dataflow(415 files, release build).Honest limits (by design, documented in
src/dataflow/mod.rs)return/?/breakbetween two writes is unmodelled — false-negative-only by construction.*p/obj.fieldnever count as tracked writes), no cross-function flow, no type info.matchpatterns anddelunmodelled (identifiers degrade to reads).format!-style{name}recovery scans macro string literals, so a brace-name in any other macro string also counts as a read (conservative)..jsfiles containing JSX.Full design rationale — the oxc portability audit, the design space considered (stack-graphs, Semgrep/Opengrep, CodeQL, Glean, SCIP, Joern), and the follow-up path (Go, use-before-def, CFG-lite if taint is ever required) — is in
notes/dataflow.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01WauUMFGGuk9J2rFa5ahHgr
Generated by Claude Code