mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 14:16:12 +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;
|
||||
var _iteratorNormalCompletion1 = !0, _didIteratorError1 = !1, _iteratorError1 = void 0;
|
||||
try {
|
||||
for(var _step1, _iterator1 = [][Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0){
|
||||
var v = _step1.value;
|
||||
v++;
|
||||
}
|
||||
for(var _step1, _iterator1 = [][Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = !0)_step1.value;
|
||||
} catch (err) {
|
||||
_didIteratorError1 = !0, _iteratorError1 = err;
|
||||
} 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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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";
|
||||
Promise.all(assignAll).then(function() {
|
||||
var b = a.asyncToGenerator(function*(e) {
|
||||
let b = 'DELETE FROM "TABLE" WHERE "UUID" IN ( ';
|
||||
for(let c in obj){
|
||||
let a = obj[c];
|
||||
b += `'${a.id}', `;
|
||||
let d = yield listOfUser(a.id);
|
||||
d.forEach((b)=>{
|
||||
var b = a.asyncToGenerator(function*(c) {
|
||||
for(let b in obj){
|
||||
let a = obj[b];
|
||||
`'${a.id}', `, (yield listOfUser(a.id)).forEach((b)=>{
|
||||
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);
|
||||
};
|
||||
}());
|
||||
|
@ -76,6 +76,9 @@ pub(crate) struct VarUsageInfo {
|
||||
|
||||
pub assign_count: usize,
|
||||
pub mutation_by_call_count: usize,
|
||||
/// ## Things to note
|
||||
///
|
||||
/// - Update is counted as usage
|
||||
pub usage_count: usize,
|
||||
|
||||
/// The variable itself is modified.
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::{collections::HashMap, mem::swap};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
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_utils::{contains_arguments, ident::IdentLike, undefined, ExprFactory, Id};
|
||||
use swc_ecma_visit::VisitMutWith;
|
||||
@ -246,8 +247,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "debug", tracing::instrument(skip(self, n, vars)))]
|
||||
pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, vars: AHashMap<Id, Box<Expr>>)
|
||||
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||
pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, vars: FxHashMap<Id, Box<Expr>>)
|
||||
where
|
||||
N: VisitMutWith<MultiReplacer>,
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ struct Optimizer<'a, M> {
|
||||
/// Used for inlining.
|
||||
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>>,
|
||||
/// Used for `hoist_props`.
|
||||
@ -703,6 +703,10 @@ where
|
||||
|
||||
self.compress_cond_to_logical_ignoring_return_value(e);
|
||||
|
||||
self.drop_unused_update(e);
|
||||
|
||||
self.drop_unused_op_assign(e);
|
||||
|
||||
match e {
|
||||
Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
|
||||
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))]
|
||||
pub(super) fn drop_unused_assignments(&mut self, e: &mut Expr) {
|
||||
let assign = match e {
|
||||
Expr::Assign(e) => e,
|
||||
pub(super) fn drop_unused_update(&mut self, e: &mut Expr) {
|
||||
if !self.options.unused {
|
||||
return;
|
||||
}
|
||||
|
||||
let update = match e {
|
||||
Expr::Update(u) => u,
|
||||
_ => 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;
|
||||
}
|
||||
|
||||
@ -529,6 +552,58 @@ where
|
||||
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
|
||||
.data
|
||||
.scopes
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{collections::AHashMap, Span};
|
||||
use swc_common::Span;
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{ident::IdentLike, prop_name_eq, ExprExt, Id};
|
||||
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 vars: AHashMap<Id, Box<Expr>>,
|
||||
pub vars: FxHashMap<Id, Box<Expr>>,
|
||||
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_3/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_3/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_2/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_3146_1/input.js
|
||||
drop_unused/issue_3146_2/input.js
|
||||
|
@ -6,7 +6,6 @@ function f2(a) {
|
||||
b;
|
||||
}
|
||||
function f3(a) {
|
||||
0;
|
||||
}
|
||||
function f4() {
|
||||
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 anyhow::{Context, Error};
|
||||
@ -8,7 +10,7 @@ use swc::{
|
||||
};
|
||||
use swc_common::{comments::Comments, FileName, FilePathMapping, SourceMap};
|
||||
use swc_ecmascript::ast::{EsVersion, Program};
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
fn convert_err(err: Error) -> JsValue {
|
||||
format!("{:?}", err).into()
|
||||
@ -156,6 +158,7 @@ pub fn transform_sync(
|
||||
{
|
||||
if experimental_plugin_bytes_resolver.is_object() {
|
||||
use js_sys::{Array, Object, Uint8Array};
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
// TODO: This is probably very inefficient, including each transform
|
||||
// deserializes plugin bytes.
|
||||
|
Loading…
Reference in New Issue
Block a user