Skip to content

Commit

Permalink
[RGen] Update the changes data structure to take in to account proper…
Browse files Browse the repository at this point in the history
…ties. (#21680)

Add all the needed structure to track changes in properies we want to
generate. This is similar to what we did with enum values, we want to
make sure that we detect any of the possible changes in a propery:

1. Modifier changed.
2. Return type changed
3. Name changed.
4. Attrs changed.
5. Accessors changed;
6. Attrs in accessors changed.
7. Modifiers in accessors changed.

Also update the co

---------

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
  • Loading branch information
mandel-macaque and GitHub Actions Autoformatter authored Nov 25, 2024
1 parent f36102a commit 3fcb5b3
Show file tree
Hide file tree
Showing 34 changed files with 2,211 additions and 192 deletions.
78 changes: 78 additions & 0 deletions src/ObjCBindings/ExportAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using ObjCRuntime;
using Registrar;

#nullable enable

namespace ObjCBindings {

[Experimental ("APL0003")]
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
public class ExportAttribute<T> : Attribute where T : Enum {

/// <summary>
/// Get/Set the selector that is expoed by the decorated method.
/// </summary >
public string? Selector { get; set; } = null;

/// <summary>
/// Get/Set the export configuration flags.
/// </summary >
public T? Flags { get; set; } = default (T);

/// <summary>
/// Get/Set the argment sematics to be used with the native method.
/// </summary >
public ArgumentSemantic ArgumentSemantic { get; set; } = ArgumentSemantic.None;

protected ExportAttribute () { }

/// <summary>
/// Mark a managed method as a exported selector.
/// </summary >
/// <param name="selector">The native selector to be exported.</param>
public ExportAttribute (string? selector)
{
Selector = selector;
}

/// <summary>
/// Mark a managed method as a exported selector.
/// </summary >
/// <param name="selector">The native selector to be exported.</param>
/// <param name="semantic">The argument semantics to use when callinb the native selector.</param>
public ExportAttribute (string? selector, ArgumentSemantic semantic)
{
Selector = selector;
ArgumentSemantic = semantic;
Flags = default (T);
}

/// <summary>
/// Mark a managed method as a exported selector.
/// </summary >
/// <param name="selector">The native selector to be exported.</param>
/// <param name="flags">The configuration flags for the managed mathod."</param>
public ExportAttribute (string? selector, T? flags)
{
Selector = selector;
ArgumentSemantic = ArgumentSemantic.None;
Flags = flags;
}

/// <summary>
/// Mark a managed method as a exported selector.
/// </summary >
/// <param name="selector">The native selector to be exported.</param>
/// <param name="semantic">The argument semantics to use when callinb the native selector.</param>
/// <param name="flags">The configuration flags for the managed mathod."</param>
public ExportAttribute (string? selector, ArgumentSemantic semantic, T? flags)
{
Selector = selector;
ArgumentSemantic = semantic;
Flags = flags;
}
}
}
73 changes: 73 additions & 0 deletions src/ObjCBindings/ExportTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Diagnostics.CodeAnalysis;

#nullable enable

namespace ObjCBindings {

/// <summary>
/// Flags to be used on methods that will generate constructors in the binding class.
/// </summary>
[Flags]
public enum Constructor : Int64 {
/// <summary>
/// Use the default values.
/// </summary>
Default = 0,

/// <summary>
/// Map to Objective-C/clang use of __attribute__((objc_designated_initializer)).
/// </summary>
DesignatedInitializer = 1 << 2,
}

/// <summary>
/// Flgs to be used in general bound methods.
/// </summary>
[Flags]
public enum Method : Int64 {
/// <summary>
/// Use the default values.
/// </summary>
Default = 0,

/// <summary>
/// Method access a variable number of args.
/// </summary>
IsVariadic = 1 << 2,

/// <summary>
/// Instruct the generator to avoid the generation of any method decorated with it in a Model.
/// </summary>
IgnoredInDelegate = 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,

}

/// <summary>
/// Flags to be used on properties.
/// </summary>
[Flags]
public enum Property : Int64 {
/// <summary>
/// Use the default values.
/// </summary>
Default = 0,

/// <summary>
/// The backing field for a property to be annotated with the .NET [ThreadStatic] attribute.
/// </summary>
IsThreadStaticAttribute = 1 << 2,

/// <summary>
/// Generate a notification for the property.
/// </summary>
Notification = 1 << 3,
}
}

2 changes: 2 additions & 0 deletions src/frameworks.sources
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,8 @@ SHARED_CORE_SOURCES = \
MinimumVersions.cs \
MonoPInvokeCallbackAttribute.cs \
ObjCBindings/BindingTypeAttribute.cs \
ObjCBindings/ExportAttribute.cs \
ObjCBindings/ExportTag.cs \
ObjCBindings/FieldAttribute.cs \
ObjCBindings/FieldTag.cs \
ObjCRuntime/ArgumentSemantic.cs \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
<Compile Include="..\..\bgen\PlatformName.cs" >
<Link>external\PlatformName.cs</Link>
</Compile>
<Compile Include="..\..\ObjCRuntime\ArgumentSemantic.cs">
<Link>external\ArgumentSemantic.cs</Link>
</Compile>
<Compile Include="..\..\ObjCBindings\ExportTag.cs" >
<Link>external\ExportTag.cs</Link>
</Compile>
<Compile Include="..\..\ObjCBindings\FieldTag.cs">
<Link>external\FieldTag.cs</Link>
</Compile>
Expand Down
117 changes: 117 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/Attributes/ExportData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using ObjCRuntime;

namespace Microsoft.Macios.Generator.Attributes;

/// <summary>
/// Represents the data found in an ExportAttribute&lt;T&gt;
/// </summary>
/// <typeparam name="T">The configuration flags used on the exported element.</typeparam>
readonly struct ExportData<T> where T : Enum {

/// <summary>
/// The exported native selector.
/// </summary>
public string? Selector { get; }

/// <summary>
/// The configuration flags used on the exported member.
/// </summary>
public T? Flags { get; }

/// <summary>
/// Argument semantics to use with the selector.
/// </summary>
public ArgumentSemantic ArgumentSemantic { get; } = ArgumentSemantic.None;

public ExportData () { }

public ExportData (string? selector)
{
Selector = selector;
}

public ExportData (string? selector, ArgumentSemantic argumentSemantic)
{
Selector = selector;
ArgumentSemantic = argumentSemantic;
}

public ExportData (string? selector, ArgumentSemantic argumentSemantic, T flags)
{
Selector = selector;
ArgumentSemantic = argumentSemantic;
Flags = flags;
}

/// <summary>
/// Try to parse the attribute data to retrieve the information of an ExportAttribute&lt;T&gt;.
/// </summary>
/// <param name="attributeData">The attribute data to be parsed.</param>
/// <param name="data">The parsed data. Null if we could not parse the attribute data.</param>
/// <returns>True if the data was parsed.</returns>
public static bool TryParse (AttributeData attributeData,
[NotNullWhen (true)] out ExportData<T>? data)
{
data = null;
var count = attributeData.ConstructorArguments.Length;
string? selector = null;
ArgumentSemantic argumentSemantic = ArgumentSemantic.None;
T? flags = default;
switch (count) {
case 1:
data = new ((string?) attributeData.ConstructorArguments [0].Value!);
break;
case 2:
// there are two possible cases in this situation.
// 1. The second argument is an ArgumentSemantic
// 2. The second argument is a T
if (attributeData.ConstructorArguments [1].Value is ArgumentSemantic) {
selector = (string?) attributeData.ConstructorArguments [0].Value!;
argumentSemantic = (ArgumentSemantic) attributeData.ConstructorArguments [1].Value!;
} else {
selector = (string?) attributeData.ConstructorArguments [0].Value!;
argumentSemantic = ArgumentSemantic.None;
flags = (T) attributeData.ConstructorArguments [1].Value!;
}
break;
case 3:
selector = (string?) attributeData.ConstructorArguments [9].Value!;
argumentSemantic = (ArgumentSemantic) attributeData.ConstructorArguments [1].Value!;
flags = (T) attributeData.ConstructorArguments [2].Value!;
break;
default:
// 0 should not be an option..
return false;
}

if (attributeData.NamedArguments.Length == 0) {
data = flags is not null ?
new (selector, argumentSemantic, flags) : new (selector, argumentSemantic);
return true;
}

foreach (var (name, value) in attributeData.NamedArguments) {
switch (name) {
case "Selector":
selector = (string?) value.Value!;
break;
case "ArgumentSemantic":
argumentSemantic = (ArgumentSemantic) value.Value!;
break;
case "Flags":
flags = (T) value.Value!;
break;
default:
data = null;
return false;
}
}

data = flags is not null ?
new (selector, argumentSemantic, flags) : new (selector, argumentSemantic);
return true;
}
}
2 changes: 2 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/AttributesNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public static class AttributesNames {
public const string BindingAttribute = "ObjCBindings.BindingTypeAttribute";
public const string FieldAttribute = "ObjCBindings.FieldAttribute";
public const string EnumFieldAttribute = "ObjCBindings.FieldAttribute<ObjCBindings.EnumValue>";
public const string ExportFieldAttribute = "ObjCBindings.ExportAttribute<ObjCBindings.Field>";
public const string ExportPropertyAttribute = "ObjCBindings.ExportAttribute<ObjCBindings.Property>";
public const string SupportedOSPlatformAttribute = "System.Runtime.Versioning.SupportedOSPlatformAttribute";
public const string UnsupportedOSPlatformAttribute = "System.Runtime.Versioning.UnsupportedOSPlatformAttribute";
public const string ObsoletedOSPlatformAttribute = "System.Runtime.Versioning.ObsoletedOSPlatformAttribute";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void Initialize (IncrementalGeneratorInitializationContext context)
return (default, false);
}

var codeChanges = CodeChanges.FromDeclaration (context.SemanticModel, declarationSyntax);
var codeChanges = CodeChanges.FromDeclaration (declarationSyntax, context.SemanticModel);
// if code changes are null, return the default value and a false to later ignore the change
return codeChanges is not null ? (codeChanges.Value, isBindingType) : (default, false);
}
Expand Down
27 changes: 27 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/AccessorKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.CodeAnalysis.CSharp;

