Skip to content

Commit

Permalink
feat(traverse): add is_static method to TraverseCtx, which is mov…
Browse files Browse the repository at this point in the history
…es 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`.
  • Loading branch information
Dunqing committed Aug 23, 2024
1 parent c7b81f5 commit 8cf8f7a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 28 deletions.
26 changes: 0 additions & 26 deletions crates/oxc_semantic/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -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:
/// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L557>
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ impl<'a> LogicalAssignmentOperators<'a> {
expr: &Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<IdentifierReference<'a>> {
if ctx.symbols().is_static(expr) {
if ctx.is_static(expr) {
return None;
}

Expand Down
15 changes: 15 additions & 0 deletions crates/oxc_traverse/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions crates/oxc_traverse/src/context/scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L557>
///
/// # 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
Expand Down

0 comments on commit 8cf8f7a

Please sign in to comment.