Skip to content

Commit 22f771e

Browse files
committed
perf(linter): filter out rules which have no relevant node types in file
1 parent b272bd6 commit 22f771e

File tree

5 files changed

+1841
-2322
lines changed

5 files changed

+1841
-2322
lines changed

crates/oxc_linter/src/lib.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,24 @@ impl Linter {
141141

142142
let rules = rules
143143
.iter()
144-
.filter(|(rule, _)| rule.should_run(&ctx_host) && !rule.is_tsgolint_rule())
144+
.filter(|(rule, _)| {
145+
if !rule.should_run(&ctx_host) {
146+
return false;
147+
}
148+
// Skip tsgolint rules in Rust linter
149+
if rule.is_tsgolint_rule() {
150+
return false;
151+
}
152+
// Skip rules that only run on nodes that this file does not contain
153+
let (ast_types, all_types, only_runs_on_nodes) = rule.types_info();
154+
if !all_types
155+
&& only_runs_on_nodes
156+
&& !ctx_host.semantic().nodes().contains_any(ast_types)
157+
{
158+
return false;
159+
}
160+
true
161+
})
145162
.map(|(rule, severity)| (rule, Rc::clone(&ctx_host).spawn(rule, *severity)));
146163

147164
let semantic = ctx_host.semantic();
@@ -183,7 +200,7 @@ impl Linter {
183200
// Collect node type information for rules. In large files, benchmarking showed it was worth
184201
// collecting rules into buckets by AST node type to avoid iterating over all rules for each node.
185202
if rule.should_run(&ctx_host) {
186-
let (ast_types, all_types) = rule.types_info();
203+
let (ast_types, all_types, _) = rule.types_info();
187204
if all_types {
188205
rules_any_ast_type.push((rule, ctx));
189206
} else {
@@ -229,7 +246,7 @@ impl Linter {
229246

230247
// For smaller files, benchmarking showed it was faster to iterate over all rules and just check the
231248
// node types as we go, rather than pre-bucketing rules by AST node type and doing extra allocations.
232-
let (ast_types, all_types) = rule.types_info();
249+
let (ast_types, all_types, _) = rule.types_info();
233250
if all_types {
234251
for node in semantic.nodes() {
235252
rule.run(node, ctx);

crates/oxc_linter/src/rule.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ pub trait RuleRunner: Rule {
7171
const NODE_TYPES: &AstTypesBitset;
7272
/// `true` if codegen can't figure out what node types rule acts on
7373
const ANY_NODE_TYPE: bool;
74+
/// `true` if this rule only has a `run` implementation and does not implement
75+
/// `run_on_symbol`, `run_once`, or `run_on_jest_node`.
76+
const ONLY_RUNS_ON_NODES: bool = false;
7477

75-
fn types_info(&self) -> (&'static AstTypesBitset, bool) {
76-
(Self::NODE_TYPES, Self::ANY_NODE_TYPE)
78+
fn types_info(&self) -> (&'static AstTypesBitset, bool, bool) {
79+
(Self::NODE_TYPES, Self::ANY_NODE_TYPE, Self::ONLY_RUNS_ON_NODES)
7780
}
7881
}
7982
pub trait RuleMeta {
@@ -410,13 +413,15 @@ mod test {
410413
&unicorn::no_zero_fractions::NoZeroFractions,
411414
&[NumericLiteral],
412415
);
416+
417+
assert!(!&jest::max_expects::MaxExpects::ONLY_RUNS_ON_NODES);
413418
}
414419

415420
fn assert_rule_runs_on_node_types<R: RuleMeta + RuleRunner>(
416421
rule: &R,
417422
node_types: &[oxc_ast::AstType],
418423
) {
419-
let (types, _) = rule.types_info();
424+
let (types, _, _) = rule.types_info();
420425
assert!(!R::ANY_NODE_TYPE, "{} should not have ANY_NODE_TYPE set to true", R::NAME);
421426
for node_type in node_types {
422427
assert!(

0 commit comments

Comments
 (0)