diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj
index ca1f355f8e9d..750d7b795410 100644
--- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj
+++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj
@@ -69,6 +69,9 @@
Generator/Extensions/TypeSymbolExtensions.Core.cs
+
+ Generator/Extensions/TypeSymbolExtensions.Generator.cs
+
Generator/Extensions/TypedConstantExtensions.cs
diff --git a/src/rgen/Microsoft.Macios.Generator/Attributes/SupportedOSPlatformData.cs b/src/rgen/Microsoft.Macios.Generator/Attributes/SupportedOSPlatformData.cs
index 35d0a168b6e2..df1897f04a3c 100644
--- a/src/rgen/Microsoft.Macios.Generator/Attributes/SupportedOSPlatformData.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Attributes/SupportedOSPlatformData.cs
@@ -28,6 +28,12 @@ internal SupportedOSPlatformData (string platformName)
(Platform, Version) = platformName.GetPlatformAndVersion ();
}
+ internal SupportedOSPlatformData (ApplePlatform platform, Version version)
+ {
+ Platform = platform;
+ Version = version;
+ }
+
///
/// Try to parse the attribute data to retrieve the information of an SupportedOSPlatformAttribute.
///
diff --git a/src/rgen/Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs b/src/rgen/Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs
index cdf39b7b59a8..72b2ca9ea549 100644
--- a/src/rgen/Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs
@@ -34,6 +34,12 @@ internal UnsupportedOSPlatformData (string platformName)
(Platform, Version) = platformName.GetPlatformAndVersion ();
}
+ internal UnsupportedOSPlatformData (ApplePlatform platform)
+ {
+ Platform = platform;
+ Version = new Version ();
+ }
+
internal UnsupportedOSPlatformData (string platformName, string? message = null) : this (platformName)
{
Message = message;
diff --git a/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs b/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs
index da94d3bf971a..798d932436c5 100644
--- a/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs
@@ -150,6 +150,7 @@ public bool Equals (PlatformAvailability other)
var obsoleteComparer = new DictionaryComparer ();
var unsupportedComparer = new DictionaryComparer ();
+ var x = Equals (SupportedVersion, other.SupportedVersion);
return Platform == other.Platform &&
Equals (SupportedVersion, other.SupportedVersion) &&
unsupportedComparer.Equals (unsupported, other.unsupported) &&
diff --git a/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailabilityBuilder.cs b/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailabilityBuilder.cs
index c606e858c0e2..320a4eefcaf6 100644
--- a/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailabilityBuilder.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailabilityBuilder.cs
@@ -22,6 +22,18 @@ public sealed class Builder {
internal Builder () { }
+ ///
+ /// Return the immutable version of the current data in the builder.
+ ///
+ public IEnumerable PlatformAvailabilities {
+ get {
+ // return the immutable version of the builder data
+ foreach (var availability in platforms.Values) {
+ yield return availability.ToImmutable ();
+ }
+ }
+ }
+
///
/// Returns the PlatformAvailability for the given platform. If we did not have a builder for the
/// platform, a new one is created and added to the dictionary.
diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs
index fcc378661967..05b51420c114 100644
--- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs
@@ -7,6 +7,7 @@
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
+using Microsoft.Macios.Generator.Availability;
namespace Microsoft.Macios.Generator.Extensions;
@@ -236,4 +237,23 @@ public static void GetInheritance (
parents = parentsBuilder.ToImmutable ();
interfaces = [.. interfacesSet];
}
+
+ ///
+ /// Returns the symbol availability taking into account the parent symbols availability.
+ ///
+ /// That means that the attributes used on the current symbol are merged with the attributes used
+ /// in all the symbol parents following the correct child-parent order.
+ ///
+ /// The symbol whose availability we want to retrieve.
+ /// A symbol availability structure for the symbol.
+ public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol)
+ {
+ var availability = GetAvailabilityForSymbol (symbol);
+ // get the parents and return the merge
+ foreach (var parent in GetParents (symbol)) {
+ availability = availability.MergeWithParent (GetAvailabilityForSymbol (parent));
+ }
+
+ return availability;
+ }
}
diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs
index 70d64b650396..ccc7e64fec6c 100644
--- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs
+++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs
@@ -58,26 +58,7 @@ static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol)
return builder.ToImmutable ();
}
-
- ///
- /// Returns the symbol availability taking into account the parent symbols availability.
- ///
- /// That means that the attributes used on the current symbol are merged with the attributes used
- /// in all the symbol parents following the correct child-parent order.
- ///
- /// The symbol whose availability we want to retrieve.
- /// A symbol availability structure for the symbol.
- public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol)
- {
- var availability = GetAvailabilityForSymbol (symbol);
- // get the parents and return the merge
- foreach (var parent in GetParents (symbol)) {
- availability = availability.MergeWithParent (GetAvailabilityForSymbol (parent));
- }
-
- return availability;
- }
-
+
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
diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/XamarinAvailabilityData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/XamarinAvailabilityData.cs
new file mode 100644
index 000000000000..b58682ff5f75
--- /dev/null
+++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/XamarinAvailabilityData.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.CodeAnalysis;
+using Microsoft.Macios.Generator.Attributes;
+using Xamarin.Utils;
+
+namespace Microsoft.Macios.Transformer.Attributes;
+
+static class XamarinAvailabilityData {
+
+ static readonly IReadOnlyDictionary supportedAttributes = new Dictionary {
+ { AttributesNames.iOSAttribute, ApplePlatform.iOS },
+ { AttributesNames.TVAttribute, ApplePlatform.TVOS },
+ { AttributesNames.MacAttribute, ApplePlatform.MacOSX },
+ { AttributesNames.MacCatalystAttribute, ApplePlatform.MacCatalyst },
+ };
+
+ static readonly IReadOnlyDictionary unsupportedAttributes = new Dictionary {
+ { AttributesNames.NoiOSAttribute, ApplePlatform.iOS },
+ { AttributesNames.NoTVAttribute, ApplePlatform.TVOS },
+ { AttributesNames.NoMacAttribute, ApplePlatform.MacOSX },
+ { AttributesNames.NoMacCatalystAttribute, ApplePlatform.MacCatalyst },
+ };
+
+ public static bool TryParseSupportedOSData (string attributeName, AttributeData attributeData,
+ [NotNullWhen (true)] out SupportedOSPlatformData? data)
+ {
+ data = null;
+ if (!supportedAttributes.TryGetValue (attributeName, out var platform)) {
+ // not a supported attribute
+ return false;
+ }
+
+ var count = attributeData.ConstructorArguments.Length;
+ int major = 0;
+ int? minor = null;
+ int? subminor = null;
+
+ // custom marshal directive values
+
+ switch (count) {
+ case 1:
+ major = (byte) attributeData.ConstructorArguments [0].Value!;
+ break;
+ case 2:
+ major = (byte) attributeData.ConstructorArguments [0].Value!;
+ minor = (byte) attributeData.ConstructorArguments [1].Value!;
+ break;
+ case 3:
+ major = (byte) attributeData.ConstructorArguments [0].Value!;
+ minor = (byte) attributeData.ConstructorArguments [1].Value!;
+ subminor = (byte) attributeData.ConstructorArguments [2].Value!;
+ break;
+ default:
+ // 0 should not be an option..
+ return false;
+ }
+
+ data = (major, minor, subminor) switch {
+ (_, null, null) => new(platform, new($"{major}")),
+ (_, not null, null) => new(platform, new(major, minor.Value)),
+ (_,not null, not null) => new(platform, new(major, minor.Value, subminor.Value)),
+ _ => throw new ArgumentOutOfRangeException ("Could not parse the version")
+ };
+ return true;
+ }
+
+ public static bool TryParseUnsupportedOSData (string attributeName, AttributeData attributeData,
+ [NotNullWhen (true)] out UnsupportedOSPlatformData? data)
+ {
+ data = null;
+ if (!unsupportedAttributes.TryGetValue (attributeName, out var platform)) {
+ // not a supported attribute
+ return false;
+ }
+
+ data = new UnsupportedOSPlatformData (platform);
+ return true;
+ }
+}
diff --git a/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs
index 0b1b6a70cb97..f6062e68bd21 100644
--- a/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs
+++ b/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs
@@ -1,12 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
+using Microsoft.Macios.Generator.Attributes;
+using Microsoft.Macios.Generator.Availability;
+using Microsoft.Macios.Transformer.Attributes;
+using Xamarin.Utils;
namespace Microsoft.Macios.Generator.Extensions;
static partial class TypeSymbolExtensions {
+ static readonly ImmutableArray allSupportedPlatforms = [
+ ApplePlatform.iOS,
+ ApplePlatform.TVOS,
+ ApplePlatform.MacOSX,
+ ApplePlatform.MacCatalyst
+ ];
+
+ ///
+ /// Return the symbol availability WITHOUT taking into account the parent symbols availability.
+ ///
+ /// The symbols whose availability attributes we want to retrieve.
+ /// The symbol availability WITHOUT taking into account the parent symbols.
+ /// This is a helper method, you probably don't want to use it.
+ internal static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol)
+ {
+ //get the attribute of the symbol and look for the Supported and Unsupported attributes and
+ // add the different platforms to the result hashsets
+ var builder = SymbolAvailability.CreateBuilder ();
+ var boundAttributes = symbol.GetAttributes ();
+ if (boundAttributes.Length == 0) {
+ // no attrs in the symbol, therefore the symbol is supported in all platforms
+ return builder.ToImmutable ();
+ }
+
+ foreach (var attributeData in boundAttributes) {
+ var attrName = attributeData.AttributeClass?.ToDisplayString ();
+ if (string.IsNullOrEmpty (attrName))
+ continue;
+
+ if (XamarinAvailabilityData.TryParseSupportedOSData (attrName, attributeData, out var availabilityData)) {
+ builder.Add (availabilityData.Value);
+ }
+
+ if (XamarinAvailabilityData.TryParseUnsupportedOSData (attrName, attributeData,
+ out var unsupportedOsPlatformData)) {
+ builder.Add (unsupportedOsPlatformData.Value);
+ }
+ }
+
+ // if a platform was not ignore or had a specific version, then it is supported, loop over what we got
+ // and add the missing platforms with the default version
+ var supportedPlatforms = builder.PlatformAvailabilities.ToArray ()
+ .Select (a => a.Platform);
+
+ // add data to all not added platforms
+ foreach (var platform in allSupportedPlatforms.Except (supportedPlatforms)) {
+ builder.Add (new SupportedOSPlatformData(platform, new Version()));
+ }
+
+ return builder.ToImmutable ();
+ }
+
public static bool IsSmartEnum (this ITypeSymbol symbol)
{
throw new NotImplementedException ();
diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/AvailabilityTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/AvailabilityTests.cs
new file mode 100644
index 000000000000..4800b0823d04
--- /dev/null
+++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/AvailabilityTests.cs
@@ -0,0 +1,147 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.Macios.Generator.Attributes;
+using Microsoft.Macios.Generator.Availability;
+using Microsoft.Macios.Generator.Extensions;
+using Xamarin.Tests;
+using Xamarin.Utils;
+
+namespace Microsoft.Macios.Transformer.Tests.Attributes;
+
+public class AvailabilityTests : BaseTransformerTestClass {
+ class TestDataTryCreate : IEnumerable