Skip to content

Commit

Permalink
[Rgen] Keep track of properties/methods/ctrs that use smart enums. (#…
Browse files Browse the repository at this point in the history
…21876)

Smart enums are special when writing the bindings. Keep track of them in
the code changes structures. For example, if a user add a BindingType
attr to an enum, we should regenerated the methods that use it.

---------

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
  • Loading branch information
mandel-macaque and GitHub Actions Autoformatter authored Dec 31, 2024
1 parent 84423cc commit a0ac2c8
Show file tree
Hide file tree
Showing 14 changed files with 598 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public static bool TryCreate (ConstructorDeclarationSyntax declaration, Semantic
IsParams = parameter.IsParams,
IsThis = parameter.IsThis,
IsNullable = parameter.NullableAnnotation == NullableAnnotation.Annotated,
IsSmartEnum = parameter.Type.IsSmartEnum (),
DefaultValue = (parameter.HasExplicitDefaultValue) ? parameter.ExplicitDefaultValue?.ToString () : null,
ReferenceKind = parameter.RefKind.ToReferenceKind (),
Attributes = parameterDeclaration.GetAttributeCodeChanges (semanticModel),
Expand Down
1 change: 1 addition & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public static bool TryCreate (MethodDeclarationSyntax declaration, SemanticModel
IsParams = parameter.IsParams,
IsThis = parameter.IsThis,
IsNullable = parameter.NullableAnnotation == NullableAnnotation.Annotated,
IsSmartEnum = parameter.Type.IsSmartEnum (),
DefaultValue = (parameter.HasExplicitDefaultValue) ? parameter.ExplicitDefaultValue?.ToString () : null,
ReferenceKind = parameter.RefKind.ToReferenceKind (),
Attributes = parameterDeclaration.GetAttributeCodeChanges (semanticModel),
Expand Down
9 changes: 9 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public bool IsNullable { get; init; }

/// <summary>
/// Returns if the parameter type is a smart enum.
/// </summary>
public bool IsSmartEnum { get; init; }

/// <summary>
/// Optional default value.
/// </summary>
Expand Down Expand Up @@ -82,6 +87,8 @@ public bool Equals (Parameter other)
return false;
if (IsNullable != other.IsNullable)
return false;
if (IsSmartEnum != other.IsSmartEnum)
return false;
if (DefaultValue != other.DefaultValue)
return false;
if (ReferenceKind != other.ReferenceKind)
Expand All @@ -107,6 +114,7 @@ public override int GetHashCode ()
hashCode.Add (IsParams);
hashCode.Add (IsThis);
hashCode.Add (IsNullable);
hashCode.Add (IsSmartEnum);
hashCode.Add (DefaultValue);
hashCode.Add ((int) ReferenceKind);
return hashCode.ToHashCode ();
Expand Down Expand Up @@ -135,6 +143,7 @@ public override string ToString ()
sb.Append ($"IsParams {IsParams}, ");
sb.Append ($"IsThis: {IsThis}, ");
sb.Append ($"IsNullable: {IsNullable}, ");
sb.Append ($"IsSmartEnum: {IsSmartEnum}, ");
sb.Append ($"DefaultValue: {DefaultValue}, ");
sb.Append ($"ReferenceKind: {ReferenceKind} }}");
return sb.ToString ();
Expand Down
14 changes: 12 additions & 2 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ namespace Microsoft.Macios.Generator.DataModel;
/// </summary>
public string Type { get; } = string.Empty;

/// <summary>
/// Returns if the parameter type is a smart enum.
/// </summary>
public bool IsSmartEnum { get; }

/// <summary>
/// The platform availability of the property.
/// </summary>
Expand Down Expand Up @@ -67,12 +72,14 @@ namespace Microsoft.Macios.Generator.DataModel;
public ImmutableArray<Accessor> Accessors { get; } = [];

internal Property (string name, string type,
bool isSmartEnum,
SymbolAvailability symbolAvailability,
ImmutableArray<AttributeCodeChange> attributes,
ImmutableArray<SyntaxToken> modifiers, ImmutableArray<Accessor> accessors)
{
Name = name;
Type = type;
IsSmartEnum = isSmartEnum;
SymbolAvailability = symbolAvailability;
Attributes = attributes;
Modifiers = modifiers;
Expand All @@ -87,6 +94,8 @@ public bool Equals (Property other)
return false;
if (Type != other.Type)
return false;
if (IsSmartEnum != other.IsSmartEnum)
return false;
if (SymbolAvailability != other.SymbolAvailability)
return false;
if (ExportFieldData != other.ExportFieldData)
Expand Down Expand Up @@ -115,7 +124,7 @@ public override bool Equals (object? obj)
/// <inheritdoc />
public override int GetHashCode ()
{
return HashCode.Combine (Name, Type, Attributes, Modifiers, Accessors);
return HashCode.Combine (Name, Type, IsSmartEnum, Attributes, Modifiers, Accessors);
}

public static bool operator == (Property left, Property right)
Expand Down Expand Up @@ -169,6 +178,7 @@ public static bool TryCreate (PropertyDeclarationSyntax declaration, SemanticMod
change = new (
name: memberName,
type: type,
isSmartEnum: propertySymbol.Type.IsSmartEnum (),
symbolAvailability: propertySupportedPlatforms,
attributes: attributes,
modifiers: [.. declaration.Modifiers],
Expand All @@ -183,7 +193,7 @@ public static bool TryCreate (PropertyDeclarationSyntax declaration, SemanticMod
public override string ToString ()
{
var sb = new StringBuilder (
$"Name: '{Name}', Type: '{Type}', Supported Platforms: {SymbolAvailability}, ExportFieldData: '{ExportFieldData?.ToString () ?? "null"}', ExportPropertyData: '{ExportPropertyData?.ToString () ?? "null"}' Attributes: [");
$"Name: '{Name}', Type: '{Type}', IsSmartEnum: {IsSmartEnum}, Supported Platforms: {SymbolAvailability}, ExportFieldData: '{ExportFieldData?.ToString () ?? "null"}', ExportPropertyData: '{ExportPropertyData?.ToString () ?? "null"}' Attributes: [");
sb.AppendJoin (",", Attributes);
sb.Append ("], Modifiers: [");
sb.AppendJoin (",", Modifiers.Select (x => x.Text));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;
Expand Down Expand Up @@ -125,6 +126,29 @@ public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol)
return availability;
}

public static bool HasAttribute (this ISymbol symbol, string attribute)
{
var boundAttributes = symbol.GetAttributes ();
if (boundAttributes.Length == 0) {
return false;
}
foreach (var attributeData in boundAttributes) {
var attrName = attributeData.AttributeClass?.ToDisplayString ();
if (attrName == attribute) {
return true;
}
}
return false;
}

public static bool IsSmartEnum (this ITypeSymbol symbol)
{
// a type is a smart enum if its type is a enum one AND it was decorated with the
// binding type attribute
return symbol.TypeKind == TypeKind.Enum
&& symbol.HasAttribute (AttributesNames.BindingAttribute);
}

public static BindingTypeData GetBindingData (this ISymbol symbol)
{
var boundAttributes = symbol.GetAttributes ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ public partial class MyClass {
new (
name: "Name",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name"])
Expand All @@ -283,7 +284,121 @@ public partial class MyClass {
new (AccessorKind.Setter, new (), [], []),
]
) {
ExportPropertyData = new ("name")
}
]
}
];

const string singlePropertySmartEnumClass = @"
using ObjCBindings;
namespace NS;
[BindingType]
public enum MyEnum {
None = 0,
}
[BindingType<Class>]
public partial class MyClass {
[Export<Property> (""name"")]
public partial MyEnum Name { get; set; }
}
";

yield return [
singlePropertySmartEnumClass,
new CodeChanges (
bindingData: new (new BindingTypeData<Class> ()),
name: "MyClass",
@namespace: ["NS"],
fullyQualifiedSymbol: "NS.MyClass",
symbolAvailability: new ()
) {
Attributes = [
new ("ObjCBindings.BindingTypeAttribute<ObjCBindings.Class>")
],
UsingDirectives = new HashSet<string> { "ObjCBindings" },
Modifiers = [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword)
],
Properties = [
new (
name: "Name",
type: "NS.MyEnum",
isSmartEnum: true,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name"])
],
modifiers: [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword),
],
accessors: [
new (AccessorKind.Getter, new (), [], []),
new (AccessorKind.Setter, new (), [], []),
]
) {
ExportPropertyData = new ("name")
}
]
}
];

