Skip to content

Commit 46ec4b6

Browse files
committed
perf(linter): rearrange rules for node type analysis
1 parent 73f2cbb commit 46ec4b6

File tree

3 files changed

+174
-159
lines changed

3 files changed

+174
-159
lines changed

crates/oxc_linter/src/generated/rule_runner_impls.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,7 +3228,8 @@ impl RuleRunner for crate::rules::unicorn::no_unnecessary_slice_end::NoUnnecessa
32283228
impl RuleRunner
32293229
for crate::rules::unicorn::no_unreadable_array_destructuring::NoUnreadableArrayDestructuring
32303230
{
3231-
const NODE_TYPES: Option<&AstTypesBitset> = None;
3231+
const NODE_TYPES: Option<&AstTypesBitset> =
3232+
Some(&AstTypesBitset::from_types(&[AstType::ArrayAssignmentTarget, AstType::ArrayPattern]));
32323233
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
32333234
}
32343235

@@ -3310,7 +3311,12 @@ impl RuleRunner for crate::rules::unicorn::prefer_add_event_listener::PreferAddE
33103311
}
33113312

33123313
impl RuleRunner for crate::rules::unicorn::prefer_array_find::PreferArrayFind {
3313-
const NODE_TYPES: Option<&AstTypesBitset> = None;
3314+
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
3315+
AstType::AssignmentExpression,
3316+
AstType::CallExpression,
3317+
AstType::ComputedMemberExpression,
3318+
AstType::VariableDeclarator,
3319+
]));
33143320
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
33153321
}
33163322

