Skip to content

Commit

Permalink
Correctly access shadowed class binding in super.* (babel#12544)
Browse files Browse the repository at this point in the history
* rename own binding inside methods if it collides with class ref. fix babel#11994

* fix name collisions in constructor

* do fix name collisions in constructor

* move logic in ReplaceSupers

* fix tests of helper-create-class-features-plugin

* remove replaceSupers in pushConstructor

* use environmentVisitor

* skip classLike nodes

* fix super ref in computed key
  • Loading branch information
Zzzen committed Jan 12, 2021
1 parent 4f83a09 commit cba64f9
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function extractElementDescriptor(/* this: File, */ classRef, superRef, path) {
superRef,
scope,
file: this,
refToPreserve: classRef,
},
true,
).replace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ function replaceThisContext(path, ref, superRef, file, loose) {
isLoose: loose,
superRef,
file,
refToPreserve: ref,
getObjectRef() {
state.needsClassRef = true;
return path.node.static
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class A extends B {
#foo() {
let A;
super.x;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["proposal-private-methods"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }

function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

var _foo = new WeakSet();

class A extends B {
constructor(...args) {
super(...args);

_foo.add(this);
}

}

var _foo2 = function _foo2() {
let _A;

_get(_getPrototypeOf(A.prototype), "x", this);
};
23 changes: 23 additions & 0 deletions packages/babel-helper-replace-supers/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ const visitor = traverse.visitors.merge([
},
]);

const unshadowSuperBindingVisitor = traverse.visitors.merge([
environmentVisitor,
{
Scopable(path, { refName }) {
// https://github.com/Zzzen/babel/pull/1#pullrequestreview-564833183
const binding = path.scope.getOwnBinding(refName);
if (binding && binding.identifier.name === refName) {
path.scope.rename(refName);
}
},
},
]);

const specHandlers = {
memoise(superMember, count) {
const { scope, node } = superMember;
Expand Down Expand Up @@ -244,6 +257,9 @@ type ReplaceSupersOptionsBase = {|
superRef: Object,
isLoose: boolean,
file: any,
// objectRef might have been shadowed in child scopes,
// in that case, we need to rename related variables.
refToPreserve?: BabelNodeIdentifier,
|};

type ReplaceSupersOptions =
Expand Down Expand Up @@ -286,6 +302,13 @@ export default class ReplaceSupers {
}

replace() {
// https://github.com/babel/babel/issues/11994
if (this.opts.refToPreserve) {
this.methodPath.traverse(unshadowSuperBindingVisitor, {
refName: this.opts.refToPreserve.name,
});
}

const handler = this.isLoose ? looseHandlers : specHandlers;

memberExpressionToFunctions(this.methodPath, visitor, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export default function transformClass(
superRef: classState.superName,
isLoose: classState.isLoose,
file: classState.file,
refToPreserve: classState.classRef,
});

replaceSupers.replace();
Expand Down Expand Up @@ -496,11 +497,6 @@ export default function transformClass(
method: { type: "ClassMethod" },
path: NodePath,
) {
// https://github.com/babel/babel/issues/1077
if (path.scope.hasOwnBinding(classState.classRef.name)) {
path.scope.rename(classState.classRef.name);
}

setState({
userConstructorPath: path,
userConstructor: method,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Foo extends Bar {
constructor() {
super();
class X {
[(() => {
let Foo;
super.method();
})()]() {}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
var Foo = /*#__PURE__*/function (_Bar) {
"use strict";

babelHelpers.inherits(Foo, _Bar);

var _super = babelHelpers.createSuper(Foo);

function Foo() {
var _thisSuper, _this;

babelHelpers.classCallCheck(this, Foo);
_this = _super.call(this);

var X = /*#__PURE__*/function () {
function X() {
babelHelpers.classCallCheck(this, X);
}

babelHelpers.createClass(X, [{
key: (() => {
var _Foo;

babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Foo.prototype)), "method", _thisSuper).call(_thisSuper);
})(),
value: function value() {}
}]);
return X;
}();

return _this;
}

return Foo;
}(Bar);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Base {
method() {}
}

class Foo extends Base {
constructor() {
super();

if (true) {
let Foo;
super.method();
}
}

method() { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
var Base = /*#__PURE__*/function () {
"use strict";

function Base() {
babelHelpers.classCallCheck(this, Base);
}

babelHelpers.createClass(Base, [{
key: "method",
value: function method() {}
}]);
return Base;
}();

var Foo = /*#__PURE__*/function (_Base) {
"use strict";

babelHelpers.inherits(Foo, _Base);

var _super = babelHelpers.createSuper(Foo);

function Foo() {
var _thisSuper, _this;

babelHelpers.classCallCheck(this, Foo);
_this = _super.call(this);

if (true) {
var _Foo2;

babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Foo.prototype)), "method", _thisSuper).call(_thisSuper);
}

return _this;
}

babelHelpers.createClass(Foo, [{
key: "method",
value: function method() {}
}]);
return Foo;
}(Base);
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Foo {
method(Foo) {
return super.method(Foo);
}
}

class Bar {
method() {
return () => {
let Bar;
return super.method(Bar);
};
}
}

class Baz {
method() {
class Baz {
f() {
let Baz = 1;
return Baz;
}
}

return super.method(Baz)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
var Foo = /*#__PURE__*/function () {
"use strict";

function Foo() {
babelHelpers.classCallCheck(this, Foo);
}

babelHelpers.createClass(Foo, [{
key: "method",
value: function method(_Foo) {
return babelHelpers.get(babelHelpers.getPrototypeOf(Foo.prototype), "method", this).call(this, _Foo);
}
}]);
return Foo;
}();

var Bar = /*#__PURE__*/function () {
"use strict";

function Bar() {
babelHelpers.classCallCheck(this, Bar);
}

babelHelpers.createClass(Bar, [{
key: "method",
value: function method() {
return () => {
var _Bar;

return babelHelpers.get(babelHelpers.getPrototypeOf(Bar.prototype), "method", this).call(this, _Bar);
};
}
}]);
return Bar;
}();

var Baz = /*#__PURE__*/function () {
"use strict";

function Baz() {
babelHelpers.classCallCheck(this, Baz);
}

babelHelpers.createClass(Baz, [{
key: "method",
value: function method() {
var _Baz = /*#__PURE__*/function () {
function _Baz() {
babelHelpers.classCallCheck(this, _Baz);
}

babelHelpers.createClass(_Baz, [{
key: "f",
value: function f() {
var Baz = 1;
return Baz;
}
}]);
return _Baz;
}();

return babelHelpers.get(babelHelpers.getPrototypeOf(Baz.prototype), "method", this).call(this, _Baz);
}
}]);
return Baz;
}();

0 comments on commit cba64f9

Please sign in to comment.