mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
feat(es/minifier): Implement more rules for dropping unused assignemnts (#4171)
This commit is contained in:
parent
e7089d8b3e
commit
6f25e5774b
@ -1 +1 @@
|
|||||||
for (let v of [])for (let v1 of [])v1++;
|
for (let v of [])for (let v1 of []);
|
||||||
|
@ -4,10 +4,7 @@ try {
|
|||||||
_step.value;
|
_step.value;
|
||||||
var _iteratorNormalCompletion1 = !0, _didIteratorError1 = !1, _iteratorError1 = void 0;
|
var _iteratorNormalCompletion1 = !0, _didIteratorError1 = !1, _iteratorError1 = void 0;
|
||||||
try {
|
try {
|
||||||
for(var _step1, _iterator1 = [][Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0){
|
for(var _step1, _iterator1 = [][Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0)_step1.value;
|
||||||
var v = _step1.value;
|
|
||||||
v++;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_didIteratorError1 = !0, _iteratorError1 = err;
|
_didIteratorError1 = !0, _iteratorError1 = err;
|
||||||
} finally{
|
} finally{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var E, a, b, x1, x2, x3, x4, x5, x6, x7;
|
var E, a, b, x1, x2, x3, x4, x6;
|
||||||
!function(E) {
|
!function(E) {
|
||||||
E[E.a = 0] = "a", E[E.b = 1] = "b";
|
E[E.a = 0] = "a", E[E.b = 1] = "b";
|
||||||
}(E || (E = {})), x1 += a, x1 += b, x1 += !0, x1 += 0, x1 += '', x1 += E.a, x1 += {}, x1 += null, x1 += void 0, x2 += a, x2 += b, x2 += !0, x2 += 0, x2 += '', x2 += E.a, x2 += {}, x2 += null, x2 += void 0, x3 += a, x3 += 0, x3 += E.a, x3 += null, x3 += void 0, x4 += a, x4 += 0, x4 += E.a, x4 += null, x4 += void 0, x5 += a, x6 += a, x6 += '', x7 += a;
|
}(E || (E = {})), x1 += a, x1 += b, x1 += !0, x1 += 0, x1 += '', x1 += E.a, x1 += {}, x1 += null, x1 += void 0, x2 += a, x2 += b, x2 += !0, x2 += 0, x2 += '', x2 += E.a, x2 += {}, x2 += null, x2 += void 0, x3 += a, x3 += 0, x3 += E.a, x3 += null, x3 += void 0, x4 += a, x4 += 0, x4 += E.a, x4 += null, x4 += void 0, x6 += a, x6 += '';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var E, a, b, x1, x2, x3, x4, x5, x6, x7;
|
var E, a, b, x1, x2, x3, x4, x6;
|
||||||
!function(E) {
|
!function(E) {
|
||||||
E[E.a = 0] = "a", E[E.b = 1] = "b";
|
E[E.a = 0] = "a", E[E.b = 1] = "b";
|
||||||
}(E || (E = {})), x1 += a, x1 += b, x1 += !0, x1 += 0, x1 += "", x1 += E.a, x1 += {}, x1 += null, x1 += void 0, x2 += a, x2 += b, x2 += !0, x2 += 0, x2 += "", x2 += E.a, x2 += {}, x2 += null, x2 += void 0, x3 += a, x3 += 0, x3 += E.a, x3 += null, x3 += void 0, x4 += a, x4 += 0, x4 += E.a, x4 += null, x4 += void 0, x5 += a, x6 += a, x6 += "", x7 += a;
|
}(E || (E = {})), x1 += a, x1 += b, x1 += !0, x1 += 0, x1 += "", x1 += E.a, x1 += {}, x1 += null, x1 += void 0, x2 += a, x2 += b, x2 += !0, x2 += 0, x2 += "", x2 += E.a, x2 += {}, x2 += null, x2 += void 0, x3 += a, x3 += 0, x3 += E.a, x3 += null, x3 += void 0, x4 += a, x4 += 0, x4 += E.a, x4 += null, x4 += void 0, x6 += a, x6 += "";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var E, x1, x2, x3, x4, x5;
|
var E;
|
||||||
!function(E) {
|
!function(E) {
|
||||||
E[E.a = 0] = "a", E[E.b = 1] = "b", E[E.c = 2] = "c";
|
E[E.a = 0] = "a", E[E.b = 1] = "b", E[E.c = 2] = "c";
|
||||||
}(E || (E = {})), x1 += '', x2 += '', x3 += '', x4 += '', x5 += '';
|
}(E || (E = {}));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
var E, x1, x2, x3, x4, x5;
|
var E;
|
||||||
!function(E) {
|
!function(E) {
|
||||||
E[E.a = 0] = "a", E[E.b = 1] = "b", E[E.c = 2] = "c";
|
E[E.a = 0] = "a", E[E.b = 1] = "b", E[E.c = 2] = "c";
|
||||||
}(E || (E = {})), x1 += "", x2 += "", x3 += "", x4 += "", x5 += "";
|
}(E || (E = {}));
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import * as a from "@swc/helpers";
|
import * as a from "@swc/helpers";
|
||||||
Promise.all(assignAll).then(function() {
|
Promise.all(assignAll).then(function() {
|
||||||
var b = a.asyncToGenerator(function*(e) {
|
var b = a.asyncToGenerator(function*(c) {
|
||||||
let b = 'DELETE FROM "TABLE" WHERE "UUID" IN ( ';
|
for(let b in obj){
|
||||||
for(let c in obj){
|
let a = obj[b];
|
||||||
let a = obj[c];
|
`'${a.id}', `, (yield listOfUser(a.id)).forEach((b)=>{
|
||||||
b += `'${a.id}', `;
|
|
||||||
let d = yield listOfUser(a.id);
|
|
||||||
d.forEach((b)=>{
|
|
||||||
insertQuery += `INSERT INTO "TABLE"("UUID", id, other_ids_here) VALUES ('${uuidv4()}', '${a.id}', now());`;
|
insertQuery += `INSERT INTO "TABLE"("UUID", id, other_ids_here) VALUES ('${uuidv4()}', '${a.id}', now());`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return function(e) {
|
return function(c) {
|
||||||
return b.apply(this, arguments);
|
return b.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
@ -76,6 +76,9 @@ pub(crate) struct VarUsageInfo {
|
|||||||
|
|
||||||
pub assign_count: usize,
|
pub assign_count: usize,
|
||||||
pub mutation_by_call_count: usize,
|
pub mutation_by_call_count: usize,
|
||||||
|
/// ## Things to note
|
||||||
|
///
|
||||||
|
/// - Update is counted as usage
|
||||||
pub usage_count: usize,
|
pub usage_count: usize,
|
||||||
|
|
||||||
/// The variable itself is modified.
|
/// The variable itself is modified.
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::{collections::HashMap, mem::swap};
|
use std::{collections::HashMap, mem::swap};
|
||||||
|
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use swc_atoms::js_word;
|
use swc_atoms::js_word;
|
||||||
use swc_common::{collections::AHashMap, pass::Either, util::take::Take, Spanned, DUMMY_SP};
|
use swc_common::{pass::Either, util::take::Take, Spanned, DUMMY_SP};
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_utils::{contains_arguments, ident::IdentLike, undefined, ExprFactory, Id};
|
use swc_ecma_utils::{contains_arguments, ident::IdentLike, undefined, ExprFactory, Id};
|
||||||
use swc_ecma_visit::VisitMutWith;
|
use swc_ecma_visit::VisitMutWith;
|
||||||
@ -246,8 +247,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "debug", tracing::instrument(skip(self, n, vars)))]
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, vars: AHashMap<Id, Box<Expr>>)
|
pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, vars: FxHashMap<Id, Box<Expr>>)
|
||||||
where
|
where
|
||||||
N: VisitMutWith<MultiReplacer>,
|
N: VisitMutWith<MultiReplacer>,
|
||||||
{
|
{
|
||||||
|
@ -195,7 +195,7 @@ struct Optimizer<'a, M> {
|
|||||||
/// Used for inlining.
|
/// Used for inlining.
|
||||||
lits: AHashMap<Id, Box<Expr>>,
|
lits: AHashMap<Id, Box<Expr>>,
|
||||||
|
|
||||||
vars_for_inlining: AHashMap<Id, Box<Expr>>,
|
vars_for_inlining: FxHashMap<Id, Box<Expr>>,
|
||||||
|
|
||||||
vars_for_prop_hoisting: AHashMap<Id, Box<Expr>>,
|
vars_for_prop_hoisting: AHashMap<Id, Box<Expr>>,
|
||||||
/// Used for `hoist_props`.
|
/// Used for `hoist_props`.
|
||||||
@ -703,6 +703,10 @@ where
|
|||||||
|
|
||||||
self.compress_cond_to_logical_ignoring_return_value(e);
|
self.compress_cond_to_logical_ignoring_return_value(e);
|
||||||
|
|
||||||
|
self.drop_unused_update(e);
|
||||||
|
|
||||||
|
self.drop_unused_op_assign(e);
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
|
Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
|
@ -508,16 +508,39 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This should be only called from ignore_return_value
|
||||||
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
pub(super) fn drop_unused_assignments(&mut self, e: &mut Expr) {
|
pub(super) fn drop_unused_update(&mut self, e: &mut Expr) {
|
||||||
let assign = match e {
|
if !self.options.unused {
|
||||||
Expr::Assign(e) => e,
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let update = match e {
|
||||||
|
Expr::Update(u) => u,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_mark = assign.span.has_mark(self.marks.non_top_level);
|
if let Expr::Ident(arg) = &*update.arg {
|
||||||
|
if let Some(var) = self.data.vars.get(&arg.to_id()) {
|
||||||
|
// Update is counted as usage
|
||||||
|
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
||||||
|
self.changed = true;
|
||||||
|
tracing::debug!(
|
||||||
|
"unused: Dropping an update '{}{:?}' because it is not used",
|
||||||
|
arg.sym,
|
||||||
|
arg.span.ctxt
|
||||||
|
);
|
||||||
|
// This will remove the update.
|
||||||
|
e.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !has_mark && !self.options.unused {
|
/// This should be only called from ignore_return_value
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
|
pub(super) fn drop_unused_op_assign(&mut self, e: &mut Expr) {
|
||||||
|
if !self.options.unused {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +552,58 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let assign = match e {
|
||||||
|
Expr::Assign(AssignExpr { op: op!("="), .. }) => return,
|
||||||
|
// RHS may not be evaluated
|
||||||
|
Expr::Assign(AssignExpr {
|
||||||
|
op: op!("&&=") | op!("||=") | op!("&&="),
|
||||||
|
..
|
||||||
|
}) => return,
|
||||||
|
Expr::Assign(e) => e,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
assign.left.map_with_mut(|left| left.normalize_ident());
|
||||||
|
|
||||||
|
if let PatOrExpr::Pat(p) = &assign.left {
|
||||||
|
if let Pat::Ident(left) = &**p {
|
||||||
|
if let Some(var) = self.data.vars.get(&left.to_id()) {
|
||||||
|
// TODO: We don't need fn_local check
|
||||||
|
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
||||||
|
self.changed = true;
|
||||||
|
tracing::debug!(
|
||||||
|
"unused: Dropping an op-assign '{}{:?}' because it is not used",
|
||||||
|
left.id.sym,
|
||||||
|
left.id.span.ctxt
|
||||||
|
);
|
||||||
|
// This will remove the op-assign.
|
||||||
|
*e = *assign.right.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
|
pub(super) fn drop_unused_assignments(&mut self, e: &mut Expr) {
|
||||||
|
if self.ctx.is_delete_arg {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.data.top.has_eval_call || self.data.top.has_with_stmt {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let assign = match e {
|
||||||
|
Expr::Assign(e) => e,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let has_mark = assign.span.has_mark(self.marks.non_top_level);
|
||||||
|
|
||||||
|
if !has_mark && !self.options.unused {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let used_arguments = self
|
let used_arguments = self
|
||||||
.data
|
.data
|
||||||
.scopes
|
.scopes
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{collections::AHashMap, Span};
|
use swc_common::Span;
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_utils::{ident::IdentLike, prop_name_eq, ExprExt, Id};
|
use swc_ecma_utils::{ident::IdentLike, prop_name_eq, ExprExt, Id};
|
||||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||||
@ -168,7 +169,7 @@ pub(crate) fn is_valid_for_lhs(e: &Expr) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct MultiReplacer {
|
pub(crate) struct MultiReplacer {
|
||||||
pub vars: AHashMap<Id, Box<Expr>>,
|
pub vars: FxHashMap<Id, Box<Expr>>,
|
||||||
pub changed: bool,
|
pub changed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,6 @@ drop_unused/issue_2105_2/input.js
|
|||||||
drop_unused/issue_2136_2/input.js
|
drop_unused/issue_2136_2/input.js
|
||||||
drop_unused/issue_2136_3/input.js
|
drop_unused/issue_2136_3/input.js
|
||||||
drop_unused/issue_2163/input.js
|
drop_unused/issue_2163/input.js
|
||||||
drop_unused/issue_2226_1/input.js
|
|
||||||
drop_unused/issue_2226_2/input.js
|
drop_unused/issue_2226_2/input.js
|
||||||
drop_unused/issue_2226_3/input.js
|
drop_unused/issue_2226_3/input.js
|
||||||
drop_unused/issue_2288/input.js
|
drop_unused/issue_2288/input.js
|
||||||
|
@ -381,6 +381,7 @@ drop_unused/issue_1656/input.js
|
|||||||
drop_unused/issue_1715_1/input.js
|
drop_unused/issue_1715_1/input.js
|
||||||
drop_unused/issue_1715_2/input.js
|
drop_unused/issue_1715_2/input.js
|
||||||
drop_unused/issue_2136_1/input.js
|
drop_unused/issue_2136_1/input.js
|
||||||
|
drop_unused/issue_2226_1/input.js
|
||||||
drop_unused/issue_2995/input.js
|
drop_unused/issue_2995/input.js
|
||||||
drop_unused/issue_3146_1/input.js
|
drop_unused/issue_3146_1/input.js
|
||||||
drop_unused/issue_3146_2/input.js
|
drop_unused/issue_3146_2/input.js
|
||||||
|
@ -6,7 +6,6 @@ function f2(a) {
|
|||||||
b;
|
b;
|
||||||
}
|
}
|
||||||
function f3(a) {
|
function f3(a) {
|
||||||
0;
|
|
||||||
}
|
}
|
||||||
function f4() {
|
function f4() {
|
||||||
var a = b;
|
var a = b;
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
//! Ensure that wrong macro definitions are caught by swc monorepo.
|
|
||||||
|
|
||||||
use swc_ecma_visit::Fold;
|
|
||||||
|
|
||||||
fn drop_console(_: ()) -> impl Fold {
|
|
||||||
DropConsole
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DropConsole;
|
|
||||||
|
|
||||||
impl Fold for DropConsole {}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(clippy::unused_unit)]
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Context, Error};
|
use anyhow::{Context, Error};
|
||||||
@ -8,7 +10,7 @@ use swc::{
|
|||||||
};
|
};
|
||||||
use swc_common::{comments::Comments, FileName, FilePathMapping, SourceMap};
|
use swc_common::{comments::Comments, FileName, FilePathMapping, SourceMap};
|
||||||
use swc_ecmascript::ast::{EsVersion, Program};
|
use swc_ecmascript::ast::{EsVersion, Program};
|
||||||
use wasm_bindgen::{prelude::*, JsCast};
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
fn convert_err(err: Error) -> JsValue {
|
fn convert_err(err: Error) -> JsValue {
|
||||||
format!("{:?}", err).into()
|
format!("{:?}", err).into()
|
||||||
@ -156,6 +158,7 @@ pub fn transform_sync(
|
|||||||
{
|
{
|
||||||
if experimental_plugin_bytes_resolver.is_object() {
|
if experimental_plugin_bytes_resolver.is_object() {
|
||||||
use js_sys::{Array, Object, Uint8Array};
|
use js_sys::{Array, Object, Uint8Array};
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
// TODO: This is probably very inefficient, including each transform
|
// TODO: This is probably very inefficient, including each transform
|
||||||
// deserializes plugin bytes.
|
// deserializes plugin bytes.
|
||||||
|
Loading…
Reference in New Issue
Block a user