diff --git a/packages/@jsii/go-runtime-test/project/covariantoverrides_test.go b/packages/@jsii/go-runtime-test/project/covariantoverrides_test.go new file mode 100644 index 0000000000..e6a3cb475f --- /dev/null +++ b/packages/@jsii/go-runtime-test/project/covariantoverrides_test.go @@ -0,0 +1,64 @@ +package tests + +import ( + "testing" + + "github.com/aws/jsii/jsii-calc/go/jsiicalc/v3/covariantoverrides/classoverrides" +) + +func TestBase(t *testing.T) { + base := classoverrides.NewBase() + if *base.Something().Name() != "Superclass" { + t.Errorf("Expected Superclass, got %s", *base.Something().Name()) + } + if *base.CreateSomething().SayHello() != "Hello Superclass" { + t.Errorf("Expected 'Hello Superclass', got %s", *base.CreateSomething().SayHello()) + } +} + +func TestMiddle(t *testing.T) { + middle := classoverrides.NewMiddle() + if *middle.Something().Name() != "Superclass" { + t.Errorf("Expected Superclass, got %s", *middle.Something().Name()) + } + if *middle.CreateSomething().SayHello() != "Hello Superclass" { + t.Errorf("Expected 'Hello Superclass', got %s", *middle.CreateSomething().SayHello()) + } +} + +func TestDerived(t *testing.T) { + derived := classoverrides.NewDerived() + if *derived.Something().Name() != "SubSubclass" { + t.Errorf("Expected SubSubclass, got %s", *derived.Something().Name()) + } + created := derived.CreateSomething() + if *created.Name() != "SubSubclass" { + t.Errorf("Expected SubSubclass, got %s", *created.Name()) + } + if *created.SayHello() != "Hello SubSubclass" { + t.Errorf("Expected 'Hello SubSubclass', got %s", *created.SayHello()) + } +} + +func TestPolymorphism(t *testing.T) { + derived := classoverrides.NewDerived() + var base classoverrides.IBase = derived + + if *base.Something().Name() != "SubSubclass" { + t.Errorf("Expected SubSubclass, got %s", *base.Something().Name()) + } +} + +func consumeSubSubclass(s classoverrides.SubSubclass) string { + return *s.Name() +} + +func TestTypeCasting(t *testing.T) { + derived := classoverrides.NewDerived() + superclassResult := derived.Something() + name := consumeSubSubclass(superclassResult.(classoverrides.SubSubclass)) + if name != "SubSubclass" { + t.Errorf("Expected SubSubclass, got %s", name) + } +} + diff --git a/packages/jsii-calc/lib/covariant-overrides/class-overrides.ts b/packages/jsii-calc/lib/covariant-overrides/class-overrides.ts index 57c31cf2fa..079b52b9dc 100644 --- a/packages/jsii-calc/lib/covariant-overrides/class-overrides.ts +++ b/packages/jsii-calc/lib/covariant-overrides/class-overrides.ts @@ -6,13 +6,33 @@ */ /** Base class in the inheritance hierarchy */ -export class Superclass {} +export class Superclass { + public name = 'Superclass'; + public sayHello(): string { + return 'Hello Superclass'; + } +} /** Derived class that extends Superclass */ -export class Subclass extends Superclass {} +export class Subclass extends Superclass { + public name = 'Subclass'; + public sayHello(): string { + return 'Hello Subclass'; + } +} /** Further derived class that extends Subclass */ -export class SubSubclass extends Subclass {} +export class SubSubclass extends Subclass { + /** + * Ensures this class is different than its parent. + */ + public unique = 'yes'; + + public name = 'SubSubclass'; + public sayHello(): string { + return 'Hello SubSubclass'; + } +} export interface IBase { readonly something: Superclass; diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index 1b4537b94d..b5b956f036 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -16749,7 +16749,7 @@ "kind": "class", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 22 + "line": 42 }, "methods": [ { @@ -16758,7 +16758,7 @@ }, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 26 + "line": 46 }, "name": "createSomething", "returns": { @@ -16778,7 +16778,7 @@ "immutable": true, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 24 + "line": 44 }, "name": "list", "type": { @@ -16797,7 +16797,7 @@ "immutable": true, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 23 + "line": 43 }, "name": "something", "overrides": "jsii-calc.covariantOverrides.classOverrides.IBase", @@ -16825,7 +16825,7 @@ "kind": "class", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 42 + "line": 62 }, "methods": [ { @@ -16834,7 +16834,7 @@ }, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 48 + "line": 68 }, "name": "createSomething", "overrides": "jsii-calc.covariantOverrides.classOverrides.Base", @@ -16855,7 +16855,7 @@ "immutable": true, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 45 + "line": 65 }, "name": "list", "overrides": "jsii-calc.covariantOverrides.classOverrides.Base", @@ -16875,7 +16875,7 @@ "immutable": true, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 44 + "line": 64 }, "name": "something", "overrides": "jsii-calc.covariantOverrides.classOverrides.Base", @@ -16895,7 +16895,7 @@ "kind": "interface", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 17 + "line": 37 }, "name": "IBase", "namespace": "covariantOverrides.classOverrides", @@ -16908,7 +16908,7 @@ "immutable": true, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 18 + "line": 38 }, "name": "something", "type": { @@ -16934,7 +16934,7 @@ "kind": "class", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 32 + "line": 52 }, "name": "Middle", "namespace": "covariantOverrides.classOverrides", @@ -16945,7 +16945,7 @@ }, "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 33 + "line": 53 }, "name": "addUnrelatedMember", "type": { @@ -16971,10 +16971,58 @@ "kind": "class", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 15 + "line": 25 }, + "methods": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 32 + }, + "name": "sayHello", + "overrides": "jsii-calc.covariantOverrides.classOverrides.Subclass", + "returns": { + "type": { + "primitive": "string" + } + } + } + ], "name": "SubSubclass", "namespace": "covariantOverrides.classOverrides", + "properties": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 31 + }, + "name": "name", + "overrides": "jsii-calc.covariantOverrides.classOverrides.Subclass", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "stability": "stable", + "summary": "Ensures this class is different than its parent." + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 29 + }, + "name": "unique", + "type": { + "primitive": "string" + } + } + ], "symbolId": "lib/covariant-overrides/class-overrides:SubSubclass" }, "jsii-calc.covariantOverrides.classOverrides.Subclass": { @@ -16993,10 +17041,44 @@ "kind": "class", "locationInModule": { "filename": "lib/covariant-overrides/class-overrides.ts", - "line": 12 + "line": 17 }, + "methods": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 19 + }, + "name": "sayHello", + "overrides": "jsii-calc.covariantOverrides.classOverrides.Superclass", + "returns": { + "type": { + "primitive": "string" + } + } + } + ], "name": "Subclass", "namespace": "covariantOverrides.classOverrides", + "properties": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 18 + }, + "name": "name", + "overrides": "jsii-calc.covariantOverrides.classOverrides.Superclass", + "type": { + "primitive": "string" + } + } + ], "symbolId": "lib/covariant-overrides/class-overrides:Subclass" }, "jsii-calc.covariantOverrides.classOverrides.Superclass": { @@ -17016,8 +17098,40 @@ "filename": "lib/covariant-overrides/class-overrides.ts", "line": 9 }, + "methods": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 11 + }, + "name": "sayHello", + "returns": { + "type": { + "primitive": "string" + } + } + } + ], "name": "Superclass", "namespace": "covariantOverrides.classOverrides", + "properties": [ + { + "docs": { + "stability": "stable" + }, + "locationInModule": { + "filename": "lib/covariant-overrides/class-overrides.ts", + "line": 10 + }, + "name": "name", + "type": { + "primitive": "string" + } + } + ], "symbolId": "lib/covariant-overrides/class-overrides:Superclass" }, "jsii-calc.homonymousForwardReferences.bar.Consumer": { @@ -19672,5 +19786,5 @@ "intersection-types" ], "version": "3.20.120", - "fingerprint": "bgdsE4i6uPRf3d8FnIARS1FO4PilyDwzanABdH+SqIg=" + "fingerprint": "6Vy4e6a5fe6HlMnZVVfUxQ6kP2NgQEfEjwgiDHv/Ssw=" } \ No newline at end of file diff --git a/packages/jsii-pacmak/lib/targets/go.ts b/packages/jsii-pacmak/lib/targets/go.ts index fa497931e7..18234855a9 100644 --- a/packages/jsii-pacmak/lib/targets/go.ts +++ b/packages/jsii-pacmak/lib/targets/go.ts @@ -56,8 +56,13 @@ export class Golang extends Target { return Promise.reject(e); } - if (process.env.JSII_BUILD_GO) { - // This step is taken to ensure that the generated code is compilable + // This step is taken to ensure that the generated code is compilable + // Do it by default, because we didn't use to and that was masking a code generation + // problem. + const doBuild = !['false', '0', 'no'].includes( + process.env.JSII_BUILD_GO ?? '1', + ); + if (doBuild) { await go('build', ['-modfile', localGoMod.path, './...'], { cwd: pkgDir, }); diff --git a/packages/jsii-pacmak/lib/targets/go/types/class.ts b/packages/jsii-pacmak/lib/targets/go/types/class.ts index 32386e3828..d967258627 100644 --- a/packages/jsii-pacmak/lib/targets/go/types/class.ts +++ b/packages/jsii-pacmak/lib/targets/go/types/class.ts @@ -1,4 +1,4 @@ -import { Method, ClassType, Initializer } from 'jsii-reflect'; +import { Method, ClassType, Initializer, Docs } from 'jsii-reflect'; import { jsiiToPascalCase } from '../../../naming-util'; import * as comparators from '../comparators'; @@ -371,9 +371,28 @@ export class ClassMethod extends GoMethod { public emitDecl({ code, documenter }: EmitContext) { const returnTypeString = this.reference?.void ? '' : ` ${this.returnType}`; documenter.emit(this.method.docs, this.apiLocation); + // Document the actual return type + if (this.returnTypeForDocs !== this.returnType) { + documenter.emit( + new Docs(this.method.system, this.method, { + summary: `Returns \`${this.returnTypeForDocs}\`, use interface conversion if needed`, + }), + this.apiLocation, + ); + } code.line(`${this.name}(${this.paramString()})${returnTypeString}`); } + private get returnTypeForDocs(): string { + if (Method.isMethod(this.method) && this.method.returns.type) { + return new GoTypeRef( + this.parent.pkg.root, + this.method.returns.type, + ).scopedReference(this.parent.pkg); + } + return this.method.toString(); + } + public get instanceArg(): string { return this.parent.name.substring(0, 1).toLowerCase(); } diff --git a/packages/jsii-pacmak/lib/targets/go/types/type-member.ts b/packages/jsii-pacmak/lib/targets/go/types/type-member.ts index 3f5bfefaee..8cd0785778 100644 --- a/packages/jsii-pacmak/lib/targets/go/types/type-member.ts +++ b/packages/jsii-pacmak/lib/targets/go/types/type-member.ts @@ -1,5 +1,6 @@ import { Callable, + Docs, MemberKind, Method, Parameter, @@ -46,6 +47,7 @@ export class GoProperty implements GoTypeMember { public readonly immutable: boolean; protected readonly apiLocation: ApiLocation; #validator: ParameterValidator | undefined | null = null; + private _propertyForSignature?: Property; public constructor( public parent: GoType, @@ -74,7 +76,7 @@ export class GoProperty implements GoTypeMember { } public get reference(): GoTypeRef { - return new GoTypeRef(this.parent.pkg.root, this.property.type); + return new GoTypeRef(this.parent.pkg.root, this.propertyForSignature.type); } public get specialDependencies(): SpecialDependencies { @@ -94,7 +96,15 @@ export class GoProperty implements GoTypeMember { public get returnType(): string { return ( this.reference?.scopedReference(this.parent.pkg) ?? - this.property.type.toString() + this.propertyForSignature.type.toString() + ); + } + + private get returnTypeForDocs(): string { + return ( + new GoTypeRef(this.parent.pkg.root, this.property.type).scopedReference( + this.parent.pkg, + ) ?? this.property.type.toString() ); } @@ -113,7 +123,9 @@ export class GoProperty implements GoTypeMember { ? `*${this.returnType}` : this.returnType; - const requiredOrOptional = this.property.optional ? 'optional' : 'required'; + const requiredOrOptional = this.propertyForSignature.optional + ? 'optional' + : 'required'; // Adds json and yaml tags for easy deserialization code.line( @@ -124,6 +136,15 @@ export class GoProperty implements GoTypeMember { public emitGetterDecl({ code, documenter }: EmitContext) { documenter.emit(this.property.docs, this.apiLocation); + // Document the actual return type + if (this.returnTypeForDocs !== this.returnType) { + documenter.emit( + new Docs(this.property.system, this.property, { + summary: `Returns \`${this.returnTypeForDocs}\`, use interface conversion if needed`, + }), + this.apiLocation, + ); + } code.line(`${this.name}() ${this.returnType}`); } @@ -179,22 +200,52 @@ export class GoProperty implements GoTypeMember { code.line(); } } + + /** + * Returns the property we're overriding + * + * This is necessary because jsii allows classes to make the type of + * properties in subclasses more specific (this is known as "covariant return + * types"), but Go doesn't support this feature. + * + * If we render the signature of the property itself, and it has changed its + * return type, Go will see that as two conflicting definitions of the same + * accessor method. + * + * So instead, we will always render the type signature of the topmost method. + * That is either the same as the current method (in which case it doesn't make + * a difference), or it is a different signature, but then that's the one + * we need to render to prevent the method collission. + */ + public get propertyForSignature(): Property { + // Cache for speed + if (this._propertyForSignature) { + return this._propertyForSignature; + } + + let ret = this.property; + while (true) { + const next = ret.overriddenProperty; + if (!next) { + this._propertyForSignature = ret; + return ret; + } + ret = next; + } + } } export abstract class GoMethod implements GoTypeMember { public readonly name: string; - public readonly parameters: GoParameter[]; protected readonly apiLocation: ApiLocation; #validator: ParameterValidator | undefined | null = null; + private _methodForSignature?: Callable; public constructor( public readonly parent: GoClass | GoInterface, public readonly method: Callable, ) { this.name = jsiiToPascalCase(method.name); - this.parameters = this.method.parameters.map( - (param) => new GoParameter(parent, param), - ); this.apiLocation = method.kind === MemberKind.Initializer @@ -202,6 +253,12 @@ export abstract class GoMethod implements GoTypeMember { : { api: 'member', fqn: parent.fqn, memberName: method.name }; } + public get parameters(): GoParameter[] { + return this.methodForSignature.parameters.map( + (param) => new GoParameter(this.parent, param), + ); + } + public get validator() { if (this.#validator === null) { this.#validator = ParameterValidator.forMethod(this); @@ -214,8 +271,9 @@ export abstract class GoMethod implements GoTypeMember { public abstract get specialDependencies(): SpecialDependencies; public get reference(): GoTypeRef | undefined { - if (Method.isMethod(this.method) && this.method.returns.type) { - return new GoTypeRef(this.parent.pkg.root, this.method.returns.type); + const sig = this.methodForSignature; + if (Method.isMethod(sig) && sig.returns.type) { + return new GoTypeRef(this.parent.pkg.root, sig.returns.type); } return undefined; } @@ -234,7 +292,8 @@ export abstract class GoMethod implements GoTypeMember { public get returnType(): string { return ( - this.reference?.scopedReference(this.parent.pkg) ?? this.method.toString() + this.reference?.scopedReference(this.parent.pkg) ?? + this.methodForSignature.toString() ); } @@ -255,6 +314,45 @@ export abstract class GoMethod implements GoTypeMember { ? '' : this.parameters.map((p) => p.toString()).join(', '); } + + /** + * Returns the first method we're overriding + * + * This is necessary because jsii allows classes to make the return type of + * methods in subclasses more specific (this is known as "covariant return + * types"), but Go doesn't support this feature. + * + * If we render the signature of the method itself, and it has changed its + * return type, Go will see that as two conflicting definitions of the same + * method. + * + * So instead, we will always render the type signature of the topmost method. + * That is either the same as the current method (in which case it doesn't make + * a difference), or it is a different signature, but then that's the one + * we need to render to prevent the method collision. + */ + public get methodForSignature(): Callable { + // Cache for speed + if (this._methodForSignature) { + return this._methodForSignature; + } + + // Not sure why `this.method :: Callable` and not `this.method :: Method`, but + // let's be safe. + if (!(this.method instanceof Method)) { + return this.method; + } + + let ret = this.method; + while (true) { + const next = ret.overriddenMethod; + if (!next) { + this._methodForSignature = ret; + return ret; + } + ret = next; + } + } } export class GoParameter { diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.js.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.js.snap index 87869dfbf4..982e03e6af 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.js.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-dotnet.test.js.snap @@ -6792,6 +6792,27 @@ namespace Amazon.JSII.Tests.CalculatorNamespace.CovariantOverrides.ClassOverride protected SubSubclass(DeputyProps props): base(props) { } + + [JsiiMethod(name: "sayHello", returnsJson: "{\\"type\\":{\\"primitive\\":\\"string\\"}}")] + public override string SayHello() + { + return InvokeInstanceMethod(new System.Type[]{}, new object[]{})!; + } + + [JsiiProperty(name: "name", typeJson: "{\\"primitive\\":\\"string\\"}")] + public override string Name + { + get => GetInstanceProperty()!; + set => SetInstanceProperty(value); + } + + /// Ensures this class is different than its parent. + [JsiiProperty(name: "unique", typeJson: "{\\"primitive\\":\\"string\\"}")] + public virtual string Unique + { + get => GetInstanceProperty()!; + set => SetInstanceProperty(value); + } } } @@ -6831,6 +6852,19 @@ namespace Amazon.JSII.Tests.CalculatorNamespace.CovariantOverrides.ClassOverride protected Subclass(DeputyProps props): base(props) { } + + [JsiiMethod(name: "sayHello", returnsJson: "{\\"type\\":{\\"primitive\\":\\"string\\"}}")] + public override string SayHello() + { + return InvokeInstanceMethod(new System.Type[]{}, new object[]{})!; + } + + [JsiiProperty(name: "name", typeJson: "{\\"primitive\\":\\"string\\"}")] + public override string Name + { + get => GetInstanceProperty()!; + set => SetInstanceProperty(value); + } } } @@ -6870,6 +6904,19 @@ namespace Amazon.JSII.Tests.CalculatorNamespace.CovariantOverrides.ClassOverride protected Superclass(DeputyProps props): base(props) { } + + [JsiiMethod(name: "sayHello", returnsJson: "{\\"type\\":{\\"primitive\\":\\"string\\"}}")] + public virtual string SayHello() + { + return InvokeInstanceMethod(new System.Type[]{}, new object[]{})!; + } + + [JsiiProperty(name: "name", typeJson: "{\\"primitive\\":\\"string\\"}")] + public virtual string Name + { + get => GetInstanceProperty()!; + set => SetInstanceProperty(value); + } } } diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-go.test.js.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-go.test.js.snap index 9e05cf1ea2..7e37e056c8 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-go.test.js.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-go.test.js.snap @@ -19125,8 +19125,10 @@ type Derived interface { AddUnrelatedMember() *float64 SetAddUnrelatedMember(val *float64) List() *[]Superclass - Something() SubSubclass - CreateSomething() SubSubclass + // Returns \`SubSubclass\`, use interface conversion if needed. + Something() Superclass + // Returns \`SubSubclass\`, use interface conversion if needed. + CreateSomething() Superclass } // The jsii proxy struct for Derived @@ -19154,8 +19156,8 @@ func (j *jsiiProxy_Derived) List() *[]Superclass { return returns } -func (j *jsiiProxy_Derived) Something() SubSubclass { - var returns SubSubclass +func (j *jsiiProxy_Derived) Something() Superclass { + var returns Superclass _jsii_.Get( j, "something", @@ -19197,8 +19199,8 @@ func (j *jsiiProxy_Derived)SetAddUnrelatedMember(val *float64) { ) } -func (d *jsiiProxy_Derived) CreateSomething() SubSubclass { - var returns SubSubclass +func (d *jsiiProxy_Derived) CreateSomething() Superclass { + var returns Superclass _jsii_.Invoke( d, @@ -19355,6 +19357,12 @@ import ( // Further derived class that extends Subclass. type SubSubclass interface { Subclass + Name() *string + SetName(val *string) + // Ensures this class is different than its parent. + Unique() *string + SetUnique(val *string) + SayHello() *string } // The jsii proxy struct for SubSubclass @@ -19362,6 +19370,27 @@ type jsiiProxy_SubSubclass struct { jsiiProxy_Subclass } +func (j *jsiiProxy_SubSubclass) Name() *string { + var returns *string + _jsii_.Get( + j, + "name", + &returns, + ) + return returns +} + +func (j *jsiiProxy_SubSubclass) Unique() *string { + var returns *string + _jsii_.Get( + j, + "unique", + &returns, + ) + return returns +} + + func NewSubSubclass() SubSubclass { _init_.Initialize() @@ -19386,6 +19415,35 @@ func NewSubSubclass_Override(s SubSubclass) { ) } +func (j *jsiiProxy_SubSubclass)SetName(val *string) { + _jsii_.Set( + j, + "name", + val, + ) +} + +func (j *jsiiProxy_SubSubclass)SetUnique(val *string) { + _jsii_.Set( + j, + "unique", + val, + ) +} + +func (s *jsiiProxy_SubSubclass) SayHello() *string { + var returns *string + + _jsii_.Invoke( + s, + "sayHello", + nil, // no parameters + &returns, + ) + + return returns +} + `; @@ -19400,6 +19458,9 @@ import ( // Derived class that extends Superclass. type Subclass interface { Superclass + Name() *string + SetName(val *string) + SayHello() *string } // The jsii proxy struct for Subclass @@ -19407,6 +19468,17 @@ type jsiiProxy_Subclass struct { jsiiProxy_Superclass } +func (j *jsiiProxy_Subclass) Name() *string { + var returns *string + _jsii_.Get( + j, + "name", + &returns, + ) + return returns +} + + func NewSubclass() Subclass { _init_.Initialize() @@ -19431,6 +19503,27 @@ func NewSubclass_Override(s Subclass) { ) } +func (j *jsiiProxy_Subclass)SetName(val *string) { + _jsii_.Set( + j, + "name", + val, + ) +} + +func (s *jsiiProxy_Subclass) SayHello() *string { + var returns *string + + _jsii_.Invoke( + s, + "sayHello", + nil, // no parameters + &returns, + ) + + return returns +} + `; @@ -19444,6 +19537,9 @@ import ( // Base class in the inheritance hierarchy. type Superclass interface { + Name() *string + SetName(val *string) + SayHello() *string } // The jsii proxy struct for Superclass @@ -19451,6 +19547,17 @@ type jsiiProxy_Superclass struct { _ byte // padding } +func (j *jsiiProxy_Superclass) Name() *string { + var returns *string + _jsii_.Get( + j, + "name", + &returns, + ) + return returns +} + + func NewSuperclass() Superclass { _init_.Initialize() @@ -19475,6 +19582,27 @@ func NewSuperclass_Override(s Superclass) { ) } +func (j *jsiiProxy_Superclass)SetName(val *string) { + _jsii_.Set( + j, + "name", + val, + ) +} + +func (s *jsiiProxy_Superclass) SayHello() *string { + var returns *string + + _jsii_.Invoke( + s, + "sayHello", + nil, // no parameters + &returns, + ) + + return returns +} + `; @@ -19545,7 +19673,11 @@ func init() { _jsii_.RegisterClass( "jsii-calc.covariantOverrides.classOverrides.SubSubclass", reflect.TypeOf((*SubSubclass)(nil)).Elem(), - nil, // no members + []_jsii_.Member{ + _jsii_.MemberProperty{JsiiProperty: "name", GoGetter: "Name"}, + _jsii_.MemberMethod{JsiiMethod: "sayHello", GoMethod: "SayHello"}, + _jsii_.MemberProperty{JsiiProperty: "unique", GoGetter: "Unique"}, + }, func() interface{} { j := jsiiProxy_SubSubclass{} _jsii_.InitJsiiProxy(&j.jsiiProxy_Subclass) @@ -19555,7 +19687,10 @@ func init() { _jsii_.RegisterClass( "jsii-calc.covariantOverrides.classOverrides.Subclass", reflect.TypeOf((*Subclass)(nil)).Elem(), - nil, // no members + []_jsii_.Member{ + _jsii_.MemberProperty{JsiiProperty: "name", GoGetter: "Name"}, + _jsii_.MemberMethod{JsiiMethod: "sayHello", GoMethod: "SayHello"}, + }, func() interface{} { j := jsiiProxy_Subclass{} _jsii_.InitJsiiProxy(&j.jsiiProxy_Superclass) @@ -19565,7 +19700,10 @@ func init() { _jsii_.RegisterClass( "jsii-calc.covariantOverrides.classOverrides.Superclass", reflect.TypeOf((*Superclass)(nil)).Elem(), - nil, // no members + []_jsii_.Member{ + _jsii_.MemberProperty{JsiiProperty: "name", GoGetter: "Name"}, + _jsii_.MemberMethod{JsiiMethod: "sayHello", GoMethod: "SayHello"}, + }, func() interface{} { return &jsiiProxy_Superclass{} }, @@ -26264,7 +26402,16 @@ exports[`Generated code for "jsii-calc": / 1`] = ` ┃ ┣━ 📄 Derived.go.diff ┃ ┣━ 🆕 Middle__checks.go ┃ ┣━ 🆕 Middle__no_checks.go - ┃ ┗━ 📄 Middle.go.diff + ┃ ┣━ 📄 Middle.go.diff + ┃ ┣━ 🆕 Subclass__checks.go + ┃ ┣━ 🆕 Subclass__no_checks.go + ┃ ┣━ 📄 Subclass.go.diff + ┃ ┣━ 🆕 SubSubclass__checks.go + ┃ ┣━ 🆕 SubSubclass__no_checks.go + ┃ ┣━ 📄 SubSubclass.go.diff + ┃ ┣━ 🆕 Superclass__checks.go + ┃ ┣━ 🆕 Superclass__no_checks.go + ┃ ┗━ 📄 Superclass.go.diff ┣━ 🆕 DataRenderer__checks.go ┣━ 🆕 DataRenderer__no_checks.go ┣━ 📄 DataRenderer.go.diff @@ -35594,7 +35741,7 @@ exports[`Generated code for "jsii-calc": /go/jsiicalc/c exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Derived.go.diff 1`] = ` --- go/jsiicalc/covariantoverrides/classoverrides/Derived.go --no-runtime-type-checking +++ go/jsiicalc/covariantoverrides/classoverrides/Derived.go --runtime-type-checking -@@ -77,10 +77,13 @@ +@@ -79,10 +79,13 @@ d, ) } @@ -35705,6 +35852,200 @@ exports[`Generated code for "jsii-calc": /go/jsiicalc/c + `; +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/SubSubclass.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/SubSubclass.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/SubSubclass.go --runtime-type-checking +@@ -65,18 +65,24 @@ + s, + ) + } + + func (j *jsiiProxy_SubSubclass)SetName(val *string) { ++ if err := j.validateSetNameParameters(val); err != nil { ++ panic(err) ++ } + _jsii_.Set( + j, + "name", + val, + ) + } + + func (j *jsiiProxy_SubSubclass)SetUnique(val *string) { ++ if err := j.validateSetUniqueParameters(val); err != nil { ++ panic(err) ++ } + _jsii_.Set( + j, + "unique", + val, + ) +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__checks.go --runtime-type-checking +@@ -0,0 +1,24 @@ ++//go:build !no_runtime_type_checking ++ ++package classoverrides ++ ++import ( ++ "fmt" ++) ++ ++func (j *jsiiProxy_SubSubclass) validateSetNameParameters(val *string) error { ++ if val == nil { ++ return fmt.Errorf("parameter val is required, but nil was provided") ++ } ++ ++ return nil ++} ++ ++func (j *jsiiProxy_SubSubclass) validateSetUniqueParameters(val *string) error { ++ if val == nil { ++ return fmt.Errorf("parameter val is required, but nil was provided") ++ } ++ ++ return nil ++} ++ +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__no_checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__no_checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/SubSubclass__no_checks.go --runtime-type-checking +@@ -0,0 +1,14 @@ ++//go:build no_runtime_type_checking ++ ++package classoverrides ++ ++// Building without runtime type checking enabled, so all the below just return nil ++ ++func (j *jsiiProxy_SubSubclass) validateSetNameParameters(val *string) error { ++ return nil ++} ++ ++func (j *jsiiProxy_SubSubclass) validateSetUniqueParameters(val *string) error { ++ return nil ++} ++ +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Subclass.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Subclass.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Subclass.go --runtime-type-checking +@@ -52,10 +52,13 @@ + s, + ) + } + + func (j *jsiiProxy_Subclass)SetName(val *string) { ++ if err := j.validateSetNameParameters(val); err != nil { ++ panic(err) ++ } + _jsii_.Set( + j, + "name", + val, + ) +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Subclass__checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Subclass__checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Subclass__checks.go --runtime-type-checking +@@ -0,0 +1,16 @@ ++//go:build !no_runtime_type_checking ++ ++package classoverrides ++ ++import ( ++ "fmt" ++) ++ ++func (j *jsiiProxy_Subclass) validateSetNameParameters(val *string) error { ++ if val == nil { ++ return fmt.Errorf("parameter val is required, but nil was provided") ++ } ++ ++ return nil ++} ++ +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Subclass__no_checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Subclass__no_checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Subclass__no_checks.go --runtime-type-checking +@@ -0,0 +1,10 @@ ++//go:build no_runtime_type_checking ++ ++package classoverrides ++ ++// Building without runtime type checking enabled, so all the below just return nil ++ ++func (j *jsiiProxy_Subclass) validateSetNameParameters(val *string) error { ++ return nil ++} ++ +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Superclass.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Superclass.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Superclass.go --runtime-type-checking +@@ -51,10 +51,13 @@ + s, + ) + } + + func (j *jsiiProxy_Superclass)SetName(val *string) { ++ if err := j.validateSetNameParameters(val); err != nil { ++ panic(err) ++ } + _jsii_.Set( + j, + "name", + val, + ) +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Superclass__checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Superclass__checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Superclass__checks.go --runtime-type-checking +@@ -0,0 +1,16 @@ ++//go:build !no_runtime_type_checking ++ ++package classoverrides ++ ++import ( ++ "fmt" ++) ++ ++func (j *jsiiProxy_Superclass) validateSetNameParameters(val *string) error { ++ if val == nil { ++ return fmt.Errorf("parameter val is required, but nil was provided") ++ } ++ ++ return nil ++} ++ +`; + +exports[`Generated code for "jsii-calc": /go/jsiicalc/covariantoverrides/classoverrides/Superclass__no_checks.go.diff 1`] = ` +--- go/jsiicalc/covariantoverrides/classoverrides/Superclass__no_checks.go --no-runtime-type-checking ++++ go/jsiicalc/covariantoverrides/classoverrides/Superclass__no_checks.go --runtime-type-checking +@@ -0,0 +1,10 @@ ++//go:build no_runtime_type_checking ++ ++package classoverrides ++ ++// Building without runtime type checking enabled, so all the below just return nil ++ ++func (j *jsiiProxy_Superclass) validateSetNameParameters(val *string) error { ++ return nil ++} ++ +`; + exports[`Generated code for "jsii-calc": /go/jsiicalc/derivedclasshasnoproperties/Base.go.diff 1`] = ` --- go/jsiicalc/derivedclasshasnoproperties/Base.go --no-runtime-type-checking +++ go/jsiicalc/derivedclasshasnoproperties/Base.go --runtime-type-checking diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.js.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.js.snap index 0d83acfda4..0d3c5a16d4 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.js.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-java.test.js.snap @@ -25206,6 +25206,46 @@ public class SubSubclass extends software.amazon.jsii.tests.calculator.covariant super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this); } + + /** + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + @Override + public @org.jetbrains.annotations.NotNull java.lang.String sayHello() { + return software.amazon.jsii.Kernel.call(this, "sayHello", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @Override + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public @org.jetbrains.annotations.NotNull java.lang.String getName() { + return software.amazon.jsii.Kernel.get(this, "name", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @Override + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public void setName(final @org.jetbrains.annotations.NotNull java.lang.String value) { + software.amazon.jsii.Kernel.set(this, "name", java.util.Objects.requireNonNull(value, "name is required")); + } + + /** + * Ensures this class is different than its parent. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public @org.jetbrains.annotations.NotNull java.lang.String getUnique() { + return software.amazon.jsii.Kernel.get(this, "unique", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + * Ensures this class is different than its parent. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public void setUnique(final @org.jetbrains.annotations.NotNull java.lang.String value) { + software.amazon.jsii.Kernel.set(this, "unique", java.util.Objects.requireNonNull(value, "unique is required")); + } } `; @@ -25236,6 +25276,30 @@ public class Subclass extends software.amazon.jsii.tests.calculator.covariant_ov super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this); } + + /** + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + @Override + public @org.jetbrains.annotations.NotNull java.lang.String sayHello() { + return software.amazon.jsii.Kernel.call(this, "sayHello", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @Override + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public @org.jetbrains.annotations.NotNull java.lang.String getName() { + return software.amazon.jsii.Kernel.get(this, "name", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @Override + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public void setName(final @org.jetbrains.annotations.NotNull java.lang.String value) { + software.amazon.jsii.Kernel.set(this, "name", java.util.Objects.requireNonNull(value, "name is required")); + } } `; @@ -25266,6 +25330,27 @@ public class Superclass extends software.amazon.jsii.JsiiObject { super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this); } + + /** + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public @org.jetbrains.annotations.NotNull java.lang.String sayHello() { + return software.amazon.jsii.Kernel.call(this, "sayHello", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public @org.jetbrains.annotations.NotNull java.lang.String getName() { + return software.amazon.jsii.Kernel.get(this, "name", software.amazon.jsii.NativeType.forClass(java.lang.String.class)); + } + + /** + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Stable) + public void setName(final @org.jetbrains.annotations.NotNull java.lang.String value) { + software.amazon.jsii.Kernel.set(this, "name", java.util.Objects.requireNonNull(value, "name is required")); + } } `; diff --git a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap index 113c202f0c..5b318a7e15 100644 --- a/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap +++ b/packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap @@ -12678,6 +12678,19 @@ class Superclass( def __init__(self) -> None: jsii.create(self.__class__, self, []) + @jsii.member(jsii_name="sayHello") + def say_hello(self) -> builtins.str: + return typing.cast(builtins.str, jsii.invoke(self, "sayHello", [])) + + @builtins.property + @jsii.member(jsii_name="name") + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + @jsii.implements(IBase) class Base( @@ -12734,6 +12747,19 @@ class Subclass( def __init__(self) -> None: jsii.create(self.__class__, self, []) + @jsii.member(jsii_name="sayHello") + def say_hello(self) -> builtins.str: + return typing.cast(builtins.str, jsii.invoke(self, "sayHello", [])) + + @builtins.property + @jsii.member(jsii_name="name") + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + class Derived( Middle, @@ -12774,6 +12800,29 @@ class SubSubclass( def __init__(self) -> None: jsii.create(self.__class__, self, []) + @jsii.member(jsii_name="sayHello") + def say_hello(self) -> builtins.str: + return typing.cast(builtins.str, jsii.invoke(self, "sayHello", [])) + + @builtins.property + @jsii.member(jsii_name="name") + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + + @builtins.property + @jsii.member(jsii_name="unique") + def unique(self) -> builtins.str: + '''Ensures this class is different than its parent.''' + return typing.cast(builtins.str, jsii.get(self, "unique")) + + @unique.setter + def unique(self, value: builtins.str) -> None: + jsii.set(self, "unique", value) # pyright: ignore[reportArgumentType] + __all__ = [ "Base", @@ -21227,7 +21276,21 @@ exports[`Generated code for "jsii-calc": /python/src/js exports[`Generated code for "jsii-calc": /python/src/jsii_calc/covariant_overrides/class_overrides/__init__.py.diff 1`] = ` --- python/src/jsii_calc/covariant_overrides/class_overrides/__init__.py --no-runtime-type-checking +++ python/src/jsii_calc/covariant_overrides/class_overrides/__init__.py --runtime-type-checking -@@ -101,10 +101,13 @@ +@@ -69,10 +69,13 @@ + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: ++ if __debug__: ++ type_hints = typing.get_type_hints(_typecheckingstub__eeb0e2f6f15e62545344a73c109909bc39f12407f617cc17046a16d750ae9821) ++ check_type(argname="argument value", value=value, expected_type=type_hints["value"]) + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + + + @jsii.implements(IBase) + class Base( +@@ -114,10 +117,13 @@ def add_unrelated_member(self) -> jsii.Number: return typing.cast(jsii.Number, jsii.get(self, "addUnrelatedMember")) @@ -21241,17 +21304,82 @@ exports[`Generated code for "jsii-calc": /python/src/js class Subclass( Superclass, -@@ -167,7 +170,13 @@ +@@ -138,10 +144,13 @@ + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: ++ if __debug__: ++ type_hints = typing.get_type_hints(_typecheckingstub__18d2a95a2ddcf18b20a0a35b0f711b8001853317f5def313f18ec3acf6385a8c) ++ check_type(argname="argument value", value=value, expected_type=type_hints["value"]) + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + + + class Derived( + Middle, +@@ -191,20 +200,26 @@ + def name(self) -> builtins.str: + return typing.cast(builtins.str, jsii.get(self, "name")) + + @name.setter + def name(self, value: builtins.str) -> None: ++ if __debug__: ++ type_hints = typing.get_type_hints(_typecheckingstub__eef308cfe64fac2288066609c39fe09f5cb1de9aeb89d015b7e45c7a44428c91) ++ check_type(argname="argument value", value=value, expected_type=type_hints["value"]) + jsii.set(self, "name", value) # pyright: ignore[reportArgumentType] + + @builtins.property + @jsii.member(jsii_name="unique") + def unique(self) -> builtins.str: + '''Ensures this class is different than its parent.''' + return typing.cast(builtins.str, jsii.get(self, "unique")) + + @unique.setter + def unique(self, value: builtins.str) -> None: ++ if __debug__: ++ type_hints = typing.get_type_hints(_typecheckingstub__b5604f917bc4b1fd9354007ab09f68bce80b3018ff4042fde2d310649dc3087d) ++ check_type(argname="argument value", value=value, expected_type=type_hints["value"]) + jsii.set(self, "unique", value) # pyright: ignore[reportArgumentType] + + + __all__ = [ + "Base", +@@ -216,7 +231,37 @@ "Superclass", ] publication.publish() ++def _typecheckingstub__eeb0e2f6f15e62545344a73c109909bc39f12407f617cc17046a16d750ae9821( ++ value: builtins.str, ++) -> None: ++ """Type checking stubs""" ++ pass ++ +def _typecheckingstub__1051efd4d7b2a018070aed93762af17bf3bf03922b4b69078c2531f572efa32b( + value: jsii.Number, +) -> None: + """Type checking stubs""" + pass ++ ++def _typecheckingstub__18d2a95a2ddcf18b20a0a35b0f711b8001853317f5def313f18ec3acf6385a8c( ++ value: builtins.str, ++) -> None: ++ """Type checking stubs""" ++ pass ++ ++def _typecheckingstub__eef308cfe64fac2288066609c39fe09f5cb1de9aeb89d015b7e45c7a44428c91( ++ value: builtins.str, ++) -> None: ++ """Type checking stubs""" ++ pass ++ ++def _typecheckingstub__b5604f917bc4b1fd9354007ab09f68bce80b3018ff4042fde2d310649dc3087d( ++ value: builtins.str, ++) -> None: ++ """Type checking stubs""" ++ pass + for cls in [IBase]: typing.cast(typing.Any, cls).__protocol_attrs__ = typing.cast(typing.Any, cls).__protocol_attrs__ - set(['__jsii_proxy_class__', '__jsii_type__']) diff --git a/packages/jsii-reflect/lib/method.ts b/packages/jsii-reflect/lib/method.ts index 78bfad12d8..e978a29d14 100644 --- a/packages/jsii-reflect/lib/method.ts +++ b/packages/jsii-reflect/lib/method.ts @@ -79,4 +79,15 @@ export class Method public get static(): boolean { return !!this.spec.static; } + + /** + * The Method that this method overrides, if any + */ + public get overriddenMethod(): Method | undefined { + const o = this.overrides; + if (o && (o.isClassType() || o.isInterfaceType())) { + return o.ownMethods.find((m) => m.name === this.name); + } + return undefined; + } } diff --git a/packages/jsii-reflect/lib/property.ts b/packages/jsii-reflect/lib/property.ts index 484ee764cc..ed815884fc 100644 --- a/packages/jsii-reflect/lib/property.ts +++ b/packages/jsii-reflect/lib/property.ts @@ -107,4 +107,15 @@ export class Property public get locationInRepository(): SourceLocation | undefined { return locationInRepository(this); } + + /** + * The Property that this property overrides, if any + */ + public get overriddenProperty(): Property | undefined { + const o = this.overrides; + if (o && (o.isClassType() || o.isInterfaceType())) { + return o.ownProperties.find((p) => p.name === this.name); + } + return undefined; + } } diff --git a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap index ed39730fbf..d432b9069a 100644 --- a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap @@ -211,14 +211,28 @@ exports[`jsii-tree --all 1`] = ` │ │ │ │ ├─┬ class SubSubclass (stable) │ │ │ │ │ ├── base: Subclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer (stable) + │ │ │ │ │ ├── () initializer (stable) + │ │ │ │ │ ├─┬ sayHello() method (stable) + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ ├─┬ name property (stable) + │ │ │ │ │ │ └── type: string + │ │ │ │ │ └─┬ unique property (stable) + │ │ │ │ │ └── type: string │ │ │ │ ├─┬ class Subclass (stable) │ │ │ │ │ ├── base: Superclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer (stable) + │ │ │ │ │ ├── () initializer (stable) + │ │ │ │ │ ├─┬ sayHello() method (stable) + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ └─┬ name property (stable) + │ │ │ │ │ └── type: string │ │ │ │ ├─┬ class Superclass (stable) │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer (stable) + │ │ │ │ │ ├── () initializer (stable) + │ │ │ │ │ ├─┬ sayHello() method (stable) + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ └─┬ name property (stable) + │ │ │ │ │ └── type: string │ │ │ │ └─┬ interface IBase (stable) │ │ │ │ └─┬ members │ │ │ │ └─┬ something property (stable) @@ -4510,13 +4524,20 @@ exports[`jsii-tree --members 1`] = ` │ │ │ │ │ └── addUnrelatedMember property │ │ │ │ ├─┬ class SubSubclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├── sayHello() method + │ │ │ │ │ ├── name property + │ │ │ │ │ └── unique property │ │ │ │ ├─┬ class Subclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├── sayHello() method + │ │ │ │ │ └── name property │ │ │ │ ├─┬ class Superclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├── sayHello() method + │ │ │ │ │ └── name property │ │ │ │ └─┬ interface IBase │ │ │ │ └─┬ members │ │ │ │ └── something property diff --git a/packages/jsii-reflect/test/__snapshots__/tree.test.js.snap b/packages/jsii-reflect/test/__snapshots__/tree.test.js.snap index dc7de3e9f3..72e39af214 100644 --- a/packages/jsii-reflect/test/__snapshots__/tree.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/tree.test.js.snap @@ -406,14 +406,28 @@ exports[`showAll 1`] = ` │ │ │ │ ├─┬ class SubSubclass │ │ │ │ │ ├── base: Subclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├─┬ sayHello() method + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ ├─┬ name property + │ │ │ │ │ │ └── type: string + │ │ │ │ │ └─┬ unique property + │ │ │ │ │ └── type: string │ │ │ │ ├─┬ class Subclass │ │ │ │ │ ├── base: Superclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├─┬ sayHello() method + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ └─┬ name property + │ │ │ │ │ └── type: string │ │ │ │ ├─┬ class Superclass │ │ │ │ │ └─┬ members - │ │ │ │ │ └── () initializer + │ │ │ │ │ ├── () initializer + │ │ │ │ │ ├─┬ sayHello() method + │ │ │ │ │ │ └── returns: string + │ │ │ │ │ └─┬ name property + │ │ │ │ │ └── type: string │ │ │ │ └─┬ interface IBase │ │ │ │ └─┬ members │ │ │ │ └─┬ something property diff --git a/packages/jsii-reflect/test/type-system.test.ts b/packages/jsii-reflect/test/type-system.test.ts index b45a7cb05f..c3cfc9df77 100644 --- a/packages/jsii-reflect/test/type-system.test.ts +++ b/packages/jsii-reflect/test/type-system.test.ts @@ -236,6 +236,9 @@ test('overridden member knows about both parent types', () => { expect(booMethod.parentType).toBe(subType); expect(booMethod.definingType).toBe(subType); expect(booMethod.overrides).toBe(superType); + + const superBooMethod = superType.allMethods.find((m) => m.name === 'boo')!; + expect(booMethod.overriddenMethod).toEqual(superBooMethod); }); describe('Stability', () => {