perf: do not pass &Atom to functions (#3818)

`Atom` is just a wrapper around `&str`, so better not to pass `&Atom` to functions, as that's a double-reference. Prefer `Atom` or `&str` instead to avoid indirection.
This commit is contained in:
overlookmotel 2024-06-22 04:48:00 +00:00
parent aaa944d66b
commit 4f7ff7e3ad
36 changed files with 173 additions and 171 deletions

View file

@ -642,9 +642,12 @@ impl<'a> PropertyKey<'a> {
Self::NumericLiteral(lit) => Some(lit.value.to_string().into()),
Self::BigintLiteral(lit) => Some(lit.raw.to_compact_str()),
Self::NullLiteral(_) => Some("null".into()),
Self::TemplateLiteral(lit) => {
lit.expressions.is_empty().then(|| lit.quasi()).flatten().map(Atom::to_compact_str)
}
Self::TemplateLiteral(lit) => lit
.expressions
.is_empty()
.then(|| lit.quasi())
.flatten()
.map(|quasi| quasi.to_compact_str()),
_ => None,
}
}
@ -661,16 +664,16 @@ impl<'a> PropertyKey<'a> {
matches!(self, Self::PrivateIdentifier(_))
}
pub fn private_name(&self) -> Option<&Atom<'a>> {
pub fn private_name(&self) -> Option<Atom<'a>> {
match self {
Self::PrivateIdentifier(ident) => Some(&ident.name),
Self::PrivateIdentifier(ident) => Some(ident.name.clone()),
_ => None,
}
}
pub fn name(&self) -> Option<CompactStr> {
if self.is_private_identifier() {
self.private_name().map(Atom::to_compact_str)
self.private_name().map(|name| name.to_compact_str())
} else {
self.static_name()
}
@ -717,8 +720,8 @@ impl<'a> TemplateLiteral<'a> {
}
/// Get single quasi from `template`
pub fn quasi(&self) -> Option<&Atom<'a>> {
self.quasis.first().and_then(|quasi| quasi.value.cooked.as_ref())
pub fn quasi(&self) -> Option<Atom<'a>> {
self.quasis.first().and_then(|quasi| quasi.value.cooked.clone())
}
}
@ -2200,7 +2203,7 @@ impl<'a> BindingPattern<'a> {
Self { kind, type_annotation: None, optional: false }
}
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
pub fn get_identifier(&self) -> Option<Atom<'a>> {
self.kind.get_identifier()
}
@ -2228,9 +2231,9 @@ pub enum BindingPatternKind<'a> {
}
impl<'a> BindingPatternKind<'a> {
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
pub fn get_identifier(&self) -> Option<Atom<'a>> {
match self {
Self::BindingIdentifier(ident) => Some(&ident.name),
Self::BindingIdentifier(ident) => Some(ident.name.clone()),
Self::AssignmentPattern(assign) => assign.left.get_identifier(),
_ => None,
}
@ -3402,10 +3405,10 @@ impl<'a> fmt::Display for ModuleExportName<'a> {
}
impl<'a> ModuleExportName<'a> {
pub fn name(&self) -> &Atom<'a> {
pub fn name(&self) -> Atom<'a> {
match self {
Self::Identifier(identifier) => &identifier.name,
Self::StringLiteral(literal) => &literal.value,
Self::Identifier(identifier) => identifier.name.clone(),
Self::StringLiteral(literal) => literal.value.clone(),
}
}
}

View file

@ -980,10 +980,10 @@ impl<'a> TSModuleDeclarationName<'a> {
matches!(self, Self::StringLiteral(_))
}
pub fn name(&self) -> &Atom<'a> {
pub fn name(&self) -> Atom<'a> {
match self {
Self::Identifier(ident) => &ident.name,
Self::StringLiteral(lit) => &lit.value,
Self::Identifier(ident) => ident.name.clone(),
Self::StringLiteral(lit) => lit.value.clone(),
}
}
}

View file

@ -1118,7 +1118,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for IdentifierName<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for BindingIdentifier<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) {
p.print_symbol(self.span, self.symbol_id.get(), &self.name);
p.print_symbol(self.span, self.symbol_id.get(), self.name.as_str());
}
}

View file

