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

feat(es/renamer): Rename synthesized identifiers even on eval #6818

Merged
merged 18 commits into from
Jan 16, 2023
88 changes: 77 additions & 11 deletions crates/swc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use swc_common::{
util::take::Take,
FileName, Mark, SourceMap,
};
use swc_ecma_ast::{EsVersion, Module};
use swc_ecma_ast::{EsVersion, Module, Script};
use swc_ecma_minifier::option::{terser::TerserTopLevelOptions, MinifyOptions};
use swc_ecma_parser::Syntax;
use swc_ecma_transforms::{
Expand Down Expand Up @@ -351,11 +351,13 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
options: self.minify,
cm: self.cm.clone(),
comments: comments.cloned(),
unresolved_mark: self.unresolved_mark,
top_level_mark: self.top_level_mark,
}),
Optional::new(
hygiene_with_config(self.hygiene.clone().unwrap_or_default()),
hygiene_with_config(swc_ecma_transforms_base::hygiene::Config {
top_level_mark: self.top_level_mark,
..self.hygiene.clone().unwrap_or_default()
}),
self.hygiene.is_some() && !is_mangler_enabled
),
Optional::new(fixer(comments.map(|v| v as &dyn Comments)), self.fixer),
Expand All @@ -367,7 +369,6 @@ struct MinifierPass {
options: Option<JsMinifyOptions>,
cm: Lrc<SourceMap>,
comments: Option<SingleThreadedComments>,
unresolved_mark: Mark,
top_level_mark: Mark,
}

Expand Down Expand Up @@ -408,13 +409,18 @@ impl VisitMut for MinifierPass {
return;
}

m.visit_mut_with(&mut hygiene());
m.visit_mut_with(&mut resolver(
self.unresolved_mark,
self.top_level_mark,
false,
m.visit_mut_with(&mut hygiene_with_config(
swc_ecma_transforms_base::hygiene::Config {
top_level_mark: self.top_level_mark,
..Default::default()
},
));

let unresolved_mark = Mark::new();
let top_level_mark = Mark::new();

m.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false));

m.map_with_mut(|m| {
swc_ecma_minifier::optimize(
m.into(),
Expand All @@ -423,14 +429,74 @@ impl VisitMut for MinifierPass {
None,
&opts,
&swc_ecma_minifier::option::ExtraOptions {
unresolved_mark: self.unresolved_mark,
top_level_mark: self.top_level_mark,
unresolved_mark,
top_level_mark,
},
)
.expect_module()
})
}
}

fn visit_mut_script(&mut self, m: &mut Script) {
if let Some(options) = &self.options {
let opts = MinifyOptions {
compress: options
.compress
.clone()
.unwrap_as_option(|default| match default {
Some(true) => Some(Default::default()),
_ => None,
})
.map(|mut v| {
if v.const_to_let.is_none() {
v.const_to_let = Some(true);
}

v.into_config(self.cm.clone())
}),
mangle: options
.mangle
.clone()
.unwrap_as_option(|default| match default {
Some(true) => Some(Default::default()),
_ => None,
}),
..Default::default()
};

if opts.compress.is_none() && opts.mangle.is_none() {
return;
}

m.visit_mut_with(&mut hygiene_with_config(
swc_ecma_transforms_base::hygiene::Config {
top_level_mark: self.top_level_mark,
..Default::default()
},
));

let unresolved_mark = Mark::new();
let top_level_mark = Mark::new();

m.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false));

m.map_with_mut(|m| {
swc_ecma_minifier::optimize(
m.into(),
self.cm.clone(),
self.comments.as_ref().map(|v| v as &dyn Comments),
None,
&opts,
&swc_ecma_minifier::option::ExtraOptions {
unresolved_mark,
top_level_mark,
},
)
.expect_script()
})
}
}
}

fn should_enable(target: EsVersion, feature: EsVersion) -> bool {
Expand Down
19 changes: 19 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/1/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true
},
"target": "es5",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
11 changes: 11 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/1/input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components';

const C1 = styled.div`
position: absolute;
`;

const C2 = styled.div`
position: absolute;
`;

