Skip to content

Commit

Permalink
[Rgen] Add a new struc that will represent the needed trivia for a sy…
Browse files Browse the repository at this point in the history
…mbol.

If we are generating code, specially in the transformer, that does not
have a specific platform, we need to generate the correct trivia to
ensure that methods are not generated in the wrong platform.
  • Loading branch information
mandel-macaque committed Jan 20, 2025
1 parent dc720d4 commit fcb7826
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
<Compile Include="../Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs" >
<Link>Generator/Attributes/UnsupportedOSPlatformData.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/ApplePlatformExtensions.cs" >
<Link>Generator/Extensions/ApplePlatformExtensions.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/CompilationExtensions.cs" >
<Link>Generator/Extensions/CompilationExtensions.cs</Link>
</Compile>
Expand All @@ -72,17 +75,8 @@
<Compile Include="../Microsoft.Macios.Generator/Extensions/StringExtensions.cs" >
<Link>Generator/Extensions/StringExtensions.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Availability/PlatformAvailability.cs" >
<Link>Generator/Availability/PlatformAvailability.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Availability/PlatformAvailabilityBuilder.cs" >
<Link>Generator/Availability/PlatformAvailabilityBuilder.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Availability/SymbolAvailability.cs" >
<Link>Generator/Availability/SymbolAvailability.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Availability/SymbolAvailabilityBuilder.cs" >
<Link>Generator/Availability/SymbolAvailabilityBuilder.cs</Link>
<Compile Include="../Microsoft.Macios.Generator/Availability/*.cs" >
<Link>Generator/Availability/*.cs</Link>
</Compile>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;
using Microsoft.Macios.Generator.Extensions;
using Xamarin.Utils;

namespace Microsoft.Macios.Generator.Availability;

readonly struct AvailabilityTrivia {

/// <summary>
/// Retrieve the trivia to add before the symbol declaration.
/// </summary>
public string? Start { get; }

/// <summary>
/// Retrieve the trivia to add after the symbol declaration.
/// </summary>
public string? End { get; }

public AvailabilityTrivia (SymbolAvailability availability)
{
// trivia is calculated based on the availability of the symbol in each platform
// we will check each of the platforms and decide for the shorts #if possible
var supportedPlatforms = new HashSet<string> ();
var unsupportedPlatforms = new HashSet<string> ();
foreach (var platformAvailability in availability.PlatformAvailabilities) {
var platformDefine = platformAvailability.Platform.ToPlatformDefine ();
if (platformDefine is null)
continue;

if (platformAvailability.IsSupported)
supportedPlatforms.Add (platformDefine);
else
unsupportedPlatforms.Add (platformDefine);
}

// if all platforms are supported, we don't need any trivia
if (unsupportedPlatforms.Count == 0) {
// all platforms are supported
Start = null;
End = null;
return;
}

if (supportedPlatforms.Count > unsupportedPlatforms.Count) {
// we have more supported platforms than unsupported ones
// we will use #if to exclude the unsupported platforms
Start = $"#if !{string.Join (" && !", unsupportedPlatforms)}";
End = "#endif";
} else {
// we have more unsupported platforms than supported ones
// we will use #if to include the supported platforms
Start = $"#if {string.Join (" || ", supportedPlatforms)}";
End = "#endif";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,26 @@ namespace Microsoft.Macios.Generator.Availability;
/// <summary>
/// Dictionary that contains all the obsoleted versions and their optional data.
/// </summary>
public readonly IReadOnlyDictionary<Version, string?> UnsupportedVersions => unsupported;
public IReadOnlyDictionary<Version, string?> UnsupportedVersions => unsupported;

readonly SortedDictionary<Version, (string? Message, string? Url)> obsoleted = new ();

/// <summary>
/// The Dictionary which contains all the unsupported versions and their optional data.
/// </summary>
public readonly IReadOnlyDictionary<Version, (string? Message, string? Url)> ObsoletedVersions => obsoleted;
public IReadOnlyDictionary<Version, (string? Message, string? Url)> ObsoletedVersions => obsoleted;

/// <summary>
/// Return if the platform is supported.
/// </summary>
public bool IsSupported {
get {
// a platform is supported if:
// 1. The supported version is not null, either the default version or a specific one
// 2. The default version is not in the unsupported list
return SupportedVersion is not null && !unsupported.ContainsKey (defaultVersion);
}
}


/// <summary>
Expand All @@ -52,6 +64,7 @@ namespace Microsoft.Macios.Generator.Availability;
/// <param name="version">Version being tested.</param>
/// <returns>True if the version is default.</returns>
public static bool IsDefaultVersion (Version version) => version == defaultVersion;


PlatformAvailability (ApplePlatform platform, Version? supportedVersion,
SortedDictionary<Version, string?> unsupportedVersions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ public SymbolAvailability () { }
}
}

/// <summary>
/// Return the symbol trivia if it has any.
/// </summary>
public AvailabilityTrivia? Trivia {
get {
// just returns the trivia if it has any, null otherwise
var trivia = new AvailabilityTrivia (this);
if (trivia.Start is not null || trivia.End is not null)
return trivia;
return null;
}
}

/// <summary>
/// Copy constructor.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Xamarin.Utils;

namespace Microsoft.Macios.Generator.Extensions;

public static class ApplePlatformExtensions {

/// <summary>
/// Return the platform define for the given ApplePlatform for use in #if directives.
/// </summary>
/// <param name="self">Apple platform.</param>
/// <returns>the platform define</returns>
public static string? ToPlatformDefine (this ApplePlatform self) => self switch {
ApplePlatform.iOS => "IOS",
ApplePlatform.TVOS => "TVOS",
ApplePlatform.MacOSX => "MONOMAC",
ApplePlatform.MacCatalyst => "__MACCATALYST__",
_ => null
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<Compile Include="../Microsoft.Macios.Generator/Availability/*.cs" >
<Link>Availability/*.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/ApplePlatformExtensions.cs" >
<Link>Extensions/ApplePlatformExtensions.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/StringExtensions.cs" >
<Link>Extensions/StringExtensions.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using Microsoft.Macios.Generator.Attributes;
using Microsoft.Macios.Generator.Availability;
using Xunit;

namespace Microsoft.Macios.Generator.Tests.Availability;

public class AvailabilityTriviaTests {

[Fact]
public void AllSupportedPlatforms ()
{
SymbolAvailability.Builder builder = SymbolAvailability.CreateBuilder ();
builder.Add (new SupportedOSPlatformData ("ios12.0"));
builder.Add (new SupportedOSPlatformData ("tvos12.0"));
builder.Add (new SupportedOSPlatformData ("macos10.14"));
builder.Add (new SupportedOSPlatformData ("macCatalyst13.0"));
var availability = builder.ToImmutable ();
var trivia = new AvailabilityTrivia (availability);
Assert.Null (trivia.Start);
Assert.Null (trivia.End);
Assert.Null (availability.Trivia);
}

[Fact]
public void SomeUnsupportedVersions () {
SymbolAvailability.Builder builder = SymbolAvailability.CreateBuilder ();
builder.Add (new SupportedOSPlatformData ("ios12.0"));
builder.Add (new UnsupportedOSPlatformData ("ios9.0"));
builder.Add (new SupportedOSPlatformData ("tvos12.0"));
builder.Add (new SupportedOSPlatformData ("macos10.14"));
builder.Add (new SupportedOSPlatformData ("maccatalyst13.0"));
var availability = builder.ToImmutable ();
var trivia = new AvailabilityTrivia (availability);
Assert.Null (trivia.Start);
Assert.Null (trivia.End);
Assert.Null (availability.Trivia);
}

[Fact]
public void SingleFullyUnsupportedPlatform () {
SymbolAvailability.Builder builder = SymbolAvailability.CreateBuilder ();
builder.Add (new UnsupportedOSPlatformData ("ios"));
builder.Add (new SupportedOSPlatformData ("tvos12.0"));
builder.Add (new SupportedOSPlatformData ("macos10.14"));
builder.Add (new SupportedOSPlatformData ("maccatalyst13.0"));
var availability = builder.ToImmutable ();
var trivia = new AvailabilityTrivia (availability);
Assert.Equal ("#if !IOS", trivia.Start);
Assert.Equal ("#endif", trivia.End);
Assert.NotNull (availability.Trivia);
}

[Fact]
public void DoubleUnsupportedPlatform () {
SymbolAvailability.Builder builder = SymbolAvailability.CreateBuilder ();
builder.Add (new SupportedOSPlatformData ("ios"));
builder.Add (new SupportedOSPlatformData ("tvos12.0"));
builder.Add (new UnsupportedOSPlatformData ("macos"));
builder.Add (new UnsupportedOSPlatformData ("maccatalyst"));
var availability = builder.ToImmutable ();
var trivia = new AvailabilityTrivia (availability);
Assert.Equal ("#if IOS || TVOS", trivia.Start);
Assert.Equal ("#endif", trivia.End);
Assert.NotNull (availability.Trivia);
}

[Fact]
public void SingleSupportedPlatform () {
SymbolAvailability.Builder builder = SymbolAvailability.CreateBuilder ();
builder.Add (new SupportedOSPlatformData ("ios"));
builder.Add (new UnsupportedOSPlatformData( "tvos"));
builder.Add (new UnsupportedOSPlatformData ("macos"));
builder.Add (new UnsupportedOSPlatformData ("maccatalyst"));
var availability = builder.ToImmutable ();
var trivia = new AvailabilityTrivia (availability);
Assert.Equal ("#if IOS", trivia.Start);
Assert.Equal ("#endif", trivia.End);
Assert.NotNull (availability.Trivia);
}

}

0 comments on commit fcb7826

Please sign in to comment.