perf(linter): compute comment fix span only for directive comments#24419
Merged
graphite-app[bot] merged 1 commit intoJul 13, 2026
Merged
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
Contributor
Merge activity
|
…24419) This is a micro-optimization but in a repo with 10k+ files with 10k+ comments, this would have some (very minor) impact that is worth doing, given that the change is so small. ## What this does `DisableDirectivesBuilder::build_impl` pre-computed the fix span for every comment in the file — before `match_directive` filters out non-directive comments, which is the overwhelming majority. The fix span is only consumed after that filter (all uses sit below the early `continue`), so for ordinary comments the computation was pure waste. This PR moves the computation below the directive check. 5 insertions, 4 deletions, no logic change. ## Benchmark Interleaved paired samples (N=40 pairs, warmup, `time.monotonic_ns()`), single rule enabled (`eslint/no-debugger`, zero diagnostics on the fixtures so the common non-reporting path is measured), baseline binary built from pristine `main`: | Fixture | Baseline | Optimized | Speedup | |---|---|---|---| | Single-line file, 10k inline `/* */` comments (~318 KB) | 91.96 ms | 8.90 ms | **10.3×** (t=297.6, 40/0 wins) | | 30k short `//` comment lines | 12.15 ms | 11.74 ms | 1.04× (t=2.7, 29/11) | | Control: comment-free 30k-line file, all rules off | 13.11 ms | 13.32 ms | 0.98× (t=-1.0, noise) | The adversarial single-line case is where the quadratic bites (minified bundles, generated code). Typical multi-line code sees a small win proportional to comment density. The comment-free control shows the deltas aren't binary-layout noise. (A rules-off "parse-only" run on the comment fixture shows the same ~10× — the directives builder runs regardless of rule config, which is exactly why this path is worth trimming.) ## Correctness - All 1169 `oxc_linter` lib tests pass, including the `fix_span_*` unit tests covering `compute_comment_fix_span`. - Diagnostics parity (`--format=json`, diagnostics array compared) is exact between baseline and optimized binaries on both fixtures and on a canary exercising `eslint-disable-line`, `eslint-disable-next-line`, block `eslint-disable`/`eslint-enable`, an unused directive, and comments sharing lines with code. - `--fix --fix-suggestions --fix-dangerously` output is byte-identical between the two binaries on that canary. - The reorder computes the same value from the same inputs for every comment that reaches a use; only the timing moves. ## AI disclosure This change was implemented with Claude Code. Reviewed by me manually to confirm the fix is safe. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
688a1b6 to
fb1edf1
Compare
Boshen
added a commit
that referenced
this pull request
Jul 14, 2026
# Oxlint ### 🚀 Features - 0433a83 linter/eslint/no-inner-declarations: Add `namespaces` option (#24044) (Boshen) - 92f154a oxlint,oxfmt: Auto-discover `.mts` config files (#24357) (camc314) - 8c1d74b linter/import/no-duplicates: Add autofix logic (#24273) (Cole Ellison) ### 🐛 Bug Fixes - 0b086de linter/jest/prefer-lowercase-title: False positive when `lowercaseFirstCharacterOnly` is false (#24414) (Connor Shea) - 097cb95 linter: Allow `vite-plus/test` and `@effect as Vitest source (#24196) (Liang) - 8337835 linter: Error on `ignorePatterns` that cannot match files aoutside the config directory (#24341) (leaysgur) - 9ba30e5 linter/oxc/bad-replace-all-arg: Add note to enhance diagnostic (#24346) (camc314) - 2ce5a33 linter: Resolve `ignorePatterns` relative to the config dir (#24339) (leaysgur) - ab90eed linter/eslint/no-loop-func: Do not error on catch variables (#24316) (Chris Opperwall) - b67f0a6 linter/eslint/no-unused-vars: Count default parameter updates as usage (#24323) (camc314) - d193f8e linter: Detect Junie agent env vars (#24277) (Jeevan Mohan Pawar) - 2aecf60 linter/eslint/no-unreachable: Handle `break` in switch stmts correctly (#24260) (camc314) ### ⚡ Performance - 7f80cac linter/vue/prop-name-casing: Precompile `ignoreProps` regex pattern (#24413) (connorshea) - 6272051 linter/typescript/no-require-imports: Compile allow patterns once (#24417) (connorshea) - fb1edf1 linter: Compute comment fix span only for directive comments (#24419) (connorshea) - 33805b9 linter/jsdoc/require-param: Compile checkTypesPattern regex once (#24420) (connorshea) - 8de6fca linter/jest/valid-title: Compile disallowedWords regex once (#24412) (Connor Shea) - 4a0d8dc linter/eslint/no-underscore-dangle: Avoid String clone per identifier (#24371) (Ian Macalinao) - f3ab04c linter/typescript/consistent-type-imports: Remove redundant Vec per violation (#24370) (Ian Macalinao) - 4d2d78d linter/typescript/prefer-ts-expect-error: Avoid String clone per comment (#24369) (Ian Macalinao) # Oxfmt ### 🚀 Features - 3a7fe74 formatter_css: Update oxc-css-parser to 0.0.7 (#24434) (leaysgur) - 0173cd3 formatter_css: Format Less :extend and merge props (#24358) (leaysgur) - 92f154a oxlint,oxfmt: Auto-discover `.mts` config files (#24357) (camc314) - df250df formatter: Support `quoteProps` for TS enum and methods (#24309) (leaysgur) - a9a5cd6 formatter_core: Expose `SourceText::as_str()` (#24281) (leaysgur) ### 🐛 Bug Fixes - 162bddf formatter: Add required parens for conditional type in type parameter constraint (#24450) (leaysgur) - 2d22a91 formatter: Determine type cast target from span instead of lexical scan (#24447) (leaysgur) - 25306e9 formatter: Do not add extra parens with type cast comment (#24444) (leaysgur) - bd6edfe formatter: Break arrow signature that exactly fills the line when cond body may hug (#24440) (leaysgur) - a99ef41 formatter: Keep quotes on method signature named new (#24432) (leaysgur) - fcc28df formatter_css: Keep glued-braket-value tight (#24352) (leaysgur) - 8337835 linter: Error on `ignorePatterns` that cannot match files aoutside the config directory (#24341) (leaysgur) - b7c7e15 formatter: Add parens for import and private field in new callee chain (#24320) (leaysgur) - 0c8f6e4 formatter: Update detect_code_removal for #24309 (#24314) (leaysgur) - a85aad0 formatter: Fix member-chain and non-null parens (#24312) (leaysgur) - 1c29c73 formatter: Preserve `TSNonNullExpression` in chain expression (#24311) (leaysgur) - 8933c0e formatter: Keep comment inside of empty `switch` block (#24308) (leaysgur) - ec26af2 formatter: Preserve blank lines between JSX attrs (#24290) (leaysgur) - 70bd54d formatter: Keep arrow function body comment (#24287) (leaysgur) - 415fe1e oxfmt: Error on ignorePatterns that cannot match files outside the config directory (#24286) (leaysgur) - eeabc4a formatter_css: Bail on EOF-recovered parse errors (#24282) (leaysgur) - 42ec8de formatter: Keep comments inside surviving parens and suppressed statement terminators (#24253) (leaysgur) - 1343779 formatter: Keep comment inline for empty statements (#24249) (leaysgur) - b996579 formatter: Print ; before trailing comments part 2 (#24246) (leaysgur) - 4f86e8c formatter: Print `;` before trailing comments (#24244) (leaysgur) - 01252e4 formatter: Add or remove parens for `let` declaration (#24215) (leaysgur) ### ⚡ Performance - eeb1913 formatter_core: Avoid per-call `Vec` work-stack in soft-line removal (#23775) (Marius Schulz) - a2f255b formatter: Use `SmallVec` for `MemberChain` collections (#23776) (Marius Schulz) ### 📚 Documentation - b52d0f5 formatter: Add TODO comment about unsound code (#24372) (overlookmotel) Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
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.
This is a micro-optimization but in a repo with 10k+ files with 10k+ comments, this would have some (very minor) impact that is worth doing, given that the change is so small.
What this does
DisableDirectivesBuilder::build_implpre-computed the fix span for every comment in the file — beforematch_directivefilters out non-directive comments, which is the overwhelming majority. The fix span is only consumed after that filter (all uses sit below the earlycontinue), so for ordinary comments the computation was pure waste. This PR moves the computation below the directive check. 5 insertions, 4 deletions, no logic change.Benchmark
Interleaved paired samples (N=40 pairs, warmup,
time.monotonic_ns()), single rule enabled (eslint/no-debugger, zero diagnostics on the fixtures so the common non-reporting path is measured), baseline binary built from pristinemain:/* */comments (~318 KB)//comment linesThe adversarial single-line case is where the quadratic bites (minified bundles, generated code). Typical multi-line code sees a small win proportional to comment density. The comment-free control shows the deltas aren't binary-layout noise. (A rules-off "parse-only" run on the comment fixture shows the same ~10× — the directives builder runs regardless of rule config, which is exactly why this path is worth trimming.)
Correctness
oxc_linterlib tests pass, including thefix_span_*unit tests coveringcompute_comment_fix_span.--format=json, diagnostics array compared) is exact between baseline and optimized binaries on both fixtures and on a canary exercisingeslint-disable-line,eslint-disable-next-line, blockeslint-disable/eslint-enable, an unused directive, and comments sharing lines with code.--fix --fix-suggestions --fix-dangerouslyoutput is byte-identical between the two binaries on that canary.AI disclosure
This change was implemented with Claude Code. Reviewed by me manually to confirm the fix is safe.
🤖 Generated with Claude Code