From 52861eaf7606bc78dda0bec7b3643d796cc21197 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Thu, 8 Jul 2021 23:14:19 -0700 Subject: [PATCH 1/5] Recognize MacCatalyst as a superset of iOS and apply platform guard attributes that will inform the analyzer of the relationship. --- .../src/System/OperatingSystem.cs | 16 ++++++-- .../tests/System/OperatingSystemTests.cs | 37 ++++++++++++++----- .../System.Runtime/ref/System.Runtime.cs | 5 +++ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs index 0b483517b97bf..396ed7e0fa5cd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs +++ b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.Serialization; +using System.Runtime.Versioning; namespace System { @@ -101,6 +102,10 @@ public static bool IsOSPlatform(string platform) return platform.Equals("WINDOWS", StringComparison.OrdinalIgnoreCase); #elif TARGET_OSX return platform.Equals("OSX", StringComparison.OrdinalIgnoreCase) || platform.Equals("MACOS", StringComparison.OrdinalIgnoreCase); +#elif TARGET_MACCATALYST + return platform.Equals("MACCATALYST", StringComparison.OrdinalIgnoreCase) || platform.Equals("IOS", StringComparison.OrdinalIgnoreCase); +#elif TARGET_IOS + return platform.Equals("IOS", StringComparison.OrdinalIgnoreCase); #elif TARGET_UNIX return platform.Equals(s_osPlatformName, StringComparison.OrdinalIgnoreCase); #else @@ -172,18 +177,23 @@ public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = => IsAndroid() && IsOSVersionAtLeast(major, minor, build, revision); /// - /// Indicates whether the current application is running on iOS. + /// Indicates whether the current application is running on iOS or MacCatalyst. /// + /// + [SupportedOSPlatformGuard("ios")] + [SupportedOSPlatformGuard("maccatalyst")] public static bool IsIOS() => -#if TARGET_IOS +#if TARGET_IOS || TARGET_MACCATALYST true; #else false; #endif /// - /// Check for the iOS version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given iOS release. + /// Check for the iOS/MacCatalyst version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given iOS release. /// + [SupportedOSPlatformGuard("ios")] + [SupportedOSPlatformGuard("maccatalyst")] public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0) => IsIOS() && IsOSVersionAtLeast(major, minor, build, 0); diff --git a/src/libraries/System.Runtime.Extensions/tests/System/OperatingSystemTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/OperatingSystemTests.cs index 6a6b1cdd6b6a2..405cf4373f9b8 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/OperatingSystemTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/OperatingSystemTests.cs @@ -132,6 +132,23 @@ public static void OSX_Is_Treated_as_macOS() [Fact, PlatformSpecific(TestPlatforms.MacCatalyst)] public static void TestIsOSVersionAtLeast_MacCatalyst() => TestIsOSVersionAtLeast("MacCatalyst"); + [Fact, PlatformSpecific(TestPlatforms.MacCatalyst)] + public static void MacCatalyst_Is_Also_iOS() + { + Assert.True(OperatingSystem.IsOSPlatform("IOS")); + Assert.True(OperatingSystem.IsIOS()); + + AssertVersionChecks(true, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast("IOS", major, minor, build, revision)); + AssertVersionChecks(true, (major, minor, build) => OperatingSystem.IsOSPlatformVersionAtLeast("IOS", major, minor, build)); + } + + [Fact, PlatformSpecific(TestPlatforms.iOS)] + public static void IOS_Is_Not_Also_MacCatalyst() + { + Assert.False(OperatingSystem.IsOSPlatform("MacCatalyst")); + Assert.False(OperatingSystem.IsMacCatalyst()); + } + [Fact, PlatformSpecific(TestPlatforms.tvOS)] public static void TestIsOSPlatform_TvOS() => TestIsOSPlatform("tvOS", OperatingSystem.IsTvOS); @@ -146,13 +163,13 @@ public static void OSX_Is_Treated_as_macOS() private static void TestIsOSPlatform(string currentOSName, Func currentOSCheck) { - foreach (string platfromName in AllKnownPlatformNames) + foreach (string platformName in AllKnownPlatformNames) { - bool expected = currentOSName.Equals(platfromName, StringComparison.OrdinalIgnoreCase); + bool expected = currentOSName.Equals(platformName, StringComparison.OrdinalIgnoreCase); - Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName)); - Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName.ToUpper())); - Assert.Equal(expected, OperatingSystem.IsOSPlatform(platfromName.ToLower())); + Assert.Equal(expected, OperatingSystem.IsOSPlatform(platformName)); + Assert.Equal(expected, OperatingSystem.IsOSPlatform(platformName.ToUpper())); + Assert.Equal(expected, OperatingSystem.IsOSPlatform(platformName.ToLower())); } Assert.True(currentOSCheck()); @@ -176,13 +193,13 @@ private static void TestIsOSPlatform(string currentOSName, Func currentOSC private static void TestIsOSVersionAtLeast(string currentOSName) { - foreach (string platfromName in AllKnownPlatformNames) + foreach (string platformName in AllKnownPlatformNames) { - bool isCurrentOS = currentOSName.Equals(platfromName, StringComparison.OrdinalIgnoreCase); + bool isCurrentOS = currentOSName.Equals(platformName, StringComparison.OrdinalIgnoreCase); - AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName, major, minor, build, revision)); - AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName.ToLower(), major, minor, build, revision)); - AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platfromName.ToUpper(), major, minor, build, revision)); + AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platformName, major, minor, build, revision)); + AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platformName.ToLower(), major, minor, build, revision)); + AssertVersionChecks(isCurrentOS, (major, minor, build, revision) => OperatingSystem.IsOSPlatformVersionAtLeast(platformName.ToUpper(), major, minor, build, revision)); } AssertVersionChecks(currentOSName.Equals("Android", StringComparison.OrdinalIgnoreCase), OperatingSystem.IsAndroidVersionAtLeast); diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 67adfd0c6d35c..5a47202071914 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4959,13 +4959,18 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public override string ToString() { throw null; } public static bool IsOSPlatform(string platform) { throw null; } public static bool IsOSPlatformVersionAtLeast(string platform, int major, int minor = 0, int build = 0, int revision = 0) { throw null; } + public static bool IsBrowser() { throw null; } public static bool IsLinux() { throw null; } public static bool IsFreeBSD() { throw null; } public static bool IsFreeBSDVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) { throw null; } public static bool IsAndroid() { throw null; } public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) { throw null; } + [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("ios")] + [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("maccatalyst")] public static bool IsIOS() { throw null; } + [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("ios")] + [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("maccatalyst")] public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0) { throw null; } public static bool IsMacOS() { throw null; } public static bool IsMacOSVersionAtLeast(int major, int minor = 0, int build = 0) { throw null; } From c74858fc9cfff48f2580f12f3ec3ce579f1eb255 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Mon, 12 Jul 2021 20:16:37 -0700 Subject: [PATCH 2/5] Remove errant remarks comment --- .../System.Private.CoreLib/src/System/OperatingSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs index 396ed7e0fa5cd..8d01222f7e5a9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs +++ b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs @@ -179,7 +179,6 @@ public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = /// /// Indicates whether the current application is running on iOS or MacCatalyst. /// - /// [SupportedOSPlatformGuard("ios")] [SupportedOSPlatformGuard("maccatalyst")] public static bool IsIOS() => From 03306cd7f3ff59ad4b5497cd09ac08b9ea898490 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Mon, 12 Jul 2021 21:38:38 -0700 Subject: [PATCH 3/5] Remove unused private field from maccatalyst and ios --- .../System.Private.CoreLib/src/System/OperatingSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs index 8d01222f7e5a9..fdd41f38ebc61 100644 --- a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs +++ b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs @@ -9,7 +9,7 @@ namespace System { public sealed class OperatingSystem : ISerializable, ICloneable { -#if TARGET_UNIX && !TARGET_OSX +#if TARGET_UNIX && !TARGET_OSX && !TARGET_MACCATALYST && !TARGET_IOS private static readonly string s_osPlatformName = Interop.Sys.GetUnixName(); #endif From 6db3d88efd8fedc668a876df471b9703394f1b9a Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Tue, 13 Jul 2021 09:54:55 -0700 Subject: [PATCH 4/5] Remove errant blank line --- src/libraries/System.Runtime/ref/System.Runtime.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 5a47202071914..5b444bc43331e 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4959,7 +4959,6 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public override string ToString() { throw null; } public static bool IsOSPlatform(string platform) { throw null; } public static bool IsOSPlatformVersionAtLeast(string platform, int major, int minor = 0, int build = 0, int revision = 0) { throw null; } - public static bool IsBrowser() { throw null; } public static bool IsLinux() { throw null; } public static bool IsFreeBSD() { throw null; } From 17bd9a50df5c6d38e5eb1695f392a85b12fdd579 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Tue, 13 Jul 2021 10:26:53 -0700 Subject: [PATCH 5/5] Only apply guard attributes for additional platforms, not the inferred one --- .../System.Private.CoreLib/src/System/OperatingSystem.cs | 2 -- src/libraries/System.Runtime/ref/System.Runtime.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs index fdd41f38ebc61..ddb7768bdfe25 100644 --- a/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs +++ b/src/libraries/System.Private.CoreLib/src/System/OperatingSystem.cs @@ -179,7 +179,6 @@ public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = /// /// Indicates whether the current application is running on iOS or MacCatalyst. /// - [SupportedOSPlatformGuard("ios")] [SupportedOSPlatformGuard("maccatalyst")] public static bool IsIOS() => #if TARGET_IOS || TARGET_MACCATALYST @@ -191,7 +190,6 @@ public static bool IsIOS() => /// /// Check for the iOS/MacCatalyst version (returned by 'libobjc.get_operatingSystemVersion') with a >= version comparison. Used to guard APIs that were added in the given iOS release. /// - [SupportedOSPlatformGuard("ios")] [SupportedOSPlatformGuard("maccatalyst")] public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0) => IsIOS() && IsOSVersionAtLeast(major, minor, build, 0); diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 5b444bc43331e..d658156a8771d 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4965,10 +4965,8 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public static bool IsFreeBSDVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) { throw null; } public static bool IsAndroid() { throw null; } public static bool IsAndroidVersionAtLeast(int major, int minor = 0, int build = 0, int revision = 0) { throw null; } - [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("ios")] [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("maccatalyst")] public static bool IsIOS() { throw null; } - [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("ios")] [System.Runtime.Versioning.SupportedOSPlatformGuardAttribute("maccatalyst")] public static bool IsIOSVersionAtLeast(int major, int minor = 0, int build = 0) { throw null; } public static bool IsMacOS() { throw null; }