Inserting shadowed 'this' bindings in constructors after super - fixes T7191

This commit is contained in:
Logan Smyth 2016-03-12 16:15:26 -08:00
parent 5373733b8d
commit e3af434250
3 changed files with 57 additions and 5 deletions

View File

@ -1,15 +1,29 @@
import Plugin from "../plugin";
import * as t from "babel-types";
const SUPER_THIS_BOUND = Symbol("super this bound");
const superVisitor = {
CallExpression(path){
if (!path.get("callee").isSuper()) return;
const {node} = path;
if (node[SUPER_THIS_BOUND]) return;
node[SUPER_THIS_BOUND] = true;
path.replaceWith(t.assignmentExpression("=", this.id, node));
}
};
export default new Plugin({
visitor: {
ThisExpression(path) {
remap(path, "this", () => t.thisExpression());
remap(path, "this");
},
ReferencedIdentifier(path) {
if (path.node.name === "arguments") {
remap(path, "arguments", () => t.identifier("arguments"));
remap(path, "arguments");
}
}
}
@ -23,7 +37,7 @@ function shouldShadow(path, shadowPath) {
}
}
function remap(path, key, create) {
function remap(path, key) {
// ensure that we're shadowed
let shadowPath = path.inShadow(key);
if (!shouldShadow(path, shadowPath)) return;
@ -74,11 +88,19 @@ function remap(path, key, create) {
let cached = fnPath.getData(key);
if (cached) return path.replaceWith(cached);
let init = create();
let id = path.scope.generateUidIdentifier(key);
fnPath.setData(key, id);
fnPath.scope.push({ id, init });
if (key === "this" && fnPath.isMethod({kind: "constructor"})){
fnPath.scope.push({ id });
fnPath.traverse(superVisitor, { id });
} else {
const init = key === "this" ? t.thisExpression() : t.identifier(key);
fnPath.scope.push({ id, init });
}
return path.replaceWith(id);
}

View File

@ -1,3 +1,16 @@
function b() {
var t = x => this.x + x;
}
class Foo extends (function(){}) {
constructor(){
var foo = () => this;
if (true){
console.log(super(), foo());
} else {
super();
console.log(foo());
}
}
}

View File

@ -5,3 +5,20 @@ function b() {
return _this.x + x;
};
}
class Foo extends function () {} {
constructor() {
var _this2;
var foo = function () {
return _this2;
};
if (true) {
console.log(_this2 = super(), foo());
} else {
_this2 = super();
console.log(foo());
}
}
}