Skip to content

Commit e73a68e

Browse files
committed
fix(linter): support let-chains in codegen node type detection
1 parent c778cba commit e73a68e

File tree

2 files changed

+57
-16
lines changed

2 files changed

+57
-16
lines changed

crates/oxc_linter/src/generated/rule_runner_impls.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ impl RuleRunner for crate::rules::eslint::no_bitwise::NoBitwise {
136136
}
137137

138138
impl RuleRunner for crate::rules::eslint::no_caller::NoCaller {
139-
const NODE_TYPES: Option<&AstTypesBitset> = None;
139+
const NODE_TYPES: Option<&AstTypesBitset> =
140+
Some(&AstTypesBitset::from_types(&[AstType::StaticMemberExpression]));
140141
}
141142

142143
impl RuleRunner for crate::rules::eslint::no_case_declarations::NoCaseDeclarations {
@@ -250,7 +251,8 @@ impl RuleRunner for crate::rules::eslint::no_empty_pattern::NoEmptyPattern {
250251
}
251252

252253
impl RuleRunner for crate::rules::eslint::no_empty_static_block::NoEmptyStaticBlock {
253-
const NODE_TYPES: Option<&AstTypesBitset> = None;
254+
const NODE_TYPES: Option<&AstTypesBitset> =
255+
Some(&AstTypesBitset::from_types(&[AstType::StaticBlock]));
254256
}
255257

256258
impl RuleRunner for crate::rules::eslint::no_eq_null::NoEqNull {
@@ -363,7 +365,8 @@ impl RuleRunner for crate::rules::eslint::no_negated_condition::NoNegatedConditi
363365
}
364366

365367
impl RuleRunner for crate::rules::eslint::no_nested_ternary::NoNestedTernary {
366-
const NODE_TYPES: Option<&AstTypesBitset> = None;
368+
const NODE_TYPES: Option<&AstTypesBitset> =
369+
Some(&AstTypesBitset::from_types(&[AstType::ConditionalExpression]));
367370
}
368371

369372
impl RuleRunner for crate::rules::eslint::no_new::NoNew {
@@ -577,7 +580,8 @@ impl RuleRunner for crate::rules::eslint::no_useless_rename::NoUselessRename {
577580
}
578581

579582
impl RuleRunner for crate::rules::eslint::no_var::NoVar {
580-
const NODE_TYPES: Option<&AstTypesBitset> = None;
583+
const NODE_TYPES: Option<&AstTypesBitset> =
584+
Some(&AstTypesBitset::from_types(&[AstType::VariableDeclaration]));
581585
}
582586

583587
impl RuleRunner for crate::rules::eslint::no_void::NoVoid {
@@ -656,7 +660,8 @@ impl RuleRunner for crate::rules::eslint::require_await::RequireAwait {
656660
}
657661

658662
impl RuleRunner for crate::rules::eslint::require_yield::RequireYield {
659-
const NODE_TYPES: Option<&AstTypesBitset> = None;
663+
const NODE_TYPES: Option<&AstTypesBitset> =
664+
Some(&AstTypesBitset::from_types(&[AstType::Function]));
660665
}
661666

662667
impl RuleRunner for crate::rules::eslint::sort_imports::SortImports {
@@ -1132,7 +1137,8 @@ impl RuleRunner for crate::rules::jsx_a11y::aria_props::AriaProps {
11321137
}
11331138

11341139
impl RuleRunner for crate::rules::jsx_a11y::aria_role::AriaRole {
1135-
const NODE_TYPES: Option<&AstTypesBitset> = None;
1140+
const NODE_TYPES: Option<&AstTypesBitset> =
1141+
Some(&AstTypesBitset::from_types(&[AstType::JSXElement]));
11361142
}
11371143

11381144
impl RuleRunner for crate::rules::jsx_a11y::aria_unsupported_elements::AriaUnsupportedElements {
@@ -1340,7 +1346,8 @@ impl RuleRunner for crate::rules::nextjs::no_title_in_document_head::NoTitleInDo
13401346
}
13411347

13421348
impl RuleRunner for crate::rules::nextjs::no_typos::NoTypos {
1343-
const NODE_TYPES: Option<&AstTypesBitset> = None;
1349+
const NODE_TYPES: Option<&AstTypesBitset> =
1350+
Some(&AstTypesBitset::from_types(&[AstType::ExportNamedDeclaration]));
13441351
}
13451352

13461353
impl RuleRunner for crate::rules::nextjs::no_unwanted_polyfillio::NoUnwantedPolyfillio {
@@ -1828,7 +1835,8 @@ impl RuleRunner for crate::rules::typescript::no_dynamic_delete::NoDynamicDelete
18281835
}
18291836

18301837
impl RuleRunner for crate::rules::typescript::no_empty_interface::NoEmptyInterface {
1831-
const NODE_TYPES: Option<&AstTypesBitset> = None;
1838+
const NODE_TYPES: Option<&AstTypesBitset> =
1839+
Some(&AstTypesBitset::from_types(&[AstType::TSInterfaceDeclaration]));
18321840
}
18331841

18341842
impl RuleRunner for crate::rules::typescript::no_empty_object_type::NoEmptyObjectType {
@@ -2308,7 +2316,8 @@ impl RuleRunner
23082316
}
23092317

23102318
impl RuleRunner for crate::rules::unicorn::no_process_exit::NoProcessExit {
2311-
const NODE_TYPES: Option<&AstTypesBitset> = None;
2319+
const NODE_TYPES: Option<&AstTypesBitset> =
2320+
Some(&AstTypesBitset::from_types(&[AstType::CallExpression]));
23122321
}
23132322

23142323
impl RuleRunner

tasks/linter_codegen/src/if_else_detector.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,46 @@ impl IfElseKindDetector {
4949
}
5050
}
5151

52-
/// Extracts AstKind variants from an `if let` condition like `if let AstKind::Xxx(..) = node.kind()`.
52+
/// Extracts AstKind variants from an `if let` condition like `if let AstKind::Xxx(..) = node.kind()`
53+
/// or `if let AstKind::Xxx(..) = node.kind() && other_condition`.
5354
fn extract_variants_from_if_let_condition(&mut self, cond: &Expr) -> CollectionResult {
54-
let Expr::Let(let_expr) = cond else { return CollectionResult::Incomplete };
55-
// RHS must be `node.kind()`
56-
if is_node_kind_call(&let_expr.expr) {
57-
self.extract_variants_from_pat(&let_expr.pat)
58-
} else {
59-
CollectionResult::Incomplete
55+
match cond {
56+
// Simple `if let` pattern
57+
Expr::Let(let_expr) => {
58+
// RHS must be `node.kind()`
59+
if is_node_kind_call(&let_expr.expr) {
60+
self.extract_variants_from_pat(&let_expr.pat)
61+
} else {
62+
CollectionResult::Incomplete
63+
}
64+
}
65+
// `if let ... && ...` pattern (from MSRV 1.88.0)
66+
// The entire condition might be a chain of binary && operations
67+
Expr::Binary(binary) if matches!(binary.op, syn::BinOp::And(_)) => {
68+
// Try to find the let expression in the leftmost part of the chain
69+
self.extract_from_binary_and_chain(binary)
70+
}
71+
_ => CollectionResult::Incomplete,
72+
}
73+
}
74+
75+
/// Recursively extract from a binary && chain to find the let expression
76+
fn extract_from_binary_and_chain(&mut self, binary: &syn::ExprBinary) -> CollectionResult {
77+
// Check if the left side is another binary expression (nested &&)
78+
match &*binary.left {
79+
Expr::Binary(left_binary) if matches!(left_binary.op, syn::BinOp::And(_)) => {
80+
// Recursively check the left side
81+
self.extract_from_binary_and_chain(left_binary)
82+
}
83+
Expr::Let(let_expr) => {
84+
// Found the let expression
85+
if is_node_kind_call(&let_expr.expr) {
86+
self.extract_variants_from_pat(&let_expr.pat)
87+
} else {
88+
CollectionResult::Incomplete
89+
}
90+
}
91+
_ => CollectionResult::Incomplete,
6092
}
6193
}
6294

0 commit comments

Comments
 (0)