Skip to content

Commit

Permalink
Brand check the receiver of private access.get/access.set
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Feb 3, 2023
1 parent 8b7fd2b commit 584c281
Show file tree
Hide file tree
Showing 14 changed files with 42 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -35,7 +35,7 @@ export default Object.freeze({
),
applyDecs2301: helper(
"7.20.0",
'function createAddInitializerMethod(initializers,decoratorFinishedRef){return function(initializer){assertNotFinished(decoratorFinishedRef,"addInitializer"),assertCallable(initializer,"An initializer"),initializers.push(initializer)}}function memberDec(dec,name,desc,initializers,kind,isStatic,isPrivate,value,privateHas){var kindStr;switch(kind){case 1:kindStr="accessor";break;case 2:kindStr="method";break;case 3:kindStr="getter";break;case 4:kindStr="setter";break;default:kindStr="field"}var get,set,has,ctx={kind:kindStr,name:isPrivate?"#"+name:name,static:isStatic,private:isPrivate},decoratorFinishedRef={v:!1};if(0!==kind&&(ctx.addInitializer=createAddInitializerMethod(initializers,decoratorFinishedRef)),has=isPrivate?privateHas:function(receiver){return name in receiver},isPrivate||0!==kind&&2!==kind)if(2===kind)get=function(){return desc.value};else{var t=0===kind||1===kind;(t||3===kind)&&(get=function(target){return desc.get.call(target)}),(t||4===kind)&&(set=function(target,value){desc.set.call(target,value)})}else get=function(receiver){return receiver[name]},0===kind&&(set=function(receiver,v){receiver[name]=v});ctx.access=get&&set?{get:get,set:set,has:has}:get?{get:get,has:has}:{set:set,has:has};try{return dec(value,ctx)}finally{decoratorFinishedRef.v=!0}}function assertNotFinished(decoratorFinishedRef,fnName){if(decoratorFinishedRef.v)throw new Error("attempted to call "+fnName+" after decoration was finished")}function assertCallable(fn,hint){if("function"!=typeof fn)throw new TypeError(hint+" must be a function")}function assertValidReturnValue(kind,value){var type=typeof value;if(1===kind){if("object"!==type||null===value)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==value.get&&assertCallable(value.get,"accessor.get"),void 0!==value.set&&assertCallable(value.set,"accessor.set"),void 0!==value.init&&assertCallable(value.init,"accessor.init")}else if("function"!==type){var hint;throw hint=0===kind?"field":10===kind?"class":"method",new TypeError(hint+" decorators must return a function or void 0")}}function applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers){var desc,init,value,has,newValue,get,set,decs=decInfo[0];if(isPrivate?0===kind||1===kind?(desc={get:decInfo[3],set:decInfo[4]},has=decInfo[5]):(desc=3===kind?{get:decInfo[3]}:4===kind?{set:decInfo[3]}:{value:decInfo[3]},has=decInfo[4]):0!==kind&&(desc=Object.getOwnPropertyDescriptor(base,name)),1===kind?value={get:desc.get,set:desc.set}:2===kind?value=desc.value:3===kind?value=desc.get:4===kind&&(value=desc.set),"function"==typeof decs)void 0!==(newValue=memberDec(decs,name,desc,initializers,kind,isStatic,isPrivate,value,has))&&(assertValidReturnValue(kind,newValue),0===kind?init=newValue:1===kind?(init=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue);else for(var i=decs.length-1;i>=0;i--){var newInit;if(void 0!==(newValue=memberDec(decs[i],name,desc,initializers,kind,isStatic,isPrivate,value,has)))assertValidReturnValue(kind,newValue),0===kind?newInit=newValue:1===kind?(newInit=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue,void 0!==newInit&&(void 0===init?init=newInit:"function"==typeof init?init=[init,newInit]:init.push(newInit))}if(0===kind||1===kind){if(void 0===init)init=function(instance,init){return init};else if("function"!=typeof init){var ownInitializers=init;init=function(instance,init){for(var value=init,i=0;i<ownInitializers.length;i++)value=ownInitializers[i].call(instance,value);return value}}else{var originalInitializer=init;init=function(instance,init){return originalInitializer.call(instance,init)}}ret.push(init)}0!==kind&&(1===kind?(desc.get=value.get,desc.set=value.set):2===kind?desc.value=value:3===kind?desc.get=value:4===kind&&(desc.set=value),isPrivate?1===kind?(ret.push((function(instance,args){return value.get.call(instance,args)})),ret.push((function(instance,args){return value.set.call(instance,args)}))):2===kind?ret.push(value):ret.push((function(instance,args){return value.call(instance,args)})):Object.defineProperty(base,name,desc))}function applyMemberDecs(Class,decInfos){for(var protoInitializers,staticInitializers,ret=[],existingProtoNonFields=new Map,existingStaticNonFields=new Map,i=0;i<decInfos.length;i++){var decInfo=decInfos[i];if(Array.isArray(decInfo)){var base,initializers,kind=decInfo[1],name=decInfo[2],isPrivate=decInfo.length>3,isStatic=kind>=5;if(isStatic?(base=Class,0!==(kind-=5)&&(initializers=staticInitializers=staticInitializers||[])):(base=Class.prototype,0!==kind&&(initializers=protoInitializers=protoInitializers||[])),0!==kind&&!isPrivate){var existingNonFields=isStatic?existingStaticNonFields:existingProtoNonFields,existingKind=existingNonFields.get(name)||0;if(!0===existingKind||3===existingKind&&4!==kind||4===existingKind&&3!==kind)throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: "+name);!existingKind&&kind>2?existingNonFields.set(name,kind):existingNonFields.set(name,!0)}applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers)}}return pushInitializers(ret,protoInitializers),pushInitializers(ret,staticInitializers),ret}function pushInitializers(ret,initializers){initializers&&ret.push((function(instance){for(var i=0;i<initializers.length;i++)initializers[i].call(instance);return instance}))}function applyClassDecs(targetClass,classDecs){if(classDecs.length>0){for(var initializers=[],newClass=targetClass,name=targetClass.name,i=classDecs.length-1;i>=0;i--){var decoratorFinishedRef={v:!1};try{var nextNewClass=classDecs[i](newClass,{kind:"class",name:name,addInitializer:createAddInitializerMethod(initializers,decoratorFinishedRef)})}finally{decoratorFinishedRef.v=!0}void 0!==nextNewClass&&(assertValidReturnValue(10,nextNewClass),newClass=nextNewClass)}return[newClass,function(){for(var i=0;i<initializers.length;i++)initializers[i].call(newClass)}]}}export default function applyDecs2301(targetClass,memberDecs,classDecs){return{e:applyMemberDecs(targetClass,memberDecs),get c(){return applyClassDecs(targetClass,classDecs)}}}',
'function createAddInitializerMethod(initializers,decoratorFinishedRef){return function(initializer){assertNotFinished(decoratorFinishedRef,"addInitializer"),assertCallable(initializer,"An initializer"),initializers.push(initializer)}}function assertInstanceIfPrivate(has,target){if(has&&!has(target))throw new TypeError("Attempted to access private element on non-instance")}function memberDec(dec,name,desc,initializers,kind,isStatic,isPrivate,value,privateHas){var kindStr;switch(kind){case 1:kindStr="accessor";break;case 2:kindStr="method";break;case 3:kindStr="getter";break;case 4:kindStr="setter";break;default:kindStr="field"}var get,set,has,ctx={kind:kindStr,name:isPrivate?"#"+name:name,static:isStatic,private:isPrivate},decoratorFinishedRef={v:!1};if(0!==kind&&(ctx.addInitializer=createAddInitializerMethod(initializers,decoratorFinishedRef)),has=isPrivate?privateHas:function(target){return name in target},isPrivate||0!==kind&&2!==kind)if(2===kind)get=function(target){return assertInstanceIfPrivate(privateHas,target),desc.value};else{var t=0===kind||1===kind;(t||3===kind)&&(get=function(target){return assertInstanceIfPrivate(privateHas,target),desc.get.call(target)}),(t||4===kind)&&(set=function(target,value){assertInstanceIfPrivate(privateHas,target),desc.set.call(target,value)})}else get=function(target){return target[name]},0===kind&&(set=function(target,v){target[name]=v});ctx.access=get&&set?{get:get,set:set,has:has}:get?{get:get,has:has}:{set:set,has:has};try{return dec(value,ctx)}finally{decoratorFinishedRef.v=!0}}function assertNotFinished(decoratorFinishedRef,fnName){if(decoratorFinishedRef.v)throw new Error("attempted to call "+fnName+" after decoration was finished")}function assertCallable(fn,hint){if("function"!=typeof fn)throw new TypeError(hint+" must be a function")}function assertValidReturnValue(kind,value){var type=typeof value;if(1===kind){if("object"!==type||null===value)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==value.get&&assertCallable(value.get,"accessor.get"),void 0!==value.set&&assertCallable(value.set,"accessor.set"),void 0!==value.init&&assertCallable(value.init,"accessor.init")}else if("function"!==type){var hint;throw hint=0===kind?"field":10===kind?"class":"method",new TypeError(hint+" decorators must return a function or void 0")}}function applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers){var desc,init,value,has,newValue,get,set,decs=decInfo[0];if(isPrivate?0===kind||1===kind?(desc={get:decInfo[3],set:decInfo[4]},has=decInfo[5]):(desc=3===kind?{get:decInfo[3]}:4===kind?{set:decInfo[3]}:{value:decInfo[3]},has=decInfo[4]):0!==kind&&(desc=Object.getOwnPropertyDescriptor(base,name)),1===kind?value={get:desc.get,set:desc.set}:2===kind?value=desc.value:3===kind?value=desc.get:4===kind&&(value=desc.set),"function"==typeof decs)void 0!==(newValue=memberDec(decs,name,desc,initializers,kind,isStatic,isPrivate,value,has))&&(assertValidReturnValue(kind,newValue),0===kind?init=newValue:1===kind?(init=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue);else for(var i=decs.length-1;i>=0;i--){var newInit;if(void 0!==(newValue=memberDec(decs[i],name,desc,initializers,kind,isStatic,isPrivate,value,has)))assertValidReturnValue(kind,newValue),0===kind?newInit=newValue:1===kind?(newInit=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue,void 0!==newInit&&(void 0===init?init=newInit:"function"==typeof init?init=[init,newInit]:init.push(newInit))}if(0===kind||1===kind){if(void 0===init)init=function(instance,init){return init};else if("function"!=typeof init){var ownInitializers=init;init=function(instance,init){for(var value=init,i=0;i<ownInitializers.length;i++)value=ownInitializers[i].call(instance,value);return value}}else{var originalInitializer=init;init=function(instance,init){return originalInitializer.call(instance,init)}}ret.push(init)}0!==kind&&(1===kind?(desc.get=value.get,desc.set=value.set):2===kind?desc.value=value:3===kind?desc.get=value:4===kind&&(desc.set=value),isPrivate?1===kind?(ret.push((function(instance,args){return value.get.call(instance,args)})),ret.push((function(instance,args){return value.set.call(instance,args)}))):2===kind?ret.push(value):ret.push((function(instance,args){return value.call(instance,args)})):Object.defineProperty(base,name,desc))}function applyMemberDecs(Class,decInfos){for(var protoInitializers,staticInitializers,ret=[],existingProtoNonFields=new Map,existingStaticNonFields=new Map,i=0;i<decInfos.length;i++){var decInfo=decInfos[i];if(Array.isArray(decInfo)){var base,initializers,kind=decInfo[1],name=decInfo[2],isPrivate=decInfo.length>3,isStatic=kind>=5;if(isStatic?(base=Class,0!==(kind-=5)&&(initializers=staticInitializers=staticInitializers||[])):(base=Class.prototype,0!==kind&&(initializers=protoInitializers=protoInitializers||[])),0!==kind&&!isPrivate){var existingNonFields=isStatic?existingStaticNonFields:existingProtoNonFields,existingKind=existingNonFields.get(name)||0;if(!0===existingKind||3===existingKind&&4!==kind||4===existingKind&&3!==kind)throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: "+name);!existingKind&&kind>2?existingNonFields.set(name,kind):existingNonFields.set(name,!0)}applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers)}}return pushInitializers(ret,protoInitializers),pushInitializers(ret,staticInitializers),ret}function pushInitializers(ret,initializers){initializers&&ret.push((function(instance){for(var i=0;i<initializers.length;i++)initializers[i].call(instance);return instance}))}function applyClassDecs(targetClass,classDecs){if(classDecs.length>0){for(var initializers=[],newClass=targetClass,name=targetClass.name,i=classDecs.length-1;i>=0;i--){var decoratorFinishedRef={v:!1};try{var nextNewClass=classDecs[i](newClass,{kind:"class",name:name,addInitializer:createAddInitializerMethod(initializers,decoratorFinishedRef)})}finally{decoratorFinishedRef.v=!0}void 0!==nextNewClass&&(assertValidReturnValue(10,nextNewClass),newClass=nextNewClass)}return[newClass,function(){for(var i=0;i<initializers.length;i++)initializers[i].call(newClass)}]}}export default function applyDecs2301(targetClass,memberDecs,classDecs){return{e:applyMemberDecs(targetClass,memberDecs),get c(){return applyClassDecs(targetClass,classDecs)}}}',
),
asyncGeneratorDelegate: helper(
"7.0.0-beta.0",
Expand Down
24 changes: 16 additions & 8 deletions packages/babel-helpers/src/helpers/applyDecs2301.js
Expand Up @@ -26,6 +26,12 @@ function createAddInitializerMethod(initializers, decoratorFinishedRef) {
};
}

function assertInstanceIfPrivate(has, target) {
if (has && !has(target)) {
throw new TypeError("Attempted to access private element on non-instance");
}
}

function memberDec(
dec,
name,
Expand Down Expand Up @@ -75,35 +81,37 @@ function memberDec(
var get, set, has;
if (isPrivate) has = privateHas;
else {
has = function (receiver) {
return name in receiver;
has = function (target) {
return name in target;
};
}
if (!isPrivate && (kind === 0 /* FIELD */ || kind === 2) /* METHOD */) {
get = function (receiver) {
return receiver[name];
get = function (target) {
return target[name];
};
if (kind === 0 /* FIELD */) {
set = function (receiver, v) {
receiver[name] = v;
set = function (target, v) {
target[name] = v;
};
}
} else if (kind === 2 /* METHOD */) {
// Assert: isPrivate is true.
get = function () {
// TODO: Throw if !Has(receiver, name).
get = function (target) {
assertInstanceIfPrivate(privateHas, target);
return desc.value;
};
} else {
// Assert: If kind === 0, then isPrivate is true.
var t = kind === 0 /* FIELD */ || kind === 1; /* ACCESSOR */
if (t || kind === 3 /* GETTER */) {
get = function (target) {
assertInstanceIfPrivate(privateHas, target);
return desc.get.call(target);
};
}
if (t || kind === 4 /* SETTER */) {
set = function (target, value) {
assertInstanceIfPrivate(privateHas, target);
desc.set.call(target, value);
};
}
Expand Down
Expand Up @@ -36,8 +36,10 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(foo))).toBe(false);

expect(aContext.access.get(foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
aContext.access.set(foo, 123);
expect(aContext.access.get(foo)).toBe(125);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(aContext.name).toBe('#a');
expect(aContext.kind).toBe('accessor');
expect(aContext.static).toBe(false);
Expand Down
Expand Up @@ -34,8 +34,11 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(Foo))).toBe(false);

expect(aContext.access.get(Foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
aContext.access.set(Foo, 123);
expect(aContext.access.get(Foo)).toBe(125);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(aContext.access.get(Foo)).toBe(125);
expect(aContext.name).toBe('#a');
expect(aContext.kind).toBe('accessor');
expect(aContext.static).toBe(true);
Expand Down
Expand Up @@ -23,8 +23,11 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(foo))).toBe(false);

expect(aContext.access.get(foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
aContext.access.set(foo, 123);
expect(aContext.access.get(foo)).toBe(123);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(aContext.access.get(foo)).toBe(123);
expect(aContext.name).toBe('#a');
expect(aContext.kind).toBe('field');
expect(aContext.static).toBe(false);
Expand Down
Expand Up @@ -21,8 +21,11 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(Foo))).toBe(false);

expect(aContext.access.get(Foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
aContext.access.set(Foo, 123);
expect(aContext.access.get(Foo)).toBe(123);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(aContext.access.get(Foo)).toBe(123);
expect(aContext.name).toBe('#a');
expect(aContext.kind).toBe('field');
expect(aContext.static).toBe(true);
Expand Down
Expand Up @@ -30,6 +30,7 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(foo))).toBe(false);

expect(aContext.access.get(foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
expect(foo.getA()).toBe(2);
foo.value = 123;
expect(aContext.access.get(foo)).toBe(124);
Expand Down
Expand Up @@ -28,6 +28,7 @@ expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(Foo))).toBe(false);

expect(aContext.access.get(Foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
expect(Foo.getA()).toBe(2);
Foo.value = 123;
expect(aContext.access.get(Foo)).toBe(124);
Expand Down
Expand Up @@ -50,9 +50,12 @@ expect(a_setterContext.access.has(Object.create(foo))).toBe(false);
expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has);

expect(a_getterContext.access.get(foo)).toBe(2);
expect(() => a_getterContext.access.get({})).toThrow(TypeError);
expect(foo.getA()).toBe(2);
a_setterContext.access.set(foo, 123);
expect(a_getterContext.access.get(foo)).toBe(125);
expect(() => a_setterContext.access.set({}, 456)).toThrow(TypeError);
expect(a_getterContext.access.get(foo)).toBe(125);
expect(foo.getA()).toBe(125);
foo.setA(456);
expect(a_getterContext.access.get(foo)).toBe(458);
Expand Down
Expand Up @@ -48,9 +48,12 @@ expect(a_setterContext.access.has(Object.create(Foo))).toBe(false);
expect(a_getterContext.access.has).not.toBe(a_setterContext.access.has);

expect(a_getterContext.access.get(Foo)).toBe(2);
expect(() => a_getterContext.access.get({})).toThrow(TypeError);
expect(Foo.getA()).toBe(2);
a_setterContext.access.set(Foo, 123);
expect(a_getterContext.access.get(Foo)).toBe(125);
expect(() => a_setterContext.access.set({}, 456)).toThrow(TypeError);
expect(a_getterContext.access.get(Foo)).toBe(125);
expect(Foo.getA()).toBe(125);
Foo.setA(456);
expect(a_getterContext.access.get(Foo)).toBe(458);
Expand Down
Expand Up @@ -31,6 +31,7 @@ expect(aContext.access.has(Object.create(foo))).toBe(false);

// First call gets the method, second call calls the method with correct `this`
expect(aContext.access.get(foo).call(foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
expect(foo.callA()).toBe(2);
foo.value = 123;
expect(aContext.access.get(foo).call(foo)).toBe(124);
Expand Down
Expand Up @@ -29,6 +29,7 @@ expect(aContext.access.has(Object.create(Foo))).toBe(false);

// First call gets the method, second call calls the method with correct `this`
expect(aContext.access.get(Foo).call(Foo)).toBe(2);
expect(() => aContext.access.get({})).toThrow(TypeError);
expect(Foo.callA()).toBe(2);
Foo.value = 123;
expect(aContext.access.get(Foo).call(Foo)).toBe(124);
Expand Down
Expand Up @@ -32,6 +32,8 @@ expect(aContext.access.has(Object.create(foo))).toBe(false);
expect(foo.value).toBe(1);
aContext.access.set(foo, 123);
expect(foo.value).toBe(124);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(foo.value).toBe(124);
foo.setA(456);
expect(foo.value).toBe(457);

Expand Down
Expand Up @@ -30,6 +30,8 @@ expect(aContext.access.has(Object.create(Foo))).toBe(false);
expect(Foo.value).toBe(1);
aContext.access.set(Foo, 123);
expect(Foo.value).toBe(124);
expect(() => aContext.access.set({}, 456)).toThrow(TypeError);
expect(Foo.value).toBe(124);
Foo.setA(456);
expect(Foo.value).toBe(457);

Expand Down

0 comments on commit 584c281

Please sign in to comment.