From 8cec1efb935afd99056d14ecc70ae194af9fb089 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 20 Sep 2015 20:02:45 -0400 Subject: [PATCH] mark side-effects later, to avoid late declarations breaking stuff --- src/Module.js | 2 +- src/Statement.js | 37 ++++++++++++++++++----------- test/form/unused-side-effect/foo.js | 7 ++++++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/Module.js b/src/Module.js index 17810a8..01b461a 100644 --- a/src/Module.js +++ b/src/Module.js @@ -439,7 +439,7 @@ export default class Module { markAllSideEffects () { this.statements.forEach( statement => { - if ( statement.hasSideEffects ) statement.mark(); + statement.markSideEffect(); }); } diff --git a/src/Statement.js b/src/Statement.js index fad15ad..1a165b4 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -52,7 +52,6 @@ export default class Statement { this.dependantIds = []; this.namespaceReplacements = []; - this.hasSideEffects = false; this.isIncluded = false; this.isImportDeclaration = node.type === 'ImportDeclaration'; @@ -173,19 +172,6 @@ export default class Statement { if ( isFunctionDeclaration( node, parent ) ) writeDepth += 1; if ( /Function/.test( node.type ) && !isIife( node, parent ) ) readDepth += 1; - // If this is a top-level call expression, or an assignment to a global, - // this statement will need to be marked - if ( !readDepth ) { - if ( node.type === 'CallExpression' ) { - this.hasSideEffects = true; - } else if ( node.type in modifierNodes ) { - let subject = node[ modifierNodes[ node.type ] ]; - while ( subject.type === 'MemberExpression' ) subject = subject.object; - - if ( !this.module.locals.defines( subject.name ) ) this.hasSideEffects = true; - } - } - if ( node._scope ) scope = node._scope; this.checkForReads( scope, node, parent, !readDepth ); @@ -411,6 +397,29 @@ export default class Statement { }); } + markSideEffect () { + const statement = this; + + walk( this.node, { + enter ( node, parent ) { + if ( /Function/.test( node.type ) && !isIife( node, parent ) ) return this.skip(); + + // If this is a top-level call expression, or an assignment to a global, + // this statement will need to be marked + if ( node.type === 'CallExpression' ) { + statement.mark(); + } + + else if ( node.type in modifierNodes ) { + let subject = node[ modifierNodes[ node.type ] ]; + while ( subject.type === 'MemberExpression' ) subject = subject.object; + + if ( statement.module.bundle.globals.defines( subject.name ) ) statement.mark(); + } + } + }); + } + replaceIdentifiers ( magicString, names, bundleExports ) { const statement = this; diff --git a/test/form/unused-side-effect/foo.js b/test/form/unused-side-effect/foo.js index f5aa754..7953f6e 100644 --- a/test/form/unused-side-effect/foo.js +++ b/test/form/unused-side-effect/foo.js @@ -3,4 +3,11 @@ uid = 1; uid += 1; uid++; +// ensure identifiers aren't treated as globals just because +// var declaration hasn't been encountered yet... +uid2 = 1; +uid2 += 1; +uid2++; +var uid2; + export var foo = 42;