swc_ecma_transforms_compat/es2015/
function_name.rsuse swc_common::util::take::Take;
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Parallel;
use swc_ecma_utils::{private_ident, IdentUsageFinder};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
use swc_trace_macro::swc_trace;
#[tracing::instrument(level = "info", skip_all)]
pub fn function_name() -> impl 'static + Copy + Fold + VisitMut {
    as_folder(FnName)
}
#[derive(Clone, Copy)]
struct FnName;
impl Parallel for FnName {
    fn create(&self) -> Self {
        *self
    }
    fn merge(&mut self, _: Self) {}
}
struct Rename {
    name: Option<Ident>,
}
fn prepare(i: Ident) -> Ident {
    if i.is_reserved() || i.is_reserved_in_strict_mode(true) || i.is_reserved_in_strict_bind() {
        return private_ident!(i.span, format!("_{}", i.sym));
    }
    private_ident!(i.span, i.sym)
}
#[swc_trace]
impl VisitMut for FnName {
    noop_visit_mut_type!();
    fn visit_mut_assign_expr(&mut self, expr: &mut AssignExpr) {
        expr.visit_mut_children_with(self);
        if expr.op != op!("=") {
            return;
        }
        if let Some(ident) = expr.left.as_ident_mut() {
            let mut folder = Rename {
                name: Some(ident.clone()),
            };
            expr.right.visit_mut_with(&mut folder);
        }
    }
    fn visit_mut_key_value_prop(&mut self, p: &mut KeyValueProp) {
        p.visit_mut_children_with(self);
        if let Expr::Fn(expr @ FnExpr { ident: None, .. }) = &mut *p.value {
            p.value = if let PropName::Ident(ref i) = p.key {
                Box::new(Expr::Fn(FnExpr {
                    ident: Some(prepare(i.clone())),
                    ..expr.take()
                }))
            } else {
                Box::new(Expr::Fn(expr.take()))
            };
        };
    }
    fn visit_mut_var_declarator(&mut self, decl: &mut VarDeclarator) {
        decl.visit_mut_children_with(self);
        if let Pat::Ident(ref mut ident) = decl.name {
            let mut folder = Rename {
                name: Some(prepare(ident.id.clone())),
            };
            decl.init.visit_mut_with(&mut folder);
        }
    }
}
macro_rules! impl_for {
    ($name:ident, $T:tt) => {
        fn $name(&mut self, node: &mut $T) {
            match node.ident {
                Some(..) => return,
                None => {
                    let name = match self.name.take() {
                        None => {
                            node.ident = None;
                            return;
                        }
                        Some(name) => name,
                    };
                    if IdentUsageFinder::find(&name.to_id(), &*node) {
                        node.ident = None;
                    } else {
                        node.ident = Some(name);
                    }
                }
            }
        }
    };
}
macro_rules! noop {
    ($name:ident, $T:tt) => {
        fn $name(&mut self, _: &mut $T) {}
    };
}
impl VisitMut for Rename {
    noop_visit_mut_type!();
    impl_for!(visit_mut_fn_expr, FnExpr);
    impl_for!(visit_mut_class_expr, ClassExpr);
    noop!(visit_mut_object_lit, ObjectLit);
    noop!(visit_mut_array_lit, ArrayLit);
    noop!(visit_mut_call_expr, CallExpr);
    noop!(visit_mut_new_expr, NewExpr);
    noop!(visit_mut_bin_expr, BinExpr);
    noop!(visit_mut_unary_expr, UnaryExpr);
}