Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/renamer): Don't use symbols used by declarations if eval exists #7116

Merged
merged 14 commits into from Mar 22, 2023
19 changes: 19 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6871/input/.swcrc
@@ -0,0 +1,19 @@
{
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": false
},
"target": "es2015",
"loose": true,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
3 changes: 3 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6871/input/index.js
@@ -0,0 +1,3 @@
async function fromTokenizer() { }
async function _fromTokenizer() { }
eval()
16 changes: 16 additions & 0 deletions crates/swc/tests/fixture/issues-6xxx/6871/output/index.js
@@ -0,0 +1,16 @@
import _async_to_generator from "@swc/helpers/src/_async_to_generator.mjs";
function fromTokenizer() {
return _fromTokenizer1.apply(this, arguments);
}
function _fromTokenizer1() {
_fromTokenizer1 = _async_to_generator(function*() {});
return _fromTokenizer1.apply(this, arguments);
}
function _fromTokenizer() {
return __fromTokenizer.apply(this, arguments);
}
function __fromTokenizer() {
__fromTokenizer = _async_to_generator(function*() {});
return __fromTokenizer.apply(this, arguments);
}
eval();
5 changes: 5 additions & 0 deletions crates/swc_ecma_minifier/tests/full/issues/7094/input.js
@@ -0,0 +1,5 @@
export function useSyncExternalStore$2(e, n, t) {
let a = n(); // any variable expect `e`
return a;
}
eval();
1 change: 1 addition & 0 deletions crates/swc_ecma_minifier/tests/full/issues/7094/output.js
@@ -0,0 +1 @@
export function useSyncExternalStore$2(r,o,u){return o()}eval();
23 changes: 20 additions & 3 deletions crates/swc_ecma_transforms_base/src/rename/collector.rs
@@ -1,7 +1,7 @@
use std::hash::Hash;

use rustc_hash::FxHashSet;
use swc_common::SyntaxContext;
use swc_common::{Mark, SyntaxContext};
use swc_ecma_ast::*;
use swc_ecma_utils::ident::IdentLike;
use swc_ecma_visit::{noop_visit_type, visit_obj_and_computed, Visit, VisitWith};
Expand Down Expand Up @@ -47,14 +47,25 @@ where
I: IdentLike + Eq + Hash + Send + Sync,
{
bindings: FxHashSet<I>,
preserved: FxHashSet<I>,
is_pat_decl: bool,

/// [None] if there's no `eval`.
pub top_level_mark_for_eval: Option<Mark>,
}

impl<I> CustomBindingCollector<I>
where
I: IdentLike + Eq + Hash + Send + Sync,
{
fn add(&mut self, i: &Ident) {
if let Some(top_level_mark) = self.top_level_mark_for_eval {
if i.span.ctxt.outer().is_descendant_of(top_level_mark) {
self.preserved.insert(I::from_ident(i));
return;
}
}

self.bindings.insert(I::from_ident(i));
}
}
Expand Down Expand Up @@ -177,15 +188,21 @@ where
}
}

pub(super) fn collect_decls<I, N>(n: &N) -> FxHashSet<I>
/// Returns `(bindings, preserved)`.
pub(super) fn collect_decls<I, N>(
n: &N,
top_level_mark_for_eval: Option<Mark>,
) -> (FxHashSet<I>, FxHashSet<I>)
where
I: IdentLike + Eq + Hash + Send + Sync,
N: VisitWith<CustomBindingCollector<I>>,
{
let mut v = CustomBindingCollector {
bindings: Default::default(),
preserved: Default::default(),
is_pat_decl: false,
top_level_mark_for_eval,
};
n.visit_with(&mut v);
v.bindings
(v.bindings, v.preserved)
}
20 changes: 15 additions & 5 deletions crates/swc_ecma_transforms_base/src/rename/mod.rs
Expand Up @@ -82,7 +82,7 @@ impl<R> RenamePass<R>
where
R: Renamer,
{
fn get_unresolved<N>(&self, n: &N) -> FxHashSet<JsWord>
fn get_unresolved<N>(&self, n: &N, has_eval: bool) -> FxHashSet<JsWord>
where
N: VisitWith<IdCollector> + VisitWith<CustomBindingCollector<Id>>,
{
Expand All @@ -93,11 +93,19 @@ where
n.visit_with(&mut v);
v.ids
};
let decls = collect_decls(n);
let (decls, preserved) = collect_decls(
n,
if has_eval {
Some(self.config.top_level_mark)
} else {
None
},
);
usages
.into_iter()
.filter(|used_id| !decls.contains(used_id))
.map(|v| v.0)
.chain(preserved.into_iter().map(|v| v.0))
.collect()
}

Expand Down Expand Up @@ -133,7 +141,7 @@ where

let mut unresolved = if !is_module_or_script {
let mut unresolved = self.unresolved.clone();
unresolved.extend(self.get_unresolved(node));
unresolved.extend(self.get_unresolved(node, has_eval));
Cow::Owned(unresolved)
} else {
Cow::Borrowed(&self.unresolved)
Expand Down Expand Up @@ -230,10 +238,11 @@ where

fn visit_mut_module(&mut self, m: &mut Module) {
self.preserved = self.renamer.preserved_ids_for_module(m);
self.unresolved = self.get_unresolved(m);

let has_eval = contains_eval(m, true);

self.unresolved = self.get_unresolved(m, has_eval);

{
let map = self.get_map(m, false, true, has_eval);

Expand All @@ -247,10 +256,11 @@ where

fn visit_mut_script(&mut self, m: &mut Script) {
self.preserved = self.renamer.preserved_ids_for_script(m);
self.unresolved = self.get_unresolved(m);

let has_eval = contains_eval(m, true);

self.unresolved = self.get_unresolved(m, has_eval);

{
let map = self.get_map(m, false, true, has_eval);

Expand Down