Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions crates/oxc_linter/src/generated/rule_runner_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,11 @@ impl RuleRunner for crate::rules::eslint::no_continue::NoContinue {
}

impl RuleRunner for crate::rules::eslint::no_control_regex::NoControlRegex {
const NODE_TYPES: Option<&AstTypesBitset> = None;
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::NewExpression,
AstType::RegExpLiteral,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}

Expand Down Expand Up @@ -506,7 +510,11 @@ impl RuleRunner for crate::rules::eslint::no_magic_numbers::NoMagicNumbers {
impl RuleRunner
for crate::rules::eslint::no_misleading_character_class::NoMisleadingCharacterClass
{
const NODE_TYPES: Option<&AstTypesBitset> = None;
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::NewExpression,
AstType::RegExpLiteral,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}

Expand Down Expand Up @@ -804,7 +812,11 @@ impl RuleRunner for crate::rules::eslint::no_unused_vars::NoUnusedVars {
}

impl RuleRunner for crate::rules::eslint::no_useless_backreference::NoUselessBackreference {
const NODE_TYPES: Option<&AstTypesBitset> = None;
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::NewExpression,
AstType::RegExpLiteral,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}

Expand Down
16 changes: 15 additions & 1 deletion tasks/linter_codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod let_else_detector;
mod match_detector;
mod member_expression_kinds;
mod node_type_set;
mod regex_node_kinds;
mod rules;
mod utils;

Expand All @@ -45,7 +46,9 @@ pub fn generate_rule_runner_impls() -> io::Result<()> {

let member_expression_kinds =
get_member_expression_kinds().expect("Failed to get member expression kinds");
let rule_runner_data = RuleRunnerData { member_expression_kinds };
let regex_node_kinds =
regex_node_kinds::get_regex_node_kinds().expect("Failed to get regex node kinds");
let rule_runner_data = RuleRunnerData { member_expression_kinds, regex_node_kinds };

let mut out = String::new();
out.push_str("// Auto-generated code, DO NOT EDIT DIRECTLY!\n");
Expand Down Expand Up @@ -152,6 +155,16 @@ fn detect_top_level_node_types(
return Some(node_types);
}

// Detect if entire body is call to `run_on_regex_node` and return those node types
if run_func.block.stmts.len() == 1
&& let syn::Stmt::Expr(syn::Expr::Call(call_expr), _) = &run_func.block.stmts[0]
&& call_expr.args.len() == 3
&& let syn::Expr::Path(path_expr) = &*call_expr.func
&& path_expr.path.is_ident("run_on_regex_node")
{
return Some(rule_runner_data.regex_node_kinds.clone());
}

None
}

Expand Down Expand Up @@ -199,6 +212,7 @@ enum CollectionResult {
/// Additional data collected for rule runner impl generation
struct RuleRunnerData {
member_expression_kinds: NodeTypeSet,
regex_node_kinds: NodeTypeSet,
}

/// Format Rust code with `rustfmt`.
Expand Down
42 changes: 42 additions & 0 deletions tasks/linter_codegen/src/regex_node_kinds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use syn::{Expr, Pat, Stmt};

use crate::{node_type_set::NodeTypeSet, utils::astkind_variant_from_path};

/// Fetches the current list of variants that are handled by `run_on_regex_node`.
/// We read the source file to avoid hardcoding the list here and ensure this will stay updated.
pub fn get_regex_node_kinds() -> Option<NodeTypeSet> {
// Read crates/oxc_linter/src/utils/regex.rs and extract all variants in `run_on_regex_node` function
let regex_utils_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()?
.parent()?
.join("crates")
.join("oxc_linter")
.join("src")
.join("utils")
.join("regex.rs");
let content = std::fs::read_to_string(regex_utils_path).ok()?;
let syntax = syn::parse_file(&content).ok()?;
let mut node_type_set = NodeTypeSet::new();
for item in syntax.items {
if let syn::Item::Fn(func) = item
&& func.sig.ident == "run_on_regex_node"
{
// Look for `match node.kind() { ... }` inside the function body
for stmt in &func.block.stmts {
if let Stmt::Expr(Expr::Match(match_expr), _) = stmt {
for arm in &match_expr.arms {
if let Pat::TupleStruct(ts) = &arm.pat
&& let Some(variant) = astkind_variant_from_path(&ts.path)
{
node_type_set.insert(variant);
}
}
if !node_type_set.is_empty() {
return Some(node_type_set);
}
}
}
}
}
None
}
Loading