Browse Source

attach scopes to BlockStatement nodes, not Function nodes. fixes #91

contingency-plan
Rich-Harris 9 years ago
parent
commit
481d28412c
  1. 43
      src/Statement.js
  2. 4
      test/function/functions-renamed-correctly/_config.js
  3. 2
      test/function/functions-renamed-correctly/after.js
  4. 2
      test/function/functions-renamed-correctly/before.js
  5. 2
      test/function/functions-renamed-correctly/main.js

43
src/Statement.js

@ -49,29 +49,23 @@ export default class Statement {
let newScope; let newScope;
switch ( node.type ) { switch ( node.type ) {
case 'FunctionExpression':
case 'FunctionDeclaration': case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
if ( node.type === 'FunctionDeclaration' ) {
scope.addDeclaration( node.id.name, node, false ); scope.addDeclaration( node.id.name, node, false );
}
case 'BlockStatement':
if ( parent && /Function/.test( parent.type ) ) {
newScope = new Scope({ newScope = new Scope({
parent: scope, parent: scope,
params: node.params, // TODO rest params? block: false,
block: false params: parent.params
}); });
// named function expressions - the name is considered // named function expressions - the name is considered
// part of the function's scope // part of the function's scope
if ( node.type === 'FunctionExpression' && node.id ) { if ( parent.type === 'FunctionExpression' && parent.id ) {
newScope.addDeclaration( node.id.name, node, false ); newScope.addDeclaration( parent.id.name, parent, false );
} }
} else {
break;
case 'BlockStatement':
if ( !/Function/.test( parent.type ) ) {
newScope = new Scope({ newScope = new Scope({
parent: scope, parent: scope,
block: true block: true
@ -136,27 +130,19 @@ export default class Statement {
if ( !this.isImportDeclaration ) { if ( !this.isImportDeclaration ) {
walk( this.node, { walk( this.node, {
enter: ( node, parent ) => { enter: ( node, parent ) => {
if ( node._scope ) {
if ( !scope.isBlockScope ) {
if ( !isIife( node, parent ) ) readDepth += 1;
if ( isFunctionDeclaration( node, parent ) ) writeDepth += 1; if ( isFunctionDeclaration( node, parent ) ) writeDepth += 1;
} if ( /Function/.test( node.type ) && !isIife( node, parent ) ) readDepth += 1;
scope = node._scope; if ( node._scope ) scope = node._scope;
}
this.checkForReads( scope, node, parent, !readDepth ); this.checkForReads( scope, node, parent, !readDepth );
this.checkForWrites( scope, node, writeDepth ); this.checkForWrites( scope, node, writeDepth );
}, },
leave: ( node, parent ) => { leave: ( node, parent ) => {
if ( node._scope ) {
if ( !scope.isBlockScope ) {
if ( !isIife( node, parent ) ) readDepth -= 1;
if ( isFunctionDeclaration( node, parent ) ) writeDepth -= 1; if ( isFunctionDeclaration( node, parent ) ) writeDepth -= 1;
} if ( /Function/.test( node.type ) && !isIife( node, parent ) ) readDepth -= 1;
scope = scope.parent; if ( node._scope ) scope = scope.parent;
}
} }
}); });
} }
@ -364,11 +350,6 @@ export default class Statement {
let newNames = blank(); let newNames = blank();
let hasReplacements; let hasReplacements;
// special case = function foo ( foo ) {...}
if ( node.id && names[ node.id.name ] && scope.declarations[ node.id.name ] ) {
magicString.overwrite( node.id.start, node.id.end, names[ node.id.name ] );
}
keys( names ).forEach( name => { keys( names ).forEach( name => {
if ( !scope.declarations[ name ] ) { if ( !scope.declarations[ name ] ) {
newNames[ name ] = names[ name ]; newNames[ name ] = names[ name ];
@ -409,6 +390,8 @@ export default class Statement {
if ( parent.type === 'MemberExpression' && !parent.computed && node !== parent.object ) return; if ( parent.type === 'MemberExpression' && !parent.computed && node !== parent.object ) return;
if ( parent.type === 'Property' && node !== parent.value ) return; if ( parent.type === 'Property' && node !== parent.value ) return;
if ( parent.type === 'MethodDefinition' && node === parent.key ) return; if ( parent.type === 'MethodDefinition' && node === parent.key ) return;
if ( parent.type === 'FunctionExpression' ) return;
if ( /Function/.test( parent.type ) && ~parent.params.indexOf( node ) ) return;
// TODO others...? // TODO others...?
// all other identifiers should be overwritten // all other identifiers should be overwritten

4
test/function/functions-renamed-correctly/_config.js

@ -1,5 +1,3 @@
module.exports = { module.exports = {
description: 'renames function expression IDs correctly', description: 'renames function expression IDs correctly'
show: true,
solo: true
}; };

2
test/function/functions-renamed-correctly/after.js

@ -1,5 +1,5 @@
function x () { function x () {
console.log( 'after' ); return 'after';
} }
export { x as after }; export { x as after };

2
test/function/functions-renamed-correctly/before.js

@ -1,5 +1,5 @@
function x () { function x () {
console.log( 'before' ); return 'before';
} }
export { x as before }; export { x as before };

2
test/function/functions-renamed-correctly/main.js

@ -2,6 +2,6 @@ import { before } from './before';
import { x } from './factorial'; import { x } from './factorial';
import { after } from './after'; import { after } from './after';
before(); before(); // before and after ensure x is renamed
assert.equal( x( 5 ), 120 ); assert.equal( x( 5 ), 120 );
after(); after();

Loading…
Cancel
Save