2020-09-06 09:09:02 +03:00
|
|
|
use self::ops::{Operations, Operator};
|
2019-02-27 16:40:19 +03:00
|
|
|
use crate::{
|
2020-09-06 09:09:02 +03:00
|
|
|
compat::es2015::classes::native::{is_native, is_native_word},
|
2019-02-27 16:40:19 +03:00
|
|
|
scope::{IdentType, ScopeKind},
|
|
|
|
};
|
2020-12-09 08:23:44 +03:00
|
|
|
use fxhash::{FxHashMap, FxHashSet};
|
2019-12-13 09:21:25 +03:00
|
|
|
use smallvec::{smallvec, SmallVec};
|
2020-09-06 09:09:02 +03:00
|
|
|
use std::cell::RefCell;
|
2019-01-29 17:56:16 +03:00
|
|
|
use swc_atoms::JsWord;
|
2020-09-06 09:09:02 +03:00
|
|
|
use swc_common::{chain, SyntaxContext};
|
2020-02-05 14:20:25 +03:00
|
|
|
use swc_ecma_ast::*;
|
2020-09-06 09:09:02 +03:00
|
|
|
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
2019-01-29 17:56:16 +03:00
|
|
|
|
|
|
|
mod ops;
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
const LOG: bool = false;
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
trait ToBoxedStr {
|
|
|
|
fn to_boxed_str(&self) -> Box<str>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToBoxedStr for JsWord {
|
|
|
|
fn to_boxed_str(&self) -> Box<str> {
|
|
|
|
(**self).to_owned().into_boxed_str()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 06:50:19 +03:00
|
|
|
struct Hygiene<'a> {
|
2019-02-27 16:40:19 +03:00
|
|
|
current: Scope<'a>,
|
|
|
|
ident_type: IdentType,
|
2019-02-05 06:50:19 +03:00
|
|
|
}
|
|
|
|
|
2019-12-13 09:21:25 +03:00
|
|
|
type Contexts = SmallVec<[SyntaxContext; 32]>;
|
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
impl<'a> Hygiene<'a> {
|
|
|
|
fn add_declared_ref(&mut self, ident: Ident) {
|
|
|
|
let ctxt = ident.span.ctxt();
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Declaring {}{:?} ", ident.sym, ctxt);
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
let can_declare_without_renaming =
|
|
|
|
self.current.can_declare(&ident.sym.to_boxed_str(), ctxt);
|
2019-01-29 17:56:16 +03:00
|
|
|
let sym = self.current.change_symbol(ident.sym, ctxt);
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Changed symbol to {}{:?} ", sym, ctxt);
|
|
|
|
}
|
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
self.current
|
|
|
|
.declared_symbols
|
|
|
|
.borrow_mut()
|
2020-09-06 09:09:02 +03:00
|
|
|
.entry(sym.to_boxed_str())
|
|
|
|
.or_default()
|
2019-01-29 17:56:16 +03:00
|
|
|
.push(ctxt);
|
|
|
|
|
|
|
|
if can_declare_without_renaming {
|
|
|
|
// skip if previous symbol is declared on the same level.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Renaming from decl");
|
|
|
|
}
|
|
|
|
self.rename(sym, ctxt);
|
|
|
|
}
|
|
|
|
|
2020-08-14 09:08:36 +03:00
|
|
|
fn add_used_ref(&mut self, ident: &Ident) {
|
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Ident ref: {}{:?}", ident.sym, ident.span.ctxt);
|
|
|
|
}
|
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
let ctxt = ident.span.ctxt();
|
|
|
|
|
2020-08-14 09:08:36 +03:00
|
|
|
// Commented out because of https://github.com/swc-project/swc/issues/962
|
|
|
|
|
|
|
|
// self.current
|
|
|
|
// .declared_symbols
|
|
|
|
// .borrow_mut()
|
|
|
|
// .entry(ident.sym.clone())
|
|
|
|
// .or_insert_with(Vec::new)
|
|
|
|
// .push(ctxt);
|
2020-01-22 04:43:59 +03:00
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
// We rename declaration instead of usage
|
|
|
|
let conflicts = self.current.conflicts(ident.sym.clone(), ctxt);
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) && LOG && !conflicts.is_empty() {
|
|
|
|
eprintln!("Renaming from usage");
|
|
|
|
}
|
2020-01-22 04:43:59 +03:00
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
for cx in conflicts {
|
|
|
|
self.rename(ident.sym.clone(), cx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rename(&mut self, sym: JsWord, ctxt: SyntaxContext) {
|
|
|
|
// symbol conflicts
|
|
|
|
let renamed = {
|
|
|
|
let mut i = 0;
|
|
|
|
loop {
|
|
|
|
i += 1;
|
2020-09-06 09:09:02 +03:00
|
|
|
let sym = format!("{}{}", sym, i);
|
2019-01-29 17:56:16 +03:00
|
|
|
|
|
|
|
if !self.current.is_declared(&sym) {
|
|
|
|
break sym;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("\t{}{:?} -> {}", sym, ctxt, renamed);
|
|
|
|
}
|
|
|
|
|
2019-06-16 04:22:15 +03:00
|
|
|
let sym = self.current.change_symbol(sym, ctxt);
|
2020-09-06 09:09:02 +03:00
|
|
|
let boxed_sym = sym.to_boxed_str();
|
2020-12-09 08:23:44 +03:00
|
|
|
{
|
|
|
|
let scope = self.current.scope_of(&boxed_sym, ctxt);
|
|
|
|
|
|
|
|
// Update symbol list
|
|
|
|
let mut declared_symbols = scope.declared_symbols.borrow_mut();
|
|
|
|
|
|
|
|
let is_not_renamed = !scope.ops.borrow().rename.contains_key(&(sym.clone(), ctxt));
|
|
|
|
|
|
|
|
debug_assert!(
|
|
|
|
is_not_renamed,
|
|
|
|
"failed to rename {}{:?}: should not rename an ident multiple time\n{:?}",
|
|
|
|
sym,
|
|
|
|
ctxt,
|
|
|
|
scope.ops.borrow(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let old = declared_symbols.entry(sym.to_boxed_str()).or_default();
|
|
|
|
old.retain(|c| *c != ctxt);
|
|
|
|
// debug_assert!(old.is_empty() || old.len() == 1);
|
|
|
|
|
|
|
|
let new = declared_symbols
|
|
|
|
.entry(renamed.clone().into_boxed_str())
|
|
|
|
.or_insert_with(|| Vec::with_capacity(2));
|
|
|
|
new.push(ctxt);
|
|
|
|
debug_assert!(new.len() == 1);
|
|
|
|
|
|
|
|
scope
|
|
|
|
.ops
|
|
|
|
.borrow_mut()
|
|
|
|
.rename
|
|
|
|
.insert((sym, ctxt), renamed.clone().into());
|
|
|
|
}
|
|
|
|
self.current.renamed.insert(renamed.into());
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-23 20:18:22 +03:00
|
|
|
pub fn hygiene() -> impl Fold + 'static {
|
2019-12-28 05:25:54 +03:00
|
|
|
chain!(
|
2020-09-06 09:09:02 +03:00
|
|
|
as_folder(Hygiene {
|
2019-02-05 06:50:19 +03:00
|
|
|
current: Default::default(),
|
2019-02-27 16:40:19 +03:00
|
|
|
ident_type: IdentType::Ref,
|
2020-09-06 09:09:02 +03:00
|
|
|
}),
|
2020-08-18 19:29:49 +03:00
|
|
|
as_folder(MarkClearer)
|
2019-02-05 06:50:19 +03:00
|
|
|
)
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
|
2020-08-18 19:29:49 +03:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
struct MarkClearer;
|
|
|
|
impl VisitMut for MarkClearer {
|
|
|
|
noop_visit_mut_type!();
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_ident(&mut self, ident: &mut Ident) {
|
|
|
|
ident.span.ctxt = SyntaxContext::empty();
|
2020-08-18 19:29:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
impl<'a> Hygiene<'a> {
|
2020-09-06 09:09:02 +03:00
|
|
|
fn apply_ops<N>(&mut self, node: &mut N)
|
2019-01-29 17:56:16 +03:00
|
|
|
where
|
2020-09-06 09:09:02 +03:00
|
|
|
for<'o> N: VisitMutWith<Operator<'o>>,
|
2019-01-29 17:56:16 +03:00
|
|
|
{
|
|
|
|
let ops = self.current.ops.borrow();
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
if ops.rename.is_empty() {
|
|
|
|
return;
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
2020-09-06 09:09:02 +03:00
|
|
|
node.visit_mut_with(&mut Operator(&ops))
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Hygiene<'a> {
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_fn(&mut self, ident: Option<Ident>, node: &mut Function) {
|
2019-01-29 17:56:16 +03:00
|
|
|
match ident {
|
|
|
|
Some(ident) => {
|
|
|
|
self.add_declared_ref(ident);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut folder = Hygiene {
|
2019-11-17 07:21:53 +03:00
|
|
|
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
2019-02-27 16:40:19 +03:00
|
|
|
ident_type: IdentType::Ref,
|
2019-01-29 17:56:16 +03:00
|
|
|
};
|
|
|
|
|
2019-04-28 08:58:52 +03:00
|
|
|
folder.ident_type = IdentType::Ref;
|
2020-09-06 09:09:02 +03:00
|
|
|
node.decorators.visit_mut_with(&mut folder);
|
2019-04-28 08:58:52 +03:00
|
|
|
|
2019-02-27 16:40:19 +03:00
|
|
|
folder.ident_type = IdentType::Binding;
|
2020-09-06 09:09:02 +03:00
|
|
|
node.params.visit_mut_with(&mut folder);
|
2019-01-29 17:56:16 +03:00
|
|
|
|
2019-02-27 16:40:19 +03:00
|
|
|
folder.ident_type = IdentType::Ref;
|
2020-09-06 09:09:02 +03:00
|
|
|
node.body
|
|
|
|
.as_mut()
|
|
|
|
.map(|stmt| stmt.visit_mut_children_with(&mut folder));
|
2019-01-29 17:56:16 +03:00
|
|
|
|
|
|
|
folder.apply_ops(node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Scope<'a> {
|
|
|
|
/// Parent scope of this scope
|
|
|
|
pub parent: Option<&'a Scope<'a>>,
|
|
|
|
|
|
|
|
/// Kind of the scope.
|
|
|
|
pub kind: ScopeKind,
|
|
|
|
|
|
|
|
/// All references declared in this scope
|
2020-09-06 09:09:02 +03:00
|
|
|
pub declared_symbols: RefCell<FxHashMap<Box<str>, Vec<SyntaxContext>>>,
|
2019-01-29 17:56:16 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
pub(crate) ops: RefCell<Operations>,
|
2020-12-09 08:23:44 +03:00
|
|
|
pub renamed: FxHashSet<JsWord>,
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
|
2019-02-05 06:50:19 +03:00
|
|
|
impl<'a> Default for Scope<'a> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Scope::new(ScopeKind::Fn, None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
impl<'a> Scope<'a> {
|
|
|
|
pub fn new(kind: ScopeKind, parent: Option<&'a Scope<'a>>) -> Self {
|
|
|
|
Scope {
|
|
|
|
parent,
|
|
|
|
kind,
|
|
|
|
declared_symbols: Default::default(),
|
|
|
|
// children: Default::default(),
|
|
|
|
ops: Default::default(),
|
2020-12-09 08:23:44 +03:00
|
|
|
renamed: Default::default(),
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn scope_of(&self, sym: &Box<str>, ctxt: SyntaxContext) -> &'a Scope<'_> {
|
|
|
|
if let Some(prev) = self.declared_symbols.borrow().get(sym) {
|
2019-01-29 17:56:16 +03:00
|
|
|
if prev.contains(&ctxt) {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.parent {
|
|
|
|
Some(ref parent) => parent.scope_of(sym, ctxt),
|
|
|
|
_ => self,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn can_declare(&self, sym: &Box<str>, ctxt: SyntaxContext) -> bool {
|
2019-01-29 17:56:16 +03:00
|
|
|
match self.parent {
|
|
|
|
None => {}
|
|
|
|
Some(parent) => {
|
2020-09-06 09:09:02 +03:00
|
|
|
if !parent.can_declare(sym, ctxt) {
|
2019-01-29 17:56:16 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 08:54:52 +03:00
|
|
|
if is_native(&sym) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-09 08:23:44 +03:00
|
|
|
if self.renamed.contains(&(&**sym).into()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
if let Some(ctxts) = self.declared_symbols.borrow().get(sym) {
|
2019-11-17 07:21:53 +03:00
|
|
|
ctxts.contains(&ctxt)
|
2019-01-29 17:56:16 +03:00
|
|
|
} else {
|
|
|
|
// No variable named `sym` is declared
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns all **conflicting** contexts.
|
|
|
|
///
|
|
|
|
/// It other words, all `SyntaxContext`s with same `sym` will be returned,
|
|
|
|
/// even when defined on parent scope.
|
2019-12-13 02:47:46 +03:00
|
|
|
|
2019-12-13 09:21:25 +03:00
|
|
|
fn conflicts(&mut self, sym: JsWord, ctxt: SyntaxContext) -> Contexts {
|
2019-01-29 17:56:16 +03:00
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Finding conflicts for {}{:?} ", sym, ctxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
let sym = self.change_symbol(sym, ctxt);
|
|
|
|
|
2019-12-13 09:21:25 +03:00
|
|
|
let mut ctxts = smallvec![];
|
|
|
|
{
|
2020-09-06 09:09:02 +03:00
|
|
|
if let Some(cxs) = self.declared_symbols.get_mut().get(&*sym) {
|
2019-12-13 09:21:25 +03:00
|
|
|
if cxs.len() != 1 || cxs[0] != ctxt {
|
|
|
|
ctxts.extend_from_slice(&cxs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut cur = self.parent;
|
2019-01-29 17:56:16 +03:00
|
|
|
|
|
|
|
while let Some(scope) = cur {
|
2020-09-06 09:09:02 +03:00
|
|
|
if let Some(cxs) = scope.declared_symbols.borrow().get(&*sym) {
|
2019-12-13 09:21:25 +03:00
|
|
|
if cxs.len() != 1 || cxs[0] != ctxt {
|
|
|
|
ctxts.extend_from_slice(&cxs);
|
|
|
|
}
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cur = scope.parent;
|
|
|
|
}
|
2019-12-13 09:21:25 +03:00
|
|
|
|
2019-01-29 17:56:16 +03:00
|
|
|
ctxts.retain(|c| *c != ctxt);
|
2020-01-22 04:43:59 +03:00
|
|
|
ctxts.dedup();
|
2019-01-29 17:56:16 +03:00
|
|
|
|
|
|
|
ctxts
|
|
|
|
}
|
|
|
|
|
|
|
|
fn change_symbol(&self, mut sym: JsWord, ctxt: SyntaxContext) -> JsWord {
|
|
|
|
let mut cur = Some(self);
|
|
|
|
|
|
|
|
while let Some(scope) = cur {
|
2020-09-06 09:09:02 +03:00
|
|
|
if let Some(to) = scope.ops.borrow().rename.get(&(sym.clone(), ctxt)) {
|
|
|
|
if cfg!(debug_assertions) && LOG {
|
|
|
|
eprintln!("Changing symbol: {}{:?} -> {}", sym, ctxt, to);
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
2020-09-06 09:09:02 +03:00
|
|
|
sym = to.clone()
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cur = scope.parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
sym
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn is_declared(&self, sym: &str) -> bool {
|
2019-01-29 17:56:16 +03:00
|
|
|
if self.declared_symbols.borrow().contains_key(sym) {
|
|
|
|
return true;
|
|
|
|
}
|
2020-09-06 09:09:02 +03:00
|
|
|
for (_, to) in &self.ops.borrow().rename {
|
|
|
|
if to == sym {
|
|
|
|
return true;
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
match self.parent {
|
|
|
|
Some(parent) => parent.is_declared(sym),
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
macro_rules! track_ident_mut {
|
|
|
|
() => {
|
|
|
|
fn visit_mut_export_specifier(&mut self, s: &mut ExportSpecifier) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Ref;
|
|
|
|
s.visit_mut_children_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_import_specifier(&mut self, s: &mut ImportSpecifier) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
|
|
|
|
|
|
|
match s {
|
|
|
|
ImportSpecifier::Named(ImportNamedSpecifier { imported: None, .. })
|
|
|
|
| ImportSpecifier::Namespace(..)
|
|
|
|
| ImportSpecifier::Default(..) => s.visit_mut_children_with(self),
|
|
|
|
ImportSpecifier::Named(s) => s.local.visit_mut_with(self),
|
|
|
|
};
|
|
|
|
|
|
|
|
self.ident_type = old;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
|
|
|
f.param.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
|
|
|
|
f.body.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
// impl<'a> Fold for $T<'a> {
|
|
|
|
// fn fold(&mut self, f: GetterProp) -> GetterProp {
|
|
|
|
// let body = f.body.visit_mut_with(self);
|
|
|
|
|
|
|
|
// GetterProp { body, ..c }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
fn visit_mut_labeled_stmt(&mut self, s: &mut LabeledStmt) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Label;
|
|
|
|
s.label.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
2020-08-18 19:29:49 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
s.body.visit_mut_with(self);
|
|
|
|
}
|
2019-01-29 17:56:16 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_break_stmt(&mut self, s: &mut BreakStmt) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Label;
|
|
|
|
s.label.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_continue_stmt(&mut self, s: &mut ContinueStmt) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Label;
|
|
|
|
s.label.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_class_decl(&mut self, n: &mut ClassDecl) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
|
|
|
n.ident.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
|
|
|
|
n.class.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_class_expr(&mut self, n: &mut ClassExpr) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
|
|
|
n.ident.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
|
|
|
|
n.class.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_key_value_pat_prop(&mut self, n: &mut KeyValuePatProp) {
|
|
|
|
n.key.visit_mut_with(self);
|
|
|
|
n.value.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_class(&mut self, c: &mut Class) {
|
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Ref;
|
|
|
|
c.decorators.visit_mut_with(self);
|
|
|
|
|
|
|
|
self.ident_type = IdentType::Ref;
|
|
|
|
c.super_class.visit_mut_with(self);
|
|
|
|
|
|
|
|
self.ident_type = IdentType::Binding;
|
|
|
|
c.type_params.visit_mut_with(self);
|
|
|
|
|
|
|
|
self.ident_type = IdentType::Ref;
|
|
|
|
c.super_type_params.visit_mut_with(self);
|
|
|
|
|
|
|
|
self.ident_type = IdentType::Ref;
|
|
|
|
c.implements.visit_mut_with(self);
|
|
|
|
self.ident_type = old;
|
|
|
|
|
|
|
|
c.body.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_mut_prop_name(&mut self, n: &mut PropName) {
|
|
|
|
match n {
|
|
|
|
PropName::Computed(c) => {
|
|
|
|
c.visit_mut_with(self);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> VisitMut for Hygiene<'a> {
|
|
|
|
noop_visit_mut_type!();
|
|
|
|
|
|
|
|
track_ident_mut!();
|
|
|
|
|
|
|
|
fn visit_mut_arrow_expr(&mut self, node: &mut ArrowExpr) {
|
2019-02-05 06:50:19 +03:00
|
|
|
let mut folder = Hygiene {
|
2019-11-17 07:21:53 +03:00
|
|
|
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
2019-02-27 16:40:19 +03:00
|
|
|
ident_type: IdentType::Ref,
|
2019-02-05 06:50:19 +03:00
|
|
|
};
|
|
|
|
|
2019-02-27 16:40:19 +03:00
|
|
|
folder.ident_type = IdentType::Binding;
|
2020-09-06 09:09:02 +03:00
|
|
|
node.params.visit_mut_with(&mut folder);
|
2019-01-29 17:56:16 +03:00
|
|
|
|
2019-02-27 16:40:19 +03:00
|
|
|
folder.ident_type = IdentType::Ref;
|
2020-09-06 09:09:02 +03:00
|
|
|
node.body.visit_mut_with(&mut folder);
|
2019-02-05 06:50:19 +03:00
|
|
|
|
|
|
|
folder.apply_ops(node)
|
2019-01-29 17:56:16 +03:00
|
|
|
}
|
2019-12-03 05:50:33 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_block_stmt(&mut self, node: &mut BlockStmt) {
|
2020-07-23 20:18:22 +03:00
|
|
|
let mut folder = Hygiene {
|
|
|
|
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
|
|
|
ident_type: IdentType::Ref,
|
|
|
|
};
|
2020-09-06 09:09:02 +03:00
|
|
|
node.visit_mut_children_with(&mut folder);
|
2020-07-23 20:18:22 +03:00
|
|
|
|
|
|
|
folder.apply_ops(node)
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_catch_clause(&mut self, c: &mut CatchClause) {
|
2019-12-03 05:50:33 +03:00
|
|
|
let mut folder = Hygiene {
|
|
|
|
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
|
|
|
ident_type: IdentType::Ref,
|
|
|
|
};
|
|
|
|
folder.ident_type = IdentType::Binding;
|
2020-09-06 09:09:02 +03:00
|
|
|
c.param.visit_mut_with(&mut folder);
|
2019-12-03 05:50:33 +03:00
|
|
|
folder.ident_type = IdentType::Ref;
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
c.body.visit_mut_with(&mut folder);
|
2019-12-03 05:50:33 +03:00
|
|
|
}
|
2020-07-23 20:18:22 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_constructor(&mut self, c: &mut Constructor) {
|
2020-07-23 20:18:22 +03:00
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
2020-09-06 09:09:02 +03:00
|
|
|
c.params.visit_mut_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
self.ident_type = old;
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
c.body.as_mut().map(|bs| bs.visit_mut_children_with(self));
|
|
|
|
c.key.visit_mut_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
|
|
|
|
self.apply_ops(c)
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_expr(&mut self, node: &mut Expr) {
|
2020-07-23 20:18:22 +03:00
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Ref;
|
2020-09-06 09:09:02 +03:00
|
|
|
match node {
|
|
|
|
Expr::Ident(..) => node.visit_mut_children_with(self),
|
2020-07-23 20:18:22 +03:00
|
|
|
Expr::Member(e) => {
|
|
|
|
if e.computed {
|
2020-09-06 09:09:02 +03:00
|
|
|
e.obj.visit_mut_with(self);
|
|
|
|
e.prop.visit_mut_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
} else {
|
2020-09-06 09:09:02 +03:00
|
|
|
e.obj.visit_mut_with(self)
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
Expr::This(..) => {}
|
2020-07-23 20:18:22 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
_ => node.visit_mut_children_with(self),
|
2020-07-23 20:18:22 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
self.ident_type = old;
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_fn_decl(&mut self, node: &mut FnDecl) {
|
|
|
|
self.visit_mut_fn(Some(node.ident.clone()), &mut node.function);
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_fn_expr(&mut self, node: &mut FnExpr) {
|
|
|
|
self.visit_mut_fn(node.ident.clone(), &mut node.function);
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
2020-10-02 05:07:40 +03:00
|
|
|
fn visit_mut_private_name(&mut self, _: &mut PrivateName) {}
|
|
|
|
|
2020-07-23 20:18:22 +03:00
|
|
|
/// Invoked for `IdetifierRefrence` / `BindingIdentifier`
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_ident(&mut self, i: &mut Ident) {
|
2020-07-23 20:18:22 +03:00
|
|
|
if i.sym == js_word!("arguments") || i.sym == js_word!("undefined") {
|
2020-09-06 09:09:02 +03:00
|
|
|
return;
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
match self.ident_type {
|
|
|
|
IdentType::Binding => self.add_declared_ref(i.clone()),
|
|
|
|
IdentType::Ref => {
|
|
|
|
// Special cases
|
2020-09-06 09:09:02 +03:00
|
|
|
if is_native_word(&i.sym) {
|
|
|
|
return;
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
2020-08-14 09:08:36 +03:00
|
|
|
self.add_used_ref(&i);
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
IdentType::Label => {
|
|
|
|
// We currently does not touch labels
|
2020-09-06 09:09:02 +03:00
|
|
|
return;
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_module(&mut self, module: &mut Module) {
|
|
|
|
module.visit_mut_children_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
self.apply_ops(module)
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_object_lit(&mut self, node: &mut ObjectLit) {
|
2020-07-23 20:18:22 +03:00
|
|
|
let mut folder = Hygiene {
|
|
|
|
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
|
|
|
ident_type: IdentType::Ref,
|
|
|
|
};
|
2020-09-06 09:09:02 +03:00
|
|
|
node.visit_mut_children_with(&mut folder);
|
2020-07-23 20:18:22 +03:00
|
|
|
|
|
|
|
folder.apply_ops(node)
|
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_try_stmt(&mut self, node: &mut TryStmt) {
|
|
|
|
node.block.visit_mut_children_with(self);
|
|
|
|
|
|
|
|
node.handler.visit_mut_with(self);
|
|
|
|
node.finalizer.visit_mut_children_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
fn visit_mut_var_declarator(&mut self, decl: &mut VarDeclarator) {
|
2020-07-23 20:18:22 +03:00
|
|
|
let old = self.ident_type;
|
|
|
|
self.ident_type = IdentType::Binding;
|
2020-09-06 09:09:02 +03:00
|
|
|
decl.name.visit_mut_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
self.ident_type = old;
|
|
|
|
|
2020-09-06 09:09:02 +03:00
|
|
|
decl.init.visit_mut_with(self);
|
2020-07-23 20:18:22 +03:00
|
|
|
}
|
2019-12-03 05:50:33 +03:00
|
|
|
}
|