const string singlePropertyEnumClass = @"
using ObjCBindings;
namespace NS;
public enum MyEnum {
None = 0,
}
[BindingType<Class>]
public partial class MyClass {
[Export<Property> (""name"")]
public partial MyEnum Name { get; set; }
}
";

yield return [
singlePropertyEnumClass,
new CodeChanges (
bindingData: new (new BindingTypeData<Class> ()),
name: "MyClass",
@namespace: ["NS"],
fullyQualifiedSymbol: "NS.MyClass",
symbolAvailability: new ()
) {
Attributes = [
new ("ObjCBindings.BindingTypeAttribute<ObjCBindings.Class>")
],
UsingDirectives = new HashSet<string> { "ObjCBindings" },
Modifiers = [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword)
],
Properties = [
new (
name: "Name",
type: "NS.MyEnum",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name"])
],
modifiers: [
SyntaxFactory.Token (SyntaxKind.PublicKeyword),
SyntaxFactory.Token (SyntaxKind.PartialKeyword),
],
accessors: [
new (AccessorKind.Getter, new (), [], []),
new (AccessorKind.Setter, new (), [], []),
]
) {
ExportPropertyData = new ("name")
}
]
Expand Down Expand Up @@ -323,6 +438,7 @@ public partial class MyClass {
new (
name: "Name",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name", "ObjCBindings.Property.Notification"])
Expand Down Expand Up @@ -376,6 +492,7 @@ public partial class MyClass {
new (
name: "Name",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Field>", ["CONSTANT"])
Expand Down Expand Up @@ -432,6 +549,7 @@ public partial class MyClass {
new (
name: "Name",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name"])
Expand Down Expand Up @@ -487,6 +605,7 @@ public partial class MyClass {
new (
name: "Name",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["name"])
Expand All @@ -505,6 +624,7 @@ public partial class MyClass {
new (
name: "Surname",
type: "string",
isSmartEnum: false,
symbolAvailability: new (),
attributes: [
new ("ObjCBindings.ExportAttribute<ObjCBindings.Property>", ["surname"])
Expand Down
Loading

9 comments on commit a0ac2c8

@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

This comment was marked as outdated.

Please sign in to comment.