From 4f9dd98a97476f2a48885bb91edfb4f5f1ec7f73 Mon Sep 17 00:00:00 2001 From: Boshen Date: Wed, 6 Mar 2024 20:38:21 +0800 Subject: [PATCH] feat(span): remove `From` and `From` API because they create memory leak (#2628) closes #2621 --- crates/oxc_ast/src/ast/js.rs | 37 ++++---- .../adjacent_overload_signatures.rs | 4 +- crates/oxc_minifier/src/compressor/fold.rs | 2 +- crates/oxc_semantic/src/binder.rs | 10 +- crates/oxc_semantic/src/builder.rs | 21 ++--- crates/oxc_semantic/src/class/builder.rs | 20 ++-- crates/oxc_semantic/src/symbol.rs | 4 +- .../oxc_semantic/tests/util/symbol_tester.rs | 2 +- crates/oxc_span/src/atom.rs | 18 +--- .../src/es2015/duplicate_keys.rs | 10 +- .../src/es2015/function_name.rs | 92 +++++++++---------- .../src/es2022/class_static_block.rs | 23 ++--- .../src/proposals/decorators.rs | 17 ++-- crates/oxc_transformer/src/react_jsx/mod.rs | 10 +- .../src/regexp/regexp_flags.rs | 2 +- crates/oxc_transformer/src/typescript/mod.rs | 5 +- crates/oxc_transformer/src/utils.rs | 18 ++-- 17 files changed, 142 insertions(+), 153 deletions(-) diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index fb8bfeb99..caa3301c4 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1,7 +1,7 @@ use std::{cell::Cell, fmt, hash::Hash}; use oxc_allocator::{Box, Vec}; -use oxc_span::{Atom, SourceType, Span}; +use oxc_span::{Atom, CompactStr, SourceType, Span}; use oxc_syntax::{ operator::{ AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator, @@ -212,7 +212,7 @@ impl<'a> Expression<'a> { } } - pub fn is_specific_member_access(&'a self, object: &str, property: &str) -> bool { + pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool { match self.get_inner_expression() { Expression::MemberExpression(expr) => expr.is_specific_member_access(object, property), Expression::ChainExpression(chain) => { @@ -466,19 +466,22 @@ pub enum PropertyKey<'a> { } impl<'a> PropertyKey<'a> { - pub fn static_name(&self) -> Option> { + pub fn static_name(&self) -> Option { match self { - Self::Identifier(ident) => Some(ident.name.clone()), + Self::Identifier(ident) => Some(ident.name.to_compact_str()), Self::PrivateIdentifier(_) => None, Self::Expression(expr) => match expr { - Expression::StringLiteral(lit) => Some(lit.value.clone()), - Expression::RegExpLiteral(lit) => Some(Atom::from(lit.regex.to_string())), - Expression::NumericLiteral(lit) => Some(Atom::from(lit.value.to_string())), - Expression::BigintLiteral(lit) => Some(lit.raw.clone()), + Expression::StringLiteral(lit) => Some(lit.value.to_compact_str()), + Expression::RegExpLiteral(lit) => Some(lit.regex.to_string().into()), + Expression::NumericLiteral(lit) => Some(lit.value.to_string().into()), + Expression::BigintLiteral(lit) => Some(lit.raw.to_compact_str()), Expression::NullLiteral(_) => Some("null".into()), - Expression::TemplateLiteral(lit) => { - lit.expressions.is_empty().then(|| lit.quasi()).flatten().cloned() - } + Expression::TemplateLiteral(lit) => lit + .expressions + .is_empty() + .then(|| lit.quasi()) + .flatten() + .map(Atom::to_compact_str), _ => None, }, } @@ -496,16 +499,16 @@ impl<'a> PropertyKey<'a> { matches!(self, Self::PrivateIdentifier(_)) } - pub fn private_name(&self) -> Option> { + pub fn private_name(&self) -> Option<&Atom<'a>> { match self { - Self::PrivateIdentifier(ident) => Some(ident.name.clone()), + Self::PrivateIdentifier(ident) => Some(&ident.name), _ => None, } } - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option { if self.is_private_identifier() { - self.private_name() + self.private_name().map(Atom::to_compact_str) } else { self.static_name() } @@ -758,7 +761,7 @@ impl<'a> CallExpression<'a> { } } - pub fn is_symbol_or_symbol_for_call(&'a self) -> bool { + pub fn is_symbol_or_symbol_for_call(&self) -> bool { // TODO: is 'Symbol' reference to global object match &self.callee { Expression::Identifier(id) => id.name == "Symbol", @@ -2017,7 +2020,7 @@ impl<'a> ClassElement<'a> { } } - pub fn static_name(&self) -> Option { + pub fn static_name(&self) -> Option { match self { Self::TSIndexSignature(_) | Self::StaticBlock(_) => None, Self::MethodDefinition(def) => def.key.static_name(), diff --git a/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs b/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs index 8f597d8ca..dbffaf0cc 100644 --- a/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs +++ b/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs @@ -130,7 +130,7 @@ impl GetMethod for ClassElement<'_> { fn get_method(&self) -> Option { match self { ClassElement::MethodDefinition(def) => def.key.static_name().map(|name| Method { - name: name.to_compact_str(), + name, r#static: def.r#static, call_signature: false, kind: get_kind_from_key(&def.key), @@ -145,7 +145,7 @@ impl GetMethod for TSSignature<'_> { fn get_method(&self) -> Option { match self { TSSignature::TSMethodSignature(sig) => sig.key.static_name().map(|name| Method { - name: name.to_compact_str(), + name, r#static: false, call_signature: false, kind: get_kind_from_key(&sig.key), diff --git a/crates/oxc_minifier/src/compressor/fold.rs b/crates/oxc_minifier/src/compressor/fold.rs index 2594cbc16..8dc0ec8d7 100644 --- a/crates/oxc_minifier/src/compressor/fold.rs +++ b/crates/oxc_minifier/src/compressor/fold.rs @@ -264,7 +264,7 @@ impl<'a> Compressor<'a> { let right_string = get_string_value(right)?; // let value = left_string.to_owned(). let value = left_string + right_string; - let string_literal = StringLiteral::new(span, Atom::from(value)); + let string_literal = StringLiteral::new(span, self.ast.new_atom(&value)); Some(self.ast.literal_string_expression(string_literal)) }, diff --git a/crates/oxc_semantic/src/binder.rs b/crates/oxc_semantic/src/binder.rs index 16e82803e..9bd0010b6 100644 --- a/crates/oxc_semantic/src/binder.rs +++ b/crates/oxc_semantic/src/binder.rs @@ -1,12 +1,14 @@ //! Declare symbol for `BindingIdentifier`s +use std::borrow::Cow; + #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; use oxc_ast::{ syntax_directed_operations::{BoundNames, IsSimpleParameterList}, AstKind, }; -use oxc_span::{Atom, SourceType}; +use oxc_span::SourceType; use crate::{scope::ScopeFlags, symbol::SymbolFlags, SemanticBuilder}; @@ -343,9 +345,9 @@ impl<'a> Binder for TSEnumMember<'a> { return; } let name = match &self.id { - TSEnumMemberName::Identifier(id) => id.name.clone(), - TSEnumMemberName::StringLiteral(s) => s.value.clone(), - TSEnumMemberName::NumericLiteral(n) => Atom::from(n.value.to_string()), + TSEnumMemberName::Identifier(id) => Cow::Borrowed(id.name.as_str()), + TSEnumMemberName::StringLiteral(s) => Cow::Borrowed(s.value.as_str()), + TSEnumMemberName::NumericLiteral(n) => Cow::Owned(n.value.to_string()), TSEnumMemberName::ComputedPropertyName(_) => panic!("TODO: implement"), }; builder.declare_symbol( diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index ece511e6f..accef2f03 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -5,7 +5,7 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc}; #[allow(clippy::wildcard_imports)] use oxc_ast::{ast::*, AstKind, Trivias, TriviasMap, Visit}; use oxc_diagnostics::Error; -use oxc_span::{Atom, SourceType, Span}; +use oxc_span::{CompactStr, SourceType, Span}; use oxc_syntax::{ module_record::{ExportLocalName, ModuleRecord}, operator::AssignmentOperator, @@ -231,7 +231,7 @@ impl<'a> SemanticBuilder<'a> { pub fn declare_symbol_on_scope( &mut self, span: Span, - name: &Atom, + name: &str, scope_id: ScopeId, includes: SymbolFlags, excludes: SymbolFlags, @@ -243,16 +243,16 @@ impl<'a> SemanticBuilder<'a> { } let includes = includes | self.current_symbol_flags; - let symbol_id = self.symbols.create_symbol(span, name.clone(), includes, scope_id); + let symbol_id = self.symbols.create_symbol(span, name, includes, scope_id); self.symbols.add_declaration(self.current_node_id); - self.scope.add_binding(scope_id, name.to_compact_str(), symbol_id); + self.scope.add_binding(scope_id, CompactStr::from(name), symbol_id); symbol_id } pub fn declare_symbol( &mut self, span: Span, - name: &Atom, + name: &str, includes: SymbolFlags, excludes: SymbolFlags, ) -> SymbolId { @@ -263,14 +263,14 @@ impl<'a> SemanticBuilder<'a> { &mut self, scope_id: ScopeId, span: Span, - name: &Atom, + name: &str, excludes: SymbolFlags, report_error: bool, ) -> Option { let symbol_id = self.scope.get_binding(scope_id, name)?; if report_error && self.symbols.get_flag(symbol_id).intersects(excludes) { let symbol_span = self.symbols.get_span(symbol_id); - self.error(Redeclaration(name.to_compact_str(), symbol_span, span)); + self.error(Redeclaration(CompactStr::from(name), symbol_span, span)); } Some(symbol_id) } @@ -285,16 +285,15 @@ impl<'a> SemanticBuilder<'a> { /// Declares a `Symbol` for the node, shadowing previous declarations in the same scope. pub fn declare_shadow_symbol( &mut self, - name: &Atom, + name: &str, span: Span, scope_id: ScopeId, includes: SymbolFlags, ) -> SymbolId { let includes = includes | self.current_symbol_flags; - let symbol_id = - self.symbols.create_symbol(span, name.clone(), includes, self.current_scope_id); + let symbol_id = self.symbols.create_symbol(span, name, includes, self.current_scope_id); self.symbols.add_declaration(self.current_node_id); - self.scope.get_bindings_mut(scope_id).insert(name.to_compact_str(), symbol_id); + self.scope.get_bindings_mut(scope_id).insert(CompactStr::from(name), symbol_id); symbol_id } diff --git a/crates/oxc_semantic/src/class/builder.rs b/crates/oxc_semantic/src/class/builder.rs index f1d54d8d9..3b5bcbd20 100644 --- a/crates/oxc_semantic/src/class/builder.rs +++ b/crates/oxc_semantic/src/class/builder.rs @@ -5,7 +5,7 @@ use oxc_ast::{ }, AstKind, }; -use oxc_span::GetSpan; +use oxc_span::{Atom, GetSpan}; use oxc_syntax::class::{ClassId, ElementKind}; use crate::{AstNodeId, AstNodes}; @@ -57,15 +57,14 @@ impl ClassTableBuilder { pub fn declare_class_accessor(&mut self, property: &AccessorProperty) { let is_private = property.key.is_private_identifier(); - let name = - if is_private { property.key.private_name() } else { property.key.static_name() }; + let name = property.key.name(); if let Some(name) = name { if let Some(class_id) = self.current_class_id { self.classes.add_element( class_id, Element::new( - name.to_compact_str(), + name, property.key.span(), property.r#static, is_private, @@ -78,15 +77,14 @@ impl ClassTableBuilder { pub fn declare_class_property(&mut self, property: &PropertyDefinition) { let is_private = property.key.is_private_identifier(); - let name = - if is_private { property.key.private_name() } else { property.key.static_name() }; + let name = property.key.name(); if let Some(name) = name { if let Some(class_id) = self.current_class_id { self.classes.add_element( class_id, Element::new( - name.to_compact_str(), + name, property.key.span(), property.r#static, is_private, @@ -127,14 +125,18 @@ impl ClassTableBuilder { return; } let is_private = method.key.is_private_identifier(); - let name = if is_private { method.key.private_name() } else { method.key.static_name() }; + let name = if is_private { + method.key.private_name().map(Atom::to_compact_str) + } else { + method.key.static_name() + }; if let Some(name) = name { if let Some(class_id) = self.current_class_id { self.classes.add_element( class_id, Element::new( - name.to_compact_str(), + name, method.key.span(), method.r#static, is_private, diff --git a/crates/oxc_semantic/src/symbol.rs b/crates/oxc_semantic/src/symbol.rs index fe937e9a1..322a53a01 100644 --- a/crates/oxc_semantic/src/symbol.rs +++ b/crates/oxc_semantic/src/symbol.rs @@ -117,12 +117,12 @@ impl SymbolTable { pub fn create_symbol( &mut self, span: Span, - name: Atom, + name: &str, flag: SymbolFlags, scope_id: ScopeId, ) -> SymbolId { _ = self.spans.push(span); - _ = self.names.push(name.into_compact_str()); + _ = self.names.push(CompactStr::from(name)); _ = self.flags.push(flag); _ = self.scope_ids.push(scope_id); _ = self.resolved_references.push(vec![]); diff --git a/crates/oxc_semantic/tests/util/symbol_tester.rs b/crates/oxc_semantic/tests/util/symbol_tester.rs index 75e6b8f38..3f52fc707 100644 --- a/crates/oxc_semantic/tests/util/symbol_tester.rs +++ b/crates/oxc_semantic/tests/util/symbol_tester.rs @@ -141,7 +141,7 @@ impl<'a> SymbolTester<'a> { pub fn is_exported(mut self) -> Self { self.test_result = match self.test_result { Ok(symbol_id) => { - let binding = Atom::from(self.target_symbol_name.clone()); + let binding = self.target_symbol_name.clone(); if self.semantic.module_record().exported_bindings.contains_key(binding.as_str()) && self.semantic.scopes().get_root_binding(&binding) == Some(symbol_id) { diff --git a/crates/oxc_span/src/atom.rs b/crates/oxc_span/src/atom.rs index 3601c22c5..e65250255 100644 --- a/crates/oxc_span/src/atom.rs +++ b/crates/oxc_span/src/atom.rs @@ -1,8 +1,4 @@ -use std::{ - borrow::{Borrow, Cow}, - fmt, hash, - ops::Deref, -}; +use std::{borrow::Borrow, fmt, hash, ops::Deref}; #[cfg(feature = "serde")] use serde::{Serialize, Serializer}; @@ -82,18 +78,6 @@ impl<'a> From<&'a str> for Atom<'a> { } } -impl<'a> From for Atom<'a> { - fn from(s: String) -> Self { - Self::Compact(CompactString::from(s)) - } -} - -impl<'a> From> for Atom<'a> { - fn from(s: Cow<'_, str>) -> Self { - Self::Compact(CompactString::from(s)) - } -} - impl<'a> Deref for Atom<'a> { type Target = str; diff --git a/crates/oxc_transformer/src/es2015/duplicate_keys.rs b/crates/oxc_transformer/src/es2015/duplicate_keys.rs index f331089b6..5ac043703 100644 --- a/crates/oxc_transformer/src/es2015/duplicate_keys.rs +++ b/crates/oxc_transformer/src/es2015/duplicate_keys.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, rc::Rc}; use oxc_ast::{ast::*, AstBuilder}; -use oxc_span::{Atom, SPAN}; +use oxc_span::{CompactStr, SPAN}; use crate::options::{TransformOptions, TransformTarget}; @@ -22,9 +22,9 @@ impl<'a> DuplicateKeys<'a> { } pub fn transform_object_expression<'b>(&mut self, obj_expr: &'b mut ObjectExpression<'a>) { - let mut visited_data: HashSet = HashSet::new(); - let mut visited_getters: HashSet = HashSet::new(); - let mut visited_setters: HashSet = HashSet::new(); + let mut visited_data: HashSet = HashSet::new(); + let mut visited_getters: HashSet = HashSet::new(); + let mut visited_setters: HashSet = HashSet::new(); for property in obj_expr.properties.iter_mut() { let ObjectPropertyKind::ObjectProperty(obj_property) = property else { @@ -64,7 +64,7 @@ impl<'a> DuplicateKeys<'a> { if is_duplicate { obj_property.computed = true; - let string_literal = StringLiteral::new(SPAN, name.clone()); + let string_literal = StringLiteral::new(SPAN, self.ast.new_atom(name)); let expr = self.ast.literal_string_expression(string_literal); obj_property.key = PropertyKey::Expression(expr); } diff --git a/crates/oxc_transformer/src/es2015/function_name.rs b/crates/oxc_transformer/src/es2015/function_name.rs index 9e66440fb..239fa4dd0 100644 --- a/crates/oxc_transformer/src/es2015/function_name.rs +++ b/crates/oxc_transformer/src/es2015/function_name.rs @@ -19,7 +19,7 @@ use crate::TransformTarget; /// * /// * pub struct FunctionName<'a> { - _ast: Rc>, + ast: Rc>, ctx: TransformerCtx<'a>, unicode_escapes: bool, } @@ -31,7 +31,7 @@ impl<'a> FunctionName<'a> { options: &TransformOptions, ) -> Option { (options.target < TransformTarget::ES2015 || options.function_name).then_some(Self { - _ast: ast, + ast, ctx, // TODO hook up the plugin unicode_escapes: true, @@ -45,7 +45,7 @@ impl<'a> FunctionName<'a> { ) = &expr.left { if let Some(id) = - create_valid_identifier(target.span, target.name.clone(), self.unicode_escapes) + self.create_valid_identifier(target.span, &target.name, self.unicode_escapes) { let scope_id = self.ctx.symbols().get_scope_id_from_span(&target.span); @@ -64,19 +64,11 @@ impl<'a> FunctionName<'a> { let (id, scope_id) = match &property.key { PropertyKey::Identifier(ident) => ( - create_valid_identifier( - ident.span, - ident.name.clone(), - self.unicode_escapes, - ), + self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes), self.ctx.symbols().get_scope_id_from_span(&ident.span), ), PropertyKey::PrivateIdentifier(ident) => ( - create_valid_identifier( - ident.span, - ident.name.clone(), - self.unicode_escapes, - ), + self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes), self.ctx.symbols().get_scope_id_from_span(&ident.span), ), PropertyKey::Expression(_) => continue, @@ -95,7 +87,7 @@ impl<'a> FunctionName<'a> { if let BindingPatternKind::BindingIdentifier(ident) = &decl.id.kind { // Create a new ID instead of cloning to avoid local binding/refs if let Some(id) = - create_valid_identifier(ident.span, ident.name.clone(), self.unicode_escapes) + self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes) { let scope_id = match ident.symbol_id.get() { Some(symbol_id) => Some(self.ctx.symbols().get_scope_id(symbol_id)), @@ -133,7 +125,7 @@ impl<'a> FunctionName<'a> { // If we're shadowing, change the name if count > 0 { - id.name = Atom::from(format!("{}{}", id.name, count)); + id.name = self.ast.new_atom(&format!("{}{}", id.name, count)); } if func.id.is_none() { @@ -141,37 +133,41 @@ impl<'a> FunctionName<'a> { } } } -} - -// https://github.com/babel/babel/blob/main/packages/babel-helper-function-name/src/index.ts -// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toBindingIdentifierName.ts#L3 -// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toIdentifier.ts#L4 -#[allow(clippy::unnecessary_wraps)] -fn create_valid_identifier( - span: Span, - atom: Atom, - _unicode_escapes: bool, -) -> Option { - // NOTE: this regex fails to compile on Rust - // lazy_static! { - // static ref UNICODE_NAME: Regex = Regex::new(r"(?u)[\u{D800}-\u{DFFF}]").unwrap(); - // } - - // if !unicode_escapes && UNICODE_NAME.is_match(atom.as_str()) { - // return None; - // } - - let id = Atom::from( - atom.chars().map(|c| if is_identifier_part(c) { c } else { '_' }).collect::(), - ); - - let id = if id == "" { - Atom::from("_") - } else if id == "eval" || id == "arguments" || id == "null" || !is_valid_identifier(&id, true) { - Atom::from(format!("_{id}")) - } else { - atom - }; - - Some(BindingIdentifier::new(span, id)) + + // https://github.com/babel/babel/blob/main/packages/babel-helper-function-name/src/index.ts + // https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toBindingIdentifierName.ts#L3 + // https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toIdentifier.ts#L4 + #[allow(clippy::unnecessary_wraps)] + fn create_valid_identifier( + &self, + span: Span, + atom: &Atom<'a>, + _unicode_escapes: bool, + ) -> Option> { + // NOTE: this regex fails to compile on Rust + // lazy_static! { + // static ref UNICODE_NAME: Regex = Regex::new(r"(?u)[\u{D800}-\u{DFFF}]").unwrap(); + // } + + // if !unicode_escapes && UNICODE_NAME.is_match(atom.as_str()) { + // return None; + // } + + let id = + atom.chars().map(|c| if is_identifier_part(c) { c } else { '_' }).collect::(); + + let id = if id.is_empty() { + self.ast.new_atom("_") + } else if id == "eval" + || id == "arguments" + || id == "null" + || !is_valid_identifier(&id, true) + { + self.ast.new_atom(&format!("_{id}")) + } else { + atom.clone() + }; + + Some(BindingIdentifier::new(span, id)) + } } diff --git a/crates/oxc_transformer/src/es2022/class_static_block.rs b/crates/oxc_transformer/src/es2022/class_static_block.rs index e4b0ceaca..bacdb983a 100644 --- a/crates/oxc_transformer/src/es2022/class_static_block.rs +++ b/crates/oxc_transformer/src/es2022/class_static_block.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, rc::Rc}; +use std::{borrow::Cow, collections::HashSet, rc::Rc}; use oxc_ast::{ast::*, AstBuilder}; use oxc_span::{Atom, SPAN}; @@ -30,6 +30,7 @@ impl<'a> ClassStaticBlock<'a> { .iter() .filter_map(ClassElement::property_key) .filter_map(PropertyKey::private_name) + .cloned() .collect(); let mut i = 0; @@ -38,7 +39,7 @@ impl<'a> ClassStaticBlock<'a> { continue; }; - let static_block_private_id = generate_uid(&private_names, &mut i); + let static_block_private_id = self.generate_uid(&private_names, &mut i); let key = PropertyKey::PrivateIdentifier(self.ast.alloc(PrivateIdentifier { span: SPAN, @@ -107,16 +108,16 @@ impl<'a> ClassStaticBlock<'a> { self.ast.class_property(r#type, SPAN, key, value, false, true, self.ast.new_vec()); } } -} -fn generate_uid<'a>(deny_list: &HashSet>, i: &mut u32) -> Atom<'a> { - *i += 1; - - let mut uid: Atom = if *i == 1 { "_".to_string() } else { format!("_{i}") }.into(); - while deny_list.contains(&uid) { + fn generate_uid(&self, deny_list: &HashSet>, i: &mut u32) -> Atom<'a> { *i += 1; - uid = format!("_{i}").into(); - } - uid + let mut uid = if *i == 1 { Cow::Borrowed("_") } else { Cow::Owned(format!("_{i}")) }; + while deny_list.iter().any(|id| id.as_str() == uid.as_ref()) { + *i += 1; + uid = format!("_{i}").into(); + } + + self.ast.new_atom(&uid) + } } diff --git a/crates/oxc_transformer/src/proposals/decorators.rs b/crates/oxc_transformer/src/proposals/decorators.rs index 72d7e594f..ffc56c895 100644 --- a/crates/oxc_transformer/src/proposals/decorators.rs +++ b/crates/oxc_transformer/src/proposals/decorators.rs @@ -547,9 +547,7 @@ impl<'a> Decorators<'a> { if def.key.is_private_identifier() && !flag.is_static() { private_in_expression = - Some(self.get_is_private_function( - def.key.private_name().unwrap().clone(), - )); + Some(self.get_is_private_function(def.key.private_name().unwrap())); } name = self.get_unique_name(&if def.computed { @@ -846,9 +844,10 @@ impl<'a> Decorators<'a> { )), )); if let Some(name) = name { - decorator_elements.push(ArrayExpressionElement::Expression( - self.ast.literal_string_expression(StringLiteral::new(SPAN, name.clone())), - )); + decorator_elements + .push(ArrayExpressionElement::Expression(self.ast.literal_string_expression( + StringLiteral::new(SPAN, self.ast.new_atom(&name)), + ))); if key.is_private_identifier() { if let Some(value) = value { @@ -878,7 +877,7 @@ impl<'a> Decorators<'a> { SPAN, self.ast.new_atom("o"), )), - PrivateIdentifier::new(SPAN, name), + PrivateIdentifier::new(SPAN, self.ast.new_atom(&name)), false, ); let params = self.ast.formal_parameters( @@ -969,7 +968,7 @@ impl<'a> Decorators<'a> { } // _ => #a in _; - fn get_is_private_function(&self, name: Atom<'a>) -> Expression<'a> { + fn get_is_private_function(&self, name: &Atom<'a>) -> Expression<'a> { self.ast.arrow_function_expression( SPAN, true, @@ -1001,7 +1000,7 @@ impl<'a> Decorators<'a> { SPAN, self.ast.private_in_expression( SPAN, - PrivateIdentifier::new(SPAN, name), + PrivateIdentifier::new(SPAN, name.clone()), self.ast.identifier_reference_expression(IdentifierReference::new( SPAN, self.ast.new_atom("_"), diff --git a/crates/oxc_transformer/src/react_jsx/mod.rs b/crates/oxc_transformer/src/react_jsx/mod.rs index 431a561ac..9894467fe 100644 --- a/crates/oxc_transformer/src/react_jsx/mod.rs +++ b/crates/oxc_transformer/src/react_jsx/mod.rs @@ -8,7 +8,7 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::Error, }; -use oxc_span::{Atom, CompactStr, GetSpan, Span, SPAN}; +use oxc_span::{CompactStr, GetSpan, Span, SPAN}; use oxc_syntax::{ identifier::{is_irregular_whitespace, is_line_terminator}, xml_entities::XML_ENTITIES, @@ -596,7 +596,7 @@ impl<'a> ReactJsx<'a> { } } JSXAttributeName::NamespacedName(name) => { - let name = Atom::from(name.to_string()); + let name = self.ast.new_atom(&name.to_string()); let expr = self.ast.literal_string_expression(StringLiteral::new(SPAN, name)); self.ast.property_key_expression(expr) } @@ -623,7 +623,7 @@ impl<'a> ReactJsx<'a> { self.ctx.error(NamespaceDoesNotSupport(name.span)); } - let string_literal = StringLiteral::new(SPAN, Atom::from(name.to_string())); + let string_literal = StringLiteral::new(SPAN, self.ast.new_atom(&name.to_string())); self.ast.literal_string_expression(string_literal) } } @@ -665,7 +665,7 @@ impl<'a> ReactJsx<'a> { match value { Some(JSXAttributeValue::StringLiteral(s)) => { let jsx_text = Self::decode_entities(s.value.as_str()); - let literal = StringLiteral::new(s.span, jsx_text.into()); + let literal = StringLiteral::new(s.span, self.ast.new_atom(&jsx_text)); self.ast.literal_string_expression(literal) } Some(JSXAttributeValue::Element(e)) => { @@ -718,7 +718,7 @@ impl<'a> ReactJsx<'a> { fn transform_jsx_text(&self, text: &str) -> Option> { Self::fixup_whitespace_and_decode_entities(text).map(|s| { - let s = StringLiteral::new(SPAN, s.into()); + let s = StringLiteral::new(SPAN, self.ast.new_atom(&s)); self.ast.literal_string_expression(s) }) } diff --git a/crates/oxc_transformer/src/regexp/regexp_flags.rs b/crates/oxc_transformer/src/regexp/regexp_flags.rs index 43ce69b04..dd001c742 100644 --- a/crates/oxc_transformer/src/regexp/regexp_flags.rs +++ b/crates/oxc_transformer/src/regexp/regexp_flags.rs @@ -60,7 +60,7 @@ impl<'a> RegexpFlags<'a> { let ident = IdentifierReference::new(SPAN, Atom::from("RegExp")); let callee = self.ast.identifier_reference_expression(ident); let pattern = StringLiteral::new(SPAN, regex.pattern.clone()); - let flags = StringLiteral::new(SPAN, Atom::from(regex.flags.to_string())); + let flags = StringLiteral::new(SPAN, self.ast.new_atom(®ex.flags.to_string())); let pattern_literal = self.ast.literal_string_expression(pattern); let flags_literal = self.ast.literal_string_expression(flags); let mut arguments = self.ast.new_vec_with_capacity(2); diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index 44e711786..b3e95e4f3 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -637,7 +637,10 @@ impl<'a> TypeScript<'a> { fn get_namespace_arg_name(&mut self, name: &Atom<'a>) -> Atom<'a> { let count = self.namespace_arg_names.entry(name.clone()).or_insert(0); *count += 1; - format!("_{name}{}", if *count > 1 { count.to_string() } else { String::new() }).into() + self.ast.new_atom(&format!( + "_{name}{}", + if *count > 1 { count.to_string() } else { String::new() } + )) } /// ```TypeScript diff --git a/crates/oxc_transformer/src/utils.rs b/crates/oxc_transformer/src/utils.rs index db3ebeda2..d007908a4 100644 --- a/crates/oxc_transformer/src/utils.rs +++ b/crates/oxc_transformer/src/utils.rs @@ -2,7 +2,7 @@ use std::mem; use oxc_allocator::Vec; use oxc_ast::ast::*; -use oxc_span::{Atom, Span}; +use oxc_span::Span; use oxc_syntax::identifier::is_identifier_name; use crate::context::TransformerCtx; @@ -133,22 +133,22 @@ pub const KEYWORDS: phf::Set<&str> = phf::phf_set![ "delete", ]; -pub fn is_valid_identifier(name: &Atom, reserved: bool) -> bool { - if reserved && (KEYWORDS.contains(name.as_str()) || is_strict_reserved_word(name, true)) { +pub fn is_valid_identifier(name: &str, reserved: bool) -> bool { + if reserved && (KEYWORDS.contains(name) || is_strict_reserved_word(name, true)) { return false; } is_identifier_name(name) } -pub fn is_strict_reserved_word(name: &Atom, in_module: bool) -> bool { - is_reserved_word(name, in_module) || RESERVED_WORD_STRICT.contains(name.as_str()) +pub fn is_strict_reserved_word(name: &str, in_module: bool) -> bool { + is_reserved_word(name, in_module) || RESERVED_WORD_STRICT.contains(name) } -pub fn is_reserved_word(name: &Atom, in_module: bool) -> bool { - (in_module && name.as_str() == "await") || name.as_str() == "enum" +pub fn is_reserved_word(name: &str, in_module: bool) -> bool { + (in_module && name == "await") || name == "enum" } /// https://github.com/babel/babel/blob/main/packages/babel-types/src/validators/isValidES3Identifier.ts#L35 -pub fn is_valid_es3_identifier(name: &Atom) -> bool { - is_valid_identifier(name, true) && !RESERVED_WORDS_ES3_ONLY.contains(name.as_str()) +pub fn is_valid_es3_identifier(name: &str) -> bool { + is_valid_identifier(name, true) && !RESERVED_WORDS_ES3_ONLY.contains(name) }