handle "static" contexts in es7.functionBind - #1518

This commit is contained in:
Sebastian McKenzie
2015-05-14 16:37:44 +01:00
parent 7407b37bd9
commit 724bf52929
4 changed files with 48 additions and 7 deletions

View File

@@ -10,11 +10,23 @@ export var metadata = {
function getTempId(scope) {
var id = scope.path.getData("functionBind");
if (id) return id;
id = scope.generateTemp("context");
return scope.path.setData("functionBind", id);
}
function getStaticContext(bind, scope) {
if (bind.object) {
return scope.isStatic(bind.object) && bind.object;
} else {
return scope.isStatic(bind.callee.object) && bind.callee.object;
}
}
function inferBindContext(bind, scope) {
var staticContext = getStaticContext(bind, scope);
if (staticContext) return staticContext;
var tempId = getTempId(scope);
if (bind.object) {
bind.callee = t.sequenceExpression([
@@ -30,6 +42,7 @@ function inferBindContext(bind, scope) {
export function CallExpression(node, parent, scope, file) {
var bind = node.callee;
if (!t.isBindExpression(bind)) return;
var context = inferBindContext(bind, scope);
node.callee = t.memberExpression(bind.callee, t.identifier("call"));
node.arguments.unshift(context);

View File

@@ -263,18 +263,34 @@ export default class Scope {
return this.generateUidIdentifier(id);
}
/**
* Determine whether evaluating the specific input `node` is a consequenceless reference. ie.
* evaluating it wont result in potentially arbitrary code from being ran. The following are
* whitelisted and determined not cause side effects:
*
* - `this` expressions
* - `super` expressions
* - Bound identifiers
*/
isStatic(node: Object): boolean {
if (t.isThisExpression(node) || t.isSuper(node)) {
return true;
}
if (t.isIdentifier(node) && this.hasBinding(node.name)) {
return true;
}
return false;
}
/**
* Description
*/
generateMemoisedReference(node: Object, dontPush?: boolean): ?Object {
if (t.isThisExpression(node) || t.isSuper(node)) {
return null;
}
if (t.isIdentifier(node) && this.hasBinding(node.name)) {
return null;
}
if (this.isStatic(node)) return null;
var id = this.generateUidBasedOnNode(node);
if (!dontPush) this.push({ id });