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,
|
superRef,
|
||||||
scope,
|
scope,
|
||||||
file: this,
|
file: this,
|
||||||
|
refToPreserve: classRef,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
).replace();
|
).replace();
|
||||||
|
|||||||
@ -633,6 +633,7 @@ function replaceThisContext(path, ref, superRef, file, loose) {
|
|||||||
isLoose: loose,
|
isLoose: loose,
|
||||||
superRef,
|
superRef,
|
||||||
file,
|
file,
|
||||||
|
refToPreserve: ref,
|
||||||
getObjectRef() {
|
getObjectRef() {
|
||||||
state.needsClassRef = true;
|
state.needsClassRef = true;
|
||||||
return path.node.static
|
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 = {
|
const specHandlers = {
|
||||||
memoise(superMember, count) {
|
memoise(superMember, count) {
|
||||||
const { scope, node } = superMember;
|
const { scope, node } = superMember;
|
||||||
@ -244,6 +257,9 @@ type ReplaceSupersOptionsBase = {|
|
|||||||
superRef: Object,
|
superRef: Object,
|
||||||
isLoose: boolean,
|
isLoose: boolean,
|
||||||
file: any,
|
file: any,
|
||||||
|
// objectRef might have been shadowed in child scopes,
|
||||||
|
// in that case, we need to rename related variables.
|
||||||
|
refToPreserve?: BabelNodeIdentifier,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
type ReplaceSupersOptions =
|
type ReplaceSupersOptions =
|
||||||
@ -286,6 +302,13 @@ export default class ReplaceSupers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
replace() {
|
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;
|
const handler = this.isLoose ? looseHandlers : specHandlers;
|
||||||
|
|
||||||
memberExpressionToFunctions(this.methodPath, visitor, {
|
memberExpressionToFunctions(this.methodPath, visitor, {
|
||||||
|
|||||||
@ -174,6 +174,7 @@ export default function transformClass(
|
|||||||
superRef: classState.superName,
|
superRef: classState.superName,
|
||||||
isLoose: classState.isLoose,
|
isLoose: classState.isLoose,
|
||||||
file: classState.file,
|
file: classState.file,
|
||||||
|
refToPreserve: classState.classRef,
|
||||||
});
|
});
|
||||||
|
|
||||||
replaceSupers.replace();
|
replaceSupers.replace();
|
||||||
@ -496,11 +497,6 @@ export default function transformClass(
|
|||||||
method: { type: "ClassMethod" },
|
method: { type: "ClassMethod" },
|
||||||
path: NodePath,
|
path: NodePath,
|
||||||
) {
|
) {
|
||||||
// https://github.com/babel/babel/issues/1077
|
|
||||||
if (path.scope.hasOwnBinding(classState.classRef.name)) {
|
|
||||||
path.scope.rename(classState.classRef.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
userConstructorPath: path,
|
userConstructorPath: path,
|
||||||
userConstructor: method,
|
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