Skip to content

Commit

Permalink
fix(kernel): Set this in static contexts (#460)
Browse files Browse the repository at this point in the history
Javascript allows static members to refer to other static members
through `this`, but the `jsii-kernel` passed `null` for the `this`
context in `sinvoke`, making it impossible to invoke static methods that
made use of this feature through the `jsii` runtimes.

Fixes aws/aws-cdk#2304
  • Loading branch information
RomainMuller authored Apr 16, 2019
1 parent a5e8a93 commit c81b4c1
Show file tree
Hide file tree
Showing 15 changed files with 277 additions and 6 deletions.
29 changes: 28 additions & 1 deletion packages/jsii-calc/lib/compliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1635,4 +1635,31 @@ export interface OptionalStruct {
* @stable
*/
export class ClassWithDocs {
}
}

/**
* This is used to validate the ability to use `this` from within a static context.
*
* https://github.com/awslabs/aws-cdk/issues/2304
*/
export class StaticContext {
private static _staticVariable = true;

public static canAccessStaticContext(): boolean {
return this.staticContextAvailable();
}

private static staticContextAvailable() {
return true;
}

public static get staticVariable() {
return this._staticVariable;
}

public static set staticVariable(value: boolean) {
this._staticVariable = value;
}

private constructor() { }
}
44 changes: 43 additions & 1 deletion packages/jsii-calc/test/assembly.jsii
Original file line number Diff line number Diff line change
Expand Up @@ -5597,6 +5597,48 @@
],
"name": "SingleInstanceTwoTypes"
},
"jsii-calc.StaticContext": {
"assembly": "jsii-calc",
"docs": {
"remarks": "https://github.com/awslabs/aws-cdk/issues/2304",
"summary": "This is used to validate the ability to use `this` from within a static context."
},
"fqn": "jsii-calc.StaticContext",
"kind": "class",
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1645
},
"methods": [
{
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1648
},
"name": "canAccessStaticContext",
"returns": {
"type": {
"primitive": "boolean"
}
},
"static": true
}
],
"name": "StaticContext",
"properties": [
{
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1656
},
"name": "staticVariable",
"static": true,
"type": {
"primitive": "boolean"
}
}
]
},
"jsii-calc.Statics": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.Statics",
Expand Down Expand Up @@ -6655,5 +6697,5 @@
}
},
"version": "0.9.0",
"fingerprint": "rheLw7bhMAmuMfbnzQ4tXZyQTSYIydCp59wiBfA8Gpo="
"fingerprint": "7Kv5qQOHJ4CtCTKoLfaavS4jHjk/HJvT6aWOIZAHTvw="
}
4 changes: 2 additions & 2 deletions packages/jsii-kernel/lib/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,10 @@ export class Kernel {
}

const prototype = this._findSymbol(fqn);
const fn = prototype[method];
const fn = prototype[method] as (...params: any[]) => any;

const ret = this._ensureSync(`method '${fqn}.${method}'`, () => {
return this._wrapSandboxCode(() => fn.apply(null, this._toSandboxValues(args, ti.parameters)));
return this._wrapSandboxCode(() => fn.apply(prototype, this._toSandboxValues(args, ti.parameters)));
});

this._debug('method returned:', ret);
Expand Down
25 changes: 25 additions & 0 deletions packages/jsii-kernel/test/test.kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,31 @@ defineTest('ObjRefs are labeled with the "most correct" type', async (test, sand
}
});

/**
* This is used to validate the ability to use `this` from within a static context.
*
* https://github.com/awslabs/aws-cdk/issues/2304
*/
defineTest('sinvoke allows access to the static context', async (test, sandbox) => {
test.doesNotThrow(() => {
const response = sandbox.sinvoke({ fqn: 'jsii-calc.StaticContext', method: 'canAccessStaticContext' });
test.ok(response.result, 'The result should be true');
});
});
defineTest('sget allows access to the static context', async (test, sandbox) => {
test.doesNotThrow(() => {
const response = sandbox.sget({ fqn: 'jsii-calc.StaticContext', property: 'staticVariable' });
test.ok(response.value, 'The result should be true');
});
});
defineTest('sset allows access to the static context', async (test, sandbox) => {
test.doesNotThrow(() => {
sandbox.sset({ fqn: 'jsii-calc.StaticContext', property: 'staticVariable', value: false });
const response = sandbox.sget({ fqn: 'jsii-calc.StaticContext', property: 'staticVariable' });
test.ok(!response.value, 'The result should be true');
});
});

