-
Notifications
You must be signed in to change notification settings - Fork 554
[RGen] Handle sealed property and methods correctly. #23663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
From the [review](#23656 (review)) we noticed that sealed property and methods do not need the IsDirecBinding check. We update the struct to let use know if the method is sealed and generate the call accordingly. We just need to update some if conditions. Tests have been updated to handle this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR optimizes code generation for sealed properties and methods in the RGen (binding generator) by eliminating unnecessary IsDirectBinding checks. When properties or methods are marked as sealed, they cannot be overridden, so the generator can call Objective-C messaging directly without checking for subclass overrides.
Key changes:
- Added
IsSealedproperty to bothMethodandPropertydata models to track sealed modifiers - Updated code generation logic to bypass IsDirectBinding checks for sealed members
- Added test cases and expected output files for sealed property and method scenarios
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs | Added IsSealed property to track sealed modifier on methods |
| src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs | Added IsSealed property to track sealed modifier on properties |
| src/rgen/Microsoft.Macios.Generator/Emitters/ClassEmitterExtensions.cs | Updated code generation logic to use direct messaging for sealed members |
| tests/rgen/Microsoft.Macios.Generator.Tests/Classes/Data/MethodTests.cs | Added test case for sealed method |
| tests/rgen/Microsoft.Macios.Generator.Tests/Classes/Data/PropertyTests.cs | Added test case for sealed property |
| Multiple expected output files | Updated with generated code for sealed members without IsDirectBinding checks |
Comments suppressed due to low confidence (2)
| [SupportedOSPlatform ("macos")] | ||
| [SupportedOSPlatform ("maccatalyst13.1")] | ||
| [Export<Property> ("sealedProperty")] | ||
| public sealed partial string SelaedProperty { get; set; } |
Copilot
AI
Aug 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The property name 'SelaedProperty' contains a spelling error. It should be 'SealedProperty'.
| public sealed partial string SelaedProperty { get; set; } | |
| public sealed partial string SealedProperty { get; set; } |
| [SupportedOSPlatform ("tvos")] | ||
| [SupportedOSPlatform ("maccatalyst13.1")] | ||
| [BindingImpl (BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)] | ||
| public sealed partial string SelaedProperty |
Copilot
AI
Aug 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The property name 'SelaedProperty' contains a spelling error. It should be 'SealedProperty'.
| public sealed partial string SelaedProperty | |
| public sealed partial string SealedProperty |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
💻 [CI Build #5d3c39c] Tests on macOS X64 - Mac Sonoma (14) passed 💻✅ All tests on macOS X64 - Mac Sonoma (14) passed. Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| [SupportedOSPlatform ("macos")] | ||
| [SupportedOSPlatform ("maccatalyst13.1")] | ||
| [Export<Property> ("sealedProperty")] | ||
| public sealed partial string SelaedProperty { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The [Sealed] attribute in bgen has more than one meaning, and the one that's important here is "don't export this method to Objective-C". This means the method must not have an [Export] attribute, and as an optimization, we can skip the IsDirectBinding check (because it won't call itself because it's not exported to Objective-C).
As such, I think it would be better to use something other than the sealed keyword to mark such APIs, because there's no reason it shouldn't be possible to export a sealed method to Objective-C (also it's a rather unintituive/obscure behavior).
Ideas:
- Use a different attribute, say
[Import ("selector")]or[Expose ("selector")]instead of[Export<T> ("selector")]. - Use a property/flag on the
[Export<T>]attribute, say[Export<T> ("selector", OnlyImport = true)]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to property flag, makes the api consistent
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| var (tempVar, tempDeclaration) = GetReturnValueAuxVariable (property.ReturnType); | ||
| // if the binding is a protocol, we need to call send directly | ||
| if (context.Changes.BindingType == BindingType.Protocol) { | ||
| if (context.Changes.BindingType == BindingType.Protocol || property.IsSealed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (context.Changes.BindingType == BindingType.Protocol || property.IsSealed) { | |
| if (context.Changes.BindingType == BindingType.Protocol || property.SkipRegistration) { |
| // perform the invocation | ||
| // if the binding is a protocol, we need to call send directly | ||
| if (context.Changes.BindingType == BindingType.Protocol) { | ||
| if (context.Changes.BindingType == BindingType.Protocol || property.IsSealed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (context.Changes.BindingType == BindingType.Protocol || property.IsSealed) { | |
| if (context.Changes.BindingType == BindingType.Protocol || property.SkipRegistration) { |
| readonly bool isSealed; | ||
|
|
||
| /// <summary> | ||
| /// True if the method was marked as sealed. | ||
| /// </summary> | ||
| public bool IsSealed => isSealed; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer needed:
| readonly bool isSealed; | |
| /// <summary> | |
| /// True if the method was marked as sealed. | |
| /// </summary> | |
| public bool IsSealed => isSealed; |
| init { | ||
| modifiers = value; | ||
| isStatic = modifiers.Any (x => x.IsKind (SyntaxKind.StaticKeyword)); | ||
| isSealed = modifiers.Any (x => x.IsKind (SyntaxKind.SealedKeyword)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| isSealed = modifiers.Any (x => x.IsKind (SyntaxKind.SealedKeyword)); |
| readonly bool isSealed; | ||
|
|
||
| /// <summary> | ||
| /// True if the method was marked as sealed. | ||
| /// </summary> | ||
| public bool IsSealed => isSealed; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| readonly bool isSealed; | |
| /// <summary> | |
| /// True if the method was marked as sealed. | |
| /// </summary> | |
| public bool IsSealed => isSealed; |
| init { | ||
| modifiers = value; | ||
| isStatic = modifiers.Any (x => x.IsKind (SyntaxKind.StaticKeyword)); | ||
| isSealed = modifiers.Any (x => x.IsKind (SyntaxKind.SealedKeyword)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| isSealed = modifiers.Any (x => x.IsKind (SyntaxKind.SealedKeyword)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh I forgot I added in more than one place. Cleaning.
| [SupportedOSPlatform ("macos")] | ||
| [SupportedOSPlatform ("maccatalyst13.1")] | ||
| [Export<Property> ("sealedProperty")] | ||
| public sealed partial string SelaedProperty { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public sealed partial string SelaedProperty { get; set; } | |
| public sealed partial string SealedProperty { get; set; } |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ [CI Build #cb0fbb4] Build passed (Build packages) ✅Pipeline on Agent |
✅ [PR Build #cb0fbb4] Build passed (Detect API changes) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ API diff for current PR / commit.NET ( No breaking changes )✅ API diff vs stable.NET ( No breaking changes )ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
✅ [CI Build #cb0fbb4] Build passed (Build macOS tests) ✅Pipeline on Agent |
💻 [CI Build #cb0fbb4] Tests on macOS M1 - Mac Monterey (12) passed 💻✅ All tests on macOS M1 - Mac Monterey (12) passed. Pipeline on Agent |
💻 [CI Build #cb0fbb4] Tests on macOS M1 - Mac Ventura (13) passed 💻✅ All tests on macOS M1 - Mac Ventura (13) passed. Pipeline on Agent |
✅ [CI Build #4befbdc] Build passed (Build macOS tests) ✅Pipeline on Agent |
💻 [CI Build #cb0fbb4] Tests on macOS arm64 - Mac Sequoia (15) passed 💻✅ All tests on macOS arm64 - Mac Sequoia (15) passed. Pipeline on Agent |
💻 [CI Build #4befbdc] Tests on macOS arm64 - Mac Sequoia (15) passed 💻✅ All tests on macOS arm64 - Mac Sequoia (15) passed. Pipeline on Agent |
💻 [CI Build #4befbdc] Tests on macOS M1 - Mac Ventura (13) passed 💻✅ All tests on macOS M1 - Mac Ventura (13) passed. Pipeline on Agent |
💻 [CI Build #4befbdc] Tests on macOS M1 - Mac Monterey (12) passed 💻✅ All tests on macOS M1 - Mac Monterey (12) passed. Pipeline on Agent |
🔥 [CI Build #cb0fbb4] Test results 🔥Test results❌ Tests failed on VSTS: test results 1 tests crashed, 0 tests failed, 112 tests passed. Failures❌ monotouch tests (macOS) [attempt 3]🔥 Failed catastrophically on VSTS: test results - monotouch_macos (no summary found). Html Report (VSDrops) Download Successes✅ cecil: All 1 tests passed. Html Report (VSDrops) Download Pipeline on Agent |
|
mono Mac tests are not touch by the code changes. |
From the review we noticed that sealed property and methods do not need the IsDirecBinding check. We update the struct to let use know if the method is sealed and generate the call accordingly. We just need to update some if conditions.
Tests have been updated to handle this case.