mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 06:36:08 +03:00
Fix optimizer (#661)
This commit is contained in:
parent
348052b017
commit
f26ef0cfb7
@ -145,10 +145,7 @@ where
|
||||
let item = if preserved.contains(&idx) {
|
||||
item
|
||||
} else {
|
||||
log::info!("Dce.should_include({})", idx);
|
||||
|
||||
if self.should_include(&item) {
|
||||
log::info!("Preserving {}", idx);
|
||||
preserved.insert(idx);
|
||||
self.changed = true;
|
||||
item = self.fold_in_marking_phase(item)
|
||||
|
@ -1,16 +1,13 @@
|
||||
use super::Dce;
|
||||
use swc_common::{Fold, FoldWith};
|
||||
use swc_common::Fold;
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::find_ids;
|
||||
|
||||
impl Fold<ImportDecl> for Dce<'_> {
|
||||
fn fold(&mut self, import: ImportDecl) -> ImportDecl {
|
||||
fn fold(&mut self, mut import: ImportDecl) -> ImportDecl {
|
||||
if self.is_marked(import.span) {
|
||||
return import;
|
||||
}
|
||||
|
||||
let mut import: ImportDecl = import.fold_children(self);
|
||||
|
||||
// Side effect import
|
||||
if import.specifiers.is_empty() {
|
||||
import.span = import.span.apply_mark(self.config.used_mark);
|
||||
@ -22,19 +19,11 @@ impl Fold<ImportDecl> for Dce<'_> {
|
||||
return import;
|
||||
}
|
||||
|
||||
// TODO: Drop unused imports.
|
||||
// e.g) import { foo, bar } from './foo';
|
||||
// foo()
|
||||
// Drop unused imports.
|
||||
import.specifiers.retain(|s| self.should_include(&s));
|
||||
|
||||
let ids: Vec<Ident> = find_ids(&import.specifiers);
|
||||
|
||||
for id in ids {
|
||||
for c in &self.included {
|
||||
if c.0 == id.sym && c.1 == id.span.ctxt() {
|
||||
import.span = import.span.apply_mark(self.config.used_mark);
|
||||
return import;
|
||||
}
|
||||
}
|
||||
if !import.specifiers.is_empty() {
|
||||
import.span = import.span.apply_mark(self.config.used_mark);
|
||||
}
|
||||
|
||||
import
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::Dce;
|
||||
use fxhash::FxHashSet;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{Visit, VisitWith};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{ident::IdentLike, ExprExt, Id};
|
||||
@ -21,6 +22,18 @@ impl Dce<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SideEffectVisitor<'_> {
|
||||
fn is_exported(&self, i: &JsWord) -> bool {
|
||||
self.exports.is_none()
|
||||
|| self
|
||||
.exports
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|exported| exported.0 == *i)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SideEffectVisitor<'a> {
|
||||
included: &'a mut FxHashSet<Id>,
|
||||
exports: Option<&'a [Id]>,
|
||||
@ -198,3 +211,44 @@ impl Visit<DoWhileStmt> for SideEffectVisitor<'_> {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ImportDecl> for SideEffectVisitor<'_> {
|
||||
fn visit(&mut self, import: &ImportDecl) {
|
||||
if self.found {
|
||||
return;
|
||||
}
|
||||
|
||||
if import.specifiers.is_empty() {
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
import.visit_children(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ExportDecl> for SideEffectVisitor<'_> {
|
||||
fn visit(&mut self, _: &ExportDecl) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ExportDefaultExpr> for SideEffectVisitor<'_> {
|
||||
fn visit(&mut self, _: &ExportDefaultExpr) {
|
||||
if self.is_exported(&js_word!("default")) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<NamedExport> for SideEffectVisitor<'_> {
|
||||
fn visit(&mut self, _: &NamedExport) {
|
||||
self.found = true
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<ExportDefaultDecl> for SideEffectVisitor<'_> {
|
||||
fn visit(&mut self, _: &ExportDefaultDecl) {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,11 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(specialization)]
|
||||
|
||||
use swc_common::chain;
|
||||
use swc_ecma_transforms::{optimization::simplify::dce::dce, resolver};
|
||||
use swc_common::{chain, SyntaxContext};
|
||||
use swc_ecma_transforms::{
|
||||
optimization::simplify::dce::{self, dce},
|
||||
resolver,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
@ -21,6 +24,26 @@ macro_rules! to {
|
||||
};
|
||||
}
|
||||
|
||||
fn used(ids: &[&str], src: &str, expected: &str) {
|
||||
test_transform!(
|
||||
Default::default(),
|
||||
|_| chain!(
|
||||
resolver(),
|
||||
dce(dce::Config {
|
||||
used: Some(
|
||||
ids.into_iter()
|
||||
.map(|&v| { (v.into(), SyntaxContext::empty()) })
|
||||
.collect()
|
||||
),
|
||||
..Default::default()
|
||||
})
|
||||
),
|
||||
src,
|
||||
expected,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! optimized_out {
|
||||
($name:ident, $src:expr) => {
|
||||
to!($name, $src, "");
|
||||
@ -104,3 +127,39 @@ console.log(c);"
|
||||
optimized_out!(simple_const, "{const x = 1}");
|
||||
|
||||
noop!(assign_op, "x *= 2; use(x)");
|
||||
|
||||
optimized_out!(import_default_unused, "import foo from 'foo'");
|
||||
|
||||
optimized_out!(import_specific_unused, "import {foo} from 'foo'");
|
||||
|
||||
optimized_out!(import_mixed_unused, "import foo, { bar } from 'foo'");
|
||||
|
||||
noop!(export_named, "export { x };");
|
||||
|
||||
noop!(export_named_from, "export {foo} from 'src';");
|
||||
|
||||
noop!(
|
||||
import_default_export_named,
|
||||
"import foo from 'src'; export { foo }; "
|
||||
);
|
||||
|
||||
to!(
|
||||
import_unused_export_named,
|
||||
"import foo, { bar } from 'src'; export { foo }; ",
|
||||
"import foo from 'src'; export { foo }; "
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn export_named_unused() {
|
||||
used(&["foo"], "export { foo, bat }", "export { foo }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_default_expr_unused() {
|
||||
used(&[], "export default 5;", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_default_expr_used() {
|
||||
used(&["default"], "export default 5;", "export default 5;");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user