Skip to content

Commit

Permalink
Fix super Method Calls in Class Private Methods (#9704)
Browse files Browse the repository at this point in the history
This fixes an issue with the use of super method calls in class private methods. See #9580 for more info re: behavior of the bug.
  • Loading branch information
tim-mc authored and nicolo-ribaudo committed Mar 19, 2019
1 parent 48d66eb commit e068281
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,9 @@ function replaceThisContext(path, ref, superRef, file, loose) {
file,
getObjectRef() {
state.needsClassRef = true;
return ref;
return path.node.static ? ref : t.thisExpression();
},
});
replacer.isStatic = true;
replacer.replace();
if (path.isProperty()) {
path.traverse(thisContextVisitor, state);
Expand Down Expand Up @@ -532,7 +531,7 @@ export function buildFieldsInitNodes(
const isField = prop.isProperty();
const isMethod = !isField;

if (isStatic) {
if (isStatic || (isMethod && isPrivate)) {
const replaced = replaceThisContext(prop, ref, superRef, state, loose);
needsClassRef = needsClassRef || replaced;
}
Expand Down
28 changes: 20 additions & 8 deletions packages/babel-helper-replace-supers/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import * as t from "@babel/types";
*
* helpers.getPrototypeOf(CLASS.prototype)
*/
function getPrototypeOfExpression(objectRef, isStatic, file) {
function getPrototypeOfExpression(objectRef, isStatic, file, isPrivateMethod) {
objectRef = t.cloneNode(objectRef);
const targetRef = isStatic
? objectRef
: t.memberExpression(objectRef, t.identifier("prototype"));
const targetRef =
isStatic || isPrivateMethod
? objectRef
: t.memberExpression(objectRef, t.identifier("prototype"));

return t.callExpression(file.addHelper("getPrototypeOf"), [targetRef]);
}
Expand Down Expand Up @@ -98,15 +99,25 @@ const specHandlers = {

get(superMember) {
return t.callExpression(this.file.addHelper("get"), [
getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file),
getPrototypeOfExpression(
this.getObjectRef(),
this.isStatic,
this.file,
this.isPrivateMethod,
),
this.prop(superMember),
t.thisExpression(),
]);
},

set(superMember, value) {
return t.callExpression(this.file.addHelper("set"), [
getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file),
getPrototypeOfExpression(
this.getObjectRef(),
this.isStatic,
this.file,
this.isPrivateMethod,
),
this.prop(superMember),
value,
t.thisExpression(),
Expand Down Expand Up @@ -170,8 +181,8 @@ export default class ReplaceSupers {
const path = opts.methodPath;

this.methodPath = path;
this.isStatic =
path.isClassMethod({ static: true }) || path.isObjectMethod();
this.isStatic = path.isObjectMethod() || path.node.static;
this.isPrivateMethod = path.isPrivate() && path.isMethod();

this.file = opts.file;
this.superRef = opts.superRef;
Expand Down Expand Up @@ -202,6 +213,7 @@ export default class ReplaceSupers {
memberExpressionToFunctions(this.methodPath, visitor, {
file: this.file,
isStatic: this.isStatic,
isPrivateMethod: this.isPrivateMethod,
getObjectRef: this.getObjectRef.bind(this),
superRef: this.superRef,
...handler,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Base {
superMethod() {
return 1017;
}
}

class Sub extends Base {
#privateMethod() {
return super.superMethod();
}

publicMethod() {
return this.#privateMethod();
}
}

expect((new Sub()).publicMethod()).toEqual(1017);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Base {
superMethod() {
return 1017;
}
}

class Sub extends Base {
#privateMethod() {
return super.superMethod();
}

publicMethod() {
return this.#privateMethod();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Base {
superMethod() {
return 1017;
}

}

class Sub extends Base {
constructor(...args) {
super(...args);
Object.defineProperty(this, _privateMethod, {
value: _privateMethod2
});
}

publicMethod() {
return babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod]();
}

}

var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod");

var _privateMethod2 = function _privateMethod2() {
return Base.prototype.superMethod.call(this);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class Base {
superMethod() {
return 1017;
}
}

class Sub extends Base {
#privateMethod() {
return super.superMethod();
}

publicMethod() {
return this.#privateMethod();
}
}

expect((new Sub()).publicMethod()).toEqual(1017);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Base {
superMethod() {
return 1017;
}
}

class Sub extends Base {
#privateMethod() {
return super.superMethod();
}

publicMethod() {
return this.#privateMethod();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Base {
superMethod() {
return 1017;
}

}

class Sub extends Base {
constructor(...args) {
super(...args);

_privateMethod.add(this);
}

publicMethod() {
return babelHelpers.classPrivateMethodGet(this, _privateMethod, _privateMethod2).call(this);
}

}

var _privateMethod = new WeakSet();

var _privateMethod2 = function _privateMethod2() {
return babelHelpers.get(babelHelpers.getPrototypeOf(this), "superMethod", this).call(this);
};

0 comments on commit e068281

Please sign in to comment.