mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(traverse): add is_static method to TraverseCtx, which is moves out from SymbolTable (#5067)
The [scope.isStatic](419644f27c/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`.
This commit is contained in:
parent
c7b81f5762
commit
8cf8f7a58a
5 changed files with 46 additions and 28 deletions
|
|
@ -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:
|
||||
/// <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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue