Skip to content

Commit

Permalink
[RGen] Add missing configuration options for notifications. (#22260)
Browse files Browse the repository at this point in the history
Add the missing notification configuration options for the
FieldAttribute. Do remember that we will use the analyzer to make sure
that those options are only used when the user passes the notification
flag.

---------

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
  • Loading branch information
mandel-macaque and GitHub Actions Autoformatter authored Mar 2, 2025
1 parent 085ceae commit f6c6aba
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 9 deletions.
10 changes: 10 additions & 0 deletions src/ObjCBindings/FieldAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public class FieldAttribute<T> : Attribute where T : Enum {
/// </summary>
public string? LibraryName { get; set; } = default;

/// <summary>
/// Get/Set the notification type.
/// </summary >
public Type? Type { get; set; } = null;

/// <summary>
/// Get/Set the notification center.
/// </summary >
public string? NotificationCenter { get; set; } = null;

/// <summary>
/// Create a new FieldAttribute for the given symbol and using the namespace as its containing library.
/// <param name="symbolName">The name of the symbol.</param>
Expand Down
39 changes: 37 additions & 2 deletions src/rgen/Microsoft.Macios.Generator/Attributes/FieldData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Extensions;

Expand All @@ -18,6 +19,16 @@ public enum ParsingError {
public string SymbolName { get; }
public string? LibraryName { get; }

/// <summary>
/// Gets and set the type to be used. This is a property that can be used on notifications.
/// </summary>
public string? Type { get; init; }

/// <summary>
/// The notification center to be used, if null, the default one will be used.
/// </summary>
public string? NotificationCenter { get; init; }

public T? Flags { get; } = default;

internal FieldData (string symbolName, string? libraryName, T? flags)
Expand Down Expand Up @@ -45,6 +56,11 @@ public static bool TryParse (AttributeData attributeData,
string? symbolName;
string? libraryName = null;
T? flags = default;

// notifications customizations
string? notificationType = null;
string? notificationCenter = null;

switch (count) {
case 1:
if (!attributeData.ConstructorArguments [0].TryGetIdentifier (out symbolName)) {
Expand Down Expand Up @@ -89,13 +105,23 @@ public static bool TryParse (AttributeData attributeData,
case "Flags":
flags = (T) value.Value!;
break;
case "Type":
notificationType = ((INamedTypeSymbol) value.Value!).ToDisplayString ();
break;
case "NotificationCenter":
notificationCenter = (string?) value.Value!;
break;
default:
data = null;
error = new (ParsingError.UnknownNamedArgument, name);
return false;
}
}
data = new (symbolName, libraryName, flags);

data = new (symbolName, libraryName, flags) {
Type = notificationType,
NotificationCenter = notificationCenter,
};
return true;
}

Expand All @@ -106,6 +132,10 @@ public bool Equals (FieldData<T> other)
return false;
if (LibraryName != other.LibraryName)
return false;
if (Type != other.Type)
return false;
if (NotificationCenter != other.NotificationCenter)
return false;
if (Flags is not null && other.Flags is not null) {
return Flags.Equals (other.Flags);
}
Expand Down Expand Up @@ -137,6 +167,11 @@ public override int GetHashCode ()
/// <inheritdoc />
public override string ToString ()
{
return $"{{ SymbolName: '{SymbolName}', LibraryName: '{LibraryName ?? "null"}', Flags: '{Flags}' }}";
var sb = new StringBuilder ($"{{ SymbolName: '{SymbolName}', ");
sb.Append ($"LibraryName: '{LibraryName ?? "null"}', ");
sb.Append ($"Type: '{Type ?? "null"}', ");
sb.Append ($"NotificationCenter: '{NotificationCenter ?? "null"}', ");
sb.Append ($"Flags: '{Flags}' }}");
return sb.ToString ();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ public IEnumerator<object []> GetEnumerator ()
{
yield return [
new FieldData<EnumValue> ("symbol", null, EnumValue.Default),
"{ SymbolName: 'symbol', LibraryName: 'null', Flags: 'Default' }"
"{ SymbolName: 'symbol', LibraryName: 'null', Type: 'null', NotificationCenter: 'null', Flags: 'Default' }"
];
yield return [
new FieldData<EnumValue> ("symbol", "lib", EnumValue.Default),
"{ SymbolName: 'symbol', LibraryName: 'lib', Flags: 'Default' }"
"{ SymbolName: 'symbol', LibraryName: 'lib', Type: 'null', NotificationCenter: 'null', Flags: 'Default' }"
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,150 @@ public partial class MyClass {
}
];

const string notificationCenterPropertyClass = @"
using ObjCBindings;
namespace NS;
[BindingType]
public partial class MyClass {
[Field<Property> (""name"", Flags = Property.Notification, NotificationCenter=""SharedWorkspace.NotificationCenter"")]
public partial string Name { get; set; } = string.Empty;
}
";

yield return [
notificationCenterPropertyClass,
new Binding (
bindingInfo: new (new BindingTypeData<Class> ()),
name: "MyClass",
@namespace: ["NS"],
fullyQualifiedSymbol: "NS.MyClass",
symbolAvailability: new ()
) {
Base = "object",
Interfaces = ImmutableArray<string>.Empty,
Attributes = [
new ("ObjCBindings.BindingTypeAttribute")
],
UsingDirectives = new HashSet<string> { "ObjCBindings" },
Modifiers = [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword)
],
Properties = [
new (
name: "Name",
returnType: ReturnTypeForString (),
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.FieldAttribute<ObjCBindings.Property>", ["name", "ObjCBindings.Property.Notification", "SharedWorkspace.NotificationCenter"])
],
modifiers: [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword),
],
accessors: [
new (
accessorKind: AccessorKind.Getter,
symbolAvailability: new (),
exportPropertyData: null,
attributes: [],
modifiers: []
),
new (
accessorKind: AccessorKind.Setter,
symbolAvailability: new (),
exportPropertyData: null,
attributes: [],
modifiers: []
),
]
) {

ExportFieldData = new (
fieldData: new (symbolName: "name", flags: Property.Notification) {
NotificationCenter = "SharedWorkspace.NotificationCenter",
},
libraryName: "NS"),
}
]
}
];

const string notificationTypePropertyClass = @"
using ObjCBindings;
namespace NS;
[BindingType]
public partial class MyClass {
[Field<Property> (""name"", Flags = Property.Notification, Type=typeof (UIApplicationLaunchEventArgs))]
public partial string Name { get; set; } = string.Empty;
}
public class UIApplicationLaunchEventArgs {}
";

yield return [
notificationTypePropertyClass,
new Binding (
bindingInfo: new (new BindingTypeData<Class> ()),
name: "MyClass",
@namespace: ["NS"],
fullyQualifiedSymbol: "NS.MyClass",
symbolAvailability: new ()
) {
Base = "object",
Interfaces = ImmutableArray<string>.Empty,
Attributes = [
new ("ObjCBindings.BindingTypeAttribute")
],
UsingDirectives = new HashSet<string> { "ObjCBindings" },
Modifiers = [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword)
],
Properties = [
new (
name: "Name",
returnType: ReturnTypeForString (),
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.FieldAttribute<ObjCBindings.Property>", ["name", "ObjCBindings.Property.Notification", "NS.UIApplicationLaunchEventArgs"])
],
modifiers: [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword),
],
accessors: [
new (
accessorKind: AccessorKind.Getter,
symbolAvailability: new (),
exportPropertyData: null,
attributes: [],
modifiers: []
),
new (
accessorKind: AccessorKind.Setter,
symbolAvailability: new (),
exportPropertyData: null,
attributes: [],
modifiers: []
),
]
) {

ExportFieldData = new (
fieldData: new (symbolName: "name", flags: Property.Notification) {
Type = "NS.UIApplicationLaunchEventArgs",
},
libraryName: "NS"),
}
]
}
];

