Correctly access shadowed class binding in super.* (#12544)
* rename own binding inside methods if it collides with class ref. fix #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
This commit is contained in:
parent
4f83a09dd8
commit
cba64f9a09
@ -68,6 +68,7 @@ function extractElementDescriptor(/* this: File, */ classRef, superRef, path) {
|
||||
superRef,
|
||||
scope,
|
||||
file: this,
|
||||
refToPreserve: classRef,
|
||||
},
|
||||
true,
|
||||
).replace();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
class A extends B {
|
||||
#foo() {
|
||||
let A;
|
||||
super.x;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["proposal-private-methods"]
|
||||
}
|
||||
22
packages/babel-helper-create-class-features-plugin/test/fixtures/replace-supers/method/output.js
vendored
Normal file
22
packages/babel-helper-create-class-features-plugin/test/fixtures/replace-supers/method/output.js
vendored
Normal file
@ -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);
|
||||
};
|
||||
@ -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;
|
||||
@ -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 =
|
||||
@ -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, {
|
||||
|
||||
@ -174,6 +174,7 @@ export default function transformClass(
|
||||
superRef: classState.superName,
|
||||
isLoose: classState.isLoose,
|
||||
file: classState.file,
|
||||
refToPreserve: classState.classRef,
|
||||
});
|
||||
|
||||
replaceSupers.replace();
|
||||
@ -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,
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
class Foo extends Bar {
|
||||
constructor() {
|
||||
super();
|
||||
class X {
|
||||
[(() => {
|
||||
let Foo;
|
||||
super.method();
|
||||
})()]() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
@ -0,0 +1,16 @@
|
||||
class Base {
|
||||
method() {}
|
||||
}
|
||||
|
||||
class Foo extends Base {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (true) {
|
||||
let Foo;
|
||||
super.method();
|
||||
}
|
||||
}
|
||||
|
||||
method() { }
|
||||
}
|
||||
@ -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);
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}();
|
||||
Loading…
x
Reference in New Issue
Block a user