swc_ecma_compiler/es2022/
private_in_object.rs

1use rustc_hash::FxHashSet;
2use swc_atoms::Atom;
3use swc_common::{Mark, SyntaxContext, DUMMY_SP};
4use swc_ecma_ast::*;
5use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
6
7use crate::CompilerImpl;
8
9#[derive(Debug)]
10pub(crate) enum Mode {
11    ClassExpr {
12        vars: Vec<VarDeclarator>,
13        init_exprs: Vec<Box<Expr>>,
14    },
15    ClassDecl {
16        vars: Vec<VarDeclarator>,
17    },
18}
19
20impl Default for Mode {
21    fn default() -> Self {
22        Self::ClassDecl {
23            vars: Default::default(),
24        }
25    }
26}
27
28impl Mode {
29    pub(crate) fn push_var(&mut self, n: Ident, init: Option<Box<Expr>>) {
30        match self {
31            Mode::ClassExpr { vars, init_exprs } => {
32                vars.push(VarDeclarator {
33                    span: DUMMY_SP,
34                    name: n.clone().into(),
35                    init: None,
36                    definite: Default::default(),
37                });
38                if let Some(init) = init {
39                    init_exprs.push(
40                        AssignExpr {
41                            span: DUMMY_SP,
42                            op: op!("="),
43                            left: n.into(),
44                            right: init,
45                        }
46                        .into(),
47                    );
48                }
49            }
50            Mode::ClassDecl { vars } => {
51                vars.push(VarDeclarator {
52                    span: DUMMY_SP,
53                    name: n.into(),
54                    init,
55                    definite: Default::default(),
56                });
57            }
58        }
59    }
60}
61
62#[derive(Default)]
63pub(crate) struct ClassData {
64    pub(crate) ident: Option<Ident>,
65
66    pub(crate) vars: Mode,
67
68    /// [Mark] for the current class.
69    ///
70    /// This is modified by the class visitor.
71    pub(crate) mark: Mark,
72
73    pub(crate) privates: FxHashSet<Atom>,
74
75    /// Name of private methods.
76    pub(crate) methods: Vec<Atom>,
77
78    /// Name of private statics.
79    pub(crate) statics: Vec<Atom>,
80
81    pub(crate) constructor_exprs: Vec<Box<Expr>>,
82
83    pub(crate) names_used_for_brand_checks: FxHashSet<Atom>,
84}
85
86impl CompilerImpl<'_> {
87    pub(crate) fn var_name_for_brand_check(&self, n: &PrivateName, cls: &ClassData) -> Ident {
88        let is_static = cls.statics.contains(&n.name);
89
90        let span = n.span;
91        let ctxt = SyntaxContext::empty().apply_mark(cls.mark);
92
93        if !is_static && cls.methods.contains(&n.name) {
94            if let Some(cls_name) = &cls.ident {
95                return Ident::new(format!("_brand_check_{}", cls_name.sym).into(), span, ctxt);
96            }
97        }
98
99        Ident::new(format!("_brand_check_{}", n.name).into(), span, ctxt)
100    }
101}
102
103pub(crate) struct ClassAnalyzer<'a> {
104    pub(crate) brand_check_names: &'a mut FxHashSet<Atom>,
105    pub(crate) ignore_class: bool,
106}
107
108impl Visit for ClassAnalyzer<'_> {
109    noop_visit_type!(fail);
110
111    fn visit_bin_expr(&mut self, n: &BinExpr) {
112        n.visit_children_with(self);
113
114        if n.op == op!("in") {
115            if let Expr::PrivateName(left) = &*n.left {
116                self.brand_check_names.insert(left.name.clone());
117            }
118        }
119    }
120
121    /// Noop
122    fn visit_class(&mut self, n: &Class) {
123        if self.ignore_class {
124            return;
125        }
126
127        n.visit_children_with(self);
128    }
129}