Skip to content
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

[Rgen] Allows to mark a property or accessor to marshal native exceptions #21997

Merged
merged 4 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/ObjCBindings/ExportTag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ public enum Property : Int64 {
/// Generate a notification for the property.
/// </summary>
Notification = 1 << 3,

/// <summary>
/// Make a method support native (Objective-C) exceptions. Instead of calling objc_msgSend directly, the invocation
/// will go through a custom trampoline which catches ObjectiveC exceptions and marshals them into managed exceptions.
/// </summary>
MarshalNativeExceptions = 1 << 4,

}
}

11 changes: 11 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public ExportData<ObjCBindings.Property>? ExportPropertyData { get; init; }

public bool MarshalNativeExceptions
=> ExportPropertyData is not null && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions);

/// <summary>
/// List of attribute code changes of the accessor.
/// </summary>
Expand Down Expand Up @@ -82,6 +85,14 @@ public Accessor (AccessorKind accessorKind,
return ExportPropertyData.Value.Selector;
}

/// <summary>
/// Returns if the accessor should marshal native exceptions with the associated property.
/// </summary>
/// <param name="property">The property associated with the accessor.</param>
/// <returns>True if either the accessor or the property were marked with the MarshalNativeExceptions flag.</returns>
public bool ShouldMarshalNativeExceptions (in Property property)
=> MarshalNativeExceptions || property.MarshalNativeExceptions;

/// <inheritdoc />
public bool Equals (Accessor other)
{
Expand Down
5 changes: 5 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public ExportData<ObjCBindings.Method> ExportMethodData { get; }

/// <summary>
/// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions.
/// </summary>
public bool MarshalNativeExceptions => ExportMethodData.Flags.HasFlag (ObjCBindings.Method.MarshalNativeExceptions);

/// <summary>
/// Get the attributes added to the constructor.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ public bool IsNotification
/// </summary>
public ImmutableArray<AttributeCodeChange> Attributes { get; } = [];

/// <summary>
/// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions.
/// </summary>
public bool MarshalNativeExceptions
=> IsProperty && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions);

/// <summary>
/// Get the modifiers of the property.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma warning disable APL0003
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;
using Microsoft.Macios.Generator.DataModel;
using ObjCRuntime;
using Xunit;
using static Microsoft.Macios.Generator.Tests.TestDataFactory;

Expand Down Expand Up @@ -469,4 +471,45 @@ public void GetSetterSelectorExportData ()
Assert.NotNull (selector);
Assert.Equal (customSelector, selector);
}

[Theory]
[InlineData (false, false, false)]
[InlineData (false, true, true)]
[InlineData (true, false, true)]
[InlineData (true, true, true)]
public void ShouldMarshalNativeExceptionsBothFalse (bool propertyHasFlag, bool accessorHasFalg, bool expectedResult)
{
var property = new Property (
name: "MyProperty",
returnType: ReturnTypeForString (),
symbolAvailability: new (),
attributes: [],
modifiers: [],
accessors: []
) {
ExportPropertyData = new (
selector: "selector",
argumentSemantic: ArgumentSemantic.None,
flags: propertyHasFlag ? ObjCBindings.Property.MarshalNativeExceptions : ObjCBindings.Property.Default),
};

var accessor = new Accessor (
accessorKind: AccessorKind.Getter,
symbolAvailability: new (),
exportPropertyData: new (
selector: "selector",
argumentSemantic: ArgumentSemantic.None,
flags: accessorHasFalg ? ObjCBindings.Property.MarshalNativeExceptions : ObjCBindings.Property.Default),
attributes: [
new ("First"),
new ("Second"),
],
modifiers: [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PrivateKeyword)
]);
Assert.Equal (expectedResult, accessor.ShouldMarshalNativeExceptions (property));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;
using Microsoft.Macios.Generator.DataModel;
using ObjCRuntime;
using Xamarin.Tests;
using Xamarin.Utils;
using Xunit;
Expand Down Expand Up @@ -444,6 +445,44 @@ public class TestClass {
}
];

const string marshallNativeException = @"
using System;
using ObjCBindings;

namespace Test;

public class TestClass {

[Export<Property>(""name"", Property.MarshalNativeExceptions)]
public string Name { get; }
}
";
yield return [
marshallNativeException,
new Property (
name: "Name",
returnType: ReturnTypeForString (),
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name", "ObjCBindings.Property.MarshalNativeExceptions"])
],
modifiers: [
SyntaxFactory.Token (kind: SyntaxKind.PublicKeyword),
],
accessors: [
new (
accessorKind: AccessorKind.Getter,
symbolAvailability: new (),
exportPropertyData: null,
attributes: [],
modifiers: []
)
]
) {
ExportPropertyData = new (selector: "name", ArgumentSemantic.None, ObjCBindings.Property.MarshalNativeExceptions),
}
];

const string valueTypeProperty = @"
using System;
using ObjCBindings;
Expand Down
Loading