From 9bf39cd9858f809d33c15ba14a9399a7e72c26e2 Mon Sep 17 00:00:00 2001 From: TJ Lambert <50846373+tj-devel709@users.noreply.github.com> Date: Mon, 6 Jun 2022 10:05:38 -0500 Subject: [PATCH] [homekit] Add nullability to (generated and manual) bindings (#15111) * go through the nullable ignores and add test * Enable Nullability * use is null * save a few lines Co-authored-by: TJ Lambert --- src/HomeKit/HMActionSet.cs | 4 ++- src/HomeKit/HMCharacteristic.cs | 2 ++ src/HomeKit/HMCharacteristicMetadata.cs | 2 ++ src/HomeKit/HMCharacteristicProperties.cs | 2 ++ src/HomeKit/HMCompat.cs | 2 ++ src/HomeKit/HMEventTrigger.cs | 12 +++++-- src/HomeKit/HMHome.cs | 14 ++++++-- src/HomeKit/HMService.cs | 2 ++ src/homekit.cs | 33 ++++++++--------- .../HomeKit/HMCharacteristicTest.cs | 36 +++++++++++++++++++ .../common-HomeKit.ignore | 25 +++---------- tests/xtro-sharpie/common-HomeKit.ignore | 25 +++---------- 12 files changed, 98 insertions(+), 61 deletions(-) create mode 100644 tests/monotouch-test/HomeKit/HMCharacteristicTest.cs diff --git a/src/HomeKit/HMActionSet.cs b/src/HomeKit/HMActionSet.cs index 647e92657e..d09670c1cb 100644 --- a/src/HomeKit/HMActionSet.cs +++ b/src/HomeKit/HMActionSet.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using ObjCRuntime; using Foundation; @@ -17,7 +19,7 @@ namespace HomeKit { get { var s = _ActionSetType; // safety in case the field does not exists / cannot be loaded / new in future iOS versions... - if (s == null) + if (s is null) return HMActionSetType.Unknown; if (s == HMActionSetTypesInternal.WakeUp) return HMActionSetType.WakeUp; diff --git a/src/HomeKit/HMCharacteristic.cs b/src/HomeKit/HMCharacteristic.cs index dadecd2966..fd2abf66df 100644 --- a/src/HomeKit/HMCharacteristic.cs +++ b/src/HomeKit/HMCharacteristic.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using ObjCRuntime; using Foundation; diff --git a/src/HomeKit/HMCharacteristicMetadata.cs b/src/HomeKit/HMCharacteristicMetadata.cs index 1c78e66c6d..c4211472e6 100644 --- a/src/HomeKit/HMCharacteristicMetadata.cs +++ b/src/HomeKit/HMCharacteristicMetadata.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using ObjCRuntime; diff --git a/src/HomeKit/HMCharacteristicProperties.cs b/src/HomeKit/HMCharacteristicProperties.cs index 0478bbe31e..d443fc9a3b 100644 --- a/src/HomeKit/HMCharacteristicProperties.cs +++ b/src/HomeKit/HMCharacteristicProperties.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using ObjCRuntime; diff --git a/src/HomeKit/HMCompat.cs b/src/HomeKit/HMCompat.cs index 8027cc6a09..6b6872336b 100644 --- a/src/HomeKit/HMCompat.cs +++ b/src/HomeKit/HMCompat.cs @@ -98,8 +98,10 @@ namespace HomeKit { public partial class HMAccessorySetupManager { +#pragma warning disable CS0618 // HMChipServiceTopology and HMErrorHandler is obsolete public virtual void AddAndSetUpAccessories (HMChipServiceTopology topology, HMErrorHandler completion) => throw new InvalidOperationException (); public virtual Task AddAndSetUpAccessoriesAsync (HMChipServiceTopology topology) => throw new InvalidOperationException (); +#pragma warning restore CS0618 // HMChipServiceTopology and HMErrorHandler is obsolete } /* class HMAccessorySetupManager */ diff --git a/src/HomeKit/HMEventTrigger.cs b/src/HomeKit/HMEventTrigger.cs index cd410770fa..43f898cf4d 100644 --- a/src/HomeKit/HMEventTrigger.cs +++ b/src/HomeKit/HMEventTrigger.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using ObjCRuntime; using Foundation; @@ -24,7 +26,10 @@ namespace HomeKit { #endif static public NSPredicate CreatePredicateForEvaluatingTriggerOccurringBeforeSignificantEvent (HMSignificantEvent significantEvent, NSDateComponents offset) { - return CreatePredicateForEvaluatingTriggerOccurringBeforeSignificantEvent (significantEvent.GetConstant (), offset); + var constant = significantEvent.GetConstant (); + if (constant is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (significantEvent)); + return CreatePredicateForEvaluatingTriggerOccurringBeforeSignificantEvent (constant, offset); } #if NET @@ -45,7 +50,10 @@ namespace HomeKit { #endif static public NSPredicate CreatePredicateForEvaluatingTriggerOccurringAfterSignificantEvent (HMSignificantEvent significantEvent, NSDateComponents offset) { - return CreatePredicateForEvaluatingTriggerOccurringAfterSignificantEvent (significantEvent.GetConstant (), offset); + var constant = significantEvent.GetConstant (); + if (constant is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (significantEvent)); + return CreatePredicateForEvaluatingTriggerOccurringAfterSignificantEvent (constant, offset); } } } diff --git a/src/HomeKit/HMHome.cs b/src/HomeKit/HMHome.cs index e7d6db38ce..7ac5d1a884 100644 --- a/src/HomeKit/HMHome.cs +++ b/src/HomeKit/HMHome.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -8,9 +10,9 @@ namespace HomeKit { public partial class HMHome { - public HMService [] GetServices (HMServiceType serviceTypes) + public HMService []? GetServices (HMServiceType serviceTypes) { - var arr = new List (); + var arr = new ServiceTypeList (); if ((serviceTypes & HMServiceType.LightBulb) == HMServiceType.LightBulb) arr.Add (HMServiceType.LightBulb.GetConstant ()); @@ -80,6 +82,14 @@ namespace HomeKit { return GetServices (arr.ToArray ()); } + class ServiceTypeList : List { + public new void Add (T? item) + { + if (item is not null) + base.Add (item); + } + } + #if !NET [NoTV] [NoWatch] diff --git a/src/HomeKit/HMService.cs b/src/HomeKit/HMService.cs index c9c9df59a7..461a6d8c08 100644 --- a/src/HomeKit/HMService.cs +++ b/src/HomeKit/HMService.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Threading.Tasks; diff --git a/src/homekit.cs b/src/homekit.cs index fe50e6f5c0..fbdc39eb2a 100644 --- a/src/homekit.cs +++ b/src/homekit.cs @@ -39,7 +39,7 @@ namespace HomeKit { [Protocolize] HMHomeManagerDelegate Delegate { get; set; } - [Export ("primaryHome", ArgumentSemantic.Retain)] + [NullAllowed, Export ("primaryHome", ArgumentSemantic.Retain)] HMHome PrimaryHome { get; } [Export ("homes", ArgumentSemantic.Copy)] @@ -391,10 +391,10 @@ namespace HomeKit { [Export ("properties", ArgumentSemantic.Copy)] NSString [] Properties { get; } - [Export ("metadata", ArgumentSemantic.Retain)] + [NullAllowed, Export ("metadata", ArgumentSemantic.Retain)] HMCharacteristicMetadata Metadata { get; } - [Export ("value", ArgumentSemantic.Copy)] + [NullAllowed, Export ("value", ArgumentSemantic.Copy)] NSObject Value { get; } [Export ("notificationEnabled")] @@ -416,7 +416,7 @@ namespace HomeKit { [NoWatch] [Async] [Export ("updateAuthorizationData:completionHandler:")] - void UpdateAuthorizationData (NSData data, Action completion); + void UpdateAuthorizationData ([NullAllowed] NSData data, Action completion); [iOS (9,0)] [Export ("localizedDescription")] @@ -500,27 +500,27 @@ namespace HomeKit { [BaseType (typeof (NSObject))] partial interface HMCharacteristicMetadata { - [Export ("minimumValue")] + [NullAllowed, Export ("minimumValue")] NSNumber MinimumValue { get; } - [Export ("maximumValue")] + [NullAllowed, Export ("maximumValue")] NSNumber MaximumValue { get; } - [Export ("stepValue")] + [NullAllowed, Export ("stepValue")] NSNumber StepValue { get; } - [Export ("maxLength")] + [NullAllowed, Export ("maxLength")] NSNumber MaxLength { get; } [Internal] - [Export ("format", ArgumentSemantic.Copy)] + [NullAllowed, Export ("format", ArgumentSemantic.Copy)] NSString _Format { get; } [Internal] - [Export ("units", ArgumentSemantic.Copy)] + [NullAllowed, Export ("units", ArgumentSemantic.Copy)] NSString _Units { get; } - [Export ("manufacturerDescription")] + [NullAllowed, Export ("manufacturerDescription")] string ManufacturerDescription { get; } [Watch (3,0), iOS (10,0)] @@ -626,6 +626,7 @@ namespace HomeKit { [EditorBrowsable (EditorBrowsableState.Advanced)] [Export ("servicesWithTypes:")] + [return: NullAllowed] HMService [] GetServices (NSString [] serviceTypes); [NoTV] @@ -934,7 +935,7 @@ namespace HomeKit { [Export ("name")] string Name { get; } - [Export ("associatedServiceType")] + [NullAllowed, Export ("associatedServiceType")] string AssociatedServiceType { get; } [Export ("characteristics", ArgumentSemantic.Copy)] @@ -1026,13 +1027,13 @@ namespace HomeKit { [Export ("fireDate", ArgumentSemantic.Copy)] NSDate FireDate { get; } - [Export ("timeZone", ArgumentSemantic.Copy)] + [NullAllowed, Export ("timeZone", ArgumentSemantic.Copy)] NSTimeZone TimeZone { get; } - [Export ("recurrence", ArgumentSemantic.Copy)] + [NullAllowed, Export ("recurrence", ArgumentSemantic.Copy)] NSDateComponents Recurrence { get; } - [Export ("recurrenceCalendar", ArgumentSemantic.Copy)] + [NullAllowed, Export ("recurrenceCalendar", ArgumentSemantic.Copy)] NSCalendar RecurrenceCalendar { get; } [NoTV] @@ -1070,7 +1071,7 @@ namespace HomeKit { [Export ("actionSets", ArgumentSemantic.Copy)] HMActionSet [] ActionSets { get; } - [Export ("lastFireDate", ArgumentSemantic.Copy)] + [NullAllowed, Export ("lastFireDate", ArgumentSemantic.Copy)] NSDate LastFireDate { get; } [NoTV] diff --git a/tests/monotouch-test/HomeKit/HMCharacteristicTest.cs b/tests/monotouch-test/HomeKit/HMCharacteristicTest.cs new file mode 100644 index 0000000000..cce5943020 --- /dev/null +++ b/tests/monotouch-test/HomeKit/HMCharacteristicTest.cs @@ -0,0 +1,36 @@ +// +// Unit tests for HMCharacteristicTest +// +// Authors: +// TJ Lambert +// +// +// Copyright 2022 Microsoft. All rights reserved. +// + +#if HAS_HOMEKIT + +using System; +using NUnit.Framework; + +using Foundation; +using HomeKit; +using ObjCRuntime; +using Xamarin.Utils; + +namespace MonoTouchFixtures.HomeKit +{ + [TestFixture] + [Preserve (AllMembers = true)] + public class HMCharacteristicTest + { + [Test] + public void WriteValueNullTest () + { + var characteristic = new HMCharacteristic (); + Assert.Throws (delegate { characteristic.WriteValue (null, null); }, $"WriteValue should accept a null argument for 'value'."); + } + } +} + +#endif // HAS_HOMEKIT diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-HomeKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-HomeKit.ignore index 51e19a11e5..161480df4a 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/common-HomeKit.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/common-HomeKit.ignore @@ -2,25 +2,10 @@ !missing-selector! HMMutablePresenceEvent::setPresenceEventType: not bound !missing-selector! HMMutablePresenceEvent::setPresenceUserType: not bound -# Initial result from new rule missing-null-allowed (Consolidating to common-HomeKit.ignore) -!missing-null-allowed! 'Foundation.NSCalendar HomeKit.HMTimerTrigger::get_RecurrenceCalendar()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSDate HomeKit.HMTrigger::get_LastFireDate()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSDateComponents HomeKit.HMTimerTrigger::get_Recurrence()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MaximumValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MaxLength()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MinimumValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_StepValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSObject HomeKit.HMCharacteristic::get_Value()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSString HomeKit.HMCharacteristicMetadata::get__Format()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSString HomeKit.HMCharacteristicMetadata::get__Units()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSTimeZone HomeKit.HMTimerTrigger::get_TimeZone()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMAccessory HomeKit.HMService::get_Accessory()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMCharacteristicMetadata HomeKit.HMCharacteristic::get_Metadata()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMHome HomeKit.HMHomeManager::get_PrimaryHome()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMRoom HomeKit.HMAccessory::get_Room()' is missing an [NullAllowed] on return type +# Xcode headers and Web docs agree that these values should not be nullable !missing-null-allowed! 'HomeKit.HMService HomeKit.HMCharacteristic::get_Service()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMService[] HomeKit.HMHome::GetServices(Foundation.NSString[])' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.String HomeKit.HMCharacteristicMetadata::get_ManufacturerDescription()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.String HomeKit.HMService::get_AssociatedServiceType()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.Void HomeKit.HMCharacteristic::UpdateAuthorizationData(Foundation.NSData,System.Action`1)' is missing an [NullAllowed] on parameter #0 +!missing-null-allowed! 'HomeKit.HMAccessory HomeKit.HMService::get_Accessory()' is missing an [NullAllowed] on return type +!missing-null-allowed! 'HomeKit.HMRoom HomeKit.HMAccessory::get_Room()' is missing an [NullAllowed] on return type + +# Xcode headers say nullable but web docs do not. After testing, this parameter cannot be null. !missing-null-allowed! 'System.Void HomeKit.HMCharacteristic::WriteValue(Foundation.NSObject,System.Action`1)' is missing an [NullAllowed] on parameter #0 diff --git a/tests/xtro-sharpie/common-HomeKit.ignore b/tests/xtro-sharpie/common-HomeKit.ignore index 51e19a11e5..161480df4a 100644 --- a/tests/xtro-sharpie/common-HomeKit.ignore +++ b/tests/xtro-sharpie/common-HomeKit.ignore @@ -2,25 +2,10 @@ !missing-selector! HMMutablePresenceEvent::setPresenceEventType: not bound !missing-selector! HMMutablePresenceEvent::setPresenceUserType: not bound -# Initial result from new rule missing-null-allowed (Consolidating to common-HomeKit.ignore) -!missing-null-allowed! 'Foundation.NSCalendar HomeKit.HMTimerTrigger::get_RecurrenceCalendar()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSDate HomeKit.HMTrigger::get_LastFireDate()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSDateComponents HomeKit.HMTimerTrigger::get_Recurrence()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MaximumValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MaxLength()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_MinimumValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSNumber HomeKit.HMCharacteristicMetadata::get_StepValue()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSObject HomeKit.HMCharacteristic::get_Value()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSString HomeKit.HMCharacteristicMetadata::get__Format()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSString HomeKit.HMCharacteristicMetadata::get__Units()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSTimeZone HomeKit.HMTimerTrigger::get_TimeZone()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMAccessory HomeKit.HMService::get_Accessory()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMCharacteristicMetadata HomeKit.HMCharacteristic::get_Metadata()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMHome HomeKit.HMHomeManager::get_PrimaryHome()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMRoom HomeKit.HMAccessory::get_Room()' is missing an [NullAllowed] on return type +# Xcode headers and Web docs agree that these values should not be nullable !missing-null-allowed! 'HomeKit.HMService HomeKit.HMCharacteristic::get_Service()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'HomeKit.HMService[] HomeKit.HMHome::GetServices(Foundation.NSString[])' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.String HomeKit.HMCharacteristicMetadata::get_ManufacturerDescription()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.String HomeKit.HMService::get_AssociatedServiceType()' is missing an [NullAllowed] on return type -!missing-null-allowed! 'System.Void HomeKit.HMCharacteristic::UpdateAuthorizationData(Foundation.NSData,System.Action`1)' is missing an [NullAllowed] on parameter #0 +!missing-null-allowed! 'HomeKit.HMAccessory HomeKit.HMService::get_Accessory()' is missing an [NullAllowed] on return type +!missing-null-allowed! 'HomeKit.HMRoom HomeKit.HMAccessory::get_Room()' is missing an [NullAllowed] on return type + +# Xcode headers say nullable but web docs do not. After testing, this parameter cannot be null. !missing-null-allowed! 'System.Void HomeKit.HMCharacteristic::WriteValue(Foundation.NSObject,System.Action`1)' is missing an [NullAllowed] on parameter #0