Skip to content

Commit 106f56f

Browse files
committed
feat(ast): add MemberExpressionKind::is_assigned_to_in_parent method (#12596)
The removal of `AstKind::SimpleAssignmentTarget` (#12401) has made it harder to determine if a node is being assigned to, because you can no longer check if the parent `AstNode` is `AstKind::SimpleAssignmentTarget`. Add a method to `MemberExpressionKind` which determines whether the parent assigns to it. Covers all possible positions where a `MemberExpression` gets assigned to - `x.y = value`, `x.y++`, `[x.y] = arr` etc. We can use this method to avoid repeating this complicated logic in many places.
1 parent c763e0e commit 106f56f

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

crates/oxc_ast/src/ast_kind_impl.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,53 @@ impl<'a> MemberExpressionKind<'a> {
519519
Self::PrivateField(member_expr) => member_expr.optional,
520520
}
521521
}
522+
523+
/// Given a [`MemberExpressionKind`] and [`AstKind`] representing its parent node,
524+
/// returns `true` if the member expression is assigned to.
525+
///
526+
/// Note: `parent` must be the parent node of the member expression.
527+
/// This method does not check that, and may return incorrect results if it's not.
528+
pub fn is_assigned_to_in_parent(&self, parent: &AstKind<'a>) -> bool {
529+
#[expect(clippy::match_same_arms)]
530+
match parent {
531+
// `x.y++`, `--x.y`
532+
// `UpdateExpression` has only 1 field containing child node - `argument`.
533+
AstKind::UpdateExpression(_) => true,
534+
// `[x.y] = arr`
535+
// `ArrayAssignmentTarget` has only 1 field containing child nodes - `elements`.
536+
AstKind::ArrayAssignmentTarget(_) => true,
537+
// `[...x.y] = arr`, `({ ...x.y } = obj)`
538+
// `AssignmentTargetRest` has only 1 field containing child node - `target`.
539+
AstKind::AssignmentTargetRest(_) => true,
540+
// `x.y = value`
541+
// Only match if member expr is on left
542+
// - not on right e.g. `assignee = x.y`.
543+
AstKind::AssignmentExpression(assign_expr) => {
544+
assign_expr.left.address() == self.address()
545+
}
546+
// `[x.y = value] = arr`, `({ prop: x.y = value } = obj)`
547+
// Only match if member expr is the assignee
548+
// - not the default value e.g. `[assignee = x.y] = arr`.
549+
AstKind::AssignmentTargetWithDefault(assign_target) => {
550+
assign_target.binding.address() == self.address()
551+
}
552+
// `({ prop: x.y } = obj)`
553+
// Only match if member expr is the assignee
554+
// - not computed prop key e.g. `({ [x.y]: assignee } = obj)`.
555+
AstKind::AssignmentTargetPropertyProperty(assign_target) => {
556+
assign_target.binding.address() == self.address()
557+
}
558+
// `for (x.y in obj)`
559+
// Only match if member expr is on left
560+
// - not object being iterated e.g. `for (assignee in x.y)`
561+
AstKind::ForInStatement(for_stmt) => for_stmt.left.address() == self.address(),
562+
// `for (x.y of obj)`
563+
// Only match if member expr is on left
564+
// - not array being iterated e.g. `for (assignee of x.y)`
565+
AstKind::ForOfStatement(for_stmt) => for_stmt.left.address() == self.address(),
566+
_ => false,
567+
}
568+
}
522569
}
523570

524571
impl GetSpan for MemberExpressionKind<'_> {

0 commit comments

Comments
 (0)