Skip to content

Commit e0279a2

Browse files
committed
perf(linter): filter out rules which have no relevant node types in file
1 parent 8b57262 commit e0279a2

File tree

5 files changed

+1831
-2322
lines changed

5 files changed

+1831
-2322
lines changed

crates/oxc_linter/src/lib.rs

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

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

145162
let semantic = ctx_host.semantic();
@@ -181,7 +198,7 @@ impl Linter {
181198
// Collect node type information for rules. In large files, benchmarking showed it was worth
182199
// collecting rules into buckets by AST node type to avoid iterating over all rules for each node.
183200
if rule.should_run(&ctx_host) {
184-
let (ast_types, all_types) = rule.types_info();
201+
let (ast_types, all_types, _) = rule.types_info();
185202
if all_types {
186203
rules_any_ast_type.push((rule, ctx));
187204
} else {
@@ -227,7 +244,7 @@ impl Linter {
227244

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

crates/oxc_linter/src/rule.rs

Lines changed: 6 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 {
@@ -416,7 +419,7 @@ mod test {
416419
rule: &R,
417420
node_types: &[oxc_ast::AstType],
418421
) {
419-
let (types, _) = rule.types_info();
422+
let (types, _, _) = rule.types_info();
420423
assert!(!R::ANY_NODE_TYPE, "{} should not have ANY_NODE_TYPE set to true", R::NAME);
421424
for node_type in node_types {
422425
assert!(

0 commit comments

Comments
 (0)