Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ internal void AddUnsupportedVersion (Version version, string? message)
if (unsupported.ContainsKey (defaultVersion))
return;
unsupported [version] = message;
// we need to ensure that if we unsupported a version that the supported version is not null, if
// it is, we need to set it to the version before the unsupported one
if (supportedVersion is null) {
supportedVersion = defaultVersion;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ public SymbolAvailability MergeWithParent (SymbolAvailability? parent)
return new (merged);
}

/// <summary>
/// Returns true if the symbol is supported in the given platform.
/// </summary>
public bool IsSupported (ApplePlatform platform)
{
// if the platform is not present, it is supported by default
var availability = this [platform];
return availability is null || availability.Value.IsSupported;
}

/// <inheritdoc />
public bool Equals (SymbolAvailability other)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.Macios.Generator.Availability;
using Microsoft.Macios.Generator.Context;
using Microsoft.Macios.Generator.Extensions;
using Xamarin.Utils;

namespace Microsoft.Macios.Generator.DataModel;

Expand Down Expand Up @@ -263,7 +264,7 @@ internal static bool Skip (MethodDeclarationSyntax methodDeclarationSyntax, Sema
/// <param name="fullyQualifiedSymbol">The fully qualified name of the symbol.</param>
/// <param name="symbolAvailability">The platform availability of the named symbol.</param>
internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @namespace,
string fullyQualifiedSymbol, SymbolAvailability symbolAvailability)
string fullyQualifiedSymbol, SymbolAvailability symbolAvailability) : this (StructState.Initialized)
{
this.bindingInfo = bindingInfo;
this.name = name;
Expand All @@ -278,7 +279,8 @@ internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @
/// <param name="enumDeclaration">The enum declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
/// <param name="validateMembers">If the struct should validate the members from the declarations. Defaults to true.</param>
Binding (EnumDeclarationSyntax enumDeclaration, RootContext context, bool validateMembers = true)
Binding (EnumDeclarationSyntax enumDeclaration, RootContext context,
bool validateMembers = true) : this (StructState.Initialized)
{
context.SemanticModel.GetSymbolData (
declaration: enumDeclaration,
Expand Down Expand Up @@ -346,7 +348,8 @@ internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @
/// <param name="classDeclaration">The class declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
/// <param name="validateMembers">If the struct should validate the members from the declarations. Defaults to true.</param>
Binding (ClassDeclarationSyntax classDeclaration, RootContext context, bool validateMembers = true)
Binding (ClassDeclarationSyntax classDeclaration, RootContext context,
bool validateMembers = true) : this (StructState.Initialized)
{
context.SemanticModel.GetSymbolData (
declaration: classDeclaration,
Expand Down Expand Up @@ -392,7 +395,8 @@ internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @
/// <param name="interfaceDeclaration">The interface declaration that triggered the change.</param>
/// <param name="context">The root binding context of the current compilation.</param>
/// <param name="validateMembers">If the struct should validate the members from the declarations. Defaults to true.</param>
Binding (InterfaceDeclarationSyntax interfaceDeclaration, RootContext context, bool validateMembers = true)
Binding (InterfaceDeclarationSyntax interfaceDeclaration, RootContext context,
bool validateMembers = true) : this (StructState.Initialized)
{
context.SemanticModel.GetSymbolData (
declaration: interfaceDeclaration,
Expand Down Expand Up @@ -471,6 +475,7 @@ internal Binding (BindingInfo bindingInfo, string name, ImmutableArray<string> @
public override string ToString ()
{
var sb = new StringBuilder ("Changes: {");
sb.Append ($"State: {State}, ");
sb.Append ($"BindingData: '{BindingInfo}', Name: '{Name}', Namespace: [");
sb.AppendJoin (", ", Namespace);
sb.Append ($"], FullyQualifiedSymbol: '{FullyQualifiedSymbol}', Base: '{Base ?? "null"}', SymbolAvailability: {SymbolAvailability}, ");
Expand Down
58 changes: 58 additions & 0 deletions src/rgen/Microsoft.Macios.Generator/DataModel/Binding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;
using Microsoft.Macios.Generator.Context;
using Xamarin.Utils;

namespace Microsoft.Macios.Generator.DataModel;

Expand All @@ -21,6 +23,22 @@ namespace Microsoft.Macios.Generator.DataModel;
[StructLayout (LayoutKind.Auto)]
readonly partial struct Binding {

/// <summary>
/// The initialization state of the struct.
/// </summary>
StructState State { get; init; } = StructState.Default;


/// <summary>
/// Gets the default, uninitialized instance of <see cref="ExportData{T}"/>.
/// </summary>
public static Binding Default { get; } = new (StructState.Default);

/// <summary>
/// Gets a value indicating whether the instance is the default, uninitialized instance.
/// </summary>
public bool IsNullOrDefault => State == StructState.Default;

readonly string name = string.Empty;
/// <summary>
/// The name of the named type that generated the code change.
Expand Down Expand Up @@ -417,4 +435,44 @@ public bool TryGetEvent (string selector, out Event? @event)
/// <returns>True if the method was found. False otherwise.</returns>
public bool TryGetMethod (string selector, out Method? method)
=> TryGetFromIndex (selector, methods, methodIndex, out method);

/// <summary>
/// Initializes a new instance of the <see cref="Binding"/> struct with a specific state.
/// </summary>
/// <param name="state">The initialization state of the struct.</param>
public Binding (StructState state)
{
State = state;
FullyQualifiedSymbol = string.Empty;
}

/// <summary>
/// Creates a new binding containing only the members available for a specific platform.
/// </summary>
/// <param name="platform">The Apple platform to filter members for.</param>
/// <returns>
/// A new <see cref="Binding"/> instance with members filtered for the specified platform,
/// or the default binding if the type itself is not available on the platform.
/// </returns>
public Binding TrimForPlatform (ApplePlatform platform)
{
// if the binding is not available in the given platform, return an empty binding
if (!SymbolAvailability.IsSupported (platform))
return Default;

// collect all the different members that we are going to keep and return the same data but
// without those members that are not available in the given platform
return this with {
EnumMembers = [.. enumMembers.Where (m => m.SymbolAvailability.IsSupported (platform))],
Properties = [.. properties.Where (p => p.SymbolAvailability.IsSupported (platform))],
ParentProtocolProperties = [.. parentProperties.Where (p => p.SymbolAvailability.IsSupported (platform))],
StrongDictionaryProperties = [.. strongDictproperties.Where (p => p.SymbolAvailability.IsSupported (platform))],
Constructors = [.. constructors.Where (c => c.SymbolAvailability.IsSupported (platform))],
Events = [.. events.Where (e => e.SymbolAvailability.IsSupported (platform))],
Methods = [.. methods.Where (m => m.SymbolAvailability.IsSupported (platform))],
ParentProtocolMethods = [.. parentMethods.Where (m => m.SymbolAvailability.IsSupported (platform))],
};

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal Binding (string name,
string fullyQualifiedSymbol,
BindingInfo bindingInfo,
SymbolAvailability symbolAvailability,
Dictionary<string, List<AttributeData>> attributes)
Dictionary<string, List<AttributeData>> attributes) : this (StructState.Initialized)
{
this.name = name;
namespaces = @namespace;
Expand All @@ -67,7 +67,8 @@ internal Binding (string name,
FullyQualifiedSymbol = fullyQualifiedSymbol;
}

internal Binding (EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol symbol, in RootContext context)
internal Binding (EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol symbol,
in RootContext context) : this (StructState.Initialized)
{
SemanticModelExtensions.GetSymbolData (
symbol: symbol,
Expand Down Expand Up @@ -269,7 +270,8 @@ internal static bool Skip (MethodDeclarationSyntax methodDeclarationSyntax, Sema
/// <param name="interfaceDeclarationSyntax">An interface that declares a binding.</param>
/// <param name="symbol"></param>
/// <param name="context">The current compilation context.</param>
internal Binding (InterfaceDeclarationSyntax interfaceDeclarationSyntax, INamedTypeSymbol symbol, in RootContext context)
internal Binding (InterfaceDeclarationSyntax interfaceDeclarationSyntax, INamedTypeSymbol symbol,
in RootContext context) : this (StructState.Initialized)
{
BaseDeclarationSyntax = interfaceDeclarationSyntax;
// basic properties of the binding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public void UnsupportPlatform (ApplePlatform platform, string attributePlatformN
Assert.Contains (defaultVersion, availability.UnsupportedVersions.Keys);
Assert.Single (availability.UnsupportedVersions);
Assert.Null (availability.UnsupportedVersions [defaultVersion]);
Assert.Null (availability.SupportedVersion);
}

[Theory]
Expand All @@ -129,6 +130,7 @@ public void UnsupportPlatformWithMessage (ApplePlatform platform, string attribu
Assert.Contains (defaultVersion, availability.UnsupportedVersions.Keys);
Assert.Single (availability.UnsupportedVersions);
Assert.Equal (message, availability.UnsupportedVersions [defaultVersion]);
Assert.Null (availability.SupportedVersion);
}

[Theory]
Expand All @@ -150,6 +152,8 @@ public void UnsupportVersionAndPlatform (ApplePlatform platform, string attribut
Assert.Contains (defaultVersion, availability.UnsupportedVersions.Keys);
Assert.Single (availability.UnsupportedVersions);
Assert.Equal (message, availability.UnsupportedVersions [defaultVersion]);
// we fully unsupported the platform
Assert.Null (availability.SupportedVersion);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ public IEnumerator<object []> GetEnumerator ()

builder.Clear ();
builder.AddUnsupportedVersion (new Version (16, 0), null);
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '', Unsupported: ['16.0': 'null'], Obsoleted: [] }"];
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '0.0', Unsupported: ['16.0': 'null'], Obsoleted: [] }"];

builder.Clear ();
builder.AddUnsupportedVersion (new Version (16, 0), "Not supported.");
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '', Unsupported: ['16.0': 'Not supported.'], Obsoleted: [] }"];
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '0.0', Unsupported: ['16.0': 'Not supported.'], Obsoleted: [] }"];

builder.Clear ();
builder.AddUnsupportedVersion (new Version (16, 0), "Not supported.");
builder.AddUnsupportedVersion (new Version (18, 0), "Not supported.");
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '', Unsupported: ['16.0': 'Not supported.', '18.0': 'Not supported.'], Obsoleted: [] }"];
yield return [builder.ToImmutable (), "{ Platform: 'iOS', Supported: '0.0', Unsupported: ['16.0': 'Not supported.', '18.0': 'Not supported.'], Obsoleted: [] }"];

builder.Clear ();
builder.AddObsoletedVersion (new Version (16, 0), null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public IEnumerator<object []> GetEnumerator ()
builder.AddSupportedVersion (ApplePlatform.iOS, new (16, 0));
builder.AddUnsupportedVersion (ApplePlatform.MacOSX, new (11, 0), null);
builder.AddSupportedVersion (ApplePlatform.MacCatalyst, new (16, 0));
yield return [builder.ToImmutable (), "[{ Platform: 'MacOSX', Supported: '', Unsupported: ['11.0': 'null'], Obsoleted: [] }, { Platform: 'iOS', Supported: '16.0', Unsupported: [], Obsoleted: [] }, { Platform: 'MacCatalyst', Supported: '16.0', Unsupported: [], Obsoleted: [] }]"];
yield return [builder.ToImmutable (), "[{ Platform: 'MacOSX', Supported: '0.0', Unsupported: ['11.0': 'null'], Obsoleted: [] }, { Platform: 'iOS', Supported: '16.0', Unsupported: [], Obsoleted: [] }, { Platform: 'MacCatalyst', Supported: '16.0', Unsupported: [], Obsoleted: [] }]"];
}

IEnumerator IEnumerable.GetEnumerator ()
Expand Down
Loading
Loading