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 50e69ddd6a51..ca1f355f8e9d 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 @@ -60,6 +60,9 @@ Generator/Attributes/UnsupportedOSPlatformData.cs + + Generator/Extensions/ApplePlatformExtensions.cs + Generator/Extensions/CompilationExtensions.cs @@ -72,17 +75,8 @@ Generator/Extensions/StringExtensions.cs - - Generator/Availability/PlatformAvailability.cs - - - Generator/Availability/PlatformAvailabilityBuilder.cs - - - Generator/Availability/SymbolAvailability.cs - - - Generator/Availability/SymbolAvailabilityBuilder.cs + + Generator/Availability/*.cs True diff --git a/src/rgen/Microsoft.Macios.Generator/Availability/AvailabilityTrivia.cs b/src/rgen/Microsoft.Macios.Generator/Availability/AvailabilityTrivia.cs new file mode 100644 index 000000000000..ce8c43729e33 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/Availability/AvailabilityTrivia.cs @@ -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 { + + /// + /// Retrieve the trivia to add before the symbol declaration. + /// + public string? Start { get; } + + /// + /// Retrieve the trivia to add after the symbol declaration. + /// + 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 (); + var unsupportedPlatforms = new HashSet (); + 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"; + } + } +} diff --git a/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs b/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs index ba83bb51bed1..da94d3bf971a 100644 --- a/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs +++ b/src/rgen/Microsoft.Macios.Generator/Availability/PlatformAvailability.cs @@ -36,14 +36,26 @@ namespace Microsoft.Macios.Generator.Availability; /// /// Dictionary that contains all the obsoleted versions and their optional data. /// - public readonly IReadOnlyDictionary UnsupportedVersions => unsupported; + public IReadOnlyDictionary UnsupportedVersions => unsupported; readonly SortedDictionary obsoleted = new (); /// /// The Dictionary which contains all the unsupported versions and their optional data. /// - public readonly IReadOnlyDictionary ObsoletedVersions => obsoleted; + public IReadOnlyDictionary ObsoletedVersions => obsoleted; + + /// + /// Return if the platform is supported. + /// + 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); + } + } /// @@ -53,6 +65,7 @@ namespace Microsoft.Macios.Generator.Availability; /// True if the version is default. public static bool IsDefaultVersion (Version version) => version == defaultVersion; + PlatformAvailability (ApplePlatform platform, Version? supportedVersion, SortedDictionary unsupportedVersions, SortedDictionary obsoletedVersions) diff --git a/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailability.cs b/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailability.cs index 29c3ab988327..da7983a06f52 100644 --- a/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailability.cs +++ b/src/rgen/Microsoft.Macios.Generator/Availability/SymbolAvailability.cs @@ -33,6 +33,19 @@ public SymbolAvailability () { } } } + /// + /// Return the symbol trivia if it has any. + /// + 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; + } + } + /// /// Copy constructor. /// diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/ApplePlatformExtensions.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/ApplePlatformExtensions.cs new file mode 100644 index 000000000000..d15da844a0d4 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/ApplePlatformExtensions.cs @@ -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 { + + /// + /// Return the platform define for the given ApplePlatform for use in #if directives. + /// + /// Apple platform. + /// the platform define + public static string? ToPlatformDefine (this ApplePlatform self) => self switch { + ApplePlatform.iOS => "IOS", + ApplePlatform.TVOS => "TVOS", + ApplePlatform.MacOSX => "MONOMAC", + ApplePlatform.MacCatalyst => "__MACCATALYST__", + _ => null + }; +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj index d60881115b74..077f463f4f9d 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj +++ b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj @@ -45,6 +45,9 @@ Availability/*.cs + + Extensions/ApplePlatformExtensions.cs + Extensions/ParameterSyntaxExtensions.cs diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/Availability/AvailabilityTriviaTests.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/Availability/AvailabilityTriviaTests.cs new file mode 100644 index 000000000000..fe70fbfc74c4 --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/Availability/AvailabilityTriviaTests.cs @@ -0,0 +1,89 @@ +// 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); + } + +}