44use std:: { path:: Path , rc:: Rc , sync:: Arc } ;
55
66use oxc_allocator:: Allocator ;
7+ use oxc_ast:: ast_kind:: AST_TYPE_MAX ;
78use oxc_semantic:: { AstNode , Semantic } ;
89
910#[ cfg( all( feature = "oxlint2" , not( feature = "disable_oxlint2" ) ) ) ]
@@ -25,6 +26,7 @@ mod module_graph_visitor;
2526mod module_record;
2627mod options;
2728mod rule;
29+ mod rule_runner_impls;
2830mod service;
2931mod tsgolint;
3032mod utils;
@@ -56,7 +58,7 @@ pub use crate::{
5658 module_record:: ModuleRecord ,
5759 options:: LintOptions ,
5860 options:: { AllowWarnDeny , InvalidFilterKind , LintFilter , LintFilterKind } ,
59- rule:: { RuleCategory , RuleFixMeta , RuleMeta } ,
61+ rule:: { RuleCategory , RuleFixMeta , RuleMeta , RuleRunner } ,
6062 service:: { LintService , LintServiceOptions , RuntimeFileSystem } ,
6163 tsgolint:: TsGoLintState ,
6264 utils:: { read_to_arena_str, read_to_string} ,
@@ -145,6 +147,9 @@ impl Linter {
145147 let should_run_on_jest_node =
146148 ctx_host. plugins ( ) . has_test ( ) && ctx_host. frameworks ( ) . is_test ( ) ;
147149
150+ // Collect rules into a Vec so that we can iterate over the rules multiple times
151+ let rules = rules. collect :: < Vec < _ > > ( ) ;
152+
148153 // IMPORTANT: We have two branches here for performance reasons:
149154 //
150155 // 1) Branch where we iterate over each node, then each rule
@@ -164,9 +169,6 @@ impl Linter {
164169 //
165170 // See https://github.com/oxc-project/oxc/pull/6600 for more context.
166171 if semantic. nodes ( ) . len ( ) > 200_000 {
167- // Collect rules into a Vec so that we can iterate over the rules multiple times
168- let rules = rules. collect :: < Vec < _ > > ( ) ;
169-
170172 for ( rule, ctx) in & rules {
171173 rule. run_once ( ctx) ;
172174 }
@@ -191,23 +193,45 @@ impl Linter {
191193 }
192194 }
193195 } else {
194- for ( rule, ref ctx) in rules {
196+ let mut rules_by_ast_type = vec ! [ Vec :: new( ) ; AST_TYPE_MAX as usize + 1 ] ;
197+ let mut rules_any_ast_type = vec ! [ ] ;
198+
199+ for ( rule, ctx) in rules. iter ( ) {
200+ if rule. should_run ( & ctx_host) {
201+ let ( ast_types, all_types) = rule. types_info ( ) ;
202+ if all_types {
203+ rules_any_ast_type. push ( ( rule, ctx) ) ;
204+ } else {
205+ for ty in ast_types {
206+ rules_by_ast_type[ ty as usize ] . push ( ( rule, ctx) ) ;
207+ }
208+ }
209+ }
210+ }
211+
212+ for ( rule, ctx) in rules. iter ( ) {
195213 rule. run_once ( ctx) ;
196214
197215 for symbol in semantic. scoping ( ) . symbol_ids ( ) {
198216 rule. run_on_symbol ( symbol, ctx) ;
199217 }
200218
201- for node in semantic. nodes ( ) {
202- rule. run ( node, ctx) ;
203- }
204-
205219 if should_run_on_jest_node {
206220 for jest_node in iter_possible_jest_call_node ( semantic) {
207221 rule. run_on_jest_node ( & jest_node, ctx) ;
208222 }
209223 }
210224 }
225+
226+ // Run rules on nodes
227+ for node in semantic. nodes ( ) {
228+ for ( rule, ctx) in & rules_by_ast_type[ node. kind ( ) . ty ( ) as usize ] {
229+ rule. run ( node, ctx) ;
230+ }
231+ for ( rule, ctx) in & rules_any_ast_type {
232+ rule. run ( node, ctx) ;
233+ }
234+ }
211235 }
212236
213237 #[ cfg( all( feature = "oxlint2" , not( feature = "disable_oxlint2" ) ) ) ]
0 commit comments