const debug = eval('');
23 changes: 23 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/1/output/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import _tagged_template_literal from "@swc/helpers/src/_tagged_template_literal.mjs";
function _templateObject() {
var data = _tagged_template_literal([
"\n position: absolute;\n"
]);
_templateObject = function _templateObject() {
return data;
};
return data;
}
function _templateObject1() {
var data = _tagged_template_literal([
"\n position: absolute;\n"
]);
_templateObject1 = function _templateObject1() {
return data;
};
return data;
}
import styled from "styled-components";
var C1 = styled.div(_templateObject());
var C2 = styled.div(_templateObject1());
var debug = eval("");
19 changes: 19 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/2/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true
},
"target": "es5",
"loose": false,
"minify": {
"compress": false,
"mangle": true
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
11 changes: 11 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/2/input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components';

const C1 = styled.div`
position: absolute;
`;

const C2 = styled.div`
position: absolute;
`;

const debug = eval('');
23 changes: 23 additions & 0 deletions crates/swc/tests/fixture/issues-5xxx/5068/2/output/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import _tagged_template_literal from "@swc/helpers/src/_tagged_template_literal.mjs";
function _templateObject() {
var n = _tagged_template_literal([
"\n position: absolute;\n"
]);
_templateObject = function r() {
return n;
};
return n;
}
function _templateObject1() {
var n = _tagged_template_literal([
"\n position: absolute;\n"
]);
_templateObject1 = function r() {
return n;
};
return n;
}
import styled from "styled-components";
var C1 = styled.div(_templateObject());
var C2 = styled.div(_templateObject1());
var debug = eval("");
7 changes: 6 additions & 1 deletion crates/swc_ecma_minifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,12 @@ pub fn optimize(
)
.compile();

n.visit_mut_with(&mut name_mangler(mangle.clone(), preserved, chars));
n.visit_mut_with(&mut name_mangler(
mangle.clone(),
preserved,
chars,
extra.top_level_mark,
));

if let Some(property_mangle_options) = &mangle.props {
mangle_properties(&mut n, &module_info, property_mangle_options.clone(), chars);
Expand Down
4 changes: 3 additions & 1 deletion crates/swc_ecma_minifier/src/pass/mangle_names/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_hash::{FxHashMap, FxHashSet};
use swc_atoms::JsWord;
use swc_common::chain;
use swc_common::{chain, Mark};
use swc_ecma_ast::{Module, *};
use swc_ecma_transforms_base::rename::{renamer, Renamer};
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
Expand All @@ -15,6 +15,7 @@ pub(crate) fn name_mangler(
options: MangleOptions,
preserved: FxHashSet<Id>,
chars: Base54Chars,
top_level_mark: Mark,
) -> impl VisitMut {
chain!(
LabelMangler {
Expand All @@ -27,6 +28,7 @@ pub(crate) fn name_mangler(
swc_ecma_transforms_base::hygiene::Config {
keep_class_names: options.keep_class_names,
safari_10: options.safari10,
top_level_mark
},
ManglingRenamer { chars, preserved }
)
Expand Down
6 changes: 5 additions & 1 deletion crates/swc_ecma_transforms_base/src/hygiene/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use swc_common::chain;
use swc_common::{chain, Mark};
use swc_ecma_ast::*;
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut};

Expand All @@ -15,6 +15,10 @@ pub struct Config {

/// If true, the bug of safari 10 is avoided.
pub safari_10: bool,

/// The marks derived from this marks will treated as `specified by user`
/// and other marks will be treated as `generated by swc`.
pub top_level_mark: Mark,
}

/// See [hygiene_with_config] for doc. Creates a `hygiene` pass with default
Expand Down
18 changes: 13 additions & 5 deletions crates/swc_ecma_transforms_base/src/rename/analyzer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use swc_common::Mark;
use swc_ecma_ast::*;
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};

Expand All @@ -9,6 +10,11 @@ pub(super) mod scope;
#[derive(Debug, Default)]
pub(super) struct Analyzer {
pub safari_10: bool,
/// If `eval` exists for the current scope, we only rename synthesized
/// identifiers.
pub has_eval: bool,
/// The [Mark] which is parent of user-specified identifiers.
pub top_level_mark: Mark,

pub is_pat_decl: bool,
pub var_belong_to_fn_scope: bool,
Expand All @@ -25,12 +31,12 @@ impl Analyzer {
if belong_to_fn_scope {
match self.scope.kind {
ScopeKind::Fn => {
self.scope.add_decl(&id);
self.scope.add_decl(&id, self.has_eval, self.top_level_mark);
}
ScopeKind::Block => self.hoisted_vars.push(id),
}
} else {
self.scope.add_decl(&id);
self.scope.add_decl(&id, self.has_eval, self.top_level_mark);
}
}

Expand All @@ -45,14 +51,16 @@ impl Analyzer {
{
let mut v = Analyzer {
safari_10: self.safari_10,
has_eval: self.has_eval,
top_level_mark: self.top_level_mark,

is_pat_decl: self.is_pat_decl,
var_belong_to_fn_scope: false,
in_catch_params: false,
scope: Scope {
kind,
..Default::default()
},
is_pat_decl: self.is_pat_decl,
var_belong_to_fn_scope: false,
in_catch_params: false,
hoisted_vars: Default::default(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
use rayon::prelude::*;
use rustc_hash::FxHashSet;
use swc_atoms::{js_word, JsWord};
use swc_common::{collections::AHashMap, util::take::Take, SyntaxContext};
use swc_common::{collections::AHashMap, util::take::Take, Mark, SyntaxContext};
use swc_ecma_ast::*;
use tracing::debug;

Expand Down Expand Up @@ -81,13 +81,17 @@ pub(super) struct ScopeData {
}

impl Scope {
pub(super) fn add_decl(&mut self, id: &Id) {
pub(super) fn add_decl(&mut self, id: &Id, has_eval: bool, top_level_mark: Mark) {
if id.0 == js_word!("arguments") {
return;
}

self.data.all.insert(fast_id(id.clone()));
if !self.data.queue.contains(id) {
if has_eval && id.1.outer().is_descendant_of(top_level_mark) {
return;
}

self.data.queue.push(id.clone());
}
}
Expand Down
Loading