crates/oxc_linter/src/rules/unicorn/no_unreadable_array_destructuring.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,24 @@ fn is_unreadable_array_destructuring<T, U>(elements: &Vec<Option<T>>, rest: Opti
5454

5555
impl Rule for NoUnreadableArrayDestructuring {
5656
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
57-
if let AstKind::ArrayPattern(array_pattern) = node.kind()
58-
&& is_unreadable_array_destructuring(
59-
&array_pattern.elements,
60-
array_pattern.rest.as_ref(),
61-
)
62-
{
63-
ctx.diagnostic(no_unreadable_array_destructuring_diagnostic(array_pattern.span));
64-
}
65-
66-
if let AstKind::ArrayAssignmentTarget(array_pattern) = node.kind()
67-
&& is_unreadable_array_destructuring(
68-
&array_pattern.elements,
69-
array_pattern.rest.as_ref(),
70-
)
71-
{
72-
ctx.diagnostic(no_unreadable_array_destructuring_diagnostic(array_pattern.span));
57+
match node.kind() {
58+
AstKind::ArrayPattern(array_pattern)
59+
if is_unreadable_array_destructuring(
60+
&array_pattern.elements,
61+
array_pattern.rest.as_ref(),
62+
) =>
63+
{
64+
ctx.diagnostic(no_unreadable_array_destructuring_diagnostic(array_pattern.span));
65+
}
66+
AstKind::ArrayAssignmentTarget(array_pattern)
67+
if is_unreadable_array_destructuring(
68+
&array_pattern.elements,
69+
array_pattern.rest.as_ref(),
70+
) =>
71+
{
72+
ctx.diagnostic(no_unreadable_array_destructuring_diagnostic(array_pattern.span));
73+
}
74+
_ => {}
7375
}
7476
}
7577
}

crates/oxc_linter/src/rules/unicorn/prefer_array_find.rs

Lines changed: 148 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -56,159 +56,166 @@ declare_oxc_lint!(
5656

5757
impl Rule for PreferArrayFind {
5858
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
59-
// Zero index access
60-
if let AstKind::ComputedMemberExpression(computed_member_expr) = node.kind()
61-
&& computed_member_expr.expression.is_number_0()
62-
&& let Expression::CallExpression(call_expr) =
63-
computed_member_expr.object.get_inner_expression()
64-
&& is_filter_call(call_expr)
65-
&& !is_left_hand_side(node, ctx)
66-
{
67-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
68-
call_expr,
69-
)));
70-
}
71-
72-
if let AstKind::CallExpression(call_expr) = node.kind()
73-
&& is_method_call(call_expr, None, Some(&["shift"]), Some(0), Some(0))
74-
&& let Some(Expression::CallExpression(filter_call_expr)) = call_expr
75-
.callee
76-
.get_inner_expression()
77-
.as_member_expression()
78-
.map(|expression| expression.object().get_inner_expression())
79-
&& is_filter_call(filter_call_expr)
80-
{
81-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
82-
filter_call_expr,
83-
)));
84-
}
59+
match node.kind() {
60+
AstKind::ComputedMemberExpression(computed_member_expr) => {
61+
// Zero index access
62+
if computed_member_expr.expression.is_number_0()
63+
&& let Expression::CallExpression(call_expr) =
64+
computed_member_expr.object.get_inner_expression()
65+
&& is_filter_call(call_expr)
66+
&& !is_left_hand_side(node, ctx)
67+
{
68+
ctx.diagnostic(prefer_array_find_diagnostic(
69+
call_expr_member_expr_property_span(call_expr),
70+
));
71+
}
72+
}
73+
AstKind::CallExpression(call_expr) => {
74+
if is_method_call(call_expr, None, Some(&["shift"]), Some(0), Some(0))
75+
&& let Some(Expression::CallExpression(filter_call_expr)) = call_expr
76+
.callee
77+
.get_inner_expression()
78+
.as_member_expression()
79+
.map(|expression| expression.object().get_inner_expression())
80+
&& is_filter_call(filter_call_expr)
81+
{
82+
ctx.diagnostic(prefer_array_find_diagnostic(
83+
call_expr_member_expr_property_span(filter_call_expr),
84+
));
85+
}
8586

86-
// `const [foo] = array.filter()`
87-
if let AstKind::VariableDeclarator(var_decl) = node.kind()
88-
&& let BindingPatternKind::ArrayPattern(array_pat) = &var_decl.id.kind
89-
&& array_pat.elements.len() == 1
90-
&& array_pat.elements[0].is_some()
91-
&& let Some(Expression::CallExpression(array_filter)) = &var_decl.init
92-
&& is_filter_call(array_filter)
93-
{
94-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
95-
array_filter,
96-
)));
97-
}
87+
// `array.filter().at(0)`
88+
// `array.filter().at(-1)`
89+
if is_method_call(call_expr, None, Some(&["at"]), Some(1), Some(1))
90+
&& call_expr.arguments.first().is_some_and(|arg| {
91+
arg.as_expression().is_some_and(|x| match x {
92+
Expression::NumericLiteral(_) if x.is_number_value(0.0) => true,
93+
Expression::UnaryExpression(u)
94+
if u.operator == UnaryOperator::UnaryNegation =>
95+
{
96+
u.argument.is_number_value(1.0)
97+
}
98+
_ => false,
99+
})
100+
})
101+
&& let Some(Expression::CallExpression(filter_call_expr)) = call_expr
102+
.callee
103+
.get_inner_expression()
104+
.as_member_expression()
105+
.map(|expression| expression.object().get_inner_expression())
106+
&& is_filter_call(filter_call_expr)
107+
{
108+
ctx.diagnostic(prefer_array_find_diagnostic(
109+
call_expr_member_expr_property_span(filter_call_expr),
110+
));
111+
}
98112

99-
// `[foo] = array.filter()`
100-
if let AstKind::AssignmentExpression(assignment_expr) = node.kind()
101-
&& let AssignmentTarget::ArrayAssignmentTarget(array_assignment_target) =
102-
&assignment_expr.left
103-
&& array_assignment_target.elements.len() == 1
104-
&& array_assignment_target.elements[0].is_some()
105-
&& let Expression::CallExpression(array_filter) = &assignment_expr.right
106-
&& is_filter_call(array_filter)
107-
{
108-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
109-
array_filter,
110-
)));
111-
}
113+
// `array.filter().pop()`
114+
if is_method_call(call_expr, None, Some(&["pop"]), Some(0), Some(0))
115+
&& let Some(Expression::CallExpression(filter_call_expr)) = call_expr
116+
.callee
117+
.get_inner_expression()
118+
.as_member_expression()
119+
.map(|expression| expression.object().get_inner_expression())
120+
&& is_filter_call(filter_call_expr)
121+
{
122+
ctx.diagnostic(prefer_array_find_diagnostic(
123+
call_expr_member_expr_property_span(filter_call_expr),
124+
));
125+
}
126+
}
127+
AstKind::VariableDeclarator(var_decl) => {
128+
// `const [foo] = array.filter()`
129+
if let BindingPatternKind::ArrayPattern(array_pat) = &var_decl.id.kind
130+
&& array_pat.elements.len() == 1
131+
&& array_pat.elements[0].is_some()
132+
&& let Some(Expression::CallExpression(array_filter)) = &var_decl.init
133+
&& is_filter_call(array_filter)
134+
{
135+
ctx.diagnostic(prefer_array_find_diagnostic(
136+
call_expr_member_expr_property_span(array_filter),
137+
));
138+
}
112139

113-
// `const foo = array.filter(); foo[0]; [bar] = foo`
114-
if let AstKind::VariableDeclarator(var_decl) = node.kind()
115-
&& let Some(Expression::CallExpression(call_expr)) = &var_decl.init
116-
&& is_filter_call(call_expr)
117-
&& !matches!(
118-
ctx.nodes().ancestor_kinds(node.id()).nth(1),
119-
Some(AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_))
120-
)
121-
&& let Some(ident) = var_decl.id.kind.get_binding_identifier()
122-
{
123-
let mut zero_index_nodes = Vec::new();
124-
let mut destructuring_nodes = Vec::new();
140+
// `const foo = array.filter(); foo[0]; [bar] = foo`
141+
if let Some(Expression::CallExpression(call_expr)) = &var_decl.init
142+
&& is_filter_call(call_expr)
143+
&& !matches!(
144+
ctx.nodes().ancestor_kinds(node.id()).nth(1),
145+
Some(
146+
AstKind::ExportDefaultDeclaration(_)
147+
| AstKind::ExportNamedDeclaration(_)
148+
)
149+
)
150+
&& let Some(ident) = var_decl.id.kind.get_binding_identifier()
151+
{
152+
let mut zero_index_nodes = Vec::new();
153+
let mut destructuring_nodes = Vec::new();
125154

126-
let mut is_used_elsewhere = false;
155+
let mut is_used_elsewhere = false;
127156

128-
for reference in ctx.symbol_references(ident.symbol_id()) {
129-
match ctx.nodes().parent_kind(reference.node_id()) {
130-
AstKind::ComputedMemberExpression(c) if c.expression.is_number_0() => {
131-
zero_index_nodes.push(reference);
132-
}
133-
AstKind::VariableDeclarator(var_declarator) => {
134-
if let BindingPatternKind::ArrayPattern(array_pat) = &var_declarator.id.kind
135-
&& array_pat.elements.len() == 1
136-
&& array_pat.elements[0].is_some()
137-
{
138-
destructuring_nodes.push(reference);
139-
}
140-
}
141-
AstKind::AssignmentExpression(assignment_expr) => {
142-
// Check for array destructuring: [foo] = items
143-
if let AssignmentTarget::ArrayAssignmentTarget(target) =
144-
&assignment_expr.left
145-
{
146-
if target.elements.len() == 1 && target.elements[0].is_some() {
147-
destructuring_nodes.push(reference);
157+
for reference in ctx.symbol_references(ident.symbol_id()) {
158+
match ctx.nodes().parent_kind(reference.node_id()) {
159+
AstKind::ComputedMemberExpression(c) if c.expression.is_number_0() => {
160+
zero_index_nodes.push(reference);
148161
}
149-
} else if let Some(SimpleAssignmentTarget::AssignmentTargetIdentifier(
150-
ident,
151-
)) = assignment_expr.left.as_simple_assignment_target()
152-
{
153-
// Check for simple reassignment: items = something
154-
if ident.span == ctx.nodes().get_node(reference.node_id()).span() {
155-
is_used_elsewhere = true; // Variable is being reassigned
162+
AstKind::VariableDeclarator(var_declarator) => {
163+
if let BindingPatternKind::ArrayPattern(array_pat) =
164+
&var_declarator.id.kind
165+
&& array_pat.elements.len() == 1
166+
&& array_pat.elements[0].is_some()
167+
{
168+
destructuring_nodes.push(reference);
169+
}
156170
}
171+
AstKind::AssignmentExpression(assignment_expr) => {
172+
// Check for array destructuring: [foo] = items
173+
if let AssignmentTarget::ArrayAssignmentTarget(target) =
174+
&assignment_expr.left
175+
{
176+
if target.elements.len() == 1 && target.elements[0].is_some() {
177+
destructuring_nodes.push(reference);
178+
}
179+
} else if let Some(
180+
SimpleAssignmentTarget::AssignmentTargetIdentifier(ident),
181+
) = assignment_expr.left.as_simple_assignment_target()
182+
{
183+
// Check for simple reassignment: items = something
184+
if ident.span
185+
== ctx.nodes().get_node(reference.node_id()).span()
186+
{
187+
is_used_elsewhere = true; // Variable is being reassigned
188+
}
189+
}
190+
}
191+
_ => is_used_elsewhere = true,
157192
}
158193
}
159-
_ => is_used_elsewhere = true,
160-
}
161-
}
162-
163-
if !is_used_elsewhere
164-
&& (!zero_index_nodes.is_empty() || !destructuring_nodes.is_empty())
165-
{
166-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
167-
call_expr,
168-
)));
169-
}
170-
}
171194

172-
// `array.filter().at(0)`
173-
// `array.filter().at(-1)`
174-
if let AstKind::CallExpression(at_call_expr) = node.kind()
175-
&& is_method_call(at_call_expr, None, Some(&["at"]), Some(1), Some(1))
176-
&& at_call_expr.arguments.first().is_some_and(|arg| {
177-
arg.as_expression().is_some_and(|x| match x {
178-
Expression::NumericLiteral(_) if x.is_number_value(0.0) => true,
179-
Expression::UnaryExpression(u)
180-
if u.operator == UnaryOperator::UnaryNegation =>
195+
if !is_used_elsewhere
196+
&& (!zero_index_nodes.is_empty() || !destructuring_nodes.is_empty())
181197
{
182-
u.argument.is_number_value(1.0)
198+
ctx.diagnostic(prefer_array_find_diagnostic(
199+
call_expr_member_expr_property_span(call_expr),
200+
));
183201
}
184-
_ => false,
185-
})
186-
})
187-
&& let Some(Expression::CallExpression(filter_call_expr)) = at_call_expr
188-
.callee
189-
.get_inner_expression()
190-
.as_member_expression()
191-
.map(|expression| expression.object().get_inner_expression())
192-
&& is_filter_call(filter_call_expr)
193-
{
194-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
195-
filter_call_expr,
196-
)));
197-
}
198-
199-
// `array.filter().pop()`
200-
if let AstKind::CallExpression(pop_call_expr) = node.kind()
201-
&& is_method_call(pop_call_expr, None, Some(&["pop"]), Some(0), Some(0))
202-
&& let Some(Expression::CallExpression(filter_call_expr)) = pop_call_expr
203-
.callee
204-
.get_inner_expression()
205-
.as_member_expression()
206-
.map(|expression| expression.object().get_inner_expression())
207-
&& is_filter_call(filter_call_expr)
208-
{
209-
ctx.diagnostic(prefer_array_find_diagnostic(call_expr_member_expr_property_span(
210-
filter_call_expr,
211-
)));
202+
}
203+
}
204+
AstKind::AssignmentExpression(assignment_expr) => {
205+
// `[foo] = array.filter()`
206+
if let AssignmentTarget::ArrayAssignmentTarget(array_assignment_target) =
207+
&assignment_expr.left
208+
&& array_assignment_target.elements.len() == 1
209+
&& array_assignment_target.elements[0].is_some()
210+
&& let Expression::CallExpression(array_filter) = &assignment_expr.right
211+
&& is_filter_call(array_filter)
212+
{
213+
ctx.diagnostic(prefer_array_find_diagnostic(
214+
call_expr_member_expr_property_span(array_filter),
215+
));
216+
}
217+
}
218+
_ => {}
212219
}
213220
}
214221
}

0 commit comments

Comments
 (0)