diff --git a/packages/babel-core/src/transformation/internal-plugins/shadow-functions.js b/packages/babel-core/src/transformation/internal-plugins/shadow-functions.js index 5a5681d67c..980ff3c26c 100644 --- a/packages/babel-core/src/transformation/internal-plugins/shadow-functions.js +++ b/packages/babel-core/src/transformation/internal-plugins/shadow-functions.js @@ -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); } diff --git a/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/actual.js b/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/actual.js index 3175c884d0..a657a0291f 100644 --- a/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/actual.js +++ b/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/actual.js @@ -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()); + } + } +} diff --git a/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/expected.js b/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/expected.js index 78d4cce09c..9b2880edbb 100644 --- a/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/expected.js +++ b/packages/babel-plugin-transform-es2015-arrow-functions/test/fixtures/arrow-functions/this/expected.js @@ -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()); + } + } +}