From 8cf8f7a58a4dbb6ded5fe379f11f33073ac94141 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Fri, 23 Aug 2024 07:14:08 +0000 Subject: [PATCH] feat(traverse): add `is_static` method to `TraverseCtx`, which is moves out from SymbolTable (#5067) The [scope.isStatic](https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L557) method we port it from Babel. This method is useful for `transformer`. So we should move it out from `SymbolTable`, and it would be better to put it to `TraverseCtx`. --- crates/oxc_semantic/src/symbol.rs | 26 ----------------- .../src/es2020/nullish_coalescing_operator.rs | 2 +- .../es2021/logical_assignment_operators.rs | 2 +- crates/oxc_traverse/src/context/mod.rs | 15 ++++++++++ crates/oxc_traverse/src/context/scoping.rs | 29 +++++++++++++++++++ 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/crates/oxc_semantic/src/symbol.rs b/crates/oxc_semantic/src/symbol.rs index b7e25eab94c54..b186d564eed01 100644 --- a/crates/oxc_semantic/src/symbol.rs +++ b/crates/oxc_semantic/src/symbol.rs @@ -1,6 +1,5 @@ #![allow(non_snake_case)] // Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]` -use oxc_ast::ast::Expression; use oxc_index::IndexVec; use oxc_span::{CompactStr, Span}; pub use oxc_syntax::{ @@ -204,31 +203,6 @@ impl SymbolTable { .map(|reference_id| &self.references[*reference_id]) } - /// Determine whether evaluating the specific input `node` is a consequenceless reference. ie. - /// evaluating it won't result in potentially arbitrary code from being ran. The following are - /// allowed and determined not to cause side effects: - /// - /// - `this` expressions - /// - `super` expressions - /// - Bound identifiers - /// - /// Reference: - /// - pub fn is_static(&self, expr: &Expression) -> bool { - match expr { - Expression::ThisExpression(_) | Expression::Super(_) => true, - Expression::Identifier(ident) => { - ident.reference_id.get().map_or(false, |reference_id| { - self.get_reference(reference_id).symbol_id().map_or_else( - || self.has_binding(reference_id), - |symbol_id| self.get_resolved_references(symbol_id).all(|r| !r.is_write()), - ) - }) - } - _ => false, - } - } - pub fn reserve(&mut self, additional_symbols: usize, additional_references: usize) { self.spans.reserve(additional_symbols); self.names.reserve(additional_symbols); diff --git a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs index 372ba7df9d4a6..e42070c4dda57 100644 --- a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs +++ b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs @@ -89,7 +89,7 @@ impl<'a> Traverse<'a> for NullishCoalescingOperator<'a> { }; // skip creating extra reference when `left` is static - if ctx.symbols().is_static(&logical_expr.left) { + if ctx.is_static(&logical_expr.left) { *expr = Self::create_conditional_expression( Self::clone_expression(&logical_expr.left, ctx), logical_expr.left, diff --git a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs index 6699f3b7d0abe..abcfc9d0ddb65 100644 --- a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs +++ b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs @@ -351,7 +351,7 @@ impl<'a> LogicalAssignmentOperators<'a> { expr: &Expression<'a>, ctx: &mut TraverseCtx<'a>, ) -> Option> { - if ctx.symbols().is_static(expr) { + if ctx.is_static(expr) { return None; } diff --git a/crates/oxc_traverse/src/context/mod.rs b/crates/oxc_traverse/src/context/mod.rs index b97473d541a5c..f1e76c6c6f75e 100644 --- a/crates/oxc_traverse/src/context/mod.rs +++ b/crates/oxc_traverse/src/context/mod.rs @@ -417,6 +417,21 @@ impl<'a> TraverseCtx<'a> { ) -> IdentifierReference<'a> { self.scoping.clone_identifier_reference(ident, flags) } + + /// Determine whether evaluating the specific input `node` is a consequenceless reference. + /// + /// I.E evaluating it won't result in potentially arbitrary code from being ran. The following are + /// allowed and determined not to cause side effects: + /// + /// - `this` expressions + /// - `super` expressions + /// - Bound identifiers + /// + /// This is a shortcut for `ctx.scoping.is_static`. + #[inline] + pub fn is_static(&self, expr: &Expression) -> bool { + self.scoping.is_static(expr) + } } // Methods used internally within crate diff --git a/crates/oxc_traverse/src/context/scoping.rs b/crates/oxc_traverse/src/context/scoping.rs index 02a8e9d7fee20..e53d4078aaa7c 100644 --- a/crates/oxc_traverse/src/context/scoping.rs +++ b/crates/oxc_traverse/src/context/scoping.rs @@ -372,6 +372,35 @@ impl TraverseScoping { let symbol_id = reference.symbol_id(); self.create_reference_id(ident.span, ident.name.clone(), symbol_id, flags) } + + /// Determine whether evaluating the specific input `node` is a consequenceless reference. + /// + /// I.E evaluating it won't result in potentially arbitrary code from being ran. The following are + /// allowed and determined not to cause side effects: + /// + /// - `this` expressions + /// - `super` expressions + /// - Bound identifiers + /// + /// Based on Babel's `scope.isStatic` logic. + /// + /// + /// # Panics + /// Can only panic if [`IdentifierReference`] does not have a reference_id, which it always should. + #[inline] + pub fn is_static(&self, expr: &Expression) -> bool { + match expr { + Expression::ThisExpression(_) | Expression::Super(_) => true, + Expression::Identifier(ident) => self + .symbols + .get_reference(ident.reference_id.get().unwrap()) + .symbol_id() + .is_some_and(|symbol_id| { + self.symbols.get_resolved_references(symbol_id).all(|r| !r.is_write()) + }), + _ => false, + } + } } // Methods used internally within crate