Skip to content

Commit c821c50

Browse files
committed
perf(linter): switch no-param-reassign to run on nodes (#14604)
Allows optimization based on node types. Also slightly less code as we don't need to traverse ancestors as much anymore.
1 parent 676ee99 commit c821c50

File tree

2 files changed

+34
-42
lines changed

2 files changed

+34
-42
lines changed

crates/oxc_linter/src/generated/rule_runner_impls.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,9 @@ impl RuleRunner for crate::rules::eslint::no_object_constructor::NoObjectConstru
548548
}
549549

550550
impl RuleRunner for crate::rules::eslint::no_param_reassign::NoParamReassign {
551-
const NODE_TYPES: Option<&AstTypesBitset> = None;
552-
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::RunOnSymbol;
551+
const NODE_TYPES: Option<&AstTypesBitset> =
552+
Some(&AstTypesBitset::from_types(&[AstType::FormalParameter]));
553+
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
553554
}
554555

555556
impl RuleRunner for crate::rules::eslint::no_plusplus::NoPlusplus {

crates/oxc_linter/src/rules/eslint/no_param_reassign.rs

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use oxc_ast::{
66
ast::{
77
AssignmentExpression, AssignmentTargetPropertyIdentifier, AssignmentTargetPropertyProperty,
88
CallExpression, ChainExpression, ComputedMemberExpression, ForInStatement, ForOfStatement,
9-
FormalParameter, ObjectProperty, ParenthesizedExpression, StaticMemberExpression,
10-
TSAsExpression, TSNonNullExpression, TSSatisfiesExpression, TSTypeAssertion,
11-
UnaryExpression, UpdateExpression,
9+
ObjectProperty, ParenthesizedExpression, StaticMemberExpression, TSAsExpression,
10+
TSNonNullExpression, TSSatisfiesExpression, TSTypeAssertion, UnaryExpression,
11+
UpdateExpression,
1212
},
1313
};
1414
use oxc_diagnostics::OxcDiagnostic;
1515
use oxc_macros::declare_oxc_lint;
16-
use oxc_semantic::{NodeId, Reference, SymbolId};
16+
use oxc_semantic::{AstNode, NodeId, Reference};
1717
use oxc_span::{GetSpan, Span};
1818
use oxc_syntax::operator::UnaryOperator;
1919
use serde_json::Value;
@@ -112,55 +112,46 @@ impl Rule for NoParamReassign {
112112
rule
113113
}
114114

115-
fn run_on_symbol(&self, symbol_id: SymbolId, ctx: &LintContext<'_>) {
116-
if !is_parameter_symbol(symbol_id, ctx) {
115+
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
116+
let AstKind::FormalParameter(param) = node.kind() else {
117117
return;
118-
}
118+
};
119119

120120
let symbol_table = ctx.scoping();
121-
let declaration_id = symbol_table.symbol_declaration(symbol_id);
122-
let name = symbol_table.symbol_name(symbol_id);
121+
for ident in param.pattern.get_binding_identifiers() {
122+
let Some(symbol_id) = ident.symbol_id.get() else {
123+
continue;
124+
};
123125

124-
let mut seen_nodes: FxHashSet<NodeId> = FxHashSet::default();
126+
let declaration_id = symbol_table.symbol_declaration(symbol_id);
127+
let name = symbol_table.symbol_name(symbol_id);
125128

126-
for reference in symbol_table.get_resolved_references(symbol_id) {
127-
let node_id = reference.node_id();
128-
if !seen_nodes.insert(node_id) {
129-
continue;
130-
}
129+
let mut seen_nodes: FxHashSet<NodeId> = FxHashSet::default();
131130

132-
if ctx.nodes().ancestor_ids(node_id).any(|ancestor| ancestor == declaration_id) {
133-
continue;
134-
}
131+
for reference in symbol_table.get_resolved_references(symbol_id) {
132+
let node_id = reference.node_id();
133+
if !seen_nodes.insert(node_id) {
134+
continue;
135+
}
135136

136-
let span = ctx.semantic().reference_span(reference);
137+
if ctx.nodes().ancestor_ids(node_id).any(|ancestor| ancestor == declaration_id) {
138+
continue;
139+
}
137140

138-
if reference.is_write() {
139-
ctx.diagnostic(assignment_to_param_diagnostic(name, span));
140-
continue;
141-
}
141+
let span = ctx.semantic().reference_span(reference);
142142

143-
if self.0.props && !self.0.is_ignored(name) && is_modifying_property(reference, ctx) {
144-
ctx.diagnostic(assignment_to_param_property_diagnostic(name, span));
145-
}
146-
}
147-
}
148-
}
143+
if reference.is_write() {
144+
ctx.diagnostic(assignment_to_param_diagnostic(name, span));
145+
continue;
146+
}
149147

150-
fn is_parameter_symbol(symbol_id: SymbolId, ctx: &LintContext<'_>) -> bool {
151-
let declaration_id = ctx.scoping().symbol_declaration(symbol_id);
152-
for ancestor_id in
153-
std::iter::once(declaration_id).chain(ctx.nodes().ancestor_ids(declaration_id))
154-
{
155-
match ctx.nodes().kind(ancestor_id) {
156-
AstKind::FormalParameter(FormalParameter { .. }) => return true,
157-
AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) | AstKind::Program(_) => {
158-
return false;
148+
if self.0.props && !self.0.is_ignored(name) && is_modifying_property(reference, ctx)
149+
{
150+
ctx.diagnostic(assignment_to_param_property_diagnostic(name, span));
151+
}
159152
}
160-
_ => {}
161153
}
162154
}
163-
false
164155
}
165156

166157
fn is_modifying_property(reference: &Reference, ctx: &LintContext<'_>) -> bool {

0 commit comments

Comments
 (0)