From 21f3f792d1a6b45d858015ce8e03e07562e3c6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 28 Feb 2019 23:07:31 +0900 Subject: [PATCH] Fixes (#294) swc_ecma_transforms: - block_scoped_fn: don't fold self-modifing functions. (#288). - fixer: fix assignment in conditional expression (#293) - make resolver work with self modifying function (#292) --- .../src/compat/es2015/block_scoped_fn.rs | 95 ++++++++++++++++--- .../src/compat/es2015/function_name/mod.rs | 30 +----- .../src/compat/es2015/resolver/mod.rs | 25 +---- .../src/compat/es2015/resolver/tests.rs | 32 +++++++ ecmascript/transforms/src/fixer.rs | 14 ++- ecmascript/transforms/src/util/mod.rs | 38 ++++++++ 6 files changed, 168 insertions(+), 66 deletions(-) diff --git a/ecmascript/transforms/src/compat/es2015/block_scoped_fn.rs b/ecmascript/transforms/src/compat/es2015/block_scoped_fn.rs index 0fd5967e093..e7dfbc2ee5d 100644 --- a/ecmascript/transforms/src/compat/es2015/block_scoped_fn.rs +++ b/ecmascript/transforms/src/compat/es2015/block_scoped_fn.rs @@ -1,3 +1,4 @@ +use crate::util::UsageFinder; use ast::*; use swc_common::{Fold, FoldWith, Spanned, DUMMY_SP}; @@ -15,20 +16,26 @@ impl Fold> for BlockScopedFns { extra_stmts.push(stmt) } else { match stmt { - Stmt::Decl(Decl::Fn(decl)) => stmts.push(Stmt::Decl(Decl::Var(VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Let, - decls: vec![VarDeclarator { + Stmt::Decl(Decl::Fn(decl)) => { + if UsageFinder::find(&decl.ident, &decl.function) { + extra_stmts.push(Stmt::Decl(Decl::Fn(decl))); + continue; + } + stmts.push(Stmt::Decl(Decl::Var(VarDecl { span: DUMMY_SP, - name: Pat::Ident(decl.ident.clone()), - init: Some(box Expr::Fn(FnExpr { - ident: Some(decl.ident), - function: decl.function, - })), - definite: false, - }], - declare: false, - }))), + kind: VarDeclKind::Let, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(decl.ident.clone()), + init: Some(box Expr::Fn(FnExpr { + ident: Some(decl.ident), + function: decl.function, + })), + definite: false, + }], + declare: false, + }))) + } _ => extra_stmts.push(stmt.fold_children(self)), } } @@ -109,6 +116,68 @@ function foo(scope) { }; scope.startOperation = startOperation; } +" + ); + + test!( + ::swc_ecma_parser::Syntax::default(), + |_| BlockScopedFns, + issue_288_1, + "function components_Link_extends() { components_Link_extends = Object.assign || function \ + (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for \ + (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { \ + target[key] = source[key]; } } } return target; }; return \ + components_Link_extends.apply(this, arguments); } + +", + "function components_Link_extends() { components_Link_extends = Object.assign || function \ + (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for \ + (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { \ + target[key] = source[key]; } } } return target; }; return \ + components_Link_extends.apply(this, arguments); } + +" + ); + + test!( + ::swc_ecma_parser::Syntax::default(), + |_| BlockScopedFns, + issue_288_2, + "function _extends() { + module.exports = _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} +", + "function _extends() { + module.exports = _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} " ); diff --git a/ecmascript/transforms/src/compat/es2015/function_name/mod.rs b/ecmascript/transforms/src/compat/es2015/function_name/mod.rs index 1d0f8d7fd11..0d99859fb86 100644 --- a/ecmascript/transforms/src/compat/es2015/function_name/mod.rs +++ b/ecmascript/transforms/src/compat/es2015/function_name/mod.rs @@ -1,5 +1,6 @@ +use crate::util::UsageFinder; use ast::*; -use swc_common::{Fold, FoldWith, Visit, VisitWith}; +use swc_common::{Fold, FoldWith}; #[cfg(test)] mod tests; @@ -74,33 +75,6 @@ impl Fold for FnName { } } -struct UsageFinder<'a> { - ident: &'a Ident, - found: bool, -} - -impl<'a> Visit for UsageFinder<'a> { - fn visit(&mut self, i: &Ident) { - if i.span.ctxt() == self.ident.span.ctxt() && i.sym == self.ident.sym { - self.found = true; - } - } -} - -impl<'a> UsageFinder<'a> { - fn find(ident: &'a Ident, node: &N) -> bool - where - N: VisitWith, - { - let mut v = UsageFinder { - ident, - found: false, - }; - node.visit_with(&mut v); - v.found - } -} - macro_rules! impl_for { ($T:tt) => { impl Fold<$T> for Renamer { diff --git a/ecmascript/transforms/src/compat/es2015/resolver/mod.rs b/ecmascript/transforms/src/compat/es2015/resolver/mod.rs index 63c819af0a0..7de023f0bb7 100644 --- a/ecmascript/transforms/src/compat/es2015/resolver/mod.rs +++ b/ecmascript/transforms/src/compat/es2015/resolver/mod.rs @@ -227,31 +227,8 @@ impl<'a> Fold for Resolver<'a> { _ => None, }; - let is_class_like = match decl.init { - Some(box Expr::Fn(FnExpr { ref ident, .. })) - if cur_name.is_some() - && ident.as_ref().map(|v| &v.sym) == cur_name.as_ref().map(|v| &v.0) => - { - true - } - - Some(box Expr::Call(CallExpr { - callee: ExprOrSuper::Expr(box Expr::Fn(FnExpr { ident: None, .. })), - .. - })) - | Some(box Expr::Call(CallExpr { - callee: - ExprOrSuper::Expr(box Expr::Paren(ParenExpr { - expr: box Expr::Fn(FnExpr { ident: None, .. }), - .. - })), - .. - })) => true, - _ => false, - }; - let old_def = self.cur_defining.take(); - self.cur_defining = if is_class_like { cur_name } else { None }.into(); + self.cur_defining = cur_name; let init = decl.init.fold_children(self); diff --git a/ecmascript/transforms/src/compat/es2015/resolver/tests.rs b/ecmascript/transforms/src/compat/es2015/resolver/tests.rs index 25d8f6193ce..0bda245e6fd 100644 --- a/ecmascript/transforms/src/compat/es2015/resolver/tests.rs +++ b/ecmascript/transforms/src/compat/es2015/resolver/tests.rs @@ -632,3 +632,35 @@ identical!( } }" ); + +identical!( + issue_292_1, + "var __assign = function () { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + + return t; + }; + + return __assign.apply(this, arguments); +};" +); + +identical!( + issue_292_2, + "__assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + + return t; + }; + + __assign.apply(this, arguments);" +); diff --git a/ecmascript/transforms/src/fixer.rs b/ecmascript/transforms/src/fixer.rs index 418aa81e211..f110fa634e2 100644 --- a/ecmascript/transforms/src/fixer.rs +++ b/ecmascript/transforms/src/fixer.rs @@ -346,7 +346,7 @@ impl Fold for Fixer { Expr::Cond(expr) => { let test = match *expr.test { - e @ Expr::Seq(..) => box e.wrap_with_paren(), + e @ Expr::Seq(..) | e @ Expr::Assign(..) => box e.wrap_with_paren(), _ => expr.test, }; @@ -686,4 +686,16 @@ var store = global[SHARED] || (global[SHARED] = {}); copyright: '© 2018 Denis Pushkarev (zloirock.ru)' });" ); + + identical!( + issue_293_1, + "for (var e in a) a.hasOwnProperty(e) && ((b = a[e]) ? this[e] = b(c) : 'target' === e ? \ + this.target = d : this[e] = c[e]);" + ); + + identical!( + issue_293_2, + "(a = rb ? zb(a, c) : Ab(a, c)) ? (b = nb.getPooled(ub.beforeInput, b, c, d), b.data = a, \ + Ra(b)) : b = null;" + ); } diff --git a/ecmascript/transforms/src/util/mod.rs b/ecmascript/transforms/src/util/mod.rs index eb1aabfe16b..72cdad6cc1d 100644 --- a/ecmascript/transforms/src/util/mod.rs +++ b/ecmascript/transforms/src/util/mod.rs @@ -977,6 +977,44 @@ impl Fold for DropSpan { } } +/// Finds usage of `ident` +pub(crate) struct UsageFinder<'a> { + ident: &'a Ident, + found: bool, +} + +impl<'a> Visit for UsageFinder<'a> { + fn visit(&mut self, e: &MemberExpr) { + e.obj.visit_with(self); + + if e.computed { + e.prop.visit_with(self); + } + } +} + +impl<'a> Visit for UsageFinder<'a> { + fn visit(&mut self, i: &Ident) { + if i.span.ctxt() == self.ident.span.ctxt() && i.sym == self.ident.sym { + self.found = true; + } + } +} + +impl<'a> UsageFinder<'a> { + pub(crate) fn find(ident: &'a Ident, node: &N) -> bool + where + N: VisitWith, + { + let mut v = UsageFinder { + ident, + found: false, + }; + node.visit_with(&mut v); + v.found + } +} + lazy_static! { pub(crate) static ref CM: Arc = { Arc::new(SourceMap::new(FilePathMapping::empty())) };