Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rgen] Add support to the transformer to parse the old xamarin availability. #22023

Open
wants to merge 3 commits into
base: dev/mandel/use-apidefinitions-transformer-tests
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs">
<Link>Generator/Extensions/TypeSymbolExtensions.Core.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs">
<Link>Generator/Extensions/TypeSymbolExtensions.Generator.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypedConstantExtensions.cs" >
<Link>Generator/Extensions/TypedConstantExtensions.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ internal SupportedOSPlatformData (string platformName)
(Platform, Version) = platformName.GetPlatformAndVersion ();
}

internal SupportedOSPlatformData (ApplePlatform platform, Version version)
{
Platform = platform;
Version = version;
}

/// <summary>
/// Try to parse the attribute data to retrieve the information of an SupportedOSPlatformAttribute.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public bool Equals (PlatformAvailability other)
var obsoleteComparer = new DictionaryComparer<Version, (string?, string?)> ();
var unsupportedComparer = new DictionaryComparer<Version, string?> ();

var x = Equals (SupportedVersion, other.SupportedVersion);
return Platform == other.Platform &&
Equals (SupportedVersion, other.SupportedVersion) &&
unsupportedComparer.Equals (unsupported, other.unsupported) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ public sealed class Builder {

internal Builder () { }

/// <summary>
/// Return the immutable version of the current data in the builder.
/// </summary>
public IEnumerable<PlatformAvailability> PlatformAvailabilities {
get {
// return the immutable version of the builder data
foreach (var availability in platforms.Values) {
yield return availability.ToImmutable ();
}
}
}

/// <summary>
/// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.Macios.Generator.Availability;

namespace Microsoft.Macios.Generator.Extensions;

Expand Down Expand Up @@ -236,4 +237,23 @@ public static void GetInheritance (
parents = parentsBuilder.ToImmutable ();
interfaces = [.. interfacesSet];
}

/// <summary>
/// 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.
/// </summary>
/// <param name="symbol">The symbol whose availability we want to retrieve.</param>
/// <returns>A symbol availability structure for the symbol.</returns>
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,6 @@ static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol)
return builder.ToImmutable ();
}

/// <summary>
/// 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.
/// </summary>
/// <param name="symbol">The symbol whose availability we want to retrieve.</param>
/// <returns>A symbol availability structure for the symbol.</returns>
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string, ApplePlatform> supportedAttributes = new Dictionary<string, ApplePlatform> {
{ AttributesNames.iOSAttribute, ApplePlatform.iOS },
{ AttributesNames.TVAttribute, ApplePlatform.TVOS },
{ AttributesNames.MacAttribute, ApplePlatform.MacOSX },
{ AttributesNames.MacCatalystAttribute, ApplePlatform.MacCatalyst },
};

static readonly IReadOnlyDictionary<string, ApplePlatform> unsupportedAttributes = new Dictionary<string, ApplePlatform> {
{ 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<ApplePlatform> allSupportedPlatforms = [
ApplePlatform.iOS,
ApplePlatform.TVOS,
ApplePlatform.MacOSX,
ApplePlatform.MacCatalyst
];

/// <summary>
/// Return the symbol availability WITHOUT taking into account the parent symbols availability.
/// </summary>
/// <param name="symbol">The symbols whose availability attributes we want to retrieve.</param>
/// <returns>The symbol availability WITHOUT taking into account the parent symbols.</returns>
/// <remarks>This is a helper method, you probably don't want to use it.</remarks>
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 ();
Expand Down
Loading
Loading