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

9 comments on commit f6c6aba

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@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 (CodeQL) ✅

Pipeline on Agent
Hash: f6c6aba859f08b44ed5556abffb0e2c34ec45ae1 [CI build]

Please sign in to comment.