@ -15,7 +15,7 @@ use oxc_ast::{
ast::{BlockStatement, Directive, Expression, Program, Statement},
Comment, Trivias,
};
use oxc_span::{Atom, Span};
use oxc_span::Span;
use oxc_syntax::{
identifier::is_identifier_part,
operator::{BinaryOperator, UnaryOperator, UpdateOperator},
@ -394,7 +394,8 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
}
}
fn print_symbol(&mut self, span: Span, _symbol_id: Option<SymbolId>, fallback: &Atom) {
#[allow(clippy::needless_pass_by_value)]
fn print_symbol(&mut self, span: Span, _symbol_id: Option<SymbolId>, fallback: &str) {
// if let Some(mangler) = &self.mangler {
// if let Some(symbol_id) = symbol_id {
// let name = mangler.get_symbol_name(symbol_id);

View file

@ -61,7 +61,7 @@ impl<'a> IsolatedDeclarations<'a> {
if check_binding {
if let Some(name) = decl.id.get_identifier() {
if !self.scope.has_reference(name) {
if !self.scope.has_reference(&name) {
return None;
}
}

View file

@ -1,5 +1,5 @@
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Atom, Span};
use oxc_span::Span;
pub fn function_must_have_explicit_return_type(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
@ -133,7 +133,8 @@ pub fn computed_property_name(span: Span) -> OxcDiagnostic {
.with_label(span)
}
pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnostic {
#[allow(clippy::needless_pass_by_value)]
pub fn type_containing_private_name(name: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(format!(
"TS9039: Type containing private name '{name}' can't be used with --isolatedDeclarations."
))

View file

@ -103,17 +103,17 @@ impl<'a> IsolatedDeclarations<'a> {
fn computed_constant_value(
&self,
expr: &Expression<'a>,
enum_name: &Atom<'a>,
enum_name: &str,
prev_members: &FxHashMap<Atom<'a>, ConstantValue>,
) -> Option<ConstantValue> {
self.evaluate(expr, enum_name, prev_members)
}
#[allow(clippy::unused_self)]
#[allow(clippy::unused_self, clippy::needless_pass_by_value)]
fn evaluate_ref(
&self,
expr: &Expression<'a>,
enum_name: &Atom<'a>,
enum_name: &str,
prev_members: &FxHashMap<Atom<'a>, ConstantValue>,
) -> Option<ConstantValue> {
match expr {
@ -147,7 +147,7 @@ impl<'a> IsolatedDeclarations<'a> {
fn evaluate(
&self,
expr: &Expression<'a>,
enum_name: &Atom<'a>,
enum_name: &str,
prev_members: &FxHashMap<Atom<'a>, ConstantValue>,
) -> Option<ConstantValue> {
match expr {
@ -183,7 +183,7 @@ impl<'a> IsolatedDeclarations<'a> {
fn eval_binary_expression(
&self,
expr: &BinaryExpression<'a>,
enum_name: &Atom<'a>,
enum_name: &str,
prev_members: &FxHashMap<Atom<'a>, ConstantValue>,
) -> Option<ConstantValue> {
let left = self.evaluate(&expr.left, enum_name, prev_members)?;
@ -249,7 +249,7 @@ impl<'a> IsolatedDeclarations<'a> {
fn eval_unary_expression(
&self,
expr: &UnaryExpression<'a>,
enum_name: &Atom<'a>,
enum_name: &str,
prev_members: &FxHashMap<Atom<'a>, ConstantValue>,
) -> Option<ConstantValue> {
let value = self.evaluate(&expr.argument, enum_name, prev_members)?;

View file

@ -111,7 +111,7 @@ impl<'a> IsolatedDeclarations<'a> {
self.scope.has_reference(&specifier.local.name)
}
ImportDeclarationSpecifier::ImportNamespaceSpecifier(_) => {
self.scope.has_reference(&self.ast.new_atom(&specifier.name()))
self.scope.has_reference(specifier.name().as_str())
}
});
if specifiers.is_empty() {

View file

@ -34,7 +34,7 @@ impl<'a> ScopeTree<'a> {
self.flags.last().unwrap().contains(ScopeFlags::TsModuleBlock)
}
pub fn has_reference(&self, name: &Atom<'a>) -> bool {
pub fn has_reference(&self, name: &str) -> bool {
self.value_references.last().is_some_and(|rs| rs.contains(name))
|| self.type_references.last().is_some_and(|rs| rs.contains(name))
}
@ -43,20 +43,20 @@ impl<'a> ScopeTree<'a> {
self.value_references.last().unwrap().len() + self.type_references.last().unwrap().len()
}
fn add_value_binding(&mut self, ident: &Atom<'a>) {
self.value_bindings.last_mut().unwrap().insert(ident.clone());
fn add_value_binding(&mut self, ident: Atom<'a>) {
self.value_bindings.last_mut().unwrap().insert(ident);
}
fn add_type_binding(&mut self, ident: &Atom<'a>) {
self.type_bindings.last_mut().unwrap().insert(ident.clone());
fn add_type_binding(&mut self, ident: Atom<'a>) {
self.type_bindings.last_mut().unwrap().insert(ident);
}
fn add_value_reference(&mut self, ident: &Atom<'a>) {
self.value_references.last_mut().unwrap().insert(ident.clone());
fn add_value_reference(&mut self, ident: Atom<'a>) {
self.value_references.last_mut().unwrap().insert(ident);
}
fn add_type_reference(&mut self, ident: &Atom<'a>) {
self.type_references.last_mut().unwrap().insert(ident.clone());
fn add_type_reference(&mut self, ident: Atom<'a>) {
self.type_references.last_mut().unwrap().insert(ident);
}
/// resolve references in the current scope
@ -94,19 +94,19 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
}
fn visit_identifier_reference(&mut self, ident: &IdentifierReference<'a>) {
self.add_value_reference(&ident.name);
self.add_value_reference(ident.name.clone());
}
fn visit_binding_pattern(&mut self, pattern: &BindingPattern<'a>) {
if let BindingPatternKind::BindingIdentifier(ident) = &pattern.kind {
self.add_value_binding(&ident.name);
self.add_value_binding(ident.name.clone());
}
walk_binding_pattern(self, pattern);
}
fn visit_ts_type_name(&mut self, name: &TSTypeName<'a>) {
if let TSTypeName::IdentifierReference(ident) = name {
self.add_type_reference(&ident.name);
self.add_type_reference(ident.name.clone());
} else {
walk_ts_type_name(self, name);
}
@ -115,7 +115,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) {
if let Some(type_name) = ty.expr_name.as_ts_type_name() {
let ident = TSTypeName::get_first_name(type_name);
self.add_value_reference(&ident.name);
self.add_value_reference(ident.name.clone());
} else {
walk_ts_type_query(self, ty);
}
@ -124,16 +124,16 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
for specifier in &decl.specifiers {
if let ModuleExportName::Identifier(ident) = &specifier.local {
self.add_type_reference(&ident.name);
self.add_value_reference(&ident.name);
self.add_type_reference(ident.name.clone());
self.add_value_reference(ident.name.clone());
}
}
}
fn visit_export_default_declaration(&mut self, decl: &ExportDefaultDeclaration<'a>) {
if let ExportDefaultDeclarationKind::Identifier(ident) = &decl.declaration {
self.add_type_reference(&ident.name);
self.add_value_reference(&ident.name);
self.add_type_reference(ident.name.clone());
self.add_value_reference(ident.name.clone());
} else {
walk_export_default_declaration(self, decl);
}
@ -146,32 +146,32 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
}
Declaration::FunctionDeclaration(decl) => {
if let Some(id) = decl.id.as_ref() {
self.add_value_binding(&id.name);
self.add_value_binding(id.name.clone());
}
}
Declaration::ClassDeclaration(decl) => {
if let Some(id) = decl.id.as_ref() {
self.add_value_binding(&id.name);
self.add_value_binding(id.name.clone());
}
}
Declaration::TSTypeAliasDeclaration(decl) => {
self.add_type_binding(&decl.id.name);
self.add_type_binding(decl.id.name.clone());
}
Declaration::TSInterfaceDeclaration(decl) => {
self.add_type_binding(&decl.id.name);
self.add_type_binding(decl.id.name.clone());
}
Declaration::TSEnumDeclaration(decl) => {
self.add_value_binding(&decl.id.name);
self.add_type_binding(&decl.id.name);
self.add_value_binding(decl.id.name.clone());
self.add_type_binding(decl.id.name.clone());
}
Declaration::TSModuleDeclaration(decl) => {
if let TSModuleDeclarationName::Identifier(ident) = &decl.id {
self.add_value_binding(&ident.name);
self.add_type_binding(&ident.name);
self.add_value_binding(ident.name.clone());
self.add_type_binding(ident.name.clone());
}
}
Declaration::TSImportEqualsDeclaration(decl) => {
self.add_value_binding(&decl.id.name);
self.add_value_binding(decl.id.name.clone());
}
}
walk_declaration(self, declaration);
@ -268,7 +268,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_ts_mapped_type(&mut self, ty: &TSMappedType<'a>) {
// copy from walk_ts_mapped_type
self.enter_scope(ScopeFlags::empty());
self.add_type_binding(&ty.type_parameter.name.name);
self.add_type_binding(ty.type_parameter.name.name.clone());
if let Some(name) = &ty.name_type {
self.visit_ts_type(name);
}
@ -290,6 +290,6 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_ts_infer_type(&mut self, ty: &TSInferType<'a>) {
// copy from walk_ts_infer_type
self.add_type_binding(&ty.type_parameter.name.name);
self.add_type_binding(ty.type_parameter.name.name.clone());
}
}

View file

@ -5,7 +5,7 @@ use oxc_ast::{
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, GetSpan, Span};
use oxc_span::{GetSpan, Span};
use regex::{Matches, Regex};
use crate::{ast_util::extract_regex_flags, context::LintContext, rule::Rule, AstNode};
@ -67,7 +67,7 @@ impl Rule for NoControlRegex {
if let Some(RegexPatternData { pattern, flags, span }) = regex_pattern(node) {
let mut violations: Vec<&str> = Vec::new();
for matched_ctl_pattern in control_patterns(pattern.as_str()) {
for matched_ctl_pattern in control_patterns(pattern) {
let ctl = matched_ctl_pattern.as_str();
// check for an even number of backslashes, since these will
@ -139,7 +139,7 @@ impl Rule for NoControlRegex {
struct RegexPatternData<'a> {
/// A regex pattern, either from a literal (`/foo/`) a RegExp constructor
/// (`new RegExp("foo")`), or a RegExp function call (`RegExp("foo"))
pattern: &'a Atom<'a>,
pattern: &'a str,
/// Regex flags, if found. It's possible for this to be `Some` but have
/// no flags.
///
@ -166,7 +166,7 @@ fn regex_pattern<'a>(node: &AstNode<'a>) -> Option<RegexPatternData<'a>> {
match kind {
// regex literal
AstKind::RegExpLiteral(reg) => Some(RegexPatternData {
pattern: &reg.regex.pattern,
pattern: reg.regex.pattern.as_ref(),
flags: Some(reg.regex.flags),
span: reg.span,
}),
@ -187,7 +187,7 @@ fn regex_pattern<'a>(node: &AstNode<'a>) -> Option<RegexPatternData<'a>> {
// Note that we're intentionally reporting the entire "new
// RegExp("pat") expression, not just "pat".
Some(RegexPatternData {
pattern: &pattern.value,
pattern: pattern.value.as_ref(),
flags: extract_regex_flags(&expr.arguments),
span: kind.span(),
})
@ -215,7 +215,7 @@ fn regex_pattern<'a>(node: &AstNode<'a>) -> Option<RegexPatternData<'a>> {
// Note that we're intentionally reporting the entire "new
// RegExp("pat") expression, not just "pat".
Some(RegexPatternData {
pattern: &pattern.value,
pattern: pattern.value.as_ref(),
flags: extract_regex_flags(&expr.arguments),
span: kind.span(),
})

View file

@ -7,7 +7,7 @@ use oxc_ast::{
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNodeId;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use crate::{
context::LintContext,
@ -116,7 +116,7 @@ fn filter_and_process_jest_result<'a>(
call_expr: &'a CallExpression<'a>,
possible_jest_node: &PossibleJestNode<'a, '_>,
ctx: &LintContext<'a>,
) -> Option<(Span, &'a Atom<'a>, JestFnKind, AstNodeId)> {
) -> Option<(Span, &'a str, JestFnKind, AstNodeId)> {
let result = parse_general_jest_fn_call(call_expr, possible_jest_node, ctx)?;
let kind = result.kind;
// we only need check `describe` or `test` block
@ -135,7 +135,7 @@ fn filter_and_process_jest_result<'a>(
Some((string_lit.span, &string_lit.value, kind, parent_id))
}
Some(Argument::TemplateLiteral(template_lit)) => {
template_lit.quasi().map(|quasi| (template_lit.span, quasi, kind, parent_id))
template_lit.quasi().map(|quasi| (template_lit.span, quasi.as_str(), kind, parent_id))
}
_ => None,
}

View file

@ -204,7 +204,7 @@ impl PreferLowercaseTitle {
let Some(template_string) = template_expr.quasi() else {
return;
};
self.lint_string(ctx, template_string, template_expr.span);
self.lint_string(ctx, template_string.as_str(), template_expr.span);
}
}

View file

@ -83,7 +83,7 @@ impl Rule for NoPageCustomFont {
let AstKind::VariableDeclarator(declarator) = parent_parent_kind else {
return None;
};
declarator.id.get_identifier().map(ToString::to_string)
declarator.id.get_identifier().map(|id| id.to_string())
},
|id| Some(id.name.to_string()),
);

View file

@ -2,7 +2,7 @@ use lazy_static::lazy_static;
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use regex::Regex;
use crate::{context::LintContext, rule::Rule, AstNode};
@ -61,11 +61,11 @@ impl Rule for JsxNoCommentTextnodes {
}
}
fn control_patterns(pattern: &Atom) -> bool {
fn control_patterns(pattern: &str) -> bool {
lazy_static! {
static ref CTL_PAT: Regex = Regex::new(r"(?m)^\s*/(/|\*)",).unwrap();
}
CTL_PAT.is_match(pattern.as_str())
CTL_PAT.is_match(pattern)
}
#[test]

View file

@ -9,7 +9,7 @@ use oxc_ast::{
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, GetSpan, Span};
use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule, AstNode};
@ -245,8 +245,8 @@ impl Rule for JsxNoTargetBlank {
}
}
fn check_is_external_link(link: &Atom) -> bool {
link.as_str().contains("//")
fn check_is_external_link(link: &str) -> bool {
link.contains("//")
}
fn match_href_expression(

View file

@ -1,7 +1,7 @@
use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, GetSpan, Span};
use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule, AstNode};
@ -45,14 +45,14 @@ impl Rule for ReactInJsxScope {
_ => return,
};
let scope = ctx.scopes();
let react_name: &Atom = &Atom::from("React");
let react_name = "React";
if scope.get_binding(scope.root_scope_id(), react_name).is_some() {
return;
}
if !scope
.ancestors(node.scope_id())
.any(|v| scope.get_bindings(v).iter().any(|(k, _)| k == react_name))
.any(|v| scope.get_bindings(v).iter().any(|(k, _)| k.as_str() == react_name))
{
ctx.diagnostic(react_in_jsx_scope_diagnostic(node_span));
}

View file

@ -8,7 +8,7 @@ use oxc_cfg::{
};
use oxc_macros::declare_oxc_lint;
use oxc_semantic::{AstNodeId, AstNodes};
use oxc_span::{Atom, CompactStr};
use oxc_span::CompactStr;
use oxc_syntax::operator::AssignmentOperator;
use crate::{
@ -375,7 +375,7 @@ fn get_declaration_identifier<'a>(
match kind {
// const useHook = () => {};
AstKind::VariableDeclaration(decl) if decl.declarations.len() == 1 => {
decl.declarations[0].id.get_identifier().map(Atom::to_compact_str)
decl.declarations[0].id.get_identifier().map(|id| id.to_compact_str())
}
// useHook = () => {};
AstKind::AssignmentExpression(expr)
@ -386,7 +386,7 @@ fn get_declaration_identifier<'a>(
// const {useHook = () => {}} = {};
// ({useHook = () => {}} = {});
AstKind::AssignmentPattern(patt) => {
patt.left.get_identifier().map(Atom::to_compact_str)
patt.left.get_identifier().map(|id| id.to_compact_str())
}
// { useHook: () => {} }
// { useHook() {} }

View file

@ -1,7 +1,7 @@
use oxc_ast::{ast::Expression, AstKind};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use rustc_hash::FxHashMap;
use crate::{context::LintContext, rule::Rule, AstNode};
@ -42,7 +42,7 @@ impl Rule for NoDuplicateEnumValues {
return;
};
let mut seen_number_values: Vec<(f64, Span)> = vec![];
let mut seen_string_values: FxHashMap<&Atom, Span> = FxHashMap::default();
let mut seen_string_values: FxHashMap<&str, Span> = FxHashMap::default();
for enum_member in &enum_body.members {
let Some(initializer) = &enum_member.initializer else {
continue;
@ -58,7 +58,7 @@ impl Rule for NoDuplicateEnumValues {
}
}
Expression::StringLiteral(s) => {
if let Some(old_span) = seen_string_values.insert(&s.value, s.span) {
if let Some(old_span) = seen_string_values.insert(s.value.as_str(), s.span) {
ctx.diagnostic(no_duplicate_enum_values_diagnostic(old_span, s.span));
}
}

View file

@ -7,7 +7,7 @@ use oxc_ast::{
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{Atom, GetSpan, Span};
use oxc_span::{GetSpan, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, UnaryOperator, UpdateOperator};
use crate::{context::LintContext, rule::Rule, AstNode};
@ -57,11 +57,11 @@ impl SpanExt for Span {
}
trait ExpressionExt {
fn is_increment_of(&self, var_name: &Atom) -> bool;
fn is_increment_of(&self, var_name: &str) -> bool;
}
impl<'a> ExpressionExt for Expression<'a> {
fn is_increment_of(&self, var_name: &Atom) -> bool {
fn is_increment_of(&self, var_name: &str) -> bool {
match self {
Expression::UpdateExpression(expr) => match (&expr.argument, &expr.operator) {
(

View file

@ -5,7 +5,7 @@ use oxc_ast::{
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::SymbolId;
use oxc_span::{Atom, CompactStr, Span};
use oxc_span::{CompactStr, Span};
use crate::{context::LintContext, rule::Rule, AstNode};
@ -133,8 +133,8 @@ impl Rule for CatchErrorName {
}
impl CatchErrorName {
fn is_name_allowed(&self, name: &Atom) -> bool {
self.name == name || self.ignore.iter().any(|s| s.as_str() == name.as_str())
fn is_name_allowed(&self, name: &str) -> bool {
self.name == name || self.ignore.iter().any(|s| s.as_str() == name)
}
fn check_function_arguments(

View file

@ -5,7 +5,7 @@ use oxc_ast::{
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNodeId;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule, AstNode};
@ -132,14 +132,14 @@ fn check_function(
None
}
fn get_returned_ident<'a>(stmt: &'a Statement, is_arrow: bool) -> Option<&'a Atom<'a>> {
fn get_returned_ident<'a>(stmt: &'a Statement, is_arrow: bool) -> Option<&'a str> {
if is_arrow {
if let Statement::ExpressionStatement(expr_stmt) = &stmt {
return expr_stmt
.expression
.without_parenthesized()
.get_identifier_reference()
.map(|v| &v.name);
.map(|v| v.name.as_str());
}
}
@ -151,7 +151,10 @@ fn get_returned_ident<'a>(stmt: &'a Statement, is_arrow: bool) -> Option<&'a Ato
}
if let Statement::ReturnStatement(return_statement) = &stmt {
if let Some(return_expr) = &return_statement.argument {
return return_expr.without_parenthesized().get_identifier_reference().map(|v| &v.name);
return return_expr
.without_parenthesized()
.get_identifier_reference()
.map(|v| v.name.as_str());
}
}
@ -238,7 +241,7 @@ fn check_array_callback_methods(
return false;
};
first_param_name == returned_ident.as_str()
first_param_name == returned_ident
}
const NATIVE_COERCION_FUNCTION_NAMES: phf::Set<&'static str> = phf::phf_set! {

View file

@ -8,7 +8,6 @@ use oxc_ast::{
AstKind,
};
use oxc_semantic::{AstNode, ReferenceId};
use oxc_span::Atom;
use phf::phf_set;
use crate::LintContext;
@ -135,7 +134,7 @@ pub fn parse_expect_jest_fn_call<'a>(
pub struct PossibleJestNode<'a, 'b> {
pub node: &'b AstNode<'a>,
pub original: Option<&'a Atom<'a>>, // if this node is imported from 'jest/globals', this field will be Some(original_name), otherwise None
pub original: Option<&'a str>, // if this node is imported from 'jest/globals', this field will be Some(original_name), otherwise None
}
/// Collect all possible Jest fn Call Expression,
@ -192,9 +191,9 @@ pub fn collect_possible_jest_call_node<'a, 'b>(
})
}
fn collect_ids_referenced_to_import<'a, 'b>(
ctx: &'b LintContext<'a>,
) -> Vec<(ReferenceId, Option<&'a Atom<'a>>)> {
fn collect_ids_referenced_to_import<'a>(
ctx: &LintContext<'a>,
) -> Vec<(ReferenceId, Option<&'a str>)> {
ctx.symbols()
.resolved_references
.iter_enumerated()
@ -221,18 +220,15 @@ fn collect_ids_referenced_to_import<'a, 'b>(
None
})
.flatten()
.collect::<Vec<(ReferenceId, Option<&'a Atom<'a>>)>>()
.collect()
}
/// Find name in the Import Declaration, not use name because of lifetime not long enough.
fn find_original_name<'a>(
import_decl: &'a ImportDeclaration<'a>,
name: &str,
) -> Option<&'a Atom<'a>> {
fn find_original_name<'a>(import_decl: &'a ImportDeclaration<'a>, name: &str) -> Option<&'a str> {
import_decl.specifiers.iter().flatten().find_map(|specifier| match specifier {
ImportDeclarationSpecifier::ImportSpecifier(import_specifier) => {
if import_specifier.local.name.as_str() == name {
return Some(import_specifier.imported.name());
return Some(import_specifier.imported.name().as_str());
}
None
}
@ -266,7 +262,7 @@ pub fn get_node_name_vec<'a>(expr: &'a Expression<'a>) -> Vec<Cow<'a, str>> {
chain.push(Cow::Borrowed(&string_literal.value));
}
Expression::TemplateLiteral(template_literal) if is_pure_string(template_literal) => {
chain.push(Cow::Borrowed(template_literal.quasi().unwrap()));
chain.push(Cow::Borrowed(template_literal.quasi().unwrap().as_str()));
}
Expression::TaggedTemplateExpression(tagged_expr) => {
chain.extend(get_node_name_vec(&tagged_expr.tag));

View file

@ -8,7 +8,7 @@ use oxc_ast::{
AstKind,
};
use oxc_semantic::AstNode;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use crate::{
context::LintContext,
@ -54,7 +54,7 @@ pub fn parse_jest_fn_call<'a>(
return None;
}
let name = resolved.original.unwrap_or(resolved.local).as_str();
let name = resolved.original.unwrap_or(resolved.local);
let kind = JestFnKind::from(name);
let mut members = Vec::new();
let mut iter = chain.into_iter();
@ -261,7 +261,7 @@ pub struct ExpectFnCallOptions<'a, 'b> {
pub call_expr: &'a CallExpression<'a>,
pub members: Vec<KnownMemberExpressionProperty<'a>>,
pub name: &'a str,
pub local: &'a Atom<'a>,
pub local: &'a str,
pub head: KnownMemberExpressionProperty<'a>,
pub node: &'b AstNode<'a>,
pub ctx: &'b LintContext<'a>,
@ -288,10 +288,10 @@ fn is_valid_jest_call(members: &[Cow<str>]) -> bool {
fn resolve_to_jest_fn<'a>(
call_expr: &'a CallExpression<'a>,
original: Option<&'a Atom<'a>>,
original: Option<&'a str>,
) -> Option<ResolvedJestFn<'a>> {
let ident = resolve_first_ident(&call_expr.callee)?;
Some(ResolvedJestFn { local: &ident.name, original })
Some(ResolvedJestFn { local: ident.name.as_str(), original })
}
fn resolve_first_ident<'a>(expr: &'a Expression<'a>) -> Option<&'a IdentifierReference<'a>> {
@ -357,8 +357,8 @@ impl<'a> ParsedExpectFnCall<'a> {
}
struct ResolvedJestFn<'a> {
pub local: &'a Atom<'a>,
pub original: Option<&'a Atom<'a>>,
pub local: &'a str,
pub original: Option<&'a str>,
}
#[derive(Clone, Copy, Debug)]

View file

@ -113,13 +113,13 @@ impl<'a> ParserImpl<'a> {
(self.end_span(span), Atom::from(name))
}
pub(crate) fn check_identifier(&mut self, span: Span, name: &Atom) {
pub(crate) fn check_identifier(&mut self, span: Span, name: &str) {
// It is a Syntax Error if this production has an [Await] parameter.
if self.ctx.has_await() && name.as_str() == "await" {
if self.ctx.has_await() && name == "await" {
self.error(diagnostics::identifier_async("await", span));
}
// It is a Syntax Error if this production has a [Yield] parameter.
if self.ctx.has_yield() && name.as_str() == "yield" {
if self.ctx.has_yield() && name == "yield" {
self.error(diagnostics::identifier_generator("yield", span));
}
}

View file

@ -364,7 +364,7 @@ impl<'a> Binder for TSModuleDeclaration<'a> {
};
builder.declare_symbol(
self.span,
self.id.name(),
self.id.name().as_str(),
SymbolFlags::NameSpaceModule | ambient,
SymbolFlags::None,
);

View file

@ -5,7 +5,7 @@ use oxc_ast::{
AstKind,
};
use oxc_diagnostics::{LabeledSpan, OxcDiagnostic};
use oxc_span::{Atom, GetSpan, ModuleKind, Span};
use oxc_span::{GetSpan, ModuleKind, Span};
use oxc_syntax::{
module_record::ExportLocalName,
number::NumberBase,
@ -128,17 +128,12 @@ pub const STRICT_MODE_NAMES: Set<&'static str> = phf_set! {
"yield",
};
pub fn check_identifier<'a>(
name: &Atom,
span: Span,
node: &AstNode<'a>,
ctx: &SemanticBuilder<'a>,
) {
pub fn check_identifier<'a>(name: &str, span: Span, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
// ts module block allows revered keywords
if ctx.current_scope_flags().is_ts_module_block() {
return;
}
if *name == "await" {
if name == "await" {
// It is a Syntax Error if the goal symbol of the syntactic grammar is Module and the StringValue of IdentifierName is "await".
if ctx.source_type.is_module() {
return ctx.error(reserved_keyword(name, span));
@ -150,7 +145,7 @@ pub fn check_identifier<'a>(
}
// It is a Syntax Error if this phrase is contained in strict mode code and the StringValue of IdentifierName is: "implements", "interface", "let", "package", "private", "protected", "public", "static", or "yield".
if ctx.strict_mode() && STRICT_MODE_NAMES.contains(name.as_str()) {
if ctx.strict_mode() && STRICT_MODE_NAMES.contains(name) {
ctx.error(reserved_keyword(name, span));
}
}

View file

@ -5,7 +5,7 @@ use oxc_ast::{
},
AstKind,
};
use oxc_span::{Atom, GetSpan};
use oxc_span::GetSpan;
use oxc_syntax::class::{ClassId, ElementKind};
use super::{
@ -125,7 +125,7 @@ impl ClassTableBuilder {
}
let is_private = method.key.is_private_identifier();
let name = if is_private {
method.key.private_name().map(Atom::to_compact_str)
method.key.private_name().map(|name| name.to_compact_str())
} else {
method.key.static_name()
};

View file

@ -1,5 +1,5 @@
use oxc_index::IndexVec;
use oxc_span::{Atom, CompactStr, Span};
use oxc_span::{CompactStr, Span};
use oxc_syntax::class::{ClassId, ElementId, ElementKind};
use rustc_hash::FxHashMap;
@ -76,10 +76,10 @@ impl ClassTable {
self.declarations[class_id]
}
pub fn get_element_ids(&self, class_id: ClassId, name: &Atom) -> Vec<ElementId> {
pub fn get_element_ids(&self, class_id: ClassId, name: &str) -> Vec<ElementId> {
let mut element_ids = vec![];
for (element_id, element) in self.elements[class_id].iter_enumerated() {
if element.name == *name {
if element.name == name {
element_ids.push(element_id);
// Property or Accessor only has 1 element

View file

@ -172,10 +172,8 @@ mod tests {
let allocator = Allocator::default();
let semantic = get_semantic(&allocator, source, SourceType::default());
let top_level_a = semantic
.scopes()
.get_binding(semantic.scopes().root_scope_id(), &Atom::from("a"))
.unwrap();
let top_level_a =
semantic.scopes().get_binding(semantic.scopes().root_scope_id(), "a").unwrap();
let decl = semantic.symbol_declaration(top_level_a);
match decl.kind() {

View file

@ -2,7 +2,7 @@
use oxc_ast::ast::Expression;
use oxc_index::IndexVec;
use oxc_span::{Atom, CompactStr, Span};
use oxc_span::{CompactStr, Span};
pub use oxc_syntax::{
scope::ScopeId,
symbol::{SymbolFlags, SymbolId},
@ -105,7 +105,7 @@ impl SymbolTable {
self.get_symbol_id_from_span(span).map(|symbol_id| self.get_scope_id(symbol_id))
}
pub fn get_scope_id_from_name(&self, name: &Atom) -> Option<ScopeId> {
pub fn get_scope_id_from_name(&self, name: &str) -> Option<ScopeId> {
self.get_symbol_id_from_name(name).map(|symbol_id| self.get_scope_id(symbol_id))
}

View file

@ -2,7 +2,6 @@ use std::rc::Rc;
use oxc_diagnostics::{Error, OxcDiagnostic};
use oxc_semantic::{Reference, ScopeFlags, Semantic, SymbolFlags, SymbolId};
use oxc_span::Atom;
use super::{Expect, SemanticTester};
@ -22,8 +21,7 @@ impl<'a> SymbolTester<'a> {
semantic: Semantic<'a>,
target: &str,
) -> Self {
let decl =
semantic.scopes().get_binding(semantic.scopes().root_scope_id(), &Atom::from(target));
let decl = semantic.scopes().get_binding(semantic.scopes().root_scope_id(), target);
let data = decl.map_or_else(
|| Err(OxcDiagnostic::error(format!("Could not find declaration for {target}"))),
Ok,

View file

@ -90,7 +90,8 @@ impl<'a> AutomaticScriptBindings<'a> {
fn require_create_element(&mut self, ctx: &mut TraverseCtx<'a>) -> IdentifierReference<'a> {
if self.require_create_element.is_none() {
let source = get_import_source(&self.jsx_runtime_importer, self.react_importer_len);
let source =
get_import_source(self.jsx_runtime_importer.as_str(), self.react_importer_len);
let id = self.add_require_statement("react", source, true, ctx);
self.require_create_element = Some(id);
}
@ -157,7 +158,8 @@ impl<'a> AutomaticModuleBindings<'a> {
fn import_create_element(&mut self, ctx: &mut TraverseCtx<'a>) -> IdentifierReference<'a> {
if self.import_create_element.is_none() {
let source = get_import_source(&self.jsx_runtime_importer, self.react_importer_len);
let source =
get_import_source(self.jsx_runtime_importer.as_str(), self.react_importer_len);
let id = self.add_import_statement("createElement", source, ctx);
self.import_create_element = Some(id);
}
@ -226,8 +228,8 @@ impl<'a> AutomaticModuleBindings<'a> {
}
#[inline]
fn get_import_source<'a>(jsx_runtime_importer: &Atom<'a>, react_importer_len: u32) -> Atom<'a> {
Atom::from(&jsx_runtime_importer.as_str()[..react_importer_len as usize])
fn get_import_source(jsx_runtime_importer: &str, react_importer_len: u32) -> Atom {
Atom::from(&jsx_runtime_importer[..react_importer_len as usize])
}
/// Pragma used in classic mode

View file

@ -114,7 +114,7 @@ impl<'a> TypeScriptAnnotations<'a> {
!(specifier.export_kind.is_type()
|| self
.type_identifier_names
.contains(specifier.exported.name()))
.contains(&specifier.exported.name()))
});
decl.export_kind.is_type()
@ -514,7 +514,7 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn has_value_reference(&self, name: &Atom<'a>, ctx: &TraverseCtx<'a>) -> bool {
pub fn has_value_reference(&self, name: &str, ctx: &TraverseCtx<'a>) -> bool {
if let Some(symbol_id) = ctx.scopes().get_root_binding(name) {
if ctx.symbols().get_flag(symbol_id).is_export()
&& !self.type_identifier_names.contains(name)

View file

@ -83,7 +83,7 @@ impl<'a> TypeScriptEnum<'a> {
// Foo[Foo["X"] = 0] = "X";
let enum_name = decl.id.name.clone();
let is_already_declared = self.enums.contains_key(&enum_name);
let statements = self.transform_ts_enum_members(&decl.members, &enum_name, ctx);
let statements = self.transform_ts_enum_members(&decl.members, enum_name.clone(), ctx);
let body = self.ctx.ast.function_body(decl.span, self.ctx.ast.new_vec(), statements);
let r#type = FunctionType::FunctionExpression;
let callee = self.ctx.ast.plain_function(r#type, SPAN, None, params, Some(body));
@ -152,7 +152,7 @@ impl<'a> TypeScriptEnum<'a> {
fn transform_ts_enum_members(
&mut self,
members: &Vec<'a, TSEnumMember<'a>>,
enum_name: &Atom<'a>,
enum_name: Atom<'a>,
ctx: &TraverseCtx<'a>,
) -> Vec<'a, Statement<'a>> {
let mut statements = self.ctx.ast.new_vec();
@ -292,10 +292,8 @@ impl<'a> TypeScriptEnum<'a> {
self.enums.insert(enum_name.clone(), previous_enum_members.clone());
let enum_ref = self
.ctx
.ast
.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone()));
let enum_ref =
self.ctx.ast.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name));
// return Foo;
let return_stmt = self.ctx.ast.return_statement(SPAN, Some(enum_ref));
statements.push(return_stmt);

View file

@ -170,7 +170,7 @@ impl<'a> TypeScript<'a> {
if let Some(transformed) = self.handle_nested(decl.unbox(), None, ctx) {
if names.insert(module_name.clone()) {
new_stmts.push(Statement::from(
self.create_variable_declaration(&module_name),
self.create_variable_declaration(module_name.clone()),
));
}
new_stmts.push(transformed);
@ -189,7 +189,12 @@ impl<'a> TypeScript<'a> {
Declaration::TSEnumDeclaration(_)
| Declaration::FunctionDeclaration(_)
| Declaration::ClassDeclaration(_) => {
self.add_declaration(decl, &name, &mut names, &mut new_stmts);
self.add_declaration(
decl,
name.clone(),
&mut names,
&mut new_stmts,
);
}
Declaration::VariableDeclaration(var_decl) => {
var_decl.declarations.iter().for_each(|decl| {
@ -197,7 +202,8 @@ impl<'a> TypeScript<'a> {
self.ctx.error(namespace_exporting_non_const(decl.span));
}
});
let stmts = self.handle_variable_declaration(var_decl, &name);
let stmts =
self.handle_variable_declaration(var_decl, name.clone());
new_stmts.extend(stmts);
}
Declaration::TSModuleDeclaration(module_decl) => {
@ -216,7 +222,7 @@ impl<'a> TypeScript<'a> {
) {
if names.insert(module_name.clone()) {
new_stmts.push(Statement::from(
self.create_variable_declaration(&module_name),
self.create_variable_declaration(module_name.clone()),
));
}
new_stmts.push(transformed);
@ -255,10 +261,10 @@ impl<'a> TypeScript<'a> {
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
// ^^^^^^^
fn create_variable_declaration(&self, name: &Atom<'a>) -> Declaration<'a> {
fn create_variable_declaration(&self, name: Atom<'a>) -> Declaration<'a> {
let kind = VariableDeclarationKind::Let;
let declarations = {
let ident = BindingIdentifier::new(SPAN, name.clone());
let ident = BindingIdentifier::new(SPAN, name);
let pattern_kind = self.ctx.ast.binding_pattern_identifier(ident);
let binding = self.ctx.ast.binding_pattern(pattern_kind, None, false);
let decl = self.ctx.ast.variable_declarator(SPAN, kind, binding, None, false);
@ -404,7 +410,7 @@ impl<'a> TypeScript<'a> {
fn add_declaration(
&self,
decl: Declaration<'a>,
name: &Atom<'a>,
name: Atom<'a>,
names: &mut FxHashSet<Atom<'a>>,
new_stmts: &mut Vec<'a, Statement<'a>>,
) {
@ -413,30 +419,31 @@ impl<'a> TypeScript<'a> {
let ident = decl.id().unwrap();
let item_name = ident.name.clone();
new_stmts.push(Statement::from(decl));
let assignment_statement = self.create_assignment_statement(name, &item_name);
let assignment_statement = self.create_assignment_statement(name, item_name.clone());
let assignment_statement = self.ctx.ast.expression_statement(SPAN, assignment_statement);
new_stmts.push(assignment_statement);
names.insert(item_name);
}
// name.item_name = item_name
fn create_assignment_statement(&self, name: &Atom<'a>, item_name: &Atom<'a>) -> Expression<'a> {
let ident = IdentifierReference::new(SPAN, name.clone());
fn create_assignment_statement(&self, name: Atom<'a>, item_name: Atom<'a>) -> Expression<'a> {
let ident = IdentifierReference::new(SPAN, name);
let object = self.ctx.ast.identifier_reference_expression(ident);
let property = IdentifierName::new(SPAN, item_name.clone());
let left = self.ctx.ast.static_member(SPAN, object, property, false);
let left = AssignmentTarget::from(left);
let ident = IdentifierReference::new(SPAN, item_name.clone());
let ident = IdentifierReference::new(SPAN, item_name);
let right = self.ctx.ast.identifier_reference_expression(ident);
let op = AssignmentOperator::Assign;
self.ctx.ast.assignment_expression(SPAN, op, left, right)
}
/// Convert `export const foo = 1` to `Namespace.foo = 1`;
#[allow(clippy::needless_pass_by_value)]
fn handle_variable_declaration(
&self,
mut var_decl: Box<'a, VariableDeclaration<'a>>,
name: &Atom<'a>,
name: Atom<'a>,
) -> Vec<'a, Statement<'a>> {
let is_all_binding_identifier = var_decl
.declarations
@ -475,7 +482,7 @@ impl<'a> TypeScript<'a> {
// `export const [a] = 1` transforms to `const [a] = 1; N.a = a`
let mut assignments = self.ctx.ast.new_vec();
var_decl.bound_names(&mut |id| {
assignments.push(self.create_assignment_statement(name, &id.name));
assignments.push(self.create_assignment_statement(name.clone(), id.name.clone()));
});
let mut stmts = self.ctx.ast.new_vec_with_capacity(2);

View file

@ -198,10 +198,10 @@ impl<'a> Visit<'a> for TestCase {
// There are `dedent`(in eslint-plugin-jest), `outdent`(in eslint-plugin-unicorn) and `noFormat`(in typescript-eslint)
// are known to be used to format test cases for their own purposes.
// We read the quasi of tagged template directly also for the future usage.
tag_expr.quasi.quasi().map(ToString::to_string)
tag_expr.quasi.quasi().map(|quasi| quasi.to_string())
}
Expression::TemplateLiteral(tag_expr) => {
tag_expr.quasi().map(ToString::to_string)
tag_expr.quasi().map(|quasi| quasi.to_string())
}
// handle code like ["{", "a: 1", "}"].join("\n")
Expression::CallExpression(call_expr) => {
@ -239,10 +239,10 @@ impl<'a> Visit<'a> for TestCase {
self.output = match &prop.value {
Expression::StringLiteral(s) => Some(s.value.to_string()),
Expression::TaggedTemplateExpression(tag_expr) => {
tag_expr.quasi.quasi().map(ToString::to_string)
tag_expr.quasi.quasi().map(|quasi| quasi.to_string())
}
Expression::TemplateLiteral(tag_expr) => {
tag_expr.quasi().map(ToString::to_string)
tag_expr.quasi().map(|quasi| quasi.to_string())
}
_ => None,
}
@ -293,7 +293,7 @@ impl<'a> Visit<'a> for TestCase {
if ident.name != "dedent" && ident.name != "outdent" {
return;
}
self.code = expr.quasi.quasi().map(std::string::ToString::to_string);
self.code = expr.quasi.quasi().map(|quasi| quasi.to_string());
self.config = None;
}
}