Skip to content

Commit a744aff

Browse files
committed
perf(linter): skip rules that do not have any relevant node types (#13138)
- part of #12223 - supersedes stack: #12228 This PR adds the ability to add node type information to indicate what node types a lint rule acts on. The lint rule runner can use this information to optimize running lint rules by skipping nodes, files, or rules that don't apply. This is a simple version that is focused on creating the framework for automatically generating the rule runner code. This is not the end of optimizations. Currently only 102 rules have node type information, while 471 rules have no node type information and will not be skipped. Adding node type information for more rules will improve performance. We may also be able to skip more nodes and files by being clever about how we use this information. For example, filtering out any rules which do not run on any node type, if the file contains no relevant node types for the rule. - Adds a new `RuleRunner` trait which includes information needed for indicating whether a rule has node type info or not - Adds a `oxc_linter_codegen` task which is used to generate the implementation of `RuleRunner` trait for all lint rules. This is mostly written by AI, so worth a bit of skepticism, but I've tried to manually verify the results and it looks good (just lacking more complex detection). - Currently, only rules that contain a single top-level `if` statement (or chain of `else if`), or a single `match` statement will have their node type info generated. This should give us a high level of confidence, since these patterns are relatively easy to verify and identify, but it's only a subset of all rules. Next steps will be to add support for `let...else` - Adjusts the main linting loop to use the node type information to skip rules for node types that don't apply - Updates CI to include a check for any uncommitted linter codegen changes --- ## Benchmarks In the latest version of this PR, CodSpeed shows an up to +13% increase in linter performance across large and small files. In the real-world, I've seen a ~5-15% improvement in performance, but in some cases close to zero for very small files. In either case, there appears to be little downside and a lot of potential upside here. <img width="769" height="242" alt="Screenshot 2025-08-24 at 9 29 30 PM" src="https://github.com/user-attachments/assets/d2c430c4-17a9-4606-85d5-c66c734975d9" /> <img width="757" height="308" alt="Screenshot 2025-08-24 at 9 30 24 PM" src="https://github.com/user-attachments/assets/5508464f-de55-4f4e-9ddd-58f215c4ce85" /> <img width="976" height="368" alt="Screenshot 2025-08-24 at 9 34 52 PM" src="https://github.com/user-attachments/assets/203f83c7-46f3-49f1-a1a8-e18f7ec8483b" />
1 parent bccc276 commit a744aff

File tree

13 files changed

+3589
-27
lines changed

13 files changed

+3589
-27
lines changed

.cargo/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ benchmark = "bench -p oxc_benchmark"
88
minsize = "run -p oxc_minsize --profile coverage --"
99
allocs = "run -p oxc_track_memory_allocations --profile coverage --"
1010
rule = "run -p rulegen"
11+
lintgen = "run -p oxc_linter_codegen"
1112

1213
# Build oxlint in release mode
1314
oxlint = "build --release -p oxlint --bin oxlint --features allocator"

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,31 @@ jobs:
355355
cargo run -p oxc_ast_tools
356356
git diff --exit-code ||
357357
(echo 'AST changes caused the "generated" code to get outdated. Have you forgotten to run the `just ast` command and/or commit generated codes?' && exit 1)
358+
359+
lintgen:
360+
name: Linter changes
361+
runs-on: ubuntu-latest
362+
steps:
363+
- uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1
364+
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
365+
id: filter
366+
with:
367+
filters: |
368+
src:
369+
- '.github/workflows/ci.yml'
370+
- 'crates/oxc_linter/**'
371+
- 'tasks/linter_codegen/**'
372+
373+
- uses: oxc-project/setup-rust@cd82e1efec7fef815e2c23d296756f31c7cdc03d # v1.0.0
374+
if: steps.filter.outputs.src == 'true'
375+
with:
376+
components: rustfmt
377+
cache-key: lintgen
378+
save-cache: ${{ github.ref_name == 'main' }}
379+
380+
- name: Check linter changes
381+
if: steps.filter.outputs.src == 'true'
382+
run: |
383+
cargo lintgen
384+
git diff --exit-code ||
385+
(echo 'Linter codegen has changed. Run the `cargo lintgen` command to update the linter code generated and commit it.' && exit 1)

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)