mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
refactor(transformer/optional-chaining): avoid multiple symbol lookups (#7421)
`IdentifierReference::is_global_reference` and `MaybeBoundIdentifier::from_identifier_reference` both look up the symbol for the identifier. Do this lookup only once, rather than twice.
This commit is contained in:
parent
971c91a2e8
commit
52784d2aea
1 changed files with 29 additions and 22 deletions
|
|
@ -51,7 +51,7 @@ use std::mem;
|
||||||
|
|
||||||
use oxc_allocator::CloneIn;
|
use oxc_allocator::CloneIn;
|
||||||
use oxc_ast::{ast::*, NONE};
|
use oxc_ast::{ast::*, NONE};
|
||||||
use oxc_semantic::{IsGlobalReference, SymbolFlags};
|
use oxc_semantic::SymbolFlags;
|
||||||
use oxc_span::SPAN;
|
use oxc_span::SPAN;
|
||||||
use oxc_traverse::{Ancestor, BoundIdentifier, MaybeBoundIdentifier, Traverse, TraverseCtx};
|
use oxc_traverse::{Ancestor, BoundIdentifier, MaybeBoundIdentifier, Traverse, TraverseCtx};
|
||||||
|
|
||||||
|
|
@ -180,17 +180,26 @@ impl<'a, 'ctx> OptionalChaining<'a, 'ctx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if we should create a temp variable for the identifier
|
/// Check if we should create a temp variable for the identifier.
|
||||||
///
|
///
|
||||||
/// Except for `eval`, we should create a temp variable for all global references
|
/// Except for `eval`, we should create a temp variable for all global references.
|
||||||
fn should_create_temp_variable_for_identifier(
|
///
|
||||||
|
/// If no temp variable required, returns `MaybeBoundIdentifier` for existing variable/global.
|
||||||
|
/// If temp variable is required, returns `None`.
|
||||||
|
fn get_existing_binding_for_identifier(
|
||||||
&self,
|
&self,
|
||||||
ident: &IdentifierReference<'a>,
|
ident: &IdentifierReference<'a>,
|
||||||
ctx: &TraverseCtx<'a>,
|
ctx: &TraverseCtx<'a>,
|
||||||
) -> bool {
|
) -> Option<MaybeBoundIdentifier<'a>> {
|
||||||
!self.ctx.assumptions.pure_getters
|
let binding = MaybeBoundIdentifier::from_identifier_reference(ident, ctx);
|
||||||
&& ident.is_global_reference(ctx.symbols())
|
if self.ctx.assumptions.pure_getters
|
||||||
&& ident.name != "eval"
|
|| binding.to_bound_identifier().is_some()
|
||||||
|
|| ident.name == "eval"
|
||||||
|
{
|
||||||
|
Some(binding)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `left === null`
|
/// Return `left === null`
|
||||||
|
|
@ -544,8 +553,7 @@ impl<'a, 'ctx> OptionalChaining<'a, 'ctx> {
|
||||||
// If the expression is an identifier and it's not a global reference, we just wrap it with checks
|
// If the expression is an identifier and it's not a global reference, we just wrap it with checks
|
||||||
// `foo` -> `foo === null || foo === void 0`
|
// `foo` -> `foo === null || foo === void 0`
|
||||||
if let Expression::Identifier(ident) = expr {
|
if let Expression::Identifier(ident) = expr {
|
||||||
if !self.should_create_temp_variable_for_identifier(ident, ctx) {
|
if let Some(binding) = self.get_existing_binding_for_identifier(ident, ctx) {
|
||||||
let binding = MaybeBoundIdentifier::from_identifier_reference(ident, ctx);
|
|
||||||
let left1 = binding.create_read_expression(ctx);
|
let left1 = binding.create_read_expression(ctx);
|
||||||
let left2 = binding.create_read_expression(ctx);
|
let left2 = binding.create_read_expression(ctx);
|
||||||
if ident.name == "eval" {
|
if ident.name == "eval" {
|
||||||
|
|
@ -568,18 +576,17 @@ impl<'a, 'ctx> OptionalChaining<'a, 'ctx> {
|
||||||
// If the [`MemberExpression::object`] is a global reference, we need to assign it to a temp binding.
|
// If the [`MemberExpression::object`] is a global reference, we need to assign it to a temp binding.
|
||||||
// i.e `foo` -> `(_foo = foo)`
|
// i.e `foo` -> `(_foo = foo)`
|
||||||
if let Expression::Identifier(ident) = object {
|
if let Expression::Identifier(ident) = object {
|
||||||
let binding = if self.should_create_temp_variable_for_identifier(ident, ctx) {
|
let binding =
|
||||||
let binding = self.generate_binding(object, ctx);
|
self.get_existing_binding_for_identifier(ident, ctx).unwrap_or_else(|| {
|
||||||
// `(_foo = foo)`
|
let binding = self.generate_binding(object, ctx);
|
||||||
*object = Self::create_assignment_expression(
|
// `(_foo = foo)`
|
||||||
binding.create_write_target(ctx),
|
*object = Self::create_assignment_expression(
|
||||||
ctx.ast.move_expression(object),
|
binding.create_write_target(ctx),
|
||||||
ctx,
|
ctx.ast.move_expression(object),
|
||||||
);
|
ctx,
|
||||||
binding.to_maybe_bound_identifier()
|
);
|
||||||
} else {
|
binding.to_maybe_bound_identifier()
|
||||||
MaybeBoundIdentifier::from_identifier_reference(ident, ctx)
|
});
|
||||||
};
|
|
||||||
self.set_binding_context(binding);
|
self.set_binding_context(binding);
|
||||||
} else if matches!(object, Expression::Super(_)) {
|
} else if matches!(object, Expression::Super(_)) {
|
||||||
self.set_this_context();
|
self.set_this_context();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue