Skip to content

Commit 69a5622

Browse files
committed
perf(linter): only run rule run functions if implemented
1 parent 5255b38 commit 69a5622

File tree

2 files changed

+59
-18
lines changed

2 files changed

+59
-18
lines changed

crates/oxc_linter/src/lib.rs

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ impl Linter {
184184
let should_run_on_jest_node =
185185
ctx_host.plugins().has_test() && ctx_host.frameworks().is_test();
186186

187-
let execute_rules = |with_ast_kind_filtering: bool| {
187+
let execute_rules = |with_runtime_optimization: bool| {
188188
// IMPORTANT: We have two branches here for performance reasons:
189189
//
190190
// 1) Branch where we iterate over each node, then each rule
@@ -217,22 +217,32 @@ impl Linter {
217217

218218
for (rule, ctx) in &rules {
219219
let rule = *rule;
220+
let run_info = rule.run_info();
220221
// Collect node type information for rules. In large files, benchmarking showed it was worth
221222
// collecting rules into buckets by AST node type to avoid iterating over all rules for each node.
222-
if with_ast_kind_filtering && let Some(ast_types) = rule.types_info() {
223+
if with_runtime_optimization
224+
&& let Some(ast_types) = rule.types_info()
225+
&& run_info.is_run_implemented()
226+
{
223227
for ty in ast_types {
224228
rules_by_ast_type[ty as usize].push((rule, ctx));
225229
}
226230
} else {
227231
rules_any_ast_type.push((rule, ctx));
228232
}
229233

230-
rule.run_once(ctx);
234+
if !with_runtime_optimization || run_info.is_run_once_implemented() {
235+
rule.run_once(ctx);
236+
}
231237
}
232238

233239
for symbol in semantic.scoping().symbol_ids() {
234240
for (rule, ctx) in &rules {
235-
rule.run_on_symbol(symbol, ctx);
241+
if !with_runtime_optimization
242+
|| rule.run_info().is_run_on_symbol_implemented()
243+
{
244+
rule.run_on_symbol(symbol, ctx);
245+
}
236246
}
237247
}
238248

@@ -249,33 +259,46 @@ impl Linter {
249259
if should_run_on_jest_node {
250260
for jest_node in iter_possible_jest_call_node(semantic) {
251261
for (rule, ctx) in &rules {
252-
rule.run_on_jest_node(&jest_node, ctx);
262+
if rule.run_info().is_run_on_jest_node_implemented() {
263+
rule.run_on_jest_node(&jest_node, ctx);
264+
}
253265
}
254266
}
255267
}
256268
} else {
257269
for (rule, ctx) in &rules {
258-
rule.run_once(ctx);
270+
let run_info = rule.run_info();
271+
if !with_runtime_optimization || run_info.is_run_once_implemented() {
272+
rule.run_once(ctx);
273+
}
259274

260-
for symbol in semantic.scoping().symbol_ids() {
261-
rule.run_on_symbol(symbol, ctx);
275+
if !with_runtime_optimization || run_info.is_run_on_symbol_implemented() {
276+
for symbol in semantic.scoping().symbol_ids() {
277+
rule.run_on_symbol(symbol, ctx);
278+
}
262279
}
263280

264-
// For smaller files, benchmarking showed it was faster to iterate over all rules and just check the
265-
// node types as we go, rather than pre-bucketing rules by AST node type and doing extra allocations.
266-
if with_ast_kind_filtering && let Some(ast_types) = rule.types_info() {
267-
for node in semantic.nodes() {
268-
if ast_types.has(node.kind().ty()) {
281+
if !with_runtime_optimization || run_info.is_run_implemented() {
282+
// For smaller files, benchmarking showed it was faster to iterate over all rules and just check the
283+
// node types as we go, rather than pre-bucketing rules by AST node type and doing extra allocations.
284+
if with_runtime_optimization && let Some(ast_types) = rule.types_info()
285+
{
286+
for node in semantic.nodes() {
287+
if ast_types.has(node.kind().ty()) {
288+
rule.run(node, ctx);
289+
}
290+
}
291+
} else {
292+
for node in semantic.nodes() {
269293
rule.run(node, ctx);
270294
}
271295
}
272-
} else {
273-
for node in semantic.nodes() {
274-
rule.run(node, ctx);
275-
}
276296
}
277297

278-
if should_run_on_jest_node {
298+
if should_run_on_jest_node
299+
&& (!with_runtime_optimization
300+
|| run_info.is_run_on_jest_node_implemented())
301+
{
279302
for jest_node in iter_possible_jest_call_node(semantic) {
280303
rule.run_on_jest_node(&jest_node, ctx);
281304
}

crates/oxc_linter/src/rule.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,24 @@ pub enum RuleRunFunctionsImplemented {
100100
RunOnJestNode,
101101
}
102102

103+
impl RuleRunFunctionsImplemented {
104+
pub fn is_run_implemented(self) -> bool {
105+
matches!(self, Self::Run | Self::Unknown)
106+
}
107+
108+
pub fn is_run_once_implemented(self) -> bool {
109+
matches!(self, Self::RunOnce | Self::Unknown)
110+
}
111+
112+
pub fn is_run_on_symbol_implemented(self) -> bool {
113+
matches!(self, Self::RunOnSymbol | Self::Unknown)
114+
}
115+
116+
pub fn is_run_on_jest_node_implemented(self) -> bool {
117+
matches!(self, Self::RunOnJestNode | Self::Unknown)
118+
}
119+
}
120+
103121
pub trait RuleMeta {
104122
const NAME: &'static str;
105123

0 commit comments

Comments
 (0)