/*
Test currently disabled because we don't have the infrastructure to make it pass.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5597,6 +5597,48 @@
],
"name": "SingleInstanceTwoTypes"
},
"jsii-calc.StaticContext": {
"assembly": "jsii-calc",
"docs": {
"remarks": "https://github.com/awslabs/aws-cdk/issues/2304",
"summary": "This is used to validate the ability to use `this` from within a static context."
},
"fqn": "jsii-calc.StaticContext",
"kind": "class",
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1645
},
"methods": [
{
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1648
},
"name": "canAccessStaticContext",
"returns": {
"type": {
"primitive": "boolean"
}
},
"static": true
}
],
"name": "StaticContext",
"properties": [
{
"locationInModule": {
"filename": "lib/compliance.ts",
"line": 1656
},
"name": "staticVariable",
"static": true,
"type": {
"primitive": "boolean"
}
}
]
},
"jsii-calc.Statics": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.Statics",
Expand Down Expand Up @@ -6655,5 +6697,5 @@
}
},
"version": "0.9.0",
"fingerprint": "rheLw7bhMAmuMfbnzQ4tXZyQTSYIydCp59wiBfA8Gpo="
"fingerprint": "7Kv5qQOHJ4CtCTKoLfaavS4jHjk/HJvT6aWOIZAHTvw="
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Amazon.JSII.Runtime.Deputy;

namespace Amazon.JSII.Tests.CalculatorNamespace
{
/// <summary>This is used to validate the ability to use `this` from within a static context.</summary>
/// <remarks>https://github.com/awslabs/aws-cdk/issues/2304</remarks>
[JsiiClass(nativeType: typeof(StaticContext), fullyQualifiedName: "jsii-calc.StaticContext")]
public class StaticContext : DeputyBase
{
protected StaticContext(ByRefValue reference): base(reference)
{
}

protected StaticContext(DeputyProps props): base(props)
{
}

[JsiiProperty(name: "staticVariable", typeJson: "{\"primitive\":\"boolean\"}")]
public static bool StaticVariable
{
get => GetStaticProperty<bool>(typeof(StaticContext));
set => SetStaticProperty(typeof(StaticContext), value);
}

[JsiiMethod(name: "canAccessStaticContext", returnsJson: "{\"type\":{\"primitive\":\"boolean\"}}")]
public static bool CanAccessStaticContext()
{
return InvokeStaticMethod<bool>(typeof(StaticContext), new object[]{});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ protected Class<?> resolveClass(final String fqn) throws ClassNotFoundException
case "jsii-calc.ReturnsPrivateImplementationOfInterface": return software.amazon.jsii.tests.calculator.ReturnsPrivateImplementationOfInterface.class;
case "jsii-calc.RuntimeTypeChecking": return software.amazon.jsii.tests.calculator.RuntimeTypeChecking.class;
case "jsii-calc.SingleInstanceTwoTypes": return software.amazon.jsii.tests.calculator.SingleInstanceTwoTypes.class;
case "jsii-calc.StaticContext": return software.amazon.jsii.tests.calculator.StaticContext.class;
case "jsii-calc.Statics": return software.amazon.jsii.tests.calculator.Statics.class;
case "jsii-calc.StringEnum": return software.amazon.jsii.tests.calculator.StringEnum.class;
case "jsii-calc.StripInternal": return software.amazon.jsii.tests.calculator.StripInternal.class;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package software.amazon.jsii.tests.calculator;

/**
* This is used to validate the ability to use `this` from within a static context.
*
* https://github.com/awslabs/aws-cdk/issues/2304
*/
@javax.annotation.Generated(value = "jsii-pacmak")
@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.StaticContext")
public class StaticContext extends software.amazon.jsii.JsiiObject {
protected StaticContext(final software.amazon.jsii.JsiiObject.InitializationMode mode) {
super(mode);
}

public static java.lang.Boolean canAccessStaticContext() {
return software.amazon.jsii.JsiiObject.jsiiStaticCall(software.amazon.jsii.tests.calculator.StaticContext.class, "canAccessStaticContext", java.lang.Boolean.class);
}

public static java.lang.Boolean getStaticVariable() {
return software.amazon.jsii.JsiiObject.jsiiStaticGet(software.amazon.jsii.tests.calculator.StaticContext.class, "staticVariable", java.lang.Boolean.class);
}

public static void setStaticVariable(final java.lang.Boolean value) {
software.amazon.jsii.JsiiObject.jsiiStaticSet(software.amazon.jsii.tests.calculator.StaticContext.class, "staticVariable", java.util.Objects.requireNonNull(value, "staticVariable is required"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,22 @@ def interface2(self) -> "IPublicInterface":
return jsii.invoke(self, "interface2", [])


class StaticContext(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.StaticContext"):
@jsii.member(jsii_name="canAccessStaticContext")
@classmethod
def can_access_static_context(cls) -> bool:
return jsii.sinvoke(cls, "canAccessStaticContext", [])

@classproperty
@jsii.member(jsii_name="staticVariable")
def static_variable(cls) -> bool:
return jsii.sget(cls, "staticVariable")

@static_variable.setter
def static_variable(cls, value: bool):
return jsii.sset(cls, "staticVariable", value)


class Statics(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.Statics"):
def __init__(self, value: str) -> None:
jsii.create(Statics, self, [value])
Expand Down Expand Up @@ -2613,6 +2629,6 @@ def parts(self, value: typing.List[scope.jsii_calc_lib.Value]):
return jsii.set(self, "parts", value)


__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithDocs", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "__jsii_assembly__", "composition"]
__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithDocs", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "StaticContext", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "__jsii_assembly__", "composition"]

publication.publish()
46 changes: 46 additions & 0 deletions packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5344,6 +5344,52 @@ SingleInstanceTwoTypes
:rtype: :py:class:`~jsii-calc.IPublicInterface`\


StaticContext
^^^^^^^^^^^^^

.. py:class:: StaticContext
**Language-specific names:**

.. tabs::

.. code-tab:: c#

using Amazon.JSII.Tests.CalculatorNamespace;

.. code-tab:: java

import software.amazon.jsii.tests.calculator.StaticContext;

.. code-tab:: javascript

const { StaticContext } = require('jsii-calc');

.. code-tab:: typescript

import { StaticContext } from 'jsii-calc';



This is used to validate the ability to use `this` from within a static context.



https://github.com/awslabs/aws-cdk/issues/2304




.. py:staticmethod:: canAccessStaticContext() -> boolean
:rtype: boolean


.. py:attribute:: staticVariable
:type: boolean *(static)*


Statics
^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions packages/jsii-reflect/test/classes.expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ ReferenceEnumFromScopedPackage
ReturnsPrivateImplementationOfInterface
RuntimeTypeChecking
SingleInstanceTwoTypes
StaticContext
Statics
StripInternal
Sum
Expand Down
8 changes: 8 additions & 0 deletions packages/jsii-reflect/test/jsii-tree.test.all.expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,14 @@ assemblies
│ │ │ └── returns: jsii-calc.InbetweenClass
│ │ └─┬ interface2() method
│ │ └── returns: jsii-calc.IPublicInterface
│ ├─┬ class StaticContext
│ │ └─┬ members
│ │ ├─┬ canAccessStaticContext() method
│ │ │ ├── static
│ │ │ └── returns: boolean
│ │ └─┬ staticVariable property
│ │ ├── static
│ │ └── type: boolean
│ ├─┬ class Statics
│ │ └─┬ members
│ │ ├─┬ <initializer>(value) initializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ assemblies
│ ├── class ReturnsPrivateImplementationOfInterface
│ ├── class RuntimeTypeChecking
│ ├── class SingleInstanceTwoTypes
│ ├── class StaticContext
│ ├── class Statics
│ ├── class StripInternal
│ ├─┬ class Sum
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ assemblies
│ │ ├── <initializer>() initializer
│ │ ├── interface1() method
│ │ └── interface2() method
│ ├─┬ class StaticContext
│ │ └─┬ members
│ │ ├── canAccessStaticContext() method
│ │ └── staticVariable property
│ ├─┬ class Statics
│ │ └─┬ members
│ │ ├── <initializer>(value) initializer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ assemblies
│ ├── class ReturnsPrivateImplementationOfInterface
│ ├── class RuntimeTypeChecking
│ ├── class SingleInstanceTwoTypes
│ ├── class StaticContext
│ ├── class Statics
│ ├── class StripInternal
│ ├── class Sum
Expand Down

0 comments on commit c81b4c1

Please sign in to comment.