namespace Microsoft.Macios.Generator.DataModel;

/// <summary>
/// Identifies the kind of accessor of a property.
/// </summary>
enum AccessorKind {
Unknown = 0,
Getter,
Setter,
Initializer,
Add,
Remove,
}

static class AccessorKindExtensions {

public static AccessorKind ToAccessorKind (this SyntaxKind self) => self switch {
SyntaxKind.GetAccessorDeclaration => AccessorKind.Getter,
SyntaxKind.SetAccessorDeclaration => AccessorKind.Setter,
SyntaxKind.InitAccessorDeclaration => AccessorKind.Initializer,
SyntaxKind.AddAccessorDeclaration => AccessorKind.Add,
SyntaxKind.RemoveAccessorDeclaration => AccessorKind.Remove,
_ => AccessorKind.Unknown,
};
}
Loading

5 comments on commit 3fcb5b3

@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] Windows Integration Tests passed 💻

All Windows Integration Tests passed.

Pipeline on Agent
Hash: 3fcb5b31698c943dec43cdf058281f8516df8c12 [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] Tests on macOS M1 - Mac Monterey (12) passed 💻

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

Pipeline on Agent
Hash: 3fcb5b31698c943dec43cdf058281f8516df8c12 [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.

✅ API diff for current PR / commit

.NET (No breaking changes)

✅ API diff vs stable

.NET (No breaking changes)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 3fcb5b31698c943dec43cdf058281f8516df8c12 [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] Tests on macOS X64 - Mac Sonoma (14) passed 💻

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

Pipeline on Agent
Hash: 3fcb5b31698c943dec43cdf058281f8516df8c12 [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] Tests on macOS M1 - Mac Ventura (13) passed 💻

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

Pipeline on Agent
Hash: 3fcb5b31698c943dec43cdf058281f8516df8c12 [CI build]

Please sign in to comment.