diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 01acc3c0907a3..338a670e8b76c 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -152,7 +152,8 @@ impl RuleRunner for crate::rules::eslint::no_bitwise::NoBitwise { } impl RuleRunner for crate::rules::eslint::no_caller::NoCaller { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::StaticMemberExpression])); } impl RuleRunner for crate::rules::eslint::no_case_declarations::NoCaseDeclarations { @@ -273,7 +274,8 @@ impl RuleRunner for crate::rules::eslint::no_empty_pattern::NoEmptyPattern { } impl RuleRunner for crate::rules::eslint::no_empty_static_block::NoEmptyStaticBlock { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::StaticBlock])); } impl RuleRunner for crate::rules::eslint::no_eq_null::NoEqNull { @@ -386,7 +388,8 @@ impl RuleRunner for crate::rules::eslint::no_negated_condition::NoNegatedConditi } impl RuleRunner for crate::rules::eslint::no_nested_ternary::NoNestedTernary { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::ConditionalExpression])); } impl RuleRunner for crate::rules::eslint::no_new::NoNew { @@ -613,7 +616,8 @@ impl RuleRunner for crate::rules::eslint::no_useless_rename::NoUselessRename { } impl RuleRunner for crate::rules::eslint::no_var::NoVar { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::VariableDeclaration])); } impl RuleRunner for crate::rules::eslint::no_void::NoVoid { @@ -693,7 +697,8 @@ impl RuleRunner for crate::rules::eslint::require_await::RequireAwait { } impl RuleRunner for crate::rules::eslint::require_yield::RequireYield { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::Function])); } impl RuleRunner for crate::rules::eslint::sort_imports::SortImports { @@ -1176,7 +1181,8 @@ impl RuleRunner for crate::rules::jsx_a11y::aria_props::AriaProps { } impl RuleRunner for crate::rules::jsx_a11y::aria_role::AriaRole { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::JSXElement])); } impl RuleRunner for crate::rules::jsx_a11y::aria_unsupported_elements::AriaUnsupportedElements { @@ -1384,7 +1390,8 @@ impl RuleRunner for crate::rules::nextjs::no_title_in_document_head::NoTitleInDo } impl RuleRunner for crate::rules::nextjs::no_typos::NoTypos { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::ExportNamedDeclaration])); } impl RuleRunner for crate::rules::nextjs::no_unwanted_polyfillio::NoUnwantedPolyfillio { @@ -1915,7 +1922,8 @@ impl RuleRunner for crate::rules::typescript::no_dynamic_delete::NoDynamicDelete } impl RuleRunner for crate::rules::typescript::no_empty_interface::NoEmptyInterface { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::TSInterfaceDeclaration])); } impl RuleRunner for crate::rules::typescript::no_empty_object_type::NoEmptyObjectType { @@ -2433,7 +2441,8 @@ impl RuleRunner } impl RuleRunner for crate::rules::unicorn::no_process_exit::NoProcessExit { - const NODE_TYPES: Option<&AstTypesBitset> = None; + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::CallExpression])); } impl RuleRunner diff --git a/tasks/linter_codegen/src/if_else_detector.rs b/tasks/linter_codegen/src/if_else_detector.rs index c72f82d0b61c4..62c62fb8c04de 100644 --- a/tasks/linter_codegen/src/if_else_detector.rs +++ b/tasks/linter_codegen/src/if_else_detector.rs @@ -49,14 +49,46 @@ impl IfElseKindDetector { } } - /// Extracts AstKind variants from an `if let` condition like `if let AstKind::Xxx(..) = node.kind()`. + /// Extracts AstKind variants from an `if let` condition like `if let AstKind::Xxx(..) = node.kind()` + /// or `if let AstKind::Xxx(..) = node.kind() && other_condition`. fn extract_variants_from_if_let_condition(&mut self, cond: &Expr) -> CollectionResult { - let Expr::Let(let_expr) = cond else { return CollectionResult::Incomplete }; - // RHS must be `node.kind()` - if is_node_kind_call(&let_expr.expr) { - self.extract_variants_from_pat(&let_expr.pat) - } else { - CollectionResult::Incomplete + match cond { + // Simple `if let` pattern + Expr::Let(let_expr) => { + // RHS must be `node.kind()` + if is_node_kind_call(&let_expr.expr) { + self.extract_variants_from_pat(&let_expr.pat) + } else { + CollectionResult::Incomplete + } + } + // `if let ... && ...` pattern (from MSRV 1.88.0) + // The entire condition might be a chain of binary && operations + Expr::Binary(binary) if matches!(binary.op, syn::BinOp::And(_)) => { + // Try to find the let expression in the leftmost part of the chain + self.extract_from_binary_and_chain(binary) + } + _ => CollectionResult::Incomplete, + } + } + + /// Recursively extract from a binary && chain to find the let expression + fn extract_from_binary_and_chain(&mut self, binary: &syn::ExprBinary) -> CollectionResult { + // Check if the left side is another binary expression (nested &&) + match &*binary.left { + Expr::Binary(left_binary) if matches!(left_binary.op, syn::BinOp::And(_)) => { + // Recursively check the left side + self.extract_from_binary_and_chain(left_binary) + } + Expr::Let(let_expr) => { + // Found the let expression + if is_node_kind_call(&let_expr.expr) { + self.extract_variants_from_pat(&let_expr.pat) + } else { + CollectionResult::Incomplete + } + } + _ => CollectionResult::Incomplete, } }