diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index db0c318a2e66c..0b09d1c3840fa 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -333,7 +333,10 @@ impl LintRunner { let linter = Linter::new(LintOptions::default(), config_store, external_linter) .with_fix(fix_options.fix_kind()) - .with_report_unused_directives(report_unused_directives); + .with_report_unused_directives(report_unused_directives) + .with_disabled_optimizations( + std::env::var("OXLINT_NO_OPTIMIZE").is_ok_and(|v| v == "1" || v == "true"), + ); let number_of_files = files_to_lint.len(); diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs index 6de66492bd447..fa9dfa4e2b798 100644 --- a/crates/oxc_linter/src/lib.rs +++ b/crates/oxc_linter/src/lib.rs @@ -90,6 +90,9 @@ pub struct Linter { options: LintOptions, config: ConfigStore, external_linter: Option, + /// Allow disabling node type optimization for testing and debugging to ensure that we are correctly + /// generating diagnostics regardless of the optimization. + disable_node_type_optimization: bool, } impl Linter { @@ -98,7 +101,7 @@ impl Linter { config: ConfigStore, external_linter: Option, ) -> Self { - Self { options, config, external_linter } + Self { options, config, external_linter, disable_node_type_optimization: false } } /// Set the kind of auto fixes to apply. @@ -114,6 +117,14 @@ impl Linter { self } + /// Allows disabling runtime optimizations for testing and debugging. Should only be called + /// via some sort of debug flag and not called normally. + #[must_use] + pub fn with_disabled_optimizations(mut self, do_not_optimize: bool) -> Self { + self.disable_node_type_optimization = do_not_optimize; + self + } + pub(crate) fn options(&self) -> &LintOptions { &self.options } @@ -188,7 +199,9 @@ impl Linter { let rule = *rule; // Collect node type information for rules. In large files, benchmarking showed it was worth // collecting rules into buckets by AST node type to avoid iterating over all rules for each node. - if let Some(ast_types) = rule.types_info() { + if !self.disable_node_type_optimization + && let Some(ast_types) = rule.types_info() + { for ty in ast_types { rules_by_ast_type[ty as usize].push((rule, ctx)); } @@ -232,7 +245,9 @@ impl Linter { // For smaller files, benchmarking showed it was faster to iterate over all rules and just check the // node types as we go, rather than pre-bucketing rules by AST node type and doing extra allocations. - if let Some(ast_types) = rule.types_info() { + if !self.disable_node_type_optimization + && let Some(ast_types) = rule.types_info() + { for node in semantic.nodes() { if ast_types.has(node.kind().ty()) { rule.run(node, ctx);