Skip to content

Commit

Permalink
Improve MemberExpression matching
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Apr 25, 2024
1 parent cb48eb2 commit 481b301
Show file tree
Hide file tree
Showing 23 changed files with 146 additions and 192 deletions.
32 changes: 18 additions & 14 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ macro_rules! add_member_expression_variants {
}
}

#[macro_export]
macro_rules! match_member_expression_variants {
($ty:ident) => {
$ty::ComputedMemberExpression(_)
| $ty::StaticMemberExpression(_)
| $ty::PrivateFieldExpression(_)
};
}
pub use match_member_expression_variants;

add_member_expression_variants! {
/// Expression
#[ast_node]
Expand Down Expand Up @@ -282,10 +292,9 @@ impl<'a> Expression<'a> {

#[allow(clippy::missing_panics_doc)] // `unwrap()` for `MemberExpression` variants cannot panic
pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool {
let inner = self.get_inner_expression();
match inner {
_ if inner.is_member_expression() => {
inner.as_member_expression().unwrap().is_specific_member_access(object, property)
match self.get_inner_expression() {
expr if expr.is_member_expression() => {
expr.as_member_expression().unwrap().is_specific_member_access(object, property)
}
Expression::ChainExpression(chain) => {
let Some(expr) = chain.expression.as_member_expression() else {
Expand Down Expand Up @@ -356,10 +365,9 @@ impl<'a> Expression<'a> {
}

pub fn get_member_expr(&self) -> Option<&MemberExpression<'a>> {
let inner = self.get_inner_expression();
match inner {
match self.get_inner_expression() {
Expression::ChainExpression(chain_expr) => chain_expr.expression.as_member_expression(),
_ => inner.as_member_expression(),
expr => expr.as_member_expression(),
}
}

Expand Down Expand Up @@ -787,9 +795,7 @@ impl<'a> MemberExpression<'a> {
let object_matches = match self.object().without_parenthesized() {
Expression::ChainExpression(x) => match &x.expression {
ChainElement::CallExpression(_) => false,
ChainElement::ComputedMemberExpression(_)
| ChainElement::StaticMemberExpression(_)
| ChainElement::PrivateFieldExpression(_) => {
match_member_expression_variants!(ChainElement) => {
let member_expr = x.expression.as_member_expression().unwrap();
member_expr.object().without_parenthesized().is_specific_id(object)
}
Expand Down Expand Up @@ -867,9 +873,7 @@ impl<'a> CallExpression<'a> {
pub fn callee_name(&self) -> Option<&str> {
match &self.callee {
Expression::Identifier(ident) => Some(ident.name.as_str()),
_ => {
self.callee.as_member_expression().and_then(MemberExpression::static_property_name)
}
expr => expr.as_member_expression().and_then(MemberExpression::static_property_name),
}
}

Expand All @@ -894,7 +898,7 @@ impl<'a> CallExpression<'a> {
// TODO: is 'Symbol' reference to global object
match &self.callee {
Expression::Identifier(id) => id.name == "Symbol",
_ => match self.callee.as_member_expression() {
expr => match expr.as_member_expression() {
Some(member) => {
matches!(member.object(), Expression::Identifier(id) if id.name == "Symbol")
&& member.static_property_name() == Some("for")
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_ast/src/ast/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ macro_rules! add_ts_type_variants {
}
}

// TODO: Create similar macros for the other inherited enums
#[macro_export]
macro_rules! match_ts_type_variants {
($ty:ident) => {
Expand Down Expand Up @@ -1180,7 +1179,7 @@ impl<'a> Decorator<'a> {
pub fn name(&self) -> Option<&str> {
match &self.expression {
Expression::Identifier(ident) => Some(&ident.name),
_ if self.expression.is_member_expression() => {
expr if expr.is_member_expression() => {
self.expression.as_member_expression().unwrap().static_property_name()
}
Expression::CallExpression(call) => {
Expand Down
6 changes: 1 addition & 5 deletions crates/oxc_ast/src/ast_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,9 @@ impl<'a> AstKind<'a> {
Expression::TSTypeAssertion(e) => Self::TSTypeAssertion(e),
Expression::TSNonNullExpression(e) => Self::TSNonNullExpression(e),
Expression::TSInstantiationExpression(e) => Self::TSInstantiationExpression(e),

Expression::ComputedMemberExpression(_)
| Expression::StaticMemberExpression(_)
| Expression::PrivateFieldExpression(_) => {
match_member_expression_variants!(Expression) => {
Self::MemberExpression(e.as_member_expression().unwrap())
}

Expression::Dummy => Self::Dummy,
}
}
Expand Down
14 changes: 7 additions & 7 deletions crates/oxc_ast/src/precedence.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use oxc_syntax::precedence::{GetPrecedence, Precedence};

use crate::ast::{
ArrowFunctionExpression, AssignmentExpression, AwaitExpression, BinaryExpression,
CallExpression, ConditionalExpression, Expression, ImportExpression, LogicalExpression,
MemberExpression, NewExpression, SequenceExpression, UnaryExpression, UpdateExpression,
YieldExpression,
match_member_expression_variants, ArrowFunctionExpression, AssignmentExpression,
AwaitExpression, BinaryExpression, CallExpression, ConditionalExpression, Expression,
ImportExpression, LogicalExpression, MemberExpression, NewExpression, SequenceExpression,
UnaryExpression, UpdateExpression, YieldExpression,
};

impl<'a> GetPrecedence for Expression<'a> {
Expand All @@ -22,9 +22,9 @@ impl<'a> GetPrecedence for Expression<'a> {
Self::AwaitExpression(expr) => expr.precedence(),
Self::NewExpression(expr) => expr.precedence(),
Self::CallExpression(expr) => expr.precedence(),
Self::ComputedMemberExpression(_)
| Self::StaticMemberExpression(_)
| Self::PrivateFieldExpression(_) => self.as_member_expression().unwrap().precedence(),
match_member_expression_variants!(Self) => {
self.as_member_expression().unwrap().precedence()
}
_ => panic!("All cases should be covered"),
}
}
Expand Down
22 changes: 5 additions & 17 deletions crates/oxc_ast/src/visit/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1484,14 +1484,10 @@ pub mod walk {
Expression::TSInstantiationExpression(expr) => {
visitor.visit_ts_instantiation_expression(expr);
}

Expression::ComputedMemberExpression(_)
| Expression::StaticMemberExpression(_)
| Expression::PrivateFieldExpression(_) => {
match_member_expression_variants!(Expression) => {
let member_expr = expr.as_member_expression().unwrap();
visitor.visit_member_expression(member_expr);
}

Expression::Dummy => dummy!(),
}
}
Expand Down Expand Up @@ -1625,14 +1621,9 @@ pub mod walk {
pub fn walk_chain_element<'a, V: Visit<'a>>(visitor: &mut V, elem: &ChainElement<'a>) {
match elem {
ChainElement::CallExpression(expr) => visitor.visit_call_expression(expr),

ChainElement::ComputedMemberExpression(_)
| ChainElement::StaticMemberExpression(_)
| ChainElement::PrivateFieldExpression(_) => {
let member_expr = elem.as_member_expression().unwrap();
visitor.visit_member_expression(member_expr);
match_member_expression_variants!(ChainElement) => {
visitor.visit_member_expression(elem.as_member_expression().unwrap());
}

ChainElement::Dummy => dummy!(),
}
}
Expand Down Expand Up @@ -1873,11 +1864,8 @@ pub mod walk {
SimpleAssignmentTarget::AssignmentTargetIdentifier(ident) => {
visitor.visit_identifier_reference(ident);
}
SimpleAssignmentTarget::ComputedMemberExpression(_)
| SimpleAssignmentTarget::StaticMemberExpression(_)
| SimpleAssignmentTarget::PrivateFieldExpression(_) => {
let member_expr = target.as_member_expression().unwrap();
visitor.visit_member_expression(member_expr);
match_member_expression_variants!(SimpleAssignmentTarget) => {
visitor.visit_member_expression(target.as_member_expression().unwrap());
}
SimpleAssignmentTarget::TSAsExpression(expr) => {
visitor.visit_expression(&expr.expression);
Expand Down
22 changes: 5 additions & 17 deletions crates/oxc_ast/src/visit/visit_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1512,14 +1512,10 @@ pub mod walk_mut {
Expression::TSInstantiationExpression(expr) => {
visitor.visit_ts_instantiation_expression(expr);
}

Expression::ComputedMemberExpression(_)
| Expression::StaticMemberExpression(_)
| Expression::PrivateFieldExpression(_) => {
match_member_expression_variants!(Expression) => {
let member_expr = expr.as_member_expression_mut().unwrap();
visitor.visit_member_expression(member_expr);
}

Expression::Dummy => dummy!(),
}
}
Expand Down Expand Up @@ -1680,14 +1676,9 @@ pub mod walk_mut {
) {
match elem {
ChainElement::CallExpression(expr) => visitor.visit_call_expression(expr),

ChainElement::ComputedMemberExpression(_)
| ChainElement::StaticMemberExpression(_)
| ChainElement::PrivateFieldExpression(_) => {
let member_expr = elem.as_member_expression_mut().unwrap();
visitor.visit_member_expression(member_expr);
match_member_expression_variants!(ChainElement) => {
visitor.visit_member_expression(elem.as_member_expression_mut().unwrap());
}

ChainElement::Dummy => dummy!(),
}
}
Expand Down Expand Up @@ -1952,11 +1943,8 @@ pub mod walk_mut {
SimpleAssignmentTarget::AssignmentTargetIdentifier(ident) => {
visitor.visit_identifier_reference(ident);
}
SimpleAssignmentTarget::ComputedMemberExpression(_)
| SimpleAssignmentTarget::StaticMemberExpression(_)
| SimpleAssignmentTarget::PrivateFieldExpression(_) => {
let member_expr = target.as_member_expression_mut().unwrap();
visitor.visit_member_expression(member_expr);
match_member_expression_variants!(SimpleAssignmentTarget) => {
visitor.visit_member_expression(target.as_member_expression_mut().unwrap());
}
SimpleAssignmentTarget::TSAsExpression(expr) => {
visitor.visit_expression(&mut expr.expression);
Expand Down
14 changes: 3 additions & 11 deletions crates/oxc_codegen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1016,13 +1016,9 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for Expression<'a> {
Self::TSTypeAssertion(e) => e.gen_expr(p, precedence, ctx),
Self::TSNonNullExpression(e) => e.expression.gen_expr(p, precedence, ctx),
Self::TSInstantiationExpression(e) => e.expression.gen_expr(p, precedence, ctx),

Self::ComputedMemberExpression(_)
| Self::StaticMemberExpression(_)
| Self::PrivateFieldExpression(_) => {
match_member_expression_variants!(Self) => {
self.as_member_expression().unwrap().gen_expr(p, precedence, ctx);
}

Self::Dummy => dummy!(),
}
}
Expand Down Expand Up @@ -1809,9 +1805,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for SimpleAssignmentTarget<'a> {
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) {
match self {
Self::AssignmentTargetIdentifier(ident) => ident.gen(p, ctx),
Self::ComputedMemberExpression(_)
| Self::StaticMemberExpression(_)
| Self::PrivateFieldExpression(_) => {
match_member_expression_variants!(Self) => {
self.as_member_expression().unwrap().gen_expr(p, precedence, ctx);
}
Self::TSAsExpression(e) => e.gen_expr(p, precedence, ctx),
Expand Down Expand Up @@ -2018,9 +2012,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for ChainExpression<'a> {
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) {
match &self.expression {
ChainElement::CallExpression(expr) => expr.gen_expr(p, precedence, ctx),
ChainElement::ComputedMemberExpression(_)
| ChainElement::StaticMemberExpression(_)
| ChainElement::PrivateFieldExpression(_) => {
match_member_expression_variants!(ChainElement) => {
self.expression.as_member_expression().unwrap().gen_expr(p, precedence, ctx);
}
ChainElement::Dummy => dummy!(),
Expand Down
19 changes: 7 additions & 12 deletions crates/oxc_linter/src/rules/eslint/getter_return.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use oxc_ast::{
ast::{
ChainElement, Expression, MemberExpression, MethodDefinitionKind, ObjectProperty,
PropertyKind,
match_member_expression_variants, ChainElement, Expression, MemberExpression,
MethodDefinitionKind, ObjectProperty, PropertyKind,
},
dummy, AstKind,
};
Expand Down Expand Up @@ -89,18 +89,13 @@ impl GetterReturn {
}

fn handle_actual_expression<'a>(callee: &'a Expression<'a>) -> bool {
let callee = callee.without_parenthesized();
match callee {
_ if callee.is_member_expression() => {
let member_expr = callee.as_member_expression().unwrap();
Self::handle_member_expression(member_expr)
match callee.without_parenthesized() {
expr if expr.is_member_expression() => {
Self::handle_member_expression(expr.as_member_expression().unwrap())
}
Expression::ChainExpression(ce) => match &ce.expression {
ChainElement::ComputedMemberExpression(_)
| ChainElement::StaticMemberExpression(_)
| ChainElement::PrivateFieldExpression(_) => {
let member_expr = ce.expression.as_member_expression().unwrap();
Self::handle_member_expression(member_expr)
match_member_expression_variants!(ChainElement) => {
Self::handle_member_expression(ce.expression.as_member_expression().unwrap())
}
ChainElement::CallExpression(_) => {
false // todo: make a test for this
Expand Down
32 changes: 20 additions & 12 deletions crates/oxc_linter/src/rules/jest/prefer_spy_on.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ impl Rule for PreferSpyOn {
return;
};

if let Expression::CallExpression(call_expr) = right {
Self::check_and_fix(assign_expr, call_expr, left_assign, node, ctx);
} else if let Some(mem_expr) = right.as_member_expression() {
if let Expression::CallExpression(call_expr) = mem_expr.object() {
match right {
Expression::CallExpression(call_expr) => {
Self::check_and_fix(assign_expr, call_expr, left_assign, node, ctx);
};
}
_ => {
if let Some(mem_expr) = right.as_member_expression() {
let Expression::CallExpression(call_expr) = mem_expr.object() else {
return;
};
Self::check_and_fix(assign_expr, call_expr, left_assign, node, ctx);
}
}
}
}
}
Expand Down Expand Up @@ -178,15 +184,17 @@ impl PreferSpyOn {
return call_expr.arguments.first();
}

if let Some(mem_expr) = call_expr.callee.as_member_expression() {
if let Some(call_expr) = Self::find_mem_expr(mem_expr) {
return Self::get_jest_fn_call(call_expr);
match &call_expr.callee {
expr if expr.is_member_expression() => {
let mem_expr = expr.as_member_expression().unwrap();
if let Some(call_expr) = Self::find_mem_expr(mem_expr) {
return Self::get_jest_fn_call(call_expr);
}
None
}
} else if let Expression::CallExpression(call_expr) = &call_expr.callee {
return Self::get_jest_fn_call(call_expr);
Expression::CallExpression(call_expr) => Self::get_jest_fn_call(call_expr),
_ => None,
}

None
}

fn find_mem_expr<'a>(mut mem_expr: &'a MemberExpression<'a>) -> Option<&'a CallExpression<'a>> {
Expand Down
Loading

0 comments on commit 481b301

Please sign in to comment.