const string fieldPropertyClass = @"
using ObjCBindings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ public void NotEqualsDifferentFieldData ()
class TestDataToString : IEnumerable<object []> {
public IEnumerator<object []> GetEnumerator ()
{

var simpleEnum = new EnumMember (
name: "EnumValue",
libraryName: "Test",
Expand All @@ -271,7 +270,6 @@ public IEnumerator<object []> GetEnumerator ()
symbolAvailability: new (),
attributes: []);
yield return [simpleEnum, "{ Name: 'EnumValue' SymbolAvailability: [] FieldInfo: Attributes: [] }"];

var fieldDataEnum = new EnumMember (
name: "EnumValue",
libraryName: "Test",
Expand All @@ -281,7 +279,7 @@ public IEnumerator<object []> GetEnumerator ()
attributes: []);
yield return [
fieldDataEnum,
"{ Name: 'EnumValue' SymbolAvailability: [] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [] }"
"{ Name: 'EnumValue' SymbolAvailability: [] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Type: 'null', NotificationCenter: 'null', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [] }",
];

var builder = SymbolAvailability.CreateBuilder ();
Expand All @@ -296,7 +294,7 @@ public IEnumerator<object []> GetEnumerator ()
attributes: []);
yield return [
availabilityEnum,
"{ Name: 'EnumValue' SymbolAvailability: [{ Platform: 'iOS', Supported: '0.0', Unsupported: [], Obsoleted: [] }] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [] }"
"{ Name: 'EnumValue' SymbolAvailability: [{ Platform: 'iOS', Supported: '0.0', Unsupported: [], Obsoleted: [] }] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Type: 'null', NotificationCenter: 'null', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [] }",
];

var attrsEnum = new EnumMember (
Expand All @@ -311,7 +309,7 @@ public IEnumerator<object []> GetEnumerator ()
]);
yield return [
attrsEnum,
"{ Name: 'EnumValue' SymbolAvailability: [{ Platform: 'iOS', Supported: '0.0', Unsupported: [], Obsoleted: [] }] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [{ Name: Attribute1, Arguments: [] }, { Name: Attribute2, Arguments: [] }] }"
"{ Name: 'EnumValue' SymbolAvailability: [{ Platform: 'iOS', Supported: '0.0', Unsupported: [], Obsoleted: [] }] FieldInfo: FieldData = { SymbolName: 'x', LibraryName: 'libName', Type: 'null', NotificationCenter: 'null', Flags: 'Default' }, LibraryName = Test, LibraryPath = /path/to/library Attributes: [{ Name: Attribute1, Arguments: [] }, { Name: Attribute2, Arguments: [] }] }",
];
}

Expand Down

7 comments on commit f6c6aba

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ [CI Build #f6c6aba] Build passed (Build packages) ✅

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ [CI Build #f6c6aba] Build passed (Build macOS tests) ✅

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build #f6c6aba] Tests on macOS M1 - Mac Monterey (12) passed 💻

All tests on macOS M1 - Mac Monterey (12) passed.

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build #f6c6aba] Windows Integration Tests passed 💻

All Windows Integration Tests passed.

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build #f6c6aba] Tests on macOS arm64 - Mac Sequoia (15) passed 💻

All tests on macOS arm64 - Mac Sequoia (15) passed.

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build #f6c6aba] Tests on macOS X64 - Mac Sonoma (14) passed 💻

All tests on macOS X64 - Mac Sonoma (14) passed.

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build #f6c6aba] Tests on macOS M1 - Mac Ventura (13) passed 💻

All tests on macOS M1 - Mac Ventura (13) passed.

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

Please sign in to comment.