diff --git a/Make.config b/Make.config index ca5418986030..505f4d324d3d 100644 --- a/Make.config +++ b/Make.config @@ -44,10 +44,10 @@ include $(TOP)/Make.versions # The value is taken from the name + version of the Ref pack. # Example: given the Ref pack "Microsoft.iOS.Ref.net8.0_17.5" with the version "17.5.8030", the value # to write here would be the part after "Microsoft.iOS.Ref." + "/" + version: "net8.0_17.5/17.5.8030" -STABLE_NUGET_VERSION_iOS=net10.0_26.1/26.1.10494 -STABLE_NUGET_VERSION_tvOS=net10.0_26.1/26.1.10494 -STABLE_NUGET_VERSION_MacCatalyst=net10.0_26.1/26.1.10494 -STABLE_NUGET_VERSION_macOS=net10.0_26.1/26.1.10494 +STABLE_NUGET_VERSION_iOS=net10.0_26.2/26.2.10191 +STABLE_NUGET_VERSION_tvOS=net10.0_26.2/26.2.10191 +STABLE_NUGET_VERSION_MacCatalyst=net10.0_26.2/26.2.10191 +STABLE_NUGET_VERSION_macOS=net10.0_26.2/26.2.10191 PACKAGE_HEAD_REV=$(shell git rev-parse HEAD) diff --git a/docs/ReleaseCheckList.md b/docs/ReleaseCheckList.md index 4a14601792c9..3f0cc42dc66d 100644 --- a/docs/ReleaseCheckList.md +++ b/docs/ReleaseCheckList.md @@ -64,8 +64,7 @@ This happens after the stable version of Xcode has been released and the `xcodeX * [ ] Write release notes. * [ ] Publish NuGets to nuget.org. * [ ] Publish release notes. -* [ ] Update https://github.com/dotnet/maui/wiki/Release-Versions -* [ ] Update API diff (the `STABLE_NUGET_VERSION_*` variables in `Make.config`). Can only be done after the NuGets have been published to nuget.org. +* [ ] Update API diff (the `STABLE_NUGET_VERSION_*` variables in `Make.config`) for the `main` branch. Can only be done after the NuGets have been published to nuget.org. * [ ] Update docs by executing `docs/sync-mobile-docs.sh`. Beware if docs were modified in the [docs-mobile](https://github.com/dotnet/docs-mobile) repository by somebody else, any such changes will have to be copied back first. * [ ] Update API / reference docs. See [update-api-docs.md](https://github.com/dotnet/macios/blob/main/docs/update-api-docs.md) for instructions. * [ ] Make sure all items in the milestone for the current release have been closed. diff --git a/docs/api/Foundation/NSObjectFlag.xml b/docs/api/Foundation/NSObjectFlag.xml deleted file mode 100644 index 4d2eeee9ad5b..000000000000 --- a/docs/api/Foundation/NSObjectFlag.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - Sentinel class used by the MonoTouch framework. - - - The sole purpose for the NSObjectFlag class is to be used - as a sentinel in the NSObject class hierarchy to ensure that the - actual object initialization only happens in NSObject. - - - When you chain your constructors using NSObjectFlag.Empty the - only thing that will take place is the allocation of the - object instance, no calls to any of the init: methods in base - classes will be performed. If your code depends on this for - initialization, you are responsible for calling the proper - init method directly. For example: - - - - - - - Alternatively, if you need a base class to initialize itself, - you should call one of the other constructors that take some - parameters. - - - - - - - - \ No newline at end of file diff --git a/docs/api/Foundation/NSObservedChange.xml b/docs/api/Foundation/NSObservedChange.xml deleted file mode 100644 index fd11971e4416..000000000000 --- a/docs/api/Foundation/NSObservedChange.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - Changes that ocurred to an object being observed by Key-Value-Observing - - This class exposes the various components that were changes in a Key-Value-Observed property. - These are merely accessors to the underlying NSDictionary that is provided to the  method. - Instances of this class are provided to your callback methods that you provide to . - You can also create these objects if you have a dictionary that contains the keys from a key-value-observing change.   For example if you override the  method. - - - - - - - - \ No newline at end of file diff --git a/docs/api/UIKit/NSLayoutConstraint.xml b/docs/api/UIKit/NSLayoutConstraint.xml index 23cd25c31edf..ad03150f3679 100644 --- a/docs/api/UIKit/NSLayoutConstraint.xml +++ b/docs/api/UIKit/NSLayoutConstraint.xml @@ -31,25 +31,6 @@ var tconstraint1 = NSLayoutConstraint.Create (toolbar, NSLayoutAttribute.Width, Apple documentation for NSLayoutConstraint - - Visual format to use to create the constraints. - options. - - Pairs of names and values. The names should be strings (or NSStrings) and the values should be either UIViews, numbers (any C# number or NSNumber) or  instances that are suitable to be passed to the underlying engine.  - - -  This binds the provided name with the view or binds the name with the number as a metric. - - Factory method for creating a constraint using Visual Format Language. - An array of layout constraints that are suitable to be added to a using method. - - - - - - Constraints to activate. Activates all of the constraints passed. @@ -93,32 +74,6 @@ NSLayoutConstraint.ActivateConstraints(blueConstraints); It is easier to use the overload as it combines support for both metrics and views in a single call. - - First view in the constraint. - Attribute for the first view. - Relationships between the and the . - - Second view in the constraint. - This parameter can be . - This parameter can be . - - Attribute for the second view. - Multiplier applied to the second attribute. - Constants to add. - Factory method for creating a constraint. - - New constraint with the specified parameters. - - - - - Creates a constraint relationship between the and the that satisfies the following linear equation: - - - - = x + - - First view in the constraint. Attribute for the first view. diff --git a/docs/building-apps/build-items.md b/docs/building-apps/build-items.md index 00c3ee78d894..ff18c071b9e6 100644 --- a/docs/building-apps/build-items.md +++ b/docs/building-apps/build-items.md @@ -309,6 +309,40 @@ the `CollectAppManifestsDependsOn` property: ``` +## ReferenceNativeSymbol + +The item group `ReferenceNativeSymbol` can be used to specify how we should +handle a given native symbol: either ignore it, or ask the native linker to +keep it (by passing the symbol as `-u ...` or in a symbol file to the native +linker). + +There are two supported types of metadata: + +* `SymbolType`: either `ObjectiveCClass`, `Function` or `Field`. Used to + compute the complete native name of a symbol (for instance, the native + symbol for the Objective-C class `MyClass` is `_OBJC_CLASS_$_MyClass`, + while for a function `MyFunction` it's just `_MyFunction`. +* `SymbolMode`: either `Ignore` or not set. `Ignore` means to not pass the given + symbol to the native linker, the default is to do so. + +`SymbolType` is required, while `SymbolMode` isn't. + +Example symbol to keep: + +```xml + + + +``` + +Example symbol to ignore: + +```xml + + + +``` + ### SkipCodesignItems An item group that specifies files or directories in the app bundle that should not be signed. diff --git a/docs/building-apps/build-properties.md b/docs/building-apps/build-properties.md index 3496aa9e8ad7..a6ce2b52bad8 100644 --- a/docs/building-apps/build-properties.md +++ b/docs/building-apps/build-properties.md @@ -1093,37 +1093,7 @@ Only applicable to macOS and Mac Catalyst apps. ## ReferenceNativeSymbol -The item group `ReferenceNativeSymbol` can be used to specify how we should -handle a given native symbol: either ignore it, or ask the native linker to -keep it (by passing the symbol as `-u ...` or in a symbol file to the native -linker). - -There are two supported types of metadata: - -* `SymbolType`: either `ObjectiveCClass`, `Function` or `Field`. Used to - compute the complete native name of a symbol (for instance, the native - symbol for the Objective-C class `MyClass` is `_OBJC_CLASS_$_MyClass`, - while for a function `MyFunction` it's just `_MyFunction`. -* `SymbolMode`: either `Ignore` or not set. `Ignore` means to not pass the given - symbol to the native linker, the default is to do so. - -`SymbolType` is required, while `SymbolMode` isn't. - -Example symbol to keep: - -```xml - - - -``` - -Example symbol to ignore: - -```xml - - - -``` +See [ReferenceNativeSymbol](build-items.md#referencenativesymbols) ## RequireLinkWithAttributeForObjectiveCClassSearch @@ -1183,7 +1153,7 @@ This will pass `-W` to `open` if set to `true`. Example: ```shell -$ dotnet run -p:OpenWaitForExit=false +$ dotnet run -p:OpenWaitForExit=true ``` ### OpenArguments @@ -1348,7 +1318,7 @@ The default trim mode depends on numerous factors, and may also change in the fu The current (as of .NET 9) default values are: -* iOS and iOS: `partial` when building for device, `copy` when building for the simulator. +* iOS and tvOS: `partial` when building for device, `copy` when building for the simulator. * macOS: always `copy`. * Mac Catalyst: `partial` when building for the `"Release"` configuration, `copy` otherwise. diff --git a/docs/update-api-docs.md b/docs/update-api-docs.md index 1298b181f393..b6260c476986 100644 --- a/docs/update-api-docs.md +++ b/docs/update-api-docs.md @@ -47,7 +47,9 @@ The steps are: Once this pull request has been merged, an automated publishing job will get any changes in the `main` branch into the `live` branch, which will then show up on https://learn.microsoft.com. -7. The last step is to create a pull request in the [binaries](https://apidrop.visualstudio.com/_git/binaries) repository for the `netX.Y-xcodeZ.W` we created with the new assemblies (into the `master` branch). +7. Create a pull request in the [binaries](https://apidrop.visualstudio.com/_git/binaries) repository for the `netX.Y-xcodeZ.W` we created with the new assemblies (into the `master` branch). + +8. The final step is to flip the monikers from prerelease to live monikers (another ticket has to be created for this). ## How to create new monikers @@ -67,13 +69,15 @@ So for the initial .NET 10 release, when we shipped APIs for iOS 26.0, tvOS 26.0 We can't create monikers ourselves, we have to request their creation: 1. Go here: [Learn Request Central](https://microsoft.sharepoint.com/teams/Partnerships/SitePages/Learn%20Request%20Central.aspx) (you might have to request access the first time you go here) - a. Under "GitHub Publishing Services" click [Submit your request](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbRxxUz-ZV53lLrgTaBjGRmtBUNlkzT01CSzNBSE1SRU8yRzU5UTZFNjQyOC4u) - b. Fill in the form with: + 1. Under "GitHub Publishing Services" click [Submit your request](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbRxxUz-ZV53lLrgTaBjGRmtBUNlkzT01CSzNBSE1SRU8yRzU5UTZFNjQyOC4u) + 2. Fill in the form with: 1. I am working on publishing a new content set. 2. I need help with updating information architecture (IA) or navigation. 3. Request monikers. This will lead you to a template to fill an issue. Here's a sample of how I filled it out once: [#480959](https://dev.azure.com/msft-skilling/Content/_workitems/edit/480959). +Note: monikers are typically created as prerelease monikers. Another request has to be created to flip them to live monikers once everything else is in place. + It can be helpful to view info about all monikers here: [All monikers](https://ops.microsoft.com#/monikers) ## References diff --git a/dotnet/targets/Microsoft.Sdk.Desktop.targets b/dotnet/targets/Microsoft.Sdk.Desktop.targets index ab7dc89c24d9..c963d184024f 100644 --- a/dotnet/targets/Microsoft.Sdk.Desktop.targets +++ b/dotnet/targets/Microsoft.Sdk.Desktop.targets @@ -17,11 +17,11 @@ <_OpenArgumentsPre Condition="'$(OpenWaitForExit)' == 'true'">$(_OpenArgumentsPre) -W <_OpenArguments>$(_OpenArguments) $(RunEnvironment) open - $(_OpenArgumentsPre) -a "$(TargetDir)/$(AssemblyName).app" $(OpenArguments) $(_OpenArguments) --args + $(_OpenArgumentsPre) -a "$(TargetDir)/$(_AppBundleName).app" $(OpenArguments) $(_OpenArguments) --args - $(TargetDir)/$(AssemblyName).app/Contents/MacOS/$(AssemblyName) + $(TargetDir)/$(_AppBundleName).app/Contents/MacOS/$(_NativeExecutableName) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.DefaultItems.targets b/dotnet/targets/Xamarin.Shared.Sdk.DefaultItems.targets index b266a902fd6f..b970adc12d0d 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.DefaultItems.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.DefaultItems.targets @@ -59,13 +59,8 @@ - - <_IsDotNetSimulatorBuild Condition="$(RuntimeIdentifier.Contains('simulator')) Or $(RuntimeIdentifiers.Contains('simulator'))">true - <_IsDotNetSimulatorBuild Condition="'$(_IsDotNetSimulatorBuild)' == ''">false - - - iPhoneSimulator + iPhoneSimulator iPhone diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index bc230f5e281f..442b07f7456c 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -2434,7 +2434,6 @@ - - 10.0.0-prerelease.25516.4 + 11.0.0-prerelease.26064.3 diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx index ef5ac3448b31..be957d85a9c3 100644 --- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx +++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx @@ -87,9 +87,7 @@ - - Could not locate SDK bin directory - + @@ -225,13 +223,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx index 492695197ce5..cae2cb561191 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx @@ -111,11 +111,7 @@ - - - Could not locate SDK bin directory - - + @@ -294,13 +290,7 @@ Could not locate the {0} '{1}' SDK at path '{}' - - Could not locate the {0} '{1}' SDK usr path at '{2}' - The provided SDK path is missing a 'usr' directory. The following are literal names and should not be translated: SDK, usr -{0} - The platform name, such as 'iOS'. -{1} - The version number of the SDK. -{2} - The file path of the SDK. - + Could not find a valid Xcode developer path diff --git a/msbuild/Xamarin.MacDev.Tasks/Decompress.cs b/msbuild/Xamarin.MacDev.Tasks/Decompress.cs index fedb4d3f2027..019dc2d7b8ba 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Decompress.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Decompress.cs @@ -97,11 +97,13 @@ static string CanonicalizeZipEntryPath (string path) /// The zip to search in /// The relative path inside the zip to extract (may be a file or a directory). /// The location on disk to store the extracted results - /// The cancellation token (if any= + /// The cancellation token (if any) /// The location on disk to the extracted resource /// True if successfully decompressed, false otherwise. - public static bool TryDecompress (TaskLoggingHelper log, string zip, string resource, string decompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? decompressedResource) + public static bool TryDecompress (XamarinTask task, string zip, string resource, string decompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? decompressedResource) { + var log = task.Log; + decompressedResource = Path.Combine (decompressionDir, resource); var stampFile = decompressedResource.TrimEnd ('\\', '/') + ".stamp"; @@ -118,11 +120,11 @@ public static bool TryDecompress (TaskLoggingHelper log, string zip, string reso bool rv; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - rv = TryDecompressUsingSystemIOCompression (log, zip, resource, decompressionDir, cancellationToken); + rv = TryDecompressUsingSystemIOCompression (task, zip, resource, decompressionDir, cancellationToken); } else if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("XAMARIN_USE_SYSTEM_IO_COMPRESSION"))) { - rv = TryDecompressUsingSystemIOCompression (log, zip, resource, decompressionDir, cancellationToken); + rv = TryDecompressUsingSystemIOCompression (task, zip, resource, decompressionDir, cancellationToken); } else { - rv = TryDecompressUsingUnzip (log, zip, resource, decompressionDir, cancellationToken); + rv = TryDecompressUsingUnzip (task, zip, resource, decompressionDir, cancellationToken); } if (rv) { @@ -145,8 +147,9 @@ public static bool TryDecompress (TaskLoggingHelper log, string zip, string reso // The dir separator character in zip files is always "/", even on Windows const char zipDirectorySeparator = '/'; - static bool TryDecompressUsingUnzip (TaskLoggingHelper log, string zip, string resource, string decompressionDir, CancellationToken? cancellationToken) + static bool TryDecompressUsingUnzip (XamarinTask task, string zip, string resource, string decompressionDir, CancellationToken? cancellationToken) { + var log = task.Log; Directory.CreateDirectory (decompressionDir); var args = new List { "-u", "-o", @@ -176,12 +179,13 @@ static bool TryDecompressUsingUnzip (TaskLoggingHelper log, string zip, string r args.Add (zipPattern); } - var rv = XamarinTask.ExecuteAsync (log, "unzip", args, cancellationToken: cancellationToken).Result; + var rv = task.ExecuteAsync ("unzip", args, cancellationToken: cancellationToken).Result; return rv.ExitCode == 0; } - static bool TryDecompressUsingSystemIOCompression (TaskLoggingHelper log, string zip, string resource, string decompressionDir, CancellationToken? cancellationToken) + static bool TryDecompressUsingSystemIOCompression (XamarinTask task, string zip, string resource, string decompressionDir, CancellationToken? cancellationToken) { + var log = task.Log; var rv = true; // canonicalize input @@ -270,8 +274,9 @@ static bool TryDecompressUsingSystemIOCompression (TaskLoggingHelper log, string /// testing the System.IO.Compression implementation locally (with the caveat that if the resources /// to compress has symlinks, it may not work). /// - public static bool TryCompress (TaskLoggingHelper log, string zip, IEnumerable resources, bool overwrite, string workingDirectory, bool maxCompression = false) + public static bool TryCompress (XamarinTask task, string zip, IEnumerable resources, bool overwrite, string workingDirectory, bool maxCompression = false) { + var log = task.Log; if (overwrite) { if (File.Exists (zip)) { log.LogMessage (MessageImportance.Low, "Replacing zip file {0} with {1}", zip, string.Join (", ", resources)); @@ -293,19 +298,20 @@ public static bool TryCompress (TaskLoggingHelper log, string zip, IEnumerable resources, string workingDirectory, bool maxCompression) + static bool TryCompressUsingZip (XamarinTask task, string zip, IEnumerable resources, string workingDirectory, bool maxCompression) { + var log = task.Log; var zipArguments = new List (); if (maxCompression) zipArguments.Add ("-9"); @@ -318,7 +324,7 @@ static bool TryCompressUsingZip (TaskLoggingHelper log, string zip, IEnumerable< var relativePath = PathUtils.AbsoluteToRelative (workingDirectory, fullPath); zipArguments.Add (relativePath); } - var rv = XamarinTask.ExecuteAsync (log, "zip", zipArguments, workingDirectory: workingDirectory).Result; + var rv = task.ExecuteAsync ("zip", zipArguments, workingDirectory: workingDirectory).Result; log.LogMessage (MessageImportance.Low, "Updated {0} with {1}: {2}", zip, string.Join (", ", resources), rv.ExitCode == 0); return rv.ExitCode == 0; } @@ -330,8 +336,9 @@ static bool TryCompressUsingZip (TaskLoggingHelper log, string zip, IEnumerable< #endif // Will always add to an existing zip file (not replace) - static bool TryCompressUsingSystemIOCompression (TaskLoggingHelper log, string zip, IEnumerable resources, string workingDirectory, bool maxCompression) + static bool TryCompressUsingSystemIOCompression (XamarinTask task, string zip, IEnumerable resources, string workingDirectory, bool maxCompression) { + var log = task.Log; var rv = true; workingDirectory = Path.GetFullPath (workingDirectory); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/AlTool.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/AlTool.cs index 63e0de67c8bb..366f00d9ada1 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/AlTool.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/AlTool.cs @@ -45,7 +45,7 @@ public override bool Execute () cancellationTokenSource = new CancellationTokenSource (); var rv = ExecuteAsync (Log, executable, args, sdkDevPath: SdkDevPath, cancellationToken: cancellationTokenSource.Token).Result; - LogErrorsFromOutput (rv.StandardOutput?.ToString ()); + LogErrorsFromOutput (rv.Output.MergedOutput); return !Log.HasLoggedErrors; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs index f1c25499eb98..8d43e4cc110c 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs @@ -362,15 +362,15 @@ void Sign (SignInfo info) var environment = new Dictionary () { { "CODESIGN_ALLOCATE", GetCodesignAllocate (item) }, }; - var rv = ExecuteAsync (fileName, arguments, null, environment, mergeOutput: false).Result; + var rv = ExecuteAsync (fileName, arguments, null, environment).Result; var exitCode = rv.ExitCode; - var messages = rv.StandardOutput?.ToString () ?? string.Empty; + var messages = rv.Output.StandardOutput; if (messages.Length > 0) Log.LogMessage (MessageImportance.Normal, "{0}", messages.ToString ()); if (exitCode != 0) { - var errors = rv.StandardError?.ToString () ?? string.Empty; + var errors = rv.Output.StandardError; if (errors.Length > 0) Log.LogError (MSBStrings.E0004, item.ItemSpec, errors); else diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs index a39129a27648..0173f0474810 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs @@ -73,7 +73,7 @@ public override bool Execute () if (string.IsNullOrEmpty (enableCodeSigning)) enableCodeSigning = bundle.GetMetadata ("RequireCodeSigning"); var codesignSigningKey = bundle.GetMetadata ("CodesignSigningKey"); - if (!string.Equals (enableCodeSigning, "true") && string.IsNullOrEmpty (codesignSigningKey)) + if (!string.Equals (enableCodeSigning, "true", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty (codesignSigningKey)) continue; // Create a new item for the app bundle, and copy any metadata over. diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs index 29f19cff1f89..f30f62555eb7 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs @@ -60,16 +60,16 @@ int Compile (ITaskItem item, string outputDir, string log, string partialPlist) args.Add (partialPlist); var executable = GetExecutable (args, ToolName, CoreMlcPath); - var rv = ExecuteAsync (executable, args, sdkDevPath, mergeOutput: false).Result; + var rv = ExecuteAsync (executable, args, sdkDevPath).Result; var exitCode = rv.ExitCode; - var output = rv.StandardOutput!.ToString (); + var output = rv.Output.StandardOutput; File.WriteAllText (log, output); if (exitCode != 0) { // Note: coremlc exited with an error. Dump everything we can to help the user // diagnose the issue and then delete the log file so that rebuilding tries // again. - var errors = rv.StandardError!.ToString (); + var errors = rv.Output.StandardError; if (errors.Length > 0) Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, "{0}", errors); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs index 236255778be5..048c09394d28 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateBindingResourcePackage.cs @@ -100,7 +100,7 @@ public override bool Execute () var workingDirectory = Path.GetDirectoryName (nativeRef); if (string.IsNullOrEmpty (workingDirectory)) workingDirectory = Directory.GetCurrentDirectory (); - CompressionHelper.TryCompress (Log, zipFile, new string [] { nativeRef }, false, workingDirectory, true); + CompressionHelper.TryCompress (this, zipFile, new string [] { nativeRef }, false, workingDirectory, true); } packagedFiles.Add (zipFile); } else { diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs index 0249f04a0463..084c0cc3ecd3 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/DetectSdkLocation.cs @@ -15,13 +15,10 @@ public class DetectSdkLocations : XamarinTask, ICancelableTask { const string SdkVersionDefaultValue = "default"; #region Inputs - public string TargetArchitectures { - get; set; - } = ""; - - public string IsDotNetSimulatorBuild { + [Required] + public bool SdkIsSimulator { get; set; - } = ""; + } #endregion Inputs @@ -32,26 +29,11 @@ public string SdkRoot { get; set; } = ""; - [Output] - public string SdkBinPath { - get; set; - } = ""; - [Output] public string SdkDevPath { get; set; } = ""; - [Output] - public string SdkUsrPath { - get; set; - } = ""; - - [Output] - public bool SdkIsSimulator { - get; set; - } - [Output] public string SdkPlatform { get; set; @@ -130,14 +112,6 @@ protected void EnsureSdkPath () SdkRoot = currentSdk.GetSdkPath (SdkVersion, SdkIsSimulator); if (string.IsNullOrEmpty (SdkRoot)) Log.LogError (MSBStrings.E0084 /* Could not locate the {0} '{1}' SDK at path '{2}' */, PlatformName, SdkVersion, SdkRoot); - - SdkUsrPath = DirExists ("SDK usr directory", Path.Combine (currentSdk.DeveloperRoot, "usr")) ?? ""; - if (string.IsNullOrEmpty (SdkUsrPath)) - Log.LogError (MSBStrings.E0085 /* Could not locate the {0} '{1}' SDK usr path at '{2}' */, PlatformName, SdkVersion, SdkRoot); - - SdkBinPath = DirExists ("SDK bin directory", Path.Combine (SdkUsrPath, "bin")) ?? ""; - if (string.IsNullOrEmpty (SdkBinPath)) - Log.LogError (MSBStrings.E0032 /* Could not locate SDK bin directory */); } void EnsureXamarinSdkRoot () @@ -172,8 +146,6 @@ bool ExecuteImpl () AppleSdkSettings.Init (); - SetIsSimulator (); - if (EnsureAppleSdkRoot ()) EnsureSdkPath (); EnsureXamarinSdkRoot (); @@ -183,25 +155,6 @@ bool ExecuteImpl () return !Log.HasLoggedErrors; } - void SetIsSimulator () - { - switch (Platform) { - case ApplePlatform.MacCatalyst: - case ApplePlatform.MacOSX: - return; - } - - TargetArchitecture architectures; - if (string.IsNullOrEmpty (TargetArchitectures) || !Enum.TryParse (TargetArchitectures, out architectures)) - architectures = TargetArchitecture.Default; - - if (!string.IsNullOrEmpty (IsDotNetSimulatorBuild)) { - SdkIsSimulator = string.Equals (IsDotNetSimulatorBuild, "true", StringComparison.OrdinalIgnoreCase); - } else { - SdkIsSimulator = (architectures & (TargetArchitecture.i386 | TargetArchitecture.x86_64)) != 0; - } - } - protected bool EnsureAppleSdkRoot () { var currentSdk = CurrentSdk; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/LinkNativeCode.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/LinkNativeCode.cs index c7f3d06c0264..ad7f93d0114c 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/LinkNativeCode.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/LinkNativeCode.cs @@ -215,7 +215,7 @@ bool ExecuteUnsafe () var rv = ExecuteAsync ("xcrun", arguments, sdkDevPath: SdkDevPath, showErrorIfFailure: false).Result; if (rv.ExitCode != 0) { - var stderr = rv.StandardError?.ToString ()?.Trim (); + var stderr = rv.Output.MergedOutput; #if NET if (string.IsNullOrEmpty (stderr)) { #else diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/OptimizeImage.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/OptimizeImage.cs index 1b2dab4b0d55..6fef2efe045f 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/OptimizeImage.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/OptimizeImage.cs @@ -92,13 +92,13 @@ public override bool Execute () ForEach (listOfArguments, (arg) => { var args = arg.Arguments; var executable = GetExecutable (args, "pngcrush", PngCrushPath); - ExecuteAsync (Log, executable, args, sdkDevPath: SdkDevPath, mergeOutput: true, showErrorIfFailure: false /* we show our own error below */, cancellationToken: cancellationTokenSource.Token) + ExecuteAsync (Log, executable, args, sdkDevPath: SdkDevPath, showErrorIfFailure: false /* we show our own error below */, cancellationToken: cancellationTokenSource.Token) .ContinueWith ((v) => { Execution execution = v.Result; if (execution.ExitCode != 0) Log.LogError (MSBStrings.E7134 /* Failed to optimize the image {0}, pngcrush exited with code {1}. */, Path.GetFileName (arg.Input), execution.ExitCode); - var output = execution.StandardOutput?.ToString () ?? string.Empty; + var output = execution.Output.MergedOutput; foreach (var line in output.Split ('\n')) { LogEventsFromTextOutput (line, arg.Input, MessageImportance.Normal); } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ResolveNativeReferences.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ResolveNativeReferences.cs index 3aab40aaecd7..a40e837b802b 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ResolveNativeReferences.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ResolveNativeReferences.cs @@ -198,7 +198,7 @@ void ProcessNativeReference (ITaskItem item, string name, List native // (compressed) xcframework if (name.EndsWith (".xcframework", StringComparison.OrdinalIgnoreCase) || name.EndsWith (".xcframework.zip", StringComparison.OrdinalIgnoreCase)) { - if (!TryResolveXCFramework (Log, TargetFrameworkMoniker, SdkIsSimulator, Architectures, name, GetIntermediateDecompressionDir (item), createdFiles, cancellationToken, out var nativeLibraryPath)) + if (!TryResolveXCFramework (this, TargetFrameworkMoniker, SdkIsSimulator, Architectures, name, GetIntermediateDecompressionDir (item), createdFiles, cancellationToken, out var nativeLibraryPath)) return; var nr = new TaskItem (item); SetMetadataNativeLibrary (nr, nativeLibraryPath); @@ -208,7 +208,7 @@ void ProcessNativeReference (ITaskItem item, string name, List native // compressed framework if (name.EndsWith (".framework.zip", StringComparison.OrdinalIgnoreCase)) { - if (!CompressionHelper.TryDecompress (Log, name, Path.GetFileNameWithoutExtension (name), GetIntermediateDecompressionDir (item), createdFiles, cancellationToken, out var frameworkPath)) + if (!CompressionHelper.TryDecompress (this, name, Path.GetFileNameWithoutExtension (name), GetIntermediateDecompressionDir (item), createdFiles, cancellationToken, out var frameworkPath)) return; var nr = new TaskItem (item); nr.ItemSpec = GetActualLibrary (frameworkPath); @@ -311,14 +311,14 @@ void ProcessSidecar (ITaskItem r, string resources, List native_frame ITaskItem t = new TaskItem (r); var name = referenceNode.Attributes ["Name"].Value.Trim ('\\', '/'); if (name.EndsWith (".xcframework", StringComparison.Ordinal) || name.EndsWith (".xcframework.zip", StringComparison.Ordinal)) { - if (!TryResolveXCFramework (Log, TargetFrameworkMoniker, SdkIsSimulator, Architectures, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out var nativeLibraryPath)) + if (!TryResolveXCFramework (this, TargetFrameworkMoniker, SdkIsSimulator, Architectures, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out var nativeLibraryPath)) continue; SetMetadataNativeLibrary (t, nativeLibraryPath); } else if (name.EndsWith (".framework", StringComparison.Ordinal)) { string? frameworkPath; if (!isCompressed) { frameworkPath = Path.Combine (resources, name); - } else if (!CompressionHelper.TryDecompress (Log, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out frameworkPath)) { + } else if (!CompressionHelper.TryDecompress (this, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out frameworkPath)) { continue; } t.ItemSpec = GetActualLibrary (frameworkPath); @@ -330,7 +330,7 @@ void ProcessSidecar (ITaskItem r, string resources, List native_frame string? dylibPath; if (!isCompressed) { dylibPath = Path.Combine (resources, name); - } else if (!CompressionHelper.TryDecompress (Log, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out dylibPath)) { + } else if (!CompressionHelper.TryDecompress (this, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out dylibPath)) { continue; } t.ItemSpec = dylibPath; @@ -341,7 +341,7 @@ void ProcessSidecar (ITaskItem r, string resources, List native_frame string? aPath; if (!isCompressed) { aPath = Path.Combine (resources, name); - } else if (!CompressionHelper.TryDecompress (Log, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out aPath)) { + } else if (!CompressionHelper.TryDecompress (this, resources, name, GetIntermediateDecompressionDir (resources), createdFiles, cancellationToken, out aPath)) { continue; } t.ItemSpec = aPath; @@ -378,7 +378,7 @@ void ProcessSidecar (ITaskItem r, string resources, List native_frame /// A full path to the resolved native library within the xcframework. If 'resourcePath' is compressed, this will point to where the native library is decompressed on disk. /// /// True if a native library was successfully found. Otherwise false, and an error will have been printed to the log. - public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFrameworkMoniker, bool isSimulator, string? architectures, string path, string intermediateDecompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? nativeLibraryPath) + public static bool TryResolveXCFramework (XamarinTask task, string targetFrameworkMoniker, bool isSimulator, string? architectures, string path, string intermediateDecompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? nativeLibraryPath) { string resourcePath; string xcframework; @@ -390,7 +390,7 @@ public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFr resourcePath = Path.GetDirectoryName (path); xcframework = Path.GetFileName (path); } - return TryResolveXCFramework (log, targetFrameworkMoniker, isSimulator, architectures, resourcePath, xcframework, intermediateDecompressionDir, createdFiles, cancellationToken, out nativeLibraryPath); + return TryResolveXCFramework (task, targetFrameworkMoniker, isSimulator, architectures, resourcePath, xcframework, intermediateDecompressionDir, createdFiles, cancellationToken, out nativeLibraryPath); } /// @@ -405,8 +405,9 @@ public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFr /// A full path to the resolved native library within the xcframework. If 'resourcePath' is compressed, this will point to where the native library is decompressed on disk. /// /// True if a native library was successfully found. Otherwise false, and an error will have been printed to the log. - public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFrameworkMoniker, bool isSimulator, string? architectures, string resourcePath, string xcframework, string intermediateDecompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? nativeLibraryPath) + public static bool TryResolveXCFramework (XamarinTask task, string targetFrameworkMoniker, bool isSimulator, string? architectures, string resourcePath, string xcframework, string intermediateDecompressionDir, List createdFiles, CancellationToken? cancellationToken, [NotNullWhen (true)] out string? nativeLibraryPath) { + var log = task.Log; nativeLibraryPath = null; try { @@ -421,7 +422,7 @@ public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFr if (!isCompressed && CompressionHelper.IsCompressed (xcframework)) { var zipPath = Path.Combine (resourcePath, xcframework); var xcframeworkName = Path.GetFileNameWithoutExtension (xcframework); - if (!CompressionHelper.TryDecompress (log, zipPath, xcframeworkName, intermediateDecompressionDir, createdFiles, cancellationToken, out var decompressedXcframeworkPath)) + if (!CompressionHelper.TryDecompress (task, zipPath, xcframeworkName, intermediateDecompressionDir, createdFiles, cancellationToken, out var decompressedXcframeworkPath)) return false; nativeLibraryPath = Path.Combine (intermediateDecompressionDir, xcframeworkName, nativeLibraryRelativePath); @@ -434,7 +435,7 @@ public static bool TryResolveXCFramework (TaskLoggingHelper log, string targetFr } var zipResource = Path.Combine (xcframework, Path.GetDirectoryName (nativeLibraryRelativePath)); - if (!CompressionHelper.TryDecompress (log, resourcePath, zipResource, intermediateDecompressionDir, createdFiles, cancellationToken, out var decompressedPath)) + if (!CompressionHelper.TryDecompress (task, resourcePath, zipResource, intermediateDecompressionDir, createdFiles, cancellationToken, out var decompressedPath)) return false; nativeLibraryPath = Path.Combine (intermediateDecompressionDir, xcframework, nativeLibraryRelativePath); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/Unzip.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/Unzip.cs index 5b24af469603..5a4c4afaf1d5 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/Unzip.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/Unzip.cs @@ -79,7 +79,7 @@ bool ExecuteLocally () { var createdFiles = new List (); cancellationTokenSource = new CancellationTokenSource (); - if (!CompressionHelper.TryDecompress (Log, ZipFilePath!.ItemSpec, Resource, ExtractionPath, createdFiles, cancellationTokenSource.Token, out var _)) + if (!CompressionHelper.TryDecompress (this, ZipFilePath!.ItemSpec, Resource, ExtractionPath, createdFiles, cancellationTokenSource.Token, out var _)) return false; TouchedFiles = createdFiles.Select (v => new TaskItem (v)).ToArray (); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs index 1a7ef1623ae1..1bbb84be1afc 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs @@ -97,13 +97,13 @@ protected string GetSdkPlatform (bool isSimulator) return PlatformFrameworkHelper.GetSdkPlatform (Platform, isSimulator); } - protected System.Threading.Tasks.Task ExecuteAsync (string fileName, IList arguments, string? sdkDevPath = null, Dictionary? environment = null, bool mergeOutput = true, bool showErrorIfFailure = true, string? workingDirectory = null) + internal protected System.Threading.Tasks.Task ExecuteAsync (string fileName, IList arguments, string? sdkDevPath = null, Dictionary? environment = null, bool showErrorIfFailure = true, string? workingDirectory = null, CancellationToken? cancellationToken = null) { - return ExecuteAsync (Log, fileName, arguments, sdkDevPath, environment, mergeOutput, showErrorIfFailure, workingDirectory); + return ExecuteAsync (Log, fileName, arguments, sdkDevPath, environment, showErrorIfFailure, workingDirectory, cancellationToken); } static int executionCounter; - internal protected static async System.Threading.Tasks.Task ExecuteAsync (TaskLoggingHelper log, string fileName, IList arguments, string? sdkDevPath = null, Dictionary? environment = null, bool mergeOutput = true, bool showErrorIfFailure = true, string? workingDirectory = null, CancellationToken? cancellationToken = null) + internal protected static async System.Threading.Tasks.Task ExecuteAsync (TaskLoggingHelper log, string fileName, IList arguments, string? sdkDevPath = null, Dictionary? environment = null, bool showErrorIfFailure = true, string? workingDirectory = null, CancellationToken? cancellationToken = null) { // Create a new dictionary if we're given one, to make sure we don't change the caller's dictionary. var launchEnvironment = environment is null ? new Dictionary () : new Dictionary (environment); @@ -123,16 +123,11 @@ internal protected static async System.Threading.Tasks.Task ExecuteAs log.LogMessage (MessageImportance.Low, " {0}={1}", kvp.Key, kvp.Value); } } - var rv = await Execution.RunAsync (fileName, arguments, environment: launchEnvironment, mergeOutput: mergeOutput, workingDirectory: workingDirectory, cancellationToken: cancellationToken); + var rv = await Execution.RunAsync (fileName, arguments, environment: launchEnvironment, workingDirectory: workingDirectory, cancellationToken: cancellationToken); log.LogMessage (rv.ExitCode == 0 ? MessageImportance.Low : MessageImportance.High, MSBStrings.M0002, currentId, rv.Duration, rv.ExitCode); // Finished external tool execution #{0} in {1} and with exit code {2}. // Show the output - var output = rv.StandardOutput!.ToString (); - if (!mergeOutput) { - if (output.Length > 0) - output += Environment.NewLine; - output += rv.StandardError!.ToString (); - } + var output = rv.Output.MergedOutput; if (output.Length > 0) { var importance = MessageImportance.Low; if (rv.ExitCode != 0) @@ -141,7 +136,7 @@ internal protected static async System.Threading.Tasks.Task ExecuteAs } if (showErrorIfFailure && rv.ExitCode != 0) { - var stderr = rv.StandardError!.ToString ().Trim (); + var stderr = rv.Output.StandardError.Trim (); if (stderr.Length > 1024) stderr = stderr.Substring (0, 1024); if (string.IsNullOrEmpty (stderr)) { diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeBuildTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeBuildTask.cs index dff2c77c4f0f..79a2ffb7b36d 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeBuildTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeBuildTask.cs @@ -25,7 +25,7 @@ public override bool Execute () } args.AddRange (GenerateCommandLineCommands ()); - ExecuteAsync ("xcrun", args, sdkDevPath: SdkDevPath, mergeOutput: false, workingDirectory: WorkingDirectory).Wait (); + ExecuteAsync ("xcrun", args, sdkDevPath: SdkDevPath, workingDirectory: WorkingDirectory).Wait (); return !Log.HasLoggedErrors; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs index c7f8762a91fd..1be61b08f5fd 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs @@ -38,8 +38,6 @@ public abstract class XcodeCompilerToolTask : XamarinTask, IHasProjectDir, IHasR [Required] public string ResourcePrefix { get; set; } = string.Empty; - public string SdkBinPath { get; set; } = string.Empty; - [Required] public string SdkPlatform { get; set; } = string.Empty; @@ -53,8 +51,6 @@ public string SdkDevPath { set { sdkDevPath = value; } } - public string SdkUsrPath { get; set; } = string.Empty; - [Required] public string SdkVersion { get; set; } = string.Empty; @@ -184,12 +180,6 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) var environment = new Dictionary (); var args = new List (); - if (!string.IsNullOrEmpty (SdkBinPath)) - environment.Add ("PATH", SdkBinPath); - - if (!string.IsNullOrEmpty (SdkUsrPath)) - environment.Add ("XCODE_DEVELOPER_USR_PATH", SdkUsrPath); - if (!string.IsNullOrEmpty (SdkDevPath)) environment.Add ("DEVELOPER_DIR", SdkDevPath); @@ -229,16 +219,16 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) if (Log.HasLoggedErrors) return 1; - var rv = ExecuteAsync (tool, args, sdkDevPath, environment: environment, mergeOutput: false).Result; + var rv = ExecuteAsync (tool, args, sdkDevPath, environment: environment).Result; var exitCode = rv.ExitCode; - var messages = rv.StandardOutput!.ToString (); + var messages = rv.Output.StandardOutput; File.WriteAllText (manifest.ItemSpec, messages); if (exitCode != 0) { // Note: ibtool or actool exited with an error. Dump everything we can to help the user // diagnose the issue and then delete the manifest log file so that rebuilding tries // again (in case of ibtool's infamous spurious errors). - var errors = rv.StandardError!.ToString (); + var errors = rv.Output.StandardError; if (errors.Length > 0) Log.LogError (null, null, null, items [0].ItemSpec, 0, 0, 0, 0, "{0}", errors); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeTool.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeTool.cs index d01c1bbd408b..ee357deeaa0a 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeTool.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeTool.cs @@ -27,15 +27,9 @@ public abstract class XcodeToolTaskBase : XamarinTask, IHasProjectDir, IHasResou [Required] public string ResourcePrefix { get; set; } = string.Empty; - [Required] - public string SdkBinPath { get; set; } = string.Empty; - [Required] public string SdkDevPath { get; set; } = string.Empty; - [Required] - public string SdkUsrPath { get; set; } = string.Empty; - public string ToolExe { get { return toolExe ?? ToolName; } set { toolExe = value; } @@ -107,9 +101,6 @@ int ExecuteTool (ITaskItem input, ITaskItem output) var environment = new Dictionary (); var args = new List (); - environment.Add ("PATH", SdkBinPath); - environment.Add ("XCODE_DEVELOPER_USR_PATH", SdkUsrPath); - AppendCommandLineArguments (environment, args, input, output); var rv = ExecuteAsync (GetFullPathToTool (), args, environment: environment).Result; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/Zip.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/Zip.cs index 42300770269d..42c4b199a034 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/Zip.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/Zip.cs @@ -54,7 +54,7 @@ public override bool Execute () for (int i = 0; i < Sources.Length; i++) sources.Add (Sources [i].GetMetadata ("FullPath")); - if (!CompressionHelper.TryCompress (Log, zip, sources, false, workingDirectory, false)) + if (!CompressionHelper.TryCompress (this, zip, sources, false, workingDirectory, false)) return false; return !Log.HasLoggedErrors; diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index eaad02183e4c..1ac131fd92a6 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -908,8 +908,6 @@ Copyright (C) 2018 Microsoft. All rights reserved. ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" SdkDevPath="$(_SdkDevPath)" - SdkBinPath="$(_SdkBinPath)" - SdkUsrPath="$(_SdkUsrPath)" SdkRoot="$(_SdkRoot)" SdkPlatform="$(_SdkPlatform)" SdkVersion="$(_SdkVersion)" @@ -1044,8 +1042,6 @@ Copyright (C) 2018 Microsoft. All rights reserved. ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" SdkDevPath="$(_SdkDevPath)" - SdkBinPath="$(_SdkBinPath)" - SdkUsrPath="$(_SdkUsrPath)" SdkPlatform="$(_SdkPlatform)" SdkVersion="$(_SdkVersion)" TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)" @@ -1458,8 +1454,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" SdkDevPath="$(_SdkDevPath)" - SdkBinPath="$(_SdkBinPath)" - SdkUsrPath="$(_SdkUsrPath)"> + > @@ -2072,20 +2067,16 @@ Copyright (C) 2018 Microsoft. All rights reserved. - - - diff --git a/src/AppKit/NSColor.cs b/src/AppKit/NSColor.cs index efd20e074bc4..d886ef6434bd 100644 --- a/src/AppKit/NSColor.cs +++ b/src/AppKit/NSColor.cs @@ -442,7 +442,7 @@ public void GetComponents (out nfloat [] components) /// To be added. /// To be added. /// To be added. - public override string ToString () + public override string? ToString () { try { string name = this.ColorSpaceName; diff --git a/src/AppKit/NSOpenGLContext.cs b/src/AppKit/NSOpenGLContext.cs index f7ec233a714d..141be940c961 100644 --- a/src/AppKit/NSOpenGLContext.cs +++ b/src/AppKit/NSOpenGLContext.cs @@ -1,7 +1,5 @@ #if !__MACCATALYST__ -#if !NO_SYSTEM_DRAWING using System.Drawing; -#endif #nullable enable @@ -24,7 +22,6 @@ unsafe void SetValue (int /* GLint */ val, NSOpenGLContextParameter par) return ret; } -#if !NO_SYSTEM_DRAWING /// To be added. /// To be added. /// To be added. @@ -38,7 +35,6 @@ unsafe public Rectangle SwapRectangle { SetValues ((IntPtr) (&value), NSOpenGLContextParameter.SwapRectangle); } } -#endif /// To be added. /// To be added. diff --git a/src/AudioToolbox/AudioFile.cs b/src/AudioToolbox/AudioFile.cs index 4f63f6978a75..246d72c930df 100644 --- a/src/AudioToolbox/AudioFile.cs +++ b/src/AudioToolbox/AudioFile.cs @@ -2376,10 +2376,11 @@ public unsafe byte []? ID3Tag { public AudioFileInfoDictionary? InfoDictionary { get { var ptr = GetIntPtr (AudioFileProperty.InfoDictionary); - if (ptr == IntPtr.Zero) + var dict = Runtime.GetNSObject (ptr, owns: true); + if (dict is null) return null; - return new AudioFileInfoDictionary (new NSMutableDictionary (ptr, true)); + return new AudioFileInfoDictionary (dict); } } diff --git a/src/AudioToolbox/AudioToolbox.cs b/src/AudioToolbox/AudioToolbox.cs index 6aee49c0421d..2dd9149cd005 100644 --- a/src/AudioToolbox/AudioToolbox.cs +++ b/src/AudioToolbox/AudioToolbox.cs @@ -39,8 +39,8 @@ internal InstrumentInfo (NSDictionary d) /// To be added. /// To be added. /// To be added. - public string Name { - get { return Dictionary [NameKey].ToString (); } + public string? Name { + get { return Dictionary [NameKey]?.ToString (); } } /// To be added. diff --git a/src/CoreBluetooth/CBUUID.cs b/src/CoreBluetooth/CBUUID.cs index 184f0dff17d3..9528f9b61fb4 100644 --- a/src/CoreBluetooth/CBUUID.cs +++ b/src/CoreBluetooth/CBUUID.cs @@ -110,7 +110,7 @@ public unsafe bool Equals (CBUUID? obj) /// To be added. /// To be added. /// To be added. - public override bool Equals (object obj) + public override bool Equals (object? obj) { return base.Equals (obj); } diff --git a/src/CoreFoundation/CFException.cs b/src/CoreFoundation/CFException.cs index 8ded3146ce11..b60c80b7b051 100644 --- a/src/CoreFoundation/CFException.cs +++ b/src/CoreFoundation/CFException.cs @@ -144,7 +144,7 @@ public static CFException FromCFError (IntPtr cfErrorHandle, bool release) using (var userInfo = new NSDictionary (cfUserInfo)) { foreach (var i in userInfo) { if (i.Key is not null) - e.Data.Add (i.Key.ToString (), i.Value?.ToString ()); + e.Data.Add (i.Key.ToString () ?? "", i.Value?.ToString () ?? ""); } } } diff --git a/src/CoreGraphics/CGEventTypes.cs b/src/CoreGraphics/CGEventTypes.cs index 73f1af09291f..db2e8dd989f9 100644 --- a/src/CoreGraphics/CGEventTypes.cs +++ b/src/CoreGraphics/CGEventTypes.cs @@ -12,9 +12,8 @@ #if MONOMAC || __MACCATALYST__ -#if !NO_SYSTEM_DRAWING using System.Drawing; -#endif + using CoreFoundation; namespace CoreGraphics { diff --git a/src/CoreGraphics/CGPoint.cs b/src/CoreGraphics/CGPoint.cs index ddcf9733786a..fa6811f5be33 100644 --- a/src/CoreGraphics/CGPoint.cs +++ b/src/CoreGraphics/CGPoint.cs @@ -1,12 +1,9 @@ #nullable enable +using System.Drawing; using System.Globalization; using System.Runtime.CompilerServices; -#if !NO_SYSTEM_DRAWING -using System.Drawing; -#endif - using CoreFoundation; namespace CoreGraphics { @@ -47,7 +44,6 @@ public struct CGPoint : IEquatable { return new CGPoint (l.x - r.Width, l.y - r.Height); } -#if !NO_SYSTEM_DRAWING public static implicit operator CGPoint (PointF point) { return new CGPoint (point.X, point.Y); @@ -67,7 +63,6 @@ public static explicit operator Point (CGPoint point) { return new Point ((int) point.X, (int) point.Y); } -#endif /// To be added. /// To be added. diff --git a/src/CoreGraphics/CGRect.cs b/src/CoreGraphics/CGRect.cs index ec6933bc75bc..16604ff59134 100644 --- a/src/CoreGraphics/CGRect.cs +++ b/src/CoreGraphics/CGRect.cs @@ -1,12 +1,9 @@ #nullable enable +using System.Drawing; using System.Globalization; using System.Runtime.CompilerServices; -#if !NO_SYSTEM_DRAWING -using System.Drawing; -#endif - using CoreFoundation; namespace CoreGraphics { @@ -75,7 +72,6 @@ public static CGRect Infinite { left.Height != right.Height; } -#if !NO_SYSTEM_DRAWING public static implicit operator CGRect (RectangleF rect) { return new CGRect (rect.X, rect.Y, rect.Width, rect.Height); @@ -95,7 +91,6 @@ public static explicit operator Rectangle (CGRect rect) { return new Rectangle ((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height); } -#endif /// /// A rectangle to intersect. diff --git a/src/CoreGraphics/CGSize.cs b/src/CoreGraphics/CGSize.cs index 042b8587e542..b90f2e664007 100644 --- a/src/CoreGraphics/CGSize.cs +++ b/src/CoreGraphics/CGSize.cs @@ -1,12 +1,9 @@ #nullable enable +using System.Drawing; using System.Globalization; using System.Runtime.CompilerServices; -#if !NO_SYSTEM_DRAWING -using System.Drawing; -#endif - using CoreFoundation; namespace CoreGraphics { @@ -44,7 +41,6 @@ public struct CGSize : IEquatable { return new CGSize (l.width - r.Width, l.height - r.Height); } -#if !NO_SYSTEM_DRAWING public static implicit operator CGSize (SizeF size) { return new CGSize (size.Width, size.Height); @@ -64,7 +60,6 @@ public static explicit operator Size (CGSize size) { return new Size ((int) size.Width, (int) size.Height); } -#endif public static explicit operator CGPoint (CGSize size) { diff --git a/src/CoreImage/CIDetectorOptions.cs b/src/CoreImage/CIDetectorOptions.cs index 857711acc3c8..f6314e7137d0 100644 --- a/src/CoreImage/CIDetectorOptions.cs +++ b/src/CoreImage/CIDetectorOptions.cs @@ -89,19 +89,19 @@ internal NSDictionary ToDictionary () // Tracking exists only in iOS6+, before this the field is null (and would throw if used) if (CIDetector.Tracking is not null && TrackingEnabled is not null) { keys.Add (CIDetector.Tracking); - values.Add (NSObject.FromObject (TrackingEnabled.Value)); + values.Add (NSObject.FromObject (TrackingEnabled.Value)!); } // EyeBlink exists only in iOS7+, before this the field is null (and would throw if used) if (CIDetector.EyeBlink is not null && EyeBlink is not null) { keys.Add (CIDetector.EyeBlink); - values.Add (NSObject.FromObject (EyeBlink.Value)); + values.Add (NSObject.FromObject (EyeBlink.Value)!); } // Smile exists only in iOS7+, before this the field is null (and would throw if used) if (CIDetector.Smile is not null && Smile is not null) { keys.Add (CIDetector.Smile); - values.Add (NSObject.FromObject (Smile.Value)); + values.Add (NSObject.FromObject (Smile.Value)!); } // AspectRation exists only in iOS8+, before this the field is null (and would throw if used) if (CIDetector.AspectRatio is not null && AspectRatio is not null) { diff --git a/src/CoreText/CTFont.cs b/src/CoreText/CTFont.cs index 3f39409251b4..f3e935a4eac7 100644 --- a/src/CoreText/CTFont.cs +++ b/src/CoreText/CTFont.cs @@ -429,7 +429,10 @@ public string? Name { /// To be added. public FontFeatureGroup FeatureGroup { get { - return (FontFeatureGroup) (int) (NSNumber) Dictionary [CTFontFeatureKey.Identifier]; + var number = (NSNumber?) Dictionary [CTFontFeatureKey.Identifier]; + if (number is null) + return default; + return (FontFeatureGroup) (int) number; } } @@ -591,7 +594,10 @@ internal static CTFontFeatureSelectors Create (FontFeatureGroup featureGroup, NS /// To be added. protected int FeatureWeak { get { - return (int) (NSNumber) Dictionary [CTFontFeatureSelectorKey.Identifier]; + var number = (NSNumber?) Dictionary [CTFontFeatureSelectorKey.Identifier]; + if (number is null) + return default; + return (int) number; } } @@ -2327,7 +2333,10 @@ internal CTFontFeatureSettings (NSDictionary dictionary) /// To be added. public FontFeatureGroup FeatureGroup { get { - return (FontFeatureGroup) (int) (NSNumber) Dictionary [CTFontFeatureKey.Identifier]; + var number = (NSNumber?) Dictionary [CTFontFeatureKey.Identifier]; + if (number is null) + return default; + return (FontFeatureGroup) (int) number; } } @@ -2336,7 +2345,10 @@ public FontFeatureGroup FeatureGroup { /// To be added. public int FeatureWeak { get { - return (int) (NSNumber) Dictionary [CTFontFeatureSelectorKey.Identifier]; + var number = (NSNumber?) Dictionary [CTFontFeatureSelectorKey.Identifier]; + if (number is null) + return default; + return (int) number; } } } @@ -2375,32 +2387,32 @@ public CTFontVariationAxes (NSDictionary dictionary) /// To be added. /// To be added. /// To be added. - public NSNumber Identifier { - get { return (NSNumber) Dictionary [CTFontVariationAxisKey.Identifier]; } + public NSNumber? Identifier { + get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.Identifier]; } set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.Identifier, value); } } /// To be added. /// To be added. /// To be added. - public NSNumber MinimumValue { - get { return (NSNumber) Dictionary [CTFontVariationAxisKey.MinimumValue]; } + public NSNumber? MinimumValue { + get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.MinimumValue]; } set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.MinimumValue, value); } } /// To be added. /// To be added. /// To be added. - public NSNumber MaximumValue { - get { return (NSNumber) Dictionary [CTFontVariationAxisKey.MaximumValue]; } + public NSNumber? MaximumValue { + get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.MaximumValue]; } set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.MaximumValue, value); } } /// To be added. /// To be added. /// To be added. - public NSNumber DefaultValue { - get { return (NSNumber) Dictionary [CTFontVariationAxisKey.DefaultValue]; } + public NSNumber? DefaultValue { + get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.DefaultValue]; } set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.DefaultValue, value); } } diff --git a/src/CoreText/CTFontDescriptor.cs b/src/CoreText/CTFontDescriptor.cs index 904dc8b5f288..f76469c2c077 100644 --- a/src/CoreText/CTFontDescriptor.cs +++ b/src/CoreText/CTFontDescriptor.cs @@ -315,7 +315,7 @@ public IEnumerable? CascadeList { /// /// public NSCharacterSet? CharacterSet { - get { return (NSCharacterSet) Dictionary [CTFontDescriptorAttributeKey.CharacterSet]; } + get { return (NSCharacterSet) Dictionary [CTFontDescriptorAttributeKey.CharacterSet]!; } set { Adapter.SetValue (Dictionary, CTFontDescriptorAttributeKey.CharacterSet!, value); } } @@ -515,7 +515,7 @@ public bool? WeakEnabled { /// public bool Enabled { get { - var value = (NSNumber) Dictionary [CTFontDescriptorAttributeKey.Enabled]; + var value = (NSNumber?) Dictionary [CTFontDescriptorAttributeKey.Enabled]; if (value is null) return false; return value.Int32Value != 0; diff --git a/src/CoreText/CTTextTab.cs b/src/CoreText/CTTextTab.cs index 0f7199982583..fcb1a43b2bd6 100644 --- a/src/CoreText/CTTextTab.cs +++ b/src/CoreText/CTTextTab.cs @@ -63,8 +63,8 @@ public CTTextTabOptions (NSDictionary dictionary) /// To be added. /// To be added. /// To be added. - public NSCharacterSet ColumnTerminators { - get { return (NSCharacterSet) Dictionary [CTTextTabOptionKey.ColumnTerminators]; } + public NSCharacterSet? ColumnTerminators { + get { return (NSCharacterSet?) Dictionary [CTTextTabOptionKey.ColumnTerminators]!; } set { Adapter.SetValue (Dictionary, CTTextTabOptionKey.ColumnTerminators, value); } } } diff --git a/src/Foundation/DictionaryContainer.cs b/src/Foundation/DictionaryContainer.cs index 2957dd9cdff1..f373b9acb8eb 100644 --- a/src/Foundation/DictionaryContainer.cs +++ b/src/Foundation/DictionaryContainer.cs @@ -633,7 +633,7 @@ protected void SetArrayValue (NSString key, T []? values) if (NullCheckObjectAndRemoveKey (key, values)) { var nsValues = new NSObject [values.Length]; for (var i = 0; i < values.Length; i++) - nsValues [i] = NSObject.FromObject (values [i]); + nsValues [i] = NSObject.FromObject (values [i])!; Dictionary [key] = NSArray.FromNSObjects (nsValues); } } diff --git a/src/Foundation/NSAction.cs b/src/Foundation/NSAction.cs index a3a6d8666dd8..0772d991738a 100644 --- a/src/Foundation/NSAction.cs +++ b/src/Foundation/NSAction.cs @@ -64,9 +64,9 @@ public NSActionDispatcher (Action action) [Register ("__MonoMac_NSSynchronizationContextDispatcher")] internal sealed class NSSynchronizationContextDispatcher : NSDispatcher { readonly SendOrPostCallback d; - readonly object state; + readonly object? state; - public NSSynchronizationContextDispatcher (SendOrPostCallback d, object state) + public NSSynchronizationContextDispatcher (SendOrPostCallback d, object? state) { if (d is null) throw new ArgumentNullException (nameof (d)); @@ -149,7 +149,7 @@ internal sealed class NSAsyncSynchronizationContextDispatcher : NSAsyncDispatche SendOrPostCallback? d; object? state; - public NSAsyncSynchronizationContextDispatcher (SendOrPostCallback d, object state) + public NSAsyncSynchronizationContextDispatcher (SendOrPostCallback d, object? state) { if (d is null) throw new ArgumentNullException (nameof (d)); diff --git a/src/Foundation/NSArray.cs b/src/Foundation/NSArray.cs index db0aa8795639..84891dfd35e1 100644 --- a/src/Foundation/NSArray.cs +++ b/src/Foundation/NSArray.cs @@ -206,7 +206,13 @@ internal static NSArray From (T [] items, long count = -1) return FromNSObjects (nsoa); } - internal static NSArray FromNativeObjects (T [] items) where T : class, INativeObject +#nullable enable + /// Creates an from an array of native objects. + /// The type of native objects in the array. + /// An array of objects implementing . If null, returns an empty . + /// A new containing the specified objects. Null items are represented as . + /// This method creates a native NSArray from managed objects. Null items in the array are converted to NSNull.Null instances. + internal static NSArray FromNativeObjects (T? []? items) where T : class, INativeObject { if (items is null) return new NSArray (); @@ -214,7 +220,14 @@ internal static NSArray FromNativeObjects (T [] items) where T : class, INati return FromNativeObjects (items, items.Length); } - internal static NSArray FromNativeObjects (T [] items, nint count) where T : class, INativeObject + /// Creates an from an array of native objects with a specified count. + /// The type of native objects in the array. + /// An array of objects implementing . If null, returns an empty . + /// The number of items from the array to include in the . + /// A new containing the specified number of objects from the array. Null items are represented as . + /// Thrown when is greater than the length of , or when is negative. + /// This method creates a native NSArray from the first elements of the managed array. Null items are converted to NSNull.Null instances. + internal static NSArray FromNativeObjects (T? []? items, nint count) where T : class, INativeObject { if (items is null) return new NSArray (); @@ -222,20 +235,23 @@ internal static NSArray FromNativeObjects (T [] items, nint count) where T : if (count > items.Length) throw new ArgumentException ("count is larger than the number of items", "count"); - IntPtr buf = Marshal.AllocHGlobal ((IntPtr) (count * IntPtr.Size)); + if (count < 0) + throw new ArgumentOutOfRangeException (nameof (count), "count is negative"); + + var handles = new IntPtr [count]; for (nint i = 0; i < count; i++) { var item = items [i]; // The analyzer cannot deal with arrays, we manually keep alive the whole array below #pragma warning disable RBI0014 IntPtr h = item is null ? NSNull.Null.Handle : item.Handle; - Marshal.WriteIntPtr (buf, (int) (i * IntPtr.Size), h); + handles [i] = h; #pragma warning restore RBI0014 } - NSArray arr = Runtime.GetNSObject (NSArray.FromObjects (buf, count)); - Marshal.FreeHGlobal (buf); + var rv = FromIntPtrs (handles); GC.KeepAlive (items); - return arr; + return rv; } +#nullable disable internal static NSArray FromNSObjects (IList items) { @@ -283,6 +299,7 @@ static public NSArray FromStrings (IReadOnlyList items) } } +#nullable enable /// Create an from the specified pointers. /// Array of pointers (to instances). /// If the array is null, an is thrown. @@ -293,24 +310,25 @@ static internal NSArray FromIntPtrs (IntPtr [] items) unsafe { fixed (IntPtr* valuesPtr = items) - return Runtime.GetNSObject (NSArray.FromObjects ((IntPtr) valuesPtr, items.Length))!; + return Runtime.GetNSObject (NSArray.FromObjects ((IntPtr) valuesPtr, items.Length)) ?? new NSArray (); } } - static public NSArray FromIntPtrs (NativeHandle [] vals) + /// Create an from the specified pointers. + /// Array of pointers (to instances). + /// If the array is null, an is thrown. + public static NSArray FromIntPtrs (NativeHandle [] vals) { if (vals is null) - throw new ArgumentNullException ("vals"); - int n = vals.Length; - IntPtr buf = Marshal.AllocHGlobal (n * IntPtr.Size); - for (int i = 0; i < n; i++) - Marshal.WriteIntPtr (buf, i * IntPtr.Size, vals [i]); + throw new ArgumentNullException (nameof (vals)); - NSArray arr = Runtime.GetNSObject (NSArray.FromObjects (buf, vals.Length)); - - Marshal.FreeHGlobal (buf); - return arr; + unsafe { + fixed (NativeHandle* valuesPtr = vals) { + return Runtime.GetNSObject (NSArray.FromObjects ((IntPtr) valuesPtr, vals.Length)) ?? new NSArray (); + } + } } +#nullable disable internal static nuint GetCount (IntPtr handle) { diff --git a/src/Foundation/NSConnection.cs b/src/Foundation/NSConnection.cs index b75c7bb177c7..be8ea171dcff 100644 --- a/src/Foundation/NSConnection.cs +++ b/src/Foundation/NSConnection.cs @@ -30,40 +30,39 @@ using System.Diagnostics.CodeAnalysis; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSConnection { - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Gets the root proxy object for this connection. + /// The type of the proxy object to return. + /// The root proxy object, cast to the specified type. + /// This method retrieves the root object provided by the receiver's peer. The returned object is a proxy that represents the root object on the remote side of the connection. public TProxy GetRootProxy () where TProxy : NSObject { return GetRootProxy (_GetRootProxy ()); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static TProxy GetRootProxy (string name, string hostName) where TProxy : NSObject + /// Gets the root proxy object for the connection identified by name and host. + /// The type of the proxy object to return. + /// The name of the connection. + /// The name of the host on which the connection is registered. + /// The root proxy object for the specified connection, cast to the specified type. + /// This method retrieves the root object from a connection identified by on the specified . + public static TProxy GetRootProxy (string name, string? hostName) where TProxy : NSObject { return GetRootProxy (_GetRootProxy (name, hostName)); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static TProxy GetRootProxy (string name, string hostName, NSPortNameServer server) where TProxy : NSObject + /// Gets the root proxy object for the connection identified by name, host, and port name server. + /// The type of the proxy object to return. + /// The name of the connection. + /// The name of the host on which the connection is registered. + /// The to use for looking up the connection. + /// The root proxy object for the specified connection, cast to the specified type. + /// This method retrieves the root object from a connection identified by on the specified using the given port name server. + public static TProxy GetRootProxy (string name, string? hostName, NSPortNameServer server) where TProxy : NSObject { return GetRootProxy (_GetRootProxy (name, hostName, server)); } @@ -73,7 +72,7 @@ public static TProxy GetRootProxy (string name, string hostName, NSPortN var result = Runtime.TryGetNSObject (handle) as TProxy; if (result is null) - result = (TProxy) Activator.CreateInstance (typeof (TProxy), new object [] { handle }); + result = (TProxy) Activator.CreateInstance (typeof (TProxy), new object [] { handle })!; return result; } diff --git a/src/Foundation/NSDictionary.cs b/src/Foundation/NSDictionary.cs index 166ca912ebc9..1cb081fbd3fd 100644 --- a/src/Foundation/NSDictionary.cs +++ b/src/Foundation/NSDictionary.cs @@ -23,23 +23,25 @@ // using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSDictionary : NSObject, IDictionary, IDictionary { + /// + /// Creates an from a list of keys and values. + /// /// First key. - /// First value. - /// Remaining pais of keys and values. - /// Creates an NSDictionary from a list of NSObject keys and NSObject values. - /// - /// - /// The list of keys and values are used to create the dictionary. The number of parameters passed to this function must be even. - /// - /// - /// First value. + /// Remaining pairs of keys and values. + /// + /// + /// The list of keys and values are used to create the dictionary. The number of parameters passed to this function must be even. + /// + /// + /// - /// - /// + /// + /// public NSDictionary (NSObject first, NSObject second, params NSObject [] args) : this (PickOdd (second, args), PickEven (first, args)) { } + /// + /// Creates an from a list of keys and values. + /// /// First key. - /// First value. - /// Remaining pais of keys and values. - /// Creates an NSDictionary from a list of keys and values. - /// - /// - /// Each C# object is boxed as an NSObject by calling . - /// - /// - /// The list of keys and values are used to create the dictionary. The number of parameters passed to this function must be even. - /// - /// - /// First value. + /// Remaining pairs of keys and values. + /// + /// + /// Each C# object is boxed as an by calling . + /// + /// + /// The list of keys and values are used to create the dictionary. The number of parameters passed to this function must be even. + /// + /// + /// - /// - /// + /// + /// public NSDictionary (object first, object second, params object [] args) : this (PickOdd (second, args), PickEven (first, args)) { } @@ -125,14 +129,13 @@ internal static NSArray PickOdd (object f, object [] args) return NSArray.FromObjects (ret); } - /// Array of values for the dictionary. - /// Array of keys for the dictionary. - /// Creates a dictionary from a set of values and keys. - /// - /// - /// - /// - public static NSDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys) + /// + /// Creates a dictionary from a set of values and keys. + /// + /// Array of values for the dictionary. Null elements are stored as . + /// Array of keys for the dictionary. + /// A new containing the specified key-value pairs. + public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys) { if (objects is null) throw new ArgumentNullException (nameof (objects)); @@ -141,22 +144,20 @@ public static NSDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); - using (var no = NSArray.FromNSObjects (objects)) - using (var nk = NSArray.FromNSObjects (keys)) - return FromObjectsAndKeysInternal (no, nk); + return FromObjectsAndKeys (objects, keys, keys.Length); } + /// + /// Creates a dictionary from a set of values and keys. + /// /// Array of values for the dictionary. - /// Array of keys for the dictionary. - /// Creates a dictionary from a set of values and keys. - /// - /// - /// - /// - /// The keys and values will first be boxed into - /// NSObjects using . - /// - /// + /// Array of keys for the dictionary. + /// A new containing the specified key-value pairs. + /// + /// + /// The keys and values will first be boxed into s using . + /// + /// public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys) { if (objects is null) @@ -171,15 +172,14 @@ public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys return FromObjectsAndKeysInternal (no, nk); } - /// Array of values for the dictionary. + /// + /// Creates a dictionary from a set of values and keys. + /// + /// Array of values for the dictionary. Null elements are stored as . /// Array of keys for the dictionary. - /// Number of items to use in the creation, the number must be less than or equal to the number of elements on the arrays. - /// Creates a dictionary from a set of values and keys. - /// - /// - /// - /// - public static NSDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count) + /// Number of items to use in the creation; the number must be less than or equal to the number of elements in the arrays. + /// A new containing the specified key-value pairs. + public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys, nint count) { if (objects is null) throw new ArgumentNullException (nameof (objects)); @@ -195,18 +195,18 @@ public static NSDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] return FromObjectsAndKeysInternal (no, nk); } + /// + /// Creates a dictionary from a set of values and keys. + /// /// Array of values for the dictionary. /// Array of keys for the dictionary. - /// Number of items to use in the creation, the number must be less than or equal to the number of elements on the arrays. - /// Creates a dictionary from a set of values and keys. - /// - /// + /// Number of items to use in the creation; the number must be less than or equal to the number of elements in the arrays. + /// A new containing the specified key-value pairs. /// - /// - /// The keys and values will first be boxed into - /// NSObjects using . - /// - /// + /// + /// The keys and values will first be boxed into s using . + /// + /// public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count) { if (objects is null) @@ -225,18 +225,18 @@ public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys internal bool ContainsKeyValuePair (KeyValuePair pair) { - NSObject value; - if (!TryGetValue (pair.Key, out value)) + if (!TryGetValue (pair.Key, out var value)) return false; return EqualityComparer.Default.Equals (pair.Value, value); } #region ICollection - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Copies the elements of the dictionary to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements. + /// The zero-based index in at which copying begins. void ICollection.CopyTo (Array array, int arrayIndex) { if (array is null) @@ -255,23 +255,26 @@ void ICollection.CopyTo (Array array, int arrayIndex) array.SetValue (e.Entry, i++); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets the number of elements contained in the dictionary. + /// + /// The number of elements contained in the dictionary. int ICollection.Count { get { return (int) Count; } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets a value indicating whether access to the dictionary is synchronized (thread safe). + /// + /// Always returns . bool ICollection.IsSynchronized { get { return false; } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an object that can be used to synchronize access to the dictionary. + /// + /// An object that can be used to synchronize access to the dictionary. object ICollection.SyncRoot { get { return this; } } @@ -326,88 +329,103 @@ bool ICollection>.IsReadOnly { #region IDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. - void IDictionary.Add (object key, object value) + /// + /// Adds an element with the provided key and value to the dictionary. + /// + /// The key of the element to add. + /// The value of the element to add. + /// Always thrown as the dictionary is read-only. + void IDictionary.Add (object key, object? value) { throw new NotSupportedException (); } - /// To be added. - /// To be added. + /// + /// Removes all elements from the dictionary. + /// + /// Always thrown as the dictionary is read-only. void IDictionary.Clear () { throw new NotSupportedException (); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Determines whether the dictionary contains an element with the specified key. + /// + /// The key to locate in the dictionary. + /// if the dictionary contains an element with the key; otherwise, . bool IDictionary.Contains (object key) { if (key is null) throw new ArgumentNullException (nameof (key)); - NSObject _key = key as NSObject; + var _key = key as NSObject; if (_key is null) return false; return ContainsKey (_key); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an for the dictionary. + /// + /// An for the dictionary. IDictionaryEnumerator IDictionary.GetEnumerator () { return (IDictionaryEnumerator) ((IEnumerable>) this).GetEnumerator (); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Removes the element with the specified key from the dictionary. + /// + /// The key of the element to remove. + /// Always thrown as the dictionary is read-only. void IDictionary.Remove (object key) { throw new NotSupportedException (); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets a value indicating whether the dictionary has a fixed size. + /// + /// Always returns . bool IDictionary.IsFixedSize { get { return true; } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets a value indicating whether the dictionary is read-only. + /// + /// Always returns . bool IDictionary.IsReadOnly { get { return true; } } - object IDictionary.this [object key] { + [DisallowNull] // don't allow setting null values + object? IDictionary.this [object key] { get { - NSObject _key = key as NSObject; + var _key = key as NSObject; if (_key is null) return null; return ObjectForKey (_key); } +#pragma warning disable CS8769 // Nullability of reference types in type of parameter 'value' doesn't match implemented member 'void IDictionary.this[object key].set' set { +#pragma warning restore CS8769 throw new NotSupportedException (); } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an containing the keys of the dictionary. + /// + /// An containing the keys of the dictionary. ICollection IDictionary.Keys { get { return Keys; } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an containing the values in the dictionary. + /// + /// An containing the values in the dictionary. ICollection IDictionary.Values { get { return Values; } } @@ -421,12 +439,11 @@ void IDictionary.Add (NSObject key, NSObject value) throw new NotSupportedException (); } - /// Key to lookup in the dictionary. - /// Determines whether the specified key exists in the dictionary. - /// - /// - /// - /// + /// + /// Determines whether the specified key exists in the dictionary. + /// + /// Key to look up in the dictionary. + /// if the key exists in the dictionary; otherwise, . public bool ContainsKey (NSObject key) { return ObjectForKey (key) is not null; @@ -442,44 +459,38 @@ bool IDictionary.Remove (NSObject key) throw new NotSupportedException (); } - internal bool TryGetValue (INativeObject key, out T value) where T : class, INativeObject + internal bool TryGetValue (INativeObject key, [NotNullWhen (true)] out T? value) where T : class, INativeObject { - value = null; if (key is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key)); var ptr = _ObjectForKey (key.Handle); GC.KeepAlive (key); - if (ptr == IntPtr.Zero) - return false; - value = Runtime.GetINativeObject (ptr, false); - return true; + // NSDictionary can not contain NULLs, if you want a NULL, it exists as an NSNull + return value is not null; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public bool TryGetValue (NSObject key, out NSObject value) + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, . + /// if the dictionary contains an element with the specified key; otherwise, . + public bool TryGetValue (NSObject key, [NotNullWhen (true)] out NSObject? value) { - if (key is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (key)); - - value = ObjectForKey (key); - // NSDictionary can not contain NULLs, if you want a NULL, it exists as an NSNull - return value is not null; + return TryGetValue (key, out value); } - /// Key to lookup - /// Returns the value associated from a key in the dictionary, or null if the key is not found. - /// - /// - /// - /// - public virtual NSObject this [NSObject key] { + /// Gets the object associated with the specified key. + /// The key of the object to get. + /// The object associated with the specified key. + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public virtual NSObject? this [NSObject key] { +#pragma warning disable CS8766 // Nullability of reference types in return type of 'NSObject? NSDictionary.this[NSObject key].get' doesn't match implicitly implemented member 'NSObject IDictionary.this[NSObject key].get' get { +#pragma warning restore CS8766 return ObjectForKey (key); } set { @@ -487,13 +498,12 @@ public virtual NSObject this [NSObject key] { } } - /// Key to lookup - /// Returns the value associated from a key in the dictionary, or null if the key is not found. - /// - /// - /// - /// - public virtual NSObject this [NSString key] { + /// Gets the object associated with the specified key. + /// The key of the object to get. + /// The object associated with the specified key. + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public virtual NSObject? this [NSString key] { get { return ObjectForKey (key); } @@ -502,12 +512,13 @@ public virtual NSObject this [NSString key] { } } - /// Key to lookup - /// Returns the value associated from a key in the dictionary, or null if the key is not found. - /// - /// - /// The string will be marshalled as an NSString before performing the lookup. - public virtual NSObject this [string key] { + /// Gets the object associated with the specified key. + /// The key of the object to get. + /// The object associated with the specified key. + /// Thrown when is . + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public virtual NSObject? this [string key] { get { if (key is null) throw new ArgumentNullException ("key"); @@ -533,9 +544,10 @@ ICollection IDictionary.Values { #endregion - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an enumerator that iterates through the dictionary. + /// + /// An enumerator that can be used to iterate through the dictionary. IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); @@ -546,19 +558,20 @@ IEnumerator IEnumerable.GetEnumerator () public IEnumerator> GetEnumerator () { foreach (var key in Keys) { - yield return new KeyValuePair (key, ObjectForKey (key)); + yield return new KeyValuePair (key, ObjectForKey (key)!); } } - /// A handle to an NSObject that might be on the dictionary. - /// Low-level key lookup. - /// Handle to an object, or IntPtr.Zero if the key does not exist in the dictionary. - /// - /// In some cases, where you might be iterating over a loop, or - /// you have not surfaced a bound type, but you have the handle to - /// the key, you can use the - /// which takes a handle for the key and returns a handle for the returned object. - /// + /// + /// Low-level key lookup. + /// + /// A handle to an that might be in the dictionary. + /// Handle to an object, or if the key does not exist in the dictionary. + /// + /// In some cases, where you might be iterating over a loop, or you have not surfaced a bound type, + /// but you have the handle to the key, you can use + /// which takes a handle for the key and returns a handle for the returned object. + /// public IntPtr LowlevelObjectForKey (IntPtr key) { #if MONOMAC @@ -568,9 +581,10 @@ public IntPtr LowlevelObjectForKey (IntPtr key) #endif } - /// To be added. - /// To be added. - /// To be added. + /// + /// Converts the dictionary to an object. + /// + /// An object representing the dictionary contents. public NSFileAttributes ToFileAttributes () { return NSFileAttributes.FromDictionary (this); diff --git a/src/Foundation/NSDictionary_2.cs b/src/Foundation/NSDictionary_2.cs index 5faa76d0dc01..661d7760a002 100644 --- a/src/Foundation/NSDictionary_2.cs +++ b/src/Foundation/NSDictionary_2.cs @@ -25,40 +25,40 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] [Register ("NSDictionary", SkipRegistration = true)] public sealed partial class NSDictionary : NSDictionary, IDictionary where TKey : class, INativeObject where TValue : class, INativeObject { - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class. + /// public NSDictionary () { } + /// + /// A constructor that initializes the object from the data stored in the unarchiver object. + /// /// The unarchiver object. - /// A constructor that initializes the object from the data stored in the unarchiver object. - /// - /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. - /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. - /// The state of this object can also be serialized by using the companion method, EncodeTo. - /// + /// + /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. + /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. + /// The state of this object can also be serialized by using the companion method, EncodeTo. + /// public NSDictionary (NSCoder coder) : base (coder) { } - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from a property list file. + /// + /// The path to a property list file. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("macos")] [SupportedOSPlatform ("tvos")] @@ -72,9 +72,10 @@ public NSDictionary (string filename) { } - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from a property list at the specified URL. + /// + /// The URL to a property list file. [SupportedOSPlatform ("ios")] [SupportedOSPlatform ("macos")] [SupportedOSPlatform ("tvos")] @@ -93,9 +94,10 @@ internal NSDictionary (NativeHandle handle) { } - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from another dictionary. + /// + /// The dictionary to copy from. public NSDictionary (NSDictionary other) : base (other) { @@ -120,30 +122,37 @@ internal static bool ValidateKeysAndValues (TKey [] keys, TValue [] values) { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from parallel arrays of keys and values. + /// + /// An array of keys. + /// An array of values. public NSDictionary (TKey [] keys, TValue [] values) : this (keys, values, ValidateKeysAndValues (keys, values)) { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class with a single key-value pair. + /// + /// The key. + /// The value. public NSDictionary (TKey key, TValue value) : base (NSArray.FromNSObjects (value), NSArray.FromNSObjects (key)) { } -#nullable enable - /// Create an from this dictionary. + /// + /// Creates a from this dictionary. + /// + /// The key type for the returned dictionary. + /// The value type for the returned dictionary. /// A callback function to convert from the type of each key and value into the type to add to the returned dictionary. - /// Null if the collection of items is null, otherwise a new from this dictionary. + /// A new from this dictionary. public Dictionary ToDictionary (Func convertCallback) where K : notnull { + ArgumentNullException.ThrowIfNull (convertCallback); + var rv = new Dictionary (); foreach (var kvp in (IDictionary) this) { var converted = convertCallback (kvp.Key, kvp.Value); @@ -151,27 +160,28 @@ public Dictionary ToDictionary (Func } return rv; } -#nullable disable + // Strongly typed methods from NSDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public TValue ObjectForKey (TKey key) + /// + /// Returns the value associated with the specified key, or if the key is not present. + /// + /// The key to look up. + /// The value associated with the specified key, or if the key is not present. + public TValue? ObjectForKey (TKey key) { - if (key is null) - throw new ArgumentNullException (nameof (key)); + ArgumentNullException.ThrowIfNull (key); - TValue ret = Runtime.GetINativeObject (_ObjectForKey (key.Handle), false); + var ret = Runtime.GetINativeObject (_ObjectForKey (key.Handle), false); GC.KeepAlive (key); return ret; } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an array containing all keys in the dictionary. + /// + /// An array of keys. public TKey [] Keys { get { using (var pool = new NSAutoreleasePool ()) @@ -179,25 +189,26 @@ public TKey [] Keys { } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an array of keys corresponding to all occurrences of the specified value in the dictionary. + /// + /// The value to search for. + /// An array of keys whose corresponding values are equal to the specified value. public TKey [] KeysForObject (TValue obj) { - if (obj is null) - throw new ArgumentNullException (nameof (obj)); + ArgumentNullException.ThrowIfNull (obj); using (var pool = new NSAutoreleasePool ()) { - TKey [] ret = NSArray.ArrayFromHandle (_AllKeysForObject (obj.Handle)); + var ret = NSArray.ArrayFromHandle (_AllKeysForObject (obj.Handle)); GC.KeepAlive (obj); return ret; } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an array containing all values in the dictionary. + /// + /// An array of values. public TValue [] Values { get { using (var pool = new NSAutoreleasePool ()) @@ -205,21 +216,19 @@ public TValue [] Values { } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an array of values corresponding to a specified set of keys. + /// + /// An array of keys. + /// The marker object to substitute for values that are not present in the dictionary. + /// An array of values corresponding to the keys in the array, with the marker object substituted for missing values. public TValue [] ObjectsForKeys (TKey [] keys, TValue marker) { - if (keys is null) - throw new ArgumentNullException (nameof (keys)); - - if (marker is null) - throw new ArgumentNullException (nameof (marker)); + ArgumentNullException.ThrowIfNull (keys); + ArgumentNullException.ThrowIfNull (marker); if (keys.Length == 0) - return new TValue [] { }; + return []; using (var pool = new NSAutoreleasePool ()) { var keysArray = NSArray.From (keys); @@ -232,24 +241,24 @@ public TValue [] ObjectsForKeys (TKey [] keys, TValue marker) static NSDictionary GenericFromObjectsAndKeysInternal (NSArray objects, NSArray keys) { - var result = Runtime.GetNSObject> (_FromObjectsAndKeysInternal (objects.Handle, keys.Handle)); + var result = Runtime.GetNSObject> (_FromObjectsAndKeysInternal (objects.Handle, keys.Handle))!; GC.KeepAlive (objects); GC.KeepAlive (keys); return result; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSDictionary FromObjectsAndKeys (TValue [] objects, TKey [] keys, nint count) + /// + /// Creates a dictionary from parallel arrays of values and keys, using only the first elements. + /// + /// An array of values. Null elements are stored as . + /// An array of keys. + /// The number of elements to use from each array. + /// A new dictionary containing the specified key-value pairs. + public static NSDictionary FromObjectsAndKeys (TValue? [] objects, TKey [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); + if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count) @@ -260,31 +269,34 @@ public static NSDictionary FromObjectsAndKeys (TValue [] objects, return GenericFromObjectsAndKeysInternal (no, nk); } - public static NSDictionary FromObjectsAndKeys (TValue [] objects, TKey [] keys) + /// + /// Creates a dictionary from parallel arrays of values and keys. + /// + /// An array of values. Null elements are stored as . + /// An array of keys. + /// A new dictionary containing the specified key-value pairs. + public static NSDictionary FromObjectsAndKeys (TValue? [] objects, TKey [] keys) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); + if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); - using (var no = NSArray.FromNSObjects (objects)) - using (var nk = NSArray.FromNSObjects (keys)) - return GenericFromObjectsAndKeysInternal (no, nk); + return FromObjectsAndKeys (objects, keys, keys.Length); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Creates a dictionary from parallel arrays of object values and keys. + /// + /// An array of object values. + /// An array of object keys. + /// A new dictionary containing the specified key-value pairs. public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); + if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); @@ -293,18 +305,18 @@ public static NSDictionary FromObjectsAndKeys (object [] objects, return GenericFromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count) + /// + /// Creates a dictionary from parallel arrays of values and keys, using only the first elements. + /// + /// An array of values. Null elements are stored as . + /// An array of keys. + /// The number of elements to use from each array. + /// A new dictionary containing the specified key-value pairs. + public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); + if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count || keys.Length < count) @@ -315,18 +327,18 @@ public static NSDictionary FromObjectsAndKeys (NSObject [] objects return GenericFromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Creates a dictionary from parallel arrays of object values and keys, using only the first elements. + /// + /// An array of object values. + /// An array of object keys. + /// The number of elements to use from each array. + /// A new dictionary containing the specified key-value pairs. public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); + if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count || keys.Length < count) @@ -339,32 +351,38 @@ public static NSDictionary FromObjectsAndKeys (object [] objects, // Other implementations - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Determines whether the dictionary contains the specified key. + /// + /// The key to locate in the dictionary. + /// if the dictionary contains an element with the specified key; otherwise, . public bool ContainsKey (TKey key) { - if (key is null) - throw new ArgumentNullException (nameof (key)); + ArgumentNullException.ThrowIfNull (key); - bool ret = _ObjectForKey (key.Handle) != IntPtr.Zero; + var ret = _ObjectForKey (key.Handle) != IntPtr.Zero; GC.KeepAlive (key); return ret; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public bool TryGetValue (TKey key, out TValue value) + /// + /// Gets the value associated with the specified key. + /// + /// The key to look up. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, . + /// if the dictionary contains an element with the specified key; otherwise, . + public bool TryGetValue (TKey key, [NotNullWhen (true)] out TValue? value) { // NSDictionary can not contain NULLs, if you want a NULL, it exists as an NSNull return (value = ObjectForKey (key)) is not null; } - public TValue this [TKey key] { + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// The value associated with the specified key, or if the key is not present. + public TValue? this [TKey key] { get { return ObjectForKey (key); } @@ -386,13 +404,17 @@ bool IDictionary.Remove (TKey key) throw new NotSupportedException (); } - bool IDictionary.TryGetValue (TKey key, out TValue value) + bool IDictionary.TryGetValue (TKey key, [MaybeNullWhen (false)] out TValue value) { - return TryGetValue (key, out value); + var result = TryGetValue (key, out var nullableValue); + value = nullableValue!; + return result; } - TValue IDictionary.this [TKey key] { + TValue? IDictionary.this [TKey key] { +#pragma warning disable CS8768 // Nullability of reference types in return type doesn't match implemented member 'TValue IDictionary.this[TKey key].get' get { +#pragma warning restore CS8768 return this [key]; } set { @@ -426,20 +448,19 @@ void ICollection>.Clear () bool ICollection>.Contains (KeyValuePair item) { - TValue value; - if (!TryGetValue (item.Key, out value)) + if (!TryGetValue (item.Key, out var value)) return false; - return (object) value == (object) item.Value; + return (object?) value == (object?) item.Value; } void ICollection>.CopyTo (KeyValuePair [] array, int arrayIndex) { - if (array is null) - throw new ArgumentNullException (nameof (array)); + ArgumentNullException.ThrowIfNull (array); + if (arrayIndex < 0) throw new ArgumentOutOfRangeException (nameof (arrayIndex)); - int c = array.Length; + var c = array.Length; if ((c > 0) && (arrayIndex >= c)) throw new ArgumentException (nameof (arrayIndex) + " is equal to or greater than " + nameof (array) + ".Length"); if (arrayIndex + (int) Count > c) @@ -472,18 +493,19 @@ bool ICollection>.IsReadOnly { IEnumerator> IEnumerable>.GetEnumerator () { foreach (var key in Keys) { - yield return new KeyValuePair (key, ObjectForKey (key)); + yield return new KeyValuePair (key, ObjectForKey (key)!); } } #endregion #region IEnumerable implementation - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an enumerator that iterates through the dictionary. + /// + /// An enumerator that can be used to iterate through the dictionary. IEnumerator IEnumerable.GetEnumerator () { - return GetEnumerator (); + return ((IEnumerable>) this).GetEnumerator (); } #endregion } diff --git a/src/Foundation/NSFileManager.cs b/src/Foundation/NSFileManager.cs index 0286df101840..7a862df1f770 100644 --- a/src/Foundation/NSFileManager.cs +++ b/src/Foundation/NSFileManager.cs @@ -26,6 +26,9 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // + +using System.Diagnostics.CodeAnalysis; + using CoreFoundation; #nullable enable @@ -307,7 +310,8 @@ internal NSDictionary ToDictionary () /// To be added. /// To be added. /// To be added. - public static NSFileAttributes? FromDictionary (NSDictionary dict) + [return: NotNullIfNotNull (nameof (dict))] + public static NSFileAttributes? FromDictionary (NSDictionary? dict) { if (dict is null) return null; diff --git a/src/Foundation/NSKeyedArchiver.cs b/src/Foundation/NSKeyedArchiver.cs index 695d77d4d86c..de4090899664 100644 --- a/src/Foundation/NSKeyedArchiver.cs +++ b/src/Foundation/NSKeyedArchiver.cs @@ -22,23 +22,20 @@ // using CoreFoundation; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSKeyedArchiver { - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Sets the global class name for a specified class. + /// The class name to use during archiving. + /// The to associate with the name. + /// This method associates a class name with a class for all instances of . Use to set the class name for a specific archiver instance. public static void GlobalSetClassName (string name, Class kls) { - if (name is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (name)); - if (kls is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (kls)); + ArgumentNullException.ThrowIfNull (name); + ArgumentNullException.ThrowIfNull (kls); var ptr = CFString.CreateNative (name); ObjCRuntime.Messaging.void_objc_msgSend_IntPtr_IntPtr (class_ptr, Selector.GetHandle ("setClassName:forClass:"), ptr, kls.Handle); @@ -46,16 +43,15 @@ public static void GlobalSetClassName (string name, Class kls) CFString.ReleaseNative (ptr); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static string GlobalGetClassName (Class kls) + /// Gets the global class name for a specified class. + /// The to query. + /// The class name associated with the class, or if no class name has been set. + /// This method retrieves the class name associated with a class for all instances of . Use to get the class name for a specific archiver instance. + public static string? GlobalGetClassName (Class kls) { - if (kls is null) - ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (kls)); + ArgumentNullException.ThrowIfNull (kls); - string result = CFString.FromHandle (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr (class_ptr, Selector.GetHandle ("classNameForClass:"), kls.Handle)); + string? result = CFString.FromHandle (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr (class_ptr, Selector.GetHandle ("classNameForClass:"), kls.Handle)); GC.KeepAlive (kls); return result; } diff --git a/src/Foundation/NSLayoutConstraint.cs b/src/Foundation/NSLayoutConstraint.cs index 0361bd73c801..fac7a430c1aa 100644 --- a/src/Foundation/NSLayoutConstraint.cs +++ b/src/Foundation/NSLayoutConstraint.cs @@ -1,10 +1,10 @@ // -// Helper functions to make FromVisualLayout more palattable +// Helper functions to make FromVisualFormat more palatable // // Author: // Miguel de Icaza // -// Copyright 2014 Xamarin INc +// Copyright 2014 Xamarin Inc // #if MONOMAC @@ -13,8 +13,7 @@ using View = UIKit.UIView; #endif -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable #if MONOMAC namespace AppKit @@ -23,7 +22,7 @@ namespace UIKit #endif { public partial class NSLayoutConstraint { - static NSNumber AsNumber (object o) + static NSNumber? AsNumber (object o) { if (o is NSNumber) return (NSNumber) o; if (o is double) return new NSNumber ((double) o); @@ -42,10 +41,26 @@ static NSNumber AsNumber (object o) return null; } - /// + /// Factory method for creating a constraint using Visual Format Language. + /// Visual format to use to create the constraints. + /// Options for the format. + /// + /// Pairs of names and values. The names should be strings (or ) and the values should be either s, numbers (any C# number or ) or instances that are suitable to be passed to the underlying engine. + /// This binds the provided name with the view or binds the name with the number as a metric. + /// + /// An array of layout constraints that are suitable to be added to a using the method. + /// + /// + /// + /// + /// static public NSLayoutConstraint [] FromVisualFormat (string format, NSLayoutFormatOptions formatOptions, params object [] viewsAndMetrics) { - NSMutableDictionary views = null, metrics = null; + ArgumentNullException.ThrowIfNull (format); + ArgumentNullException.ThrowIfNull (viewsAndMetrics); + NSMutableDictionary? views = null, metrics = null; var count = viewsAndMetrics.Length; if (count != 0) { if ((count % 2) != 0) @@ -102,60 +117,60 @@ static public NSLayoutConstraint [] FromVisualFormat (string format, NSLayoutFor return FromVisualFormat (format, formatOptions, metrics, views); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// Static factory method for creating a constraint. - /// To be added. - /// To be added. + /// Factory method for creating a constraint. + /// The view or object in the constraint. + /// The attribute for the view. + /// The relationship in the constraint. + /// The multiplier applied to the attribute. + /// The constant value in the constraint. + /// A new constraint with the specified parameters. + /// Creates a constraint for a single view with a specified attribute, relation, multiplier, and constant value. public static NSLayoutConstraint Create (NSObject view1, NSLayoutAttribute attribute1, NSLayoutRelation relation, nfloat multiplier, nfloat constant) { return NSLayoutConstraint.Create (view1, attribute1, relation, null, NSLayoutAttribute.NoAttribute, multiplier, constant); } - /// To be added. - /// To be added. - /// To be added. - /// Static factory method to create a constraint based on a , an , and an . - /// To be added. - /// To be added. + /// Factory method to create a constraint based on a , an , and an . + /// The view or object in the constraint. + /// The attribute for the view. + /// The relationship in the constraint. + /// A new constraint with the specified parameters and default multiplier (1.0) and constant (0.0). + /// Creates a constraint for a single view with default multiplier and constant values. public static NSLayoutConstraint Create (NSObject view1, NSLayoutAttribute attribute1, NSLayoutRelation relation) { return NSLayoutConstraint.Create (view1, attribute1, relation, null, NSLayoutAttribute.NoAttribute, 1.0f, 0f); } - // This solves the duplicate selector export problem while not breaking the API. - /// + /// Factory method for creating a constraint. + /// First view in the constraint. + /// Attribute for the first view. + /// Relationship between the and the . + /// Second view in the constraint. This parameter can be . + /// Attribute for the second view. + /// Multiplier applied to the second attribute. + /// Constant to add. + /// A new constraint with the specified parameters. + /// Creates a constraint relationship between the and the that satisfies the following linear equation: = x + . public static NSLayoutConstraint Create (NSObject view1, NSLayoutAttribute attribute1, NSLayoutRelation relation, - NSObject view2, NSLayoutAttribute attribute2, nfloat multiplier, nfloat constant) + NSObject? view2, NSLayoutAttribute attribute2, nfloat multiplier, nfloat constant) { return Create ((INativeObject) view1, attribute1, relation, view2, attribute2, multiplier, constant); } - /// To be added. - /// For an anchor-based constraint, returns the first anchor, properly downcast to AnchorType. - /// To be added. - /// To be added. - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("tvos")] - [SupportedOSPlatform ("macos")] - public NSLayoutAnchor FirstAnchor () where AnchorType : NSObject + /// For an anchor-based constraint, returns the first anchor, properly downcast to . + /// The type of anchor to return. + /// The first anchor of the constraint, cast to the specified anchor type. + /// This method is useful for retrieving the first anchor when working with anchor-based constraints. + public NSLayoutAnchor? FirstAnchor () where AnchorType : NSObject { return Runtime.GetNSObject> (_FirstAnchor ()); } - /// To be added. - /// For an anchor-based constraint, returns the second anchor, properly downcast to AnchorType. - /// To be added. - /// To be added. - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("tvos")] - [SupportedOSPlatform ("macos")] - public NSLayoutAnchor SecondAnchor () where AnchorType : NSObject + /// For an anchor-based constraint, returns the second anchor, properly downcast to . + /// The type of anchor to return. + /// The second anchor of the constraint, cast to the specified anchor type. + /// This method is useful for retrieving the second anchor when working with anchor-based constraints. + public NSLayoutAnchor? SecondAnchor () where AnchorType : NSObject { return Runtime.GetNSObject> (_SecondAnchor ()); } diff --git a/src/Foundation/NSLocale.cs b/src/Foundation/NSLocale.cs index fd51e99efb29..a59c19bef047 100644 --- a/src/Foundation/NSLocale.cs +++ b/src/Foundation/NSLocale.cs @@ -27,216 +27,196 @@ // // -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSLocale { - /// To be added. - /// To be added. - /// To be added. - public string Identifier { + /// Gets the locale identifier string. + /// The locale identifier. + public string? Identifier { get { - return (string) (NSString) ObjectForKey (_Identifier); + return (string?) (NSString?) ObjectForKey (_Identifier); } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public string GetIdentifierDisplayName (string value) + /// Gets the display name for the specified locale identifier. + /// The locale identifier. + /// The localized display name for the identifier, or if not available. + public string? GetIdentifierDisplayName (string value) { + ArgumentNullException.ThrowIfNull (value); return DisplayNameForKey (_Identifier, value); } - /// To be added. - /// To be added. - /// To be added. - public string LanguageCode { + /// Gets the language code for the locale. + /// The language code. + public string? LanguageCode { get { - return (string) (NSString) ObjectForKey (_LanguageCode); + return (string?) (NSString?) ObjectForKey (_LanguageCode); } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public string GetLanguageCodeDisplayName (string value) + /// Gets the display name for the specified language code. + /// The language code. + /// The localized display name for the language code, or if not available. + public string? GetLanguageCodeDisplayName (string value) { + ArgumentNullException.ThrowIfNull (value); return DisplayNameForKey (_LanguageCode, value); } - /// To be added. - /// To be added. - /// To be added. - public string CountryCode { + /// Gets the country code for the locale. + /// The country code. + public string? CountryCode { get { - return (string) (NSString) ObjectForKey (_CountryCode); + return (string?) (NSString?) ObjectForKey (_CountryCode); } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public string GetCountryCodeDisplayName (string value) + /// Gets the display name for the specified country code. + /// The country code. + /// The localized display name for the country code, or if not available. + public string? GetCountryCodeDisplayName (string value) { + ArgumentNullException.ThrowIfNull (value); return DisplayNameForKey (_CountryCode, value); } - /// To be added. - /// To be added. - /// To be added. - public string ScriptCode { + /// Gets the script code for the locale. + /// The script code. + public string? ScriptCode { get { - return (string) (NSString) ObjectForKey (_ScriptCode); + return (string?) (NSString?) ObjectForKey (_ScriptCode); } } - /// To be added. - /// To be added. - /// To be added. - public string VariantCode { + /// Gets the variant code for the locale. + /// The variant code. + public string? VariantCode { get { - return (string) (NSString) ObjectForKey (_VariantCode); + return (string?) (NSString?) ObjectForKey (_VariantCode); } } - /// To be added. - /// To be added. - /// To be added. - public NSCharacterSet ExemplarCharacterSet { + /// Gets the exemplar character set for the locale. + /// The character set containing exemplar characters. + public NSCharacterSet? ExemplarCharacterSet { get { return ObjectForKey (_ExemplarCharacterSet) as NSCharacterSet; } } - /// To be added. - /// To be added. - /// To be added. - public NSCalendar Calendar { + /// Gets the calendar for the locale. + /// The object associated with the locale. + public NSCalendar? Calendar { get { return ObjectForKey (_Calendar) as NSCalendar; } } - /// To be added. - /// To be added. - /// To be added. - public string CollationIdentifier { + /// Gets the collation identifier for the locale. + /// The collation identifier. + public string? CollationIdentifier { get { - return (string) (NSString) ObjectForKey (_CollationIdentifier); + return (string?) (NSString?) ObjectForKey (_CollationIdentifier); } } - /// To be added. - /// To be added. - /// To be added. + /// Gets a value indicating whether the locale uses the metric system. + /// if the locale uses the metric system; otherwise, . public bool UsesMetricSystem { get { - return ((NSNumber) ObjectForKey (_UsesMetricSystem)).Int32Value != 0; + return (ObjectForKey (_UsesMetricSystem) as NSNumber)?.BoolValue == true; } } - /// To be added. - /// To be added. - /// To be added. - public string MeasurementSystem { + /// Gets the measurement system for the locale. + /// The measurement system identifier. + public string? MeasurementSystem { get { - return (string) (NSString) ObjectForKey (_MeasurementSystem); + return (string?) (NSString?) ObjectForKey (_MeasurementSystem); } } - /// To be added. - /// To be added. - /// To be added. - public string DecimalSeparator { + /// Gets the decimal separator for the locale. + /// The decimal separator character. + public string? DecimalSeparator { get { - return (string) (NSString) ObjectForKey (_DecimalSeparator); + return (string?) (NSString?) ObjectForKey (_DecimalSeparator); } } - /// To be added. - /// To be added. - /// To be added. - public string GroupingSeparator { + /// Gets the grouping separator for the locale. + /// The grouping separator character used in numbers. + public string? GroupingSeparator { get { - return (string) (NSString) ObjectForKey (_GroupingSeparator); + return (string?) (NSString?) ObjectForKey (_GroupingSeparator); } } - /// To be added. - /// To be added. - /// To be added. - public string CurrencySymbol { + /// Gets the currency symbol for the locale. + /// The currency symbol. + public string? CurrencySymbol { get { - return (string) (NSString) ObjectForKey (_CurrencySymbol); + return (string?) (NSString?) ObjectForKey (_CurrencySymbol); } } - /// To be added. - /// To be added. - /// To be added. - public string CurrencyCode { + /// Gets the currency code for the locale. + /// The ISO 4217 currency code. + public string? CurrencyCode { get { - return (string) (NSString) ObjectForKey (_CurrencyCode); + return (string?) (NSString?) ObjectForKey (_CurrencyCode); } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public string GetCurrencyCodeDisplayName (string value) + /// Gets the display name for the specified currency code. + /// The currency code. + /// The localized display name for the currency code, or if not available. + public string? GetCurrencyCodeDisplayName (string value) { + ArgumentNullException.ThrowIfNull (value); return DisplayNameForKey (_CurrencyCode, value); } - /// To be added. - /// To be added. - /// To be added. - public string CollatorIdentifier { + /// Gets the collator identifier for the locale. + /// The collator identifier. + public string? CollatorIdentifier { get { - return (string) (NSString) ObjectForKey (_CollatorIdentifier); + return (string?) (NSString?) ObjectForKey (_CollatorIdentifier); } } - /// To be added. - /// To be added. - /// To be added. - public string QuotationBeginDelimiterKey { + /// Gets the quotation begin delimiter for the locale. + /// The character or string used to begin a quotation. + public string? QuotationBeginDelimiterKey { get { - return (string) (NSString) ObjectForKey (_QuotationBeginDelimiterKey); + return (string?) (NSString?) ObjectForKey (_QuotationBeginDelimiterKey); } } - /// To be added. - /// To be added. - /// To be added. - public string QuotationEndDelimiterKey { + /// Gets the quotation end delimiter for the locale. + /// The character or string used to end a quotation. + public string? QuotationEndDelimiterKey { get { - return (string) (NSString) ObjectForKey (_QuotationEndDelimiterKey); + return (string?) (NSString?) ObjectForKey (_QuotationEndDelimiterKey); } } - /// To be added. - /// To be added. - /// To be added. - public string AlternateQuotationBeginDelimiterKey { + /// Gets the alternate quotation begin delimiter for the locale. + /// The character or string used to begin an alternate (nested) quotation. + public string? AlternateQuotationBeginDelimiterKey { get { - return (string) (NSString) ObjectForKey (_AlternateQuotationBeginDelimiterKey); + return (string?) (NSString?) ObjectForKey (_AlternateQuotationBeginDelimiterKey); } } - /// To be added. - /// To be added. - /// To be added. - public string AlternateQuotationEndDelimiterKey { + /// Gets the alternate quotation end delimiter for the locale. + /// The character or string used to end an alternate (nested) quotation. + public string? AlternateQuotationEndDelimiterKey { get { - return (string) (NSString) ObjectForKey (_AlternateQuotationEndDelimiterKey); + return (string?) (NSString?) ObjectForKey (_AlternateQuotationEndDelimiterKey); } } } diff --git a/src/Foundation/NSMutableAttributedString.cs b/src/Foundation/NSMutableAttributedString.cs index 84e2ecb9f64a..21462b60ebd5 100644 --- a/src/Foundation/NSMutableAttributedString.cs +++ b/src/Foundation/NSMutableAttributedString.cs @@ -33,108 +33,113 @@ using CoreText; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSMutableAttributedString { - /// C# string. - /// CoreText attributes to be applied to the string. - /// Creates an NSMutableAttributedString from a C# string and applies the specified CoreText attributes to the entire string. - /// - /// - public NSMutableAttributedString (string str, CTStringAttributes attributes) - : this (str, attributes is null ? null : attributes.Dictionary) + /// + /// Creates an NSMutableAttributedString from a C# string and applies the specified CoreText attributes to the entire string. + /// + /// The string content. + /// CoreText attributes to be applied to the string. + public NSMutableAttributedString (string str, CTStringAttributes? attributes) + : this (str, attributes?.Dictionary) { } - /// To be added. - /// Range to which the attribute will be applied. - /// Sets the attributes for the specified ranges. Any previous attributes in that range are replaces with the new values. - /// - /// + /// + /// Sets the attributes for the specified range. Any previous attributes in that range are replaced with the new values. + /// + /// The attributes to set. + /// The range to which the attributes will be applied. public void SetAttributes (NSDictionary attributes, NSRange range) { - if (attributes is null) - throw new ArgumentNullException ("attributes"); + ArgumentNullException.ThrowIfNull (attributes); LowLevelSetAttributes (attributes.Handle, range); GC.KeepAlive (attributes); } + /// + /// Sets the attributes for the specified range. Any previous attributes in that range are replaced with the new values. + /// /// CoreText attributes to be set on the string. - /// Range to which the attribute will be applied. - /// Sets the attributes for the specified ranges. Any previous attributes in that range are replaces with the new values. - /// - /// + /// The range to which the attributes will be applied. public void SetAttributes (CTStringAttributes attrs, NSRange range) { - SetAttributes (attrs is null ? null : attrs.Dictionary, range); + ArgumentNullException.ThrowIfNull (attrs); + + SetAttributes (attrs.Dictionary, range); } + /// + /// Adds attributes to the specified range of characters in the string. + /// /// The CoreText attributes to add. - /// Range to which the attribute will be applied. - /// Adds an attribute and its value to the specified range of characters in the string. - /// - /// + /// The range to which the attributes will be applied. public void AddAttributes (CTStringAttributes attrs, NSRange range) { - AddAttributes (attrs is null ? null : attrs.Dictionary, range); + ArgumentNullException.ThrowIfNull (attrs); + + AddAttributes (attrs.Dictionary, range); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Appends an attributed string and additional objects to the end of the receiver. + /// + /// The first attributed string to append. + /// Additional objects to append. Can be , , or other objects whose method will be called. public void Append (NSAttributedString first, params object [] rest) { Append (first); foreach (var obj in rest) { - if (obj is NSAttributedString) - Append ((NSAttributedString) obj); - else if (obj is string) - Append (new NSAttributedString ((string) obj)); + if (obj is NSAttributedString nsAttributedString) + Append (nsAttributedString); + else if (obj is string str) + Append (new NSAttributedString (str)); else - Append (new NSAttributedString (obj.ToString ())); + Append (new NSAttributedString (obj?.ToString () ?? "")); } } #if !MONOMAC - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public NSMutableAttributedString (string str, UIStringAttributes attributes) - : this (str, attributes is not null ? attributes.Dictionary : null) + /// + /// Creates an NSMutableAttributedString from a string with UIKit attributes. + /// + /// The string content. + /// UIKit attributes to be applied to the string. + public NSMutableAttributedString (string str, UIStringAttributes? attributes) + : this (str, attributes?.Dictionary) { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Creates an NSMutableAttributedString from a string with individual UIKit styling attributes. + /// + /// The string content. + /// The font to apply to the string. + /// The foreground (text) color. + /// The background color. + /// The stroke color for outlined text. + /// The paragraph style to apply. + /// The ligature type to use. + /// The kerning value to apply. + /// The underline style to apply. + /// The shadow effect to apply. + /// The stroke width for outlined text. + /// The strikethrough style to apply. public NSMutableAttributedString (string str, - UIFont font = null, - UIColor foregroundColor = null, - UIColor backgroundColor = null, - UIColor strokeColor = null, - NSParagraphStyle paragraphStyle = null, + UIFont? font = null, + UIColor? foregroundColor = null, + UIColor? backgroundColor = null, + UIColor? strokeColor = null, + NSParagraphStyle? paragraphStyle = null, NSLigatureType ligatures = NSLigatureType.Default, float kerning = 0, NSUnderlineStyle underlineStyle = NSUnderlineStyle.None, - NSShadow shadow = null, + NSShadow? shadow = null, float strokeWidth = 0, NSUnderlineStyle strikethroughStyle = NSUnderlineStyle.None) : this (str, ToDictionary (font, foregroundColor, backgroundColor, strokeColor, paragraphStyle, ligatures, kerning, underlineStyle, shadow, strokeWidth, strikethroughStyle)) diff --git a/src/Foundation/NSMutableAttributedString.iOS.cs b/src/Foundation/NSMutableAttributedString.iOS.cs index 27786043e59d..fd0c09fe946a 100644 --- a/src/Foundation/NSMutableAttributedString.iOS.cs +++ b/src/Foundation/NSMutableAttributedString.iOS.cs @@ -11,28 +11,33 @@ using UIKit; using CoreText; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSMutableAttributedString { - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Sets the attributes for the specified range. Any previous attributes in that range are replaced with the new values. + /// + /// The UIKit attributes to set. + /// The range to which the attributes will be applied. public void SetAttributes (UIStringAttributes attrs, NSRange range) { - SetAttributes (attrs is null ? null : attrs.Dictionary, range); + ArgumentNullException.ThrowIfNull (attrs); + + SetAttributes (attrs.Dictionary, range); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Adds attributes to the specified range of characters in the string. + /// + /// The UIKit attributes to add. + /// The range to which the attributes will be applied. public void AddAttributes (UIStringAttributes attrs, NSRange range) { - AddAttributes (attrs is null ? null : attrs.Dictionary, range); + ArgumentNullException.ThrowIfNull (attrs); + + AddAttributes (attrs.Dictionary, range); } } diff --git a/src/Foundation/NSMutableDictionary.cs b/src/Foundation/NSMutableDictionary.cs index a6cebeb5b520..10a572a9896a 100644 --- a/src/Foundation/NSMutableDictionary.cs +++ b/src/Foundation/NSMutableDictionary.cs @@ -20,32 +20,25 @@ // // Copyright 2011 - 2014 Xamarin Inc (http://www.xamarin.com) // +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using CoreFoundation; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSMutableDictionary : NSDictionary, IDictionary, IDictionary { - - // some API, like SecItemCopyMatching, returns a retained NSMutableDictionary - internal NSMutableDictionary (NativeHandle handle, bool owns) - : base (handle) - { - if (!owns) - DangerousRelease (); - } - - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Creates a mutable dictionary from the specified arrays of objects and keys. + /// The array of objects to add to the dictionary. + /// The array of keys for the objects. + /// A new mutable dictionary containing the specified objects and keys. + /// Thrown when or is . + /// Thrown when the arrays have different sizes. public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys) { if (objects is null) @@ -60,11 +53,12 @@ public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObj return FromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Creates a mutable dictionary from the specified arrays of objects and keys. + /// The array of objects to add to the dictionary. + /// The array of keys for the objects. + /// A new mutable dictionary containing the specified objects and keys. + /// Thrown when or is . + /// Thrown when the arrays have different sizes. public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys) { if (objects is null) @@ -79,12 +73,13 @@ public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object return FromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Creates a mutable dictionary from the specified number of objects and keys from the arrays. + /// The array of objects to add to the dictionary. + /// The array of keys for the objects. + /// The number of elements to copy from the arrays. + /// A new mutable dictionary containing the specified objects and keys. + /// Thrown when or is . + /// Thrown when the arrays have different sizes or is invalid. public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count) { if (objects is null) @@ -101,12 +96,13 @@ public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObj return FromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Creates a mutable dictionary from the specified number of objects and keys from the arrays. + /// The array of objects to add to the dictionary. + /// The array of keys for the objects. + /// The number of elements to copy from the arrays. + /// A new mutable dictionary containing the specified objects and keys. + /// Thrown when or is . + /// Thrown when the arrays have different sizes or is invalid. public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count) { if (objects is null) @@ -129,8 +125,7 @@ void ICollection>.Add (KeyValuePairTo be added. - /// To be added. + /// Removes all objects from the dictionary. public void Clear () { RemoveAllObjects (); @@ -175,11 +170,11 @@ bool ICollection>.IsReadOnly { #endregion #region IDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. - void IDictionary.Add (object key, object value) + /// Adds an element with the provided key and value to the dictionary. + /// The key of the element to add. + /// The value of the element to add. + /// Thrown when the key or value is not an . + void IDictionary.Add (object key, object? value) { var nsokey = key as NSObject; var nsovalue = value as NSObject; @@ -191,10 +186,10 @@ void IDictionary.Add (object key, object value) SetObject (nsovalue, nsokey); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Determines whether the dictionary contains an element with the specified key. + /// The key to locate in the dictionary. + /// if the dictionary contains an element with the key; otherwise, . + /// Thrown when is . bool IDictionary.Contains (object key) { if (key is null) @@ -207,17 +202,17 @@ bool IDictionary.Contains (object key) return result; } - /// To be added. - /// To be added. - /// To be added. + /// Returns an enumerator that iterates through the dictionary. + /// An for the dictionary. IDictionaryEnumerator IDictionary.GetEnumerator () { return (IDictionaryEnumerator) ((IEnumerable>) this).GetEnumerator (); } - /// To be added. - /// To be added. - /// To be added. + /// Removes the element with the specified key from the dictionary. + /// The key of the element to remove. + /// Thrown when is . + /// Thrown when the key is not an . void IDictionary.Remove (object key) { if (key is null) @@ -230,26 +225,28 @@ void IDictionary.Remove (object key) GC.KeepAlive (nskey); } - /// To be added. - /// To be added. - /// To be added. + /// Gets a value indicating whether the dictionary has a fixed size. + /// since the dictionary is mutable. bool IDictionary.IsFixedSize { get { return false; } } - /// To be added. - /// To be added. - /// To be added. + /// Gets a value indicating whether the dictionary is read-only. + /// since the dictionary is mutable. bool IDictionary.IsReadOnly { get { return false; } } - object IDictionary.this [object key] { + /// Gets or sets the object associated with the specified key. + /// The key of the object to get or set. + /// The object associated with the specified key. + /// Thrown when setting a value and the key or value is not an . + object? IDictionary.this [object key] { get { var _key = key as INativeObject; if (_key is null) return null; - object result = _ObjectForKey (_key.Handle); + object? result = _ObjectForKey (_key.Handle); GC.KeepAlive (_key); return result; } @@ -266,36 +263,33 @@ object IDictionary.this [object key] { } } - /// To be added. - /// To be added. - /// To be added. + /// Gets an containing the keys of the dictionary. + /// An containing the keys of the dictionary. ICollection IDictionary.Keys { get { return Keys; } } - /// To be added. - /// To be added. - /// To be added. + /// Gets an containing the values in the dictionary. + /// An containing the values in the dictionary. ICollection IDictionary.Values { get { return Values; } } #endregion #region IDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Adds an element with the provided key and value to the dictionary. + /// The key of the element to add. + /// The value of the element to add. public void Add (NSObject key, NSObject value) { // Inverted args. SetObject (value, key); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Removes the element with the specified key from the dictionary. + /// The key of the element to remove. + /// if the element is successfully removed; otherwise, . + /// Thrown when is . public bool Remove (NSObject key) { if (key is null) @@ -306,19 +300,27 @@ public bool Remove (NSObject key) return last != Count; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public bool TryGetValue (NSObject key, out NSObject value) + /// Gets the value associated with the specified key. + /// The key whose value to get. + /// When this method returns, the value associated with the specified key, if the key is found; otherwise, . + /// if the dictionary contains an element with the specified key; otherwise, . +#pragma warning disable CS8767 // Nullability of reference types in type of parameter 'value' of 'bool NSMutableDictionary.TryGetValue(NSObject key, out NSObject? value)' doesn't match implicitly implemented member 'bool IDictionary.TryGetValue(NSObject key, out NSObject value)' (possibly because of nullability attributes). + public bool TryGetValue (NSObject key, [NotNullWhen (true)] out NSObject? value) +#pragma warning restore CS8767 { // Can't put null in NSDictionaries, so if null is returned, the key wasn't found. return (value = ObjectForKey (key)) is not null; } - public override NSObject this [NSObject key] { + /// Gets or sets the object associated with the specified key. + /// The key of the object to get or set. + /// The object associated with the specified key. + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public override NSObject? this [NSObject key] { +#pragma warning disable CS8766 // Nullability of reference types in return type of 'NSObject? NSMutableDictionary.this[NSObject key].get' doesn't match implicitly implemented member 'NSObject IDictionary.this[NSObject key].get' get { +#pragma warning restore CS8766 return ObjectForKey (key); } set { @@ -326,7 +328,12 @@ public override NSObject this [NSObject key] { } } - public override NSObject this [NSString key] { + /// Gets or sets the object associated with the specified key. + /// The key of the object to get or set. + /// The object associated with the specified key. + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public override NSObject? this [NSString key] { get { return ObjectForKey (key); } @@ -335,10 +342,16 @@ public override NSObject this [NSString key] { } } - public override NSObject this [string key] { + /// Gets or sets the object associated with the specified key. + /// The key of the object to get or set. + /// The object associated with the specified key. + /// Thrown when is . + /// Returns if the key wasn't found. + [DisallowNull] // don't allow setting null values + public override NSObject? this [string key] { get { if (key is null) - throw new ArgumentNullException ("key"); + throw new ArgumentNullException (nameof (key)); var nss = NSString.CreateNative (key, false); try { return Runtime.GetNSObject (LowlevelObjectForKey (nss)); @@ -348,7 +361,7 @@ public override NSObject this [string key] { } set { if (key is null) - throw new ArgumentNullException ("key"); + throw new ArgumentNullException (nameof (key)); var nss = NSString.CreateNative (key, false); try { LowlevelSetObject (value, nss); @@ -358,19 +371,22 @@ public override NSObject this [string key] { } } + /// Gets an containing the keys of the dictionary. + /// An containing the keys of the dictionary. ICollection IDictionary.Keys { get { return Keys; } } + /// Gets an containing the values in the dictionary. + /// An containing the values in the dictionary. ICollection IDictionary.Values { get { return Values; } } #endregion #region IEnumerable - /// To be added. - /// To be added. - /// To be added. + /// Returns an enumerator that iterates through the dictionary. + /// An for the dictionary. IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable>) this).GetEnumerator (); @@ -383,29 +399,27 @@ IEnumerator IEnumerable.GetEnumerator () public IEnumerator> GetEnumerator () { foreach (var key in Keys) { - yield return new KeyValuePair (key, ObjectForKey (key)); + yield return new KeyValuePair (key, this [key]!); } } #endregion - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Creates a mutable dictionary from a low-level object and key pointer. + /// The object pointer. + /// The key pointer. + /// A new mutable dictionary containing the specified object and key. public static NSMutableDictionary LowlevelFromObjectAndKey (IntPtr obj, IntPtr key) { #if MONOMAC - return (NSMutableDictionary) Runtime.GetNSObject (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr (class_ptr, selDictionaryWithObject_ForKey_XHandle, obj, key)); + return (NSMutableDictionary) Runtime.GetNSObject (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr (class_ptr, selDictionaryWithObject_ForKey_XHandle, obj, key))!; #else - return (NSMutableDictionary) Runtime.GetNSObject (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr (class_ptr, Selector.GetHandle ("dictionaryWithObject:forKey:"), obj, key)); + return (NSMutableDictionary) Runtime.GetNSObject (ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr (class_ptr, Selector.GetHandle ("dictionaryWithObject:forKey:"), obj, key))!; #endif } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Sets an object for a key using low-level pointers. + /// The object pointer. + /// The key pointer. public void LowlevelSetObject (IntPtr obj, IntPtr key) { #if MONOMAC @@ -415,10 +429,10 @@ public void LowlevelSetObject (IntPtr obj, IntPtr key) #endif } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Sets an object for a key using a low-level key pointer. + /// The object to set. + /// The key pointer. + /// Thrown when is . public void LowlevelSetObject (NSObject obj, IntPtr key) { if (obj is null) @@ -428,6 +442,10 @@ public void LowlevelSetObject (NSObject obj, IntPtr key) GC.KeepAlive (obj); } + /// Sets a string value for a key using a low-level key pointer. + /// The string to set. + /// The key pointer. + /// Thrown when is . public void LowlevelSetObject (string str, IntPtr key) { if (str is null) diff --git a/src/Foundation/NSMutableDictionary_2.cs b/src/Foundation/NSMutableDictionary_2.cs index e34bd7c49a4c..590951e18f1c 100644 --- a/src/Foundation/NSMutableDictionary_2.cs +++ b/src/Foundation/NSMutableDictionary_2.cs @@ -26,33 +26,32 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] [Register ("NSMutableDictionary", SkipRegistration = true)] public sealed partial class NSMutableDictionary : NSMutableDictionary, IDictionary where TKey : class, INativeObject where TValue : class, INativeObject { - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class. + /// public NSMutableDictionary () { } + /// + /// A constructor that initializes the object from the data stored in the unarchiver object. + /// /// The unarchiver object. - /// A constructor that initializes the object from the data stored in the unarchiver object. - /// - /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. - /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. - /// The state of this object can also be serialized by using the companion method, EncodeTo. - /// + /// + /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. + /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. + /// The state of this object can also be serialized by using the companion method, EncodeTo. + /// public NSMutableDictionary (NSCoder coder) : base (coder) { @@ -63,17 +62,19 @@ internal NSMutableDictionary (NativeHandle handle) { } - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from another mutable dictionary. + /// + /// The mutable dictionary to copy from. public NSMutableDictionary (NSMutableDictionary other) : base (other) { } - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from a dictionary. + /// + /// The dictionary to copy from. public NSMutableDictionary (NSDictionary other) : base (other) { @@ -84,82 +85,46 @@ public NSMutableDictionary (NSDictionary other) { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class from parallel arrays of keys and values. + /// + /// An array of keys. + /// An array of values. public NSMutableDictionary (TKey [] keys, TValue [] values) : this (keys, values, NSDictionary.ValidateKeysAndValues (keys, values)) { } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class with a single key-value pair. + /// + /// The key. + /// The value. public NSMutableDictionary (TKey key, TValue value) : base (NSArray.FromNSObjects (value), NSArray.FromNSObjects (key)) { - - } - -#if hide_loosely_typed_members - // Hide any loosely typed base members. - [EditorBrowsable (EditorBrowsableState.Never)] - public override NSObject this[NSObject key] { - get { - return (NSObject) (object) this [(TKey) (object) key]; - } - set { - this [(TKey) (object) key] = (TValue) (object) value; - } - } - - // This one can never be correct, so make it an error to use it. - [Obsolete ("This indexer does not have the correct key type.", true)] - [EditorBrowsable (EditorBrowsableState.Never)] -#pragma warning disable 809 - public override NSObject this[string key] { -#pragma warning restore 809 - get { - throw new NotSupportedException (); - } - set { - throw new NotSupportedException (); - } - } - - // This can be correct if TKey=NSString and TValue=NSObject (but still hide it). - [EditorBrowsable (EditorBrowsableState.Never)] - public override NSObject this[NSString key] { - get { - return (NSObject) (object) this [(TKey) (object) key]; - } - set { - this [(TKey) (object) key] = (TValue) (object) value; - } } -#endif // Strongly typed methods from NSDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public TValue ObjectForKey (TKey key) + /// + /// Returns the value associated with the specified key, or if the key is not present. + /// + /// The key to look up. + /// The value associated with the specified key, or if the key is not present. + public TValue? ObjectForKey (TKey key) { - if (key is null) - throw new ArgumentNullException (nameof (key)); + ArgumentNullException.ThrowIfNull (key); var result = Runtime.GetINativeObject (_ObjectForKey (key.Handle), false); GC.KeepAlive (key); return result; } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an array containing all keys in the dictionary. + /// + /// An array of keys. public TKey [] Keys { get { using (var pool = new NSAutoreleasePool ()) @@ -167,14 +132,14 @@ public TKey [] Keys { } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an array of keys corresponding to all occurrences of the specified value in the dictionary. + /// + /// The value to search for. + /// An array of keys whose corresponding values are equal to the specified value. public TKey [] KeysForObject (TValue obj) { - if (obj is null) - throw new ArgumentNullException (nameof (obj)); + ArgumentNullException.ThrowIfNull (obj); using (var pool = new NSAutoreleasePool ()) { var result = NSArray.ArrayFromHandle (_AllKeysForObject (obj.Handle)); @@ -183,9 +148,10 @@ public TKey [] KeysForObject (TValue obj) } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets an array containing all values in the dictionary. + /// + /// An array of values. public TValue [] Values { get { using (var pool = new NSAutoreleasePool ()) @@ -193,21 +159,19 @@ public TValue [] Values { } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an array of values corresponding to a specified set of keys. + /// + /// An array of keys. + /// The marker object to substitute for values that are not present in the dictionary. + /// An array of values corresponding to the keys in the array, with the marker object substituted for missing values. public TValue [] ObjectsForKeys (TKey [] keys, TValue marker) { - if (keys is null) - throw new ArgumentNullException (nameof (keys)); - - if (marker is null) - throw new ArgumentNullException (nameof (marker)); + ArgumentNullException.ThrowIfNull (keys); + ArgumentNullException.ThrowIfNull (marker); if (keys.Length == 0) - return new TValue [] { }; + return []; var keysArray = NSArray.From (keys); var result = NSArray.ArrayFromHandle (_ObjectsForKeys (keysArray.Handle, marker.Handle)); @@ -218,31 +182,29 @@ public TValue [] ObjectsForKeys (TKey [] keys, TValue marker) // Strongly typed methods from NSMutableDictionary - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Adds a key-value pair to the dictionary. + /// + /// The key to add. + /// The value to add. public void Add (TKey key, TValue value) { - if (key is null) - throw new ArgumentNullException (nameof (key)); - - if (value is null) - throw new ArgumentNullException (nameof (value)); + ArgumentNullException.ThrowIfNull (key); + ArgumentNullException.ThrowIfNull (value); _SetObject (value.Handle, key.Handle); GC.KeepAlive (value); GC.KeepAlive (key); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Removes the value associated with the specified key from the dictionary. + /// + /// The key to remove. + /// if the key was found and removed; otherwise, . public bool Remove (TKey key) { - if (key is null) - throw new ArgumentNullException (nameof (key)); + ArgumentNullException.ThrowIfNull (key); var last = Count; _RemoveObjectForKey (key.Handle); @@ -250,26 +212,34 @@ public bool Remove (TKey key) return last != Count; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public bool TryGetValue (TKey key, out TValue value) + /// + /// Gets the value associated with the specified key. + /// + /// The key to look up. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, . + /// if the dictionary contains an element with the specified key; otherwise, . + public bool TryGetValue (TKey key, [NotNullWhen (true)] out TValue? value) { return (value = ObjectForKey (key)) is not null; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Determines whether the dictionary contains the specified key. + /// + /// The key to locate in the dictionary. + /// if the dictionary contains an element with the specified key; otherwise, . public bool ContainsKey (TKey key) { return ObjectForKey (key) is not null; } - public TValue this [TKey index] { + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// The value associated with the specified key, or if the key wasn't found. + [DisallowNull] // don't allow setting null values + public TValue? this [TKey index] { get { return ObjectForKey (index); } @@ -278,7 +248,7 @@ public TValue this [TKey index] { } } - static NSMutableDictionary GenericFromObjectsAndKeysInternal (NSArray objects, NSArray keys) + static NSMutableDictionary? GenericFromObjectsAndKeysInternal (NSArray objects, NSArray keys) { var result = Runtime.GetNSObject> (_FromObjectsAndKeysInternal (objects.Handle, keys.Handle)); GC.KeepAlive (objects); @@ -286,18 +256,17 @@ static NSMutableDictionary GenericFromObjectsAndKeysInternal (NSAr return result; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSMutableDictionary FromObjectsAndKeys (TValue [] objects, TKey [] keys, nint count) + /// + /// Creates a mutable dictionary from parallel arrays of values and keys, using only the first elements. + /// + /// An array of values. + /// An array of keys. + /// The number of elements to use from each array. + /// A new mutable dictionary containing the specified key-value pairs. + public static NSMutableDictionary? FromObjectsAndKeys (TValue [] objects, TKey [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count) @@ -308,12 +277,16 @@ public static NSMutableDictionary FromObjectsAndKeys (TValue [] ob return GenericFromObjectsAndKeysInternal (no, nk); } - public static NSMutableDictionary FromObjectsAndKeys (TValue [] objects, TKey [] keys) + /// + /// Creates a mutable dictionary from parallel arrays of values and keys. + /// + /// An array of values. + /// An array of keys. + /// A new mutable dictionary containing the specified key-value pairs. + public static NSMutableDictionary? FromObjectsAndKeys (TValue [] objects, TKey [] keys) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); @@ -322,17 +295,16 @@ public static NSMutableDictionary FromObjectsAndKeys (TValue [] ob return GenericFromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys) + /// + /// Creates a mutable dictionary from parallel arrays of object values and keys. + /// + /// An array of object values. + /// An array of object keys. + /// A new mutable dictionary containing the specified key-value pairs. + public static NSMutableDictionary? FromObjectsAndKeys (object [] objects, object [] keys) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); @@ -341,18 +313,17 @@ public static NSMutableDictionary FromObjectsAndKeys (object [] ob return GenericFromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count) + /// + /// Creates a mutable dictionary from parallel arrays of values and keys, using only the first elements. + /// + /// An array of values. + /// An array of keys. + /// The number of elements to use from each array. + /// A new mutable dictionary containing the specified key-value pairs. + public static NSMutableDictionary? FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count || keys.Length < count) @@ -363,18 +334,17 @@ public static NSMutableDictionary FromObjectsAndKeys (NSObject [] return GenericFromObjectsAndKeysInternal (no, nk); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count) + /// + /// Creates a mutable dictionary from parallel arrays of object values and keys, using only the first elements. + /// + /// An array of object values. + /// An array of object keys. + /// The number of elements to use from each array. + /// A new mutable dictionary containing the specified key-value pairs. + public static NSMutableDictionary? FromObjectsAndKeys (object [] objects, object [] keys, nint count) { - if (objects is null) - throw new ArgumentNullException (nameof (objects)); - if (keys is null) - throw new ArgumentNullException (nameof (keys)); + ArgumentNullException.ThrowIfNull (objects); + ArgumentNullException.ThrowIfNull (keys); if (objects.Length != keys.Length) throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes"); if (count < 1 || objects.Length < count || keys.Length < count) @@ -384,6 +354,7 @@ public static NSMutableDictionary FromObjectsAndKeys (object [] ob using (var nk = NSArray.FromObjects (keys)) return GenericFromObjectsAndKeysInternal (no, nk); } + #region IDictionary void IDictionary.Add (TKey key, TValue value) { @@ -395,13 +366,16 @@ bool IDictionary.Remove (TKey key) return Remove (key); } - bool IDictionary.TryGetValue (TKey key, out TValue value) + bool IDictionary.TryGetValue (TKey key, [NotNullWhen (true)] out TValue? value) { return TryGetValue (key, out value); } - TValue IDictionary.this [TKey index] { + [DisallowNull] // don't allow setting null values + TValue? IDictionary.this [TKey index] { +#pragma warning disable CS8768 // Nullability of reference types in return type doesn't match implemented member 'TValue IDictionary.this[TKey key].get' get { +#pragma warning restore CS8768 return this [index]; } set { @@ -440,18 +414,17 @@ void ICollection>.Clear () bool ICollection>.Contains (KeyValuePair item) { - TValue value; + TValue? value; if (!TryGetValue (item.Key, out value)) return false; - return (object) value == (object) item.Value; + return (object?) value == (object?) item.Value; } void ICollection>.CopyTo (KeyValuePair [] array, int arrayIndex) { - if (array is null) - throw new ArgumentNullException (nameof (array)); + ArgumentNullException.ThrowIfNull (array); if (arrayIndex < 0) throw new ArgumentOutOfRangeException (nameof (arrayIndex)); int c = array.Length; @@ -461,13 +434,16 @@ void ICollection>.CopyTo (KeyValuePair throw new ArgumentException ("Not enough room from " + nameof (arrayIndex) + " to end of " + nameof (array) + " for this dictionary"); var idx = arrayIndex; - foreach (var kvp in (IEnumerable>) this) - array [idx++] = kvp; + foreach (var key in Keys) { + var value = ObjectForKey (key); + if (value is not null) + array [idx++] = new KeyValuePair (key, value); + } } bool ICollection>.Remove (KeyValuePair item) { - TValue value; + TValue? value; if (item.Key is null) throw new ArgumentNullException (nameof (item) + ".Key"); @@ -478,7 +454,7 @@ bool ICollection>.Remove (KeyValuePair if (!TryGetValue (item.Key, out value)) return false; - if ((object) value == (object) item.Value) { + if ((object?) value == (object?) item.Value) { Remove (item.Key); return true; } @@ -502,15 +478,19 @@ bool ICollection>.IsReadOnly { #region IEnumerable> IEnumerator> IEnumerable>.GetEnumerator () { - foreach (var key in Keys) - yield return new KeyValuePair (key, ObjectForKey (key)); + foreach (var key in Keys) { + var value = ObjectForKey (key); + if (value is not null) + yield return new KeyValuePair (key, value); + } } #endregion #region IEnumerable - /// To be added. - /// To be added. - /// To be added. + /// + /// Returns an enumerator that iterates through the dictionary. + /// + /// An enumerator that can be used to iterate through the dictionary. IEnumerator IEnumerable.GetEnumerator () { return ((IEnumerable>) this).GetEnumerator (); diff --git a/src/Foundation/NSMutableOrderedSet_1.cs b/src/Foundation/NSMutableOrderedSet_1.cs index fa9db9cf360b..76d1caed0f4c 100644 --- a/src/Foundation/NSMutableOrderedSet_1.cs +++ b/src/Foundation/NSMutableOrderedSet_1.cs @@ -128,17 +128,17 @@ public void Add (TKey obj) } /// Adds the objects in the specified array to the ordered set. - /// An array of objects to add to the set. - public void AddObjects (params TKey [] source) + /// An array of objects to add to the set. Null elements are stored as . + public void AddObjects (params TKey? [] source) { ArgumentNullException.ThrowIfNull (source); _AddObjects (NSArray.FromNativeObjects (source)); } /// Inserts the specified objects at the specified indexes in the ordered set. - /// An array of objects to insert. + /// An array of objects to insert. Null elements are stored as . /// The indexes at which to insert the objects. - public void InsertObjects (TKey [] objects, NSIndexSet atIndexes) + public void InsertObjects (TKey? [] objects, NSIndexSet atIndexes) { ArgumentNullException.ThrowIfNull (objects); ArgumentNullException.ThrowIfNull (atIndexes); @@ -147,8 +147,8 @@ public void InsertObjects (TKey [] objects, NSIndexSet atIndexes) /// Replaces the objects at the specified indexes with the specified replacement objects. /// The indexes of the objects to replace. - /// An array of objects to use as replacements. - public void ReplaceObjects (NSIndexSet indexSet, params TKey [] replacementObjects) + /// An array of objects to use as replacements. Null elements are stored as . + public void ReplaceObjects (NSIndexSet indexSet, params TKey? [] replacementObjects) { ArgumentNullException.ThrowIfNull (replacementObjects); ArgumentNullException.ThrowIfNull (indexSet); @@ -165,8 +165,8 @@ public void RemoveObject (TKey obj) } /// Removes the specified objects from the ordered set. - /// An array of objects to remove from the set. - public void RemoveObjects (params TKey [] objects) + /// An array of objects to remove from the set. Null elements are interpreted as . + public void RemoveObjects (params TKey? [] objects) { ArgumentNullException.ThrowIfNull (objects); _RemoveObjects (NSArray.FromNativeObjects (objects)); diff --git a/src/Foundation/NSMutableSet.cs b/src/Foundation/NSMutableSet.cs index a81434cc2d9f..9f225b4488c8 100644 --- a/src/Foundation/NSMutableSet.cs +++ b/src/Foundation/NSMutableSet.cs @@ -29,24 +29,22 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { public partial class NSMutableSet : IEnumerable { - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the specified objects. + /// The objects to add to the set. public NSMutableSet (params NSObject [] objs) : this (NSArray.FromNSObjects (objs)) { } - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the specified strings. + /// The strings to add to the set. public NSMutableSet (params string [] strings) : this (NSArray.FromStrings (strings)) { @@ -57,10 +55,18 @@ internal NSMutableSet (params INativeObject [] objs) { } - public static NSMutableSet operator + (NSMutableSet first, NSMutableSet second) + /// Creates a new mutable set containing all objects from both sets. + /// The first set. + /// The second set. + /// A new containing the union of both sets, or if both sets are . + [return: NotNullIfNotNull (nameof (first))] + [return: NotNullIfNotNull (nameof (second))] + public static NSMutableSet? operator + (NSMutableSet? first, NSMutableSet? second) { + if (first is null && second is null) + return null; if (first is null || first.Count == 0) - return new NSMutableSet (second); + return second is null ? new NSMutableSet () : new NSMutableSet (second); if (second is null || second.Count == 0) return new NSMutableSet (first); @@ -69,10 +75,17 @@ internal NSMutableSet (params INativeObject [] objs) return copy; } - public static NSMutableSet operator - (NSMutableSet first, NSMutableSet second) + /// Creates a new mutable set with objects from the first set that are not in the second set. + /// The first set. + /// The second set. + /// A new containing the difference, or if the first set is . + [return: NotNullIfNotNull (nameof (first))] + public static NSMutableSet? operator - (NSMutableSet? first, NSMutableSet? second) { - if (first is null || first.Count == 0) + if (first is null) return null; + if (first.Count == 0) + return new NSMutableSet (); if (second is null || second.Count == 0) return new NSMutableSet (first); diff --git a/src/Foundation/NSMutableSet_1.cs b/src/Foundation/NSMutableSet_1.cs index e83c185b8f29..253d70014916 100644 --- a/src/Foundation/NSMutableSet_1.cs +++ b/src/Foundation/NSMutableSet_1.cs @@ -27,30 +27,26 @@ using System.Collections; using System.Collections.Generic; -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] + /// A strongly-typed mutable set that contains objects of type . + /// The type of objects in the set. [Register ("NSMutableSet", SkipRegistration = true)] public sealed partial class NSMutableSet : NSMutableSet, IEnumerable where TKey : class, INativeObject { - /// To be added. - /// To be added. + /// Initializes a new empty mutable set. public NSMutableSet () { } + /// Initializes the object from the data stored in the unarchiver object. /// The unarchiver object. - /// A constructor that initializes the object from the data stored in the unarchiver object. - /// - /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. - /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. - /// The state of this object can also be serialized by using the companion method, EncodeTo. - /// + /// + /// This constructor is provided to allow the class to be initialized from an unarchiver (for example, during NIB deserialization). This is part of the protocol. + /// If developers want to create a subclass of this object and continue to support deserialization from an archive, they should implement a constructor with an identical signature: taking a single parameter of type and decorate it with the [Export("initWithCoder:"] attribute declaration. + /// The state of this object can also be serialized by using the companion method, EncodeTo. + /// public NSMutableSet (NSCoder coder) : base (coder) { @@ -61,33 +57,29 @@ internal NSMutableSet (NativeHandle handle) { } - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the specified objects. + /// The objects to add to the set. public NSMutableSet (params TKey [] objs) : base (objs) { } - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the contents of the specified set. + /// The set whose contents will be copied to the new set. public NSMutableSet (NSSet other) : base (other) { } - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the contents of the specified mutable set. + /// The mutable set whose contents will be copied to the new set. public NSMutableSet (NSMutableSet other) : base (other) { } - /// To be added. - /// To be added. - /// To be added. + /// Initializes a new mutable set with the specified initial capacity. + /// The initial capacity of the set. public NSMutableSet (nint capacity) : base (capacity) { @@ -95,33 +87,30 @@ public NSMutableSet (nint capacity) // Strongly typed versions of API from NSSet - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public TKey LookupMember (TKey probe) + /// Returns the object in the set that is equal to the specified object. + /// The object to search for in the set. + /// The object in the set that is equal to , or if no such object exists. + public TKey? LookupMember (TKey probe) { if (probe is null) throw new ArgumentNullException (nameof (probe)); - TKey result = Runtime.GetINativeObject (_LookupMember (probe.Handle), false); + TKey? result = Runtime.GetINativeObject (_LookupMember (probe.Handle), false); GC.KeepAlive (probe); return result; } - /// To be added. - /// To be added. - /// To be added. - public TKey AnyObject { + /// Gets one of the objects in the set, or if the set is empty. + /// An arbitrary object from the set, or if the set contains no objects. + public TKey? AnyObject { get { return Runtime.GetINativeObject (_AnyObject, false); } } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// Determines whether the set contains the specified object. + /// The object to locate in the set. + /// if the set contains ; otherwise, . public bool Contains (TKey obj) { if (obj is null) @@ -132,18 +121,23 @@ public bool Contains (TKey obj) return result; } - /// To be added. - /// To be added. - /// To be added. + /// Converts the set to an array. + /// An array containing all the objects in the set. public TKey [] ToArray () { return base.ToArray (); } - public static NSMutableSet operator + (NSMutableSet first, NSMutableSet second) + /// Creates a new mutable set containing all objects from both sets. + /// The first set. + /// The second set. + /// A new containing the union of both sets, or if both sets are . + public static NSMutableSet? operator + (NSMutableSet? first, NSMutableSet? second) { + if (first is null && second is null) + return null; if (first is null || first.Count == 0) - return new NSMutableSet (second); + return second is null ? new NSMutableSet () : new NSMutableSet (second); if (second is null || second.Count == 0) return new NSMutableSet (first); var result = new NSMutableSet (first._SetByAddingObjectsFromSet (second.Handle)); @@ -151,7 +145,11 @@ public TKey [] ToArray () return result; } - public static NSMutableSet operator - (NSMutableSet first, NSMutableSet second) + /// Creates a new mutable set with objects from the first set that are not in the second set. + /// The first set. + /// The second set. + /// A new containing the difference, or if the first set is or empty. + public static NSMutableSet? operator - (NSMutableSet? first, NSMutableSet? second) { if (first is null || first.Count == 0) return null; @@ -163,9 +161,8 @@ public TKey [] ToArray () } // Strongly typed versions of API from NSMutableSet - /// To be added. - /// To be added. - /// To be added. + /// Adds the specified object to the set. + /// The object to add to the set. public void Add (TKey obj) { if (obj is null) @@ -175,9 +172,8 @@ public void Add (TKey obj) GC.KeepAlive (obj); } - /// To be added. - /// To be added. - /// To be added. + /// Removes the specified object from the set. + /// The object to remove from the set. public void Remove (TKey obj) { if (obj is null) @@ -187,9 +183,8 @@ public void Remove (TKey obj) GC.KeepAlive (obj); } - /// To be added. - /// To be added. - /// To be added. + /// Adds multiple objects to the set. + /// The objects to add to the set. public void AddObjects (params TKey [] objects) { if (objects is null) @@ -213,9 +208,8 @@ public void AddObjects (params TKey [] objects) #endregion #region IEnumerable implementation - /// To be added. - /// To be added. - /// To be added. + /// Returns an enumerator that iterates through the set. + /// An enumerator that can be used to iterate through the set. IEnumerator IEnumerable.GetEnumerator () { return new NSFastEnumerator (this); diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs index 6c25c77fbd8a..5c7c6ebc1d03 100644 --- a/src/Foundation/NSObject2.cs +++ b/src/Foundation/NSObject2.cs @@ -25,9 +25,7 @@ using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading; -#if !NO_SYSTEM_DRAWING using System.Drawing; -#endif using System.Diagnostics; using System.Runtime.InteropServices.ObjectiveC; @@ -41,16 +39,67 @@ using CoreGraphics; #endif -// Disable until we get around to enable + fix any issues. -#nullable disable +#nullable enable namespace Foundation { - /// - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] + /// + /// Sentinel class. + /// + /// + /// + /// The sole purpose for the class is to be used + /// as a sentinel in the class hierarchy to ensure that the + /// actual object initialization only happens in . + /// + /// + /// When you chain your constructors using the + /// only thing that will take place is the allocation of the + /// object instance; no calls to any of the init: methods in base + /// classes will be performed. If your code depends on this for + /// initialization, you are responsible for calling the proper + /// init method directly. For example: + /// + /// + /// + /// + /// + /// Alternatively, if you need a base class to initialize itself, + /// you should call one of the other constructors that take some + /// parameters. + /// + /// + /// + /// + /// public enum NSObjectFlag { /// Sentinel instance. Empty, @@ -61,7 +110,7 @@ internal interface INSObjectFactory { // The method will be implemented via custom linker step if the managed static registrar is used // for NSObject subclasses which have an (NativeHandle) or (IntPtr) constructor. [MethodImpl (MethodImplOptions.NoInlining)] - virtual static NSObject _Xamarin_ConstructNSObject (NativeHandle handle) => null; + virtual static NSObject? _Xamarin_ConstructNSObject (NativeHandle handle) => null; } #if !COREBUILD @@ -123,10 +172,6 @@ protected override bool ReleaseHandle () #if !COREBUILD /// [ObjectiveCTrackedType] - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] #endif [StructLayout (LayoutKind.Sequential)] public partial class NSObject : INativeObject @@ -144,9 +189,10 @@ public partial class NSObject : INativeObject static IntPtr selEncodeWithCoderHandle = Selector.GetHandle (selEncodeWithCoder); #endif - // replace older Mono[Touch|Mac]Assembly field (ease code sharing across platforms) - /// To be added. - /// To be added. + /// + /// Gets the assembly containing the platform-specific Foundation types. + /// + /// The assembly containing the platform-specific Foundation types. public static readonly Assembly PlatformAssembly = typeof (NSObject).Assembly; // This is exclusively for Mono @@ -161,7 +207,6 @@ unsafe NativeHandle handle { // safely from native code without having to make sure the GC doesn't move the memory around. Among // other things, this means it's accessible from threads that has never seen/run managed code without // having to attach those threads to to the managed runtime. -#nullable enable NSObjectDataHandle? data_handle; internal unsafe NSObjectData* GetData () @@ -201,7 +246,6 @@ unsafe Flags flags { get { return GetData ()->flags; } set { GetData ()->flags = value; } } -#nullable disable // This enum has a native counterpart in runtime.h [Flags] @@ -245,9 +289,10 @@ internal bool IsRegisteredToggleRef { set { flags = value ? (flags | Flags.RegisteredToggleRef) : (flags & ~Flags.RegisteredToggleRef); } } - /// To be added. - /// To be added. - /// To be added. + /// + /// Gets or sets a value indicating whether this instance uses direct Objective-C binding. + /// + /// if this instance uses direct binding; otherwise, . [DebuggerBrowsable (DebuggerBrowsableState.Never)] [EditorBrowsable (EditorBrowsableState.Never)] protected internal bool IsDirectBinding { @@ -305,11 +350,16 @@ protected NSObject (NativeHandle handle, bool alloced) Dispose (false); } - /// Releases the resources used by the NSObject object. - /// - /// The Dispose method releases the resources used by the NSObject class. - /// Calling the Dispose method when the application is finished using the NSObject ensures that all external resources used by this managed object are released as soon as possible. Once developers have invoked the Dispose method, the object is no longer useful and developers should no longer make any calls to it. For more information on releasing resources see ``Cleaning up Unmananaged Resources'' at https://msdn.microsoft.com/en-us/library/498928w2.aspx - /// + /// Releases the resources used by the object. + /// + /// The method releases the resources used by the class. + /// + /// Calling the method when the application is finished using the ensures that all + /// external resources used by this managed object are released as soon as possible. Once developers have invoked + /// the method, the object is no longer useful and developers should no longer make any calls to it. + /// For more information on releasing resources see Cleaning up unmanaged resources. + /// + /// public void Dispose () { Dispose (true); @@ -329,7 +379,10 @@ internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flag } // This function is called from native code before any constructors have executed. - var type = (Type) Runtime.GetGCHandleTarget (type_gchandle); + var type = (Type?) Runtime.GetGCHandleTarget (type_gchandle); + if (type is null) + return IntPtr.Zero; + try { var obj = (NSObject) RuntimeHelpers.GetUninitializedObject (type); obj.handle = handle; @@ -385,13 +438,12 @@ static void RegisterToggleReference (NSObject obj, IntPtr handle, bool isCustomT -The class is not a custom type - it must wrap a framework class. */ /// Promotes a regular peer object (IsDirectBinding is true) into a toggleref object. - /// - /// This turns a regular peer object (one that has - /// IsDirectBinding set to true) into a toggleref object. This - /// is necessary when you are storing to a backing field whose - /// objc_c semantics is not copy or retain. This is an internal - /// method. - /// + /// + /// This turns a regular peer object (one that has set to true) + /// into a toggleref object. This is necessary when storing managed state (for instance into + /// a backing field), so that the managed peer isn't collected by the GC before the native object + /// is freed. This is an internal method. + /// [EditorBrowsable (EditorBrowsableState.Never)] protected void MarkDirty () { @@ -483,7 +535,7 @@ static bool IsProtocol (Type type, IntPtr protocol) { while (type != typeof (NSObject) && type is not null) { var attrs = type.GetCustomAttributes (typeof (ProtocolAttribute), false); - var protocolAttribute = (ProtocolAttribute) (attrs.Length > 0 ? attrs [0] : null); + var protocolAttribute = (ProtocolAttribute?) (attrs.Length > 0 ? attrs [0] : null); if (protocolAttribute is not null && !protocolAttribute.IsInformal) { string name; @@ -491,7 +543,7 @@ static bool IsProtocol (Type type, IntPtr protocol) name = protocolAttribute.Name; } else { attrs = type.GetCustomAttributes (typeof (RegisterAttribute), false); - var registerAttribute = (RegisterAttribute) (attrs.Length > 0 ? attrs [0] : null); + var registerAttribute = (RegisterAttribute?) (attrs.Length > 0 ? attrs [0] : null); if (registerAttribute is not null && !string.IsNullOrEmpty (registerAttribute.Name)) { name = registerAttribute.Name; } else { @@ -503,7 +555,10 @@ static bool IsProtocol (Type type, IntPtr protocol) if (proto != IntPtr.Zero && proto == protocol) return true; } - type = type.BaseType; + var baseType = type.BaseType; + if (baseType is null) + return false; + type = baseType; } return false; @@ -559,7 +614,7 @@ public virtual bool ConformsToProtocol (NativeHandle protocol) var classHandle = ClassHandle; lock (Runtime.protocol_cache) { ref var map = ref CollectionsMarshal.GetValueRefOrAddDefault (Runtime.protocol_cache, classHandle, out var exists); - if (!exists) + if (!exists || map is null) map = new (); ref var result = ref CollectionsMarshal.GetValueRefOrAddDefault (map, protocol, out exists); if (!exists) @@ -665,15 +720,15 @@ public NSObject DangerousAutorelease () return this; } - /// Handle used to represent the methods in the base class for this NSObject. - /// An opaque pointer, represents an Objective-C objc_super object pointing to our base class. - /// - /// This property is used to access members of a base class. - /// This is typically used when you call any of the Messaging - /// methods to invoke methods that were implemented in your base - /// class, instead of invoking the implementation in the current - /// class. - /// + /// Handle used to represent the methods in the base class for this . + /// An opaque pointer, represents an Objective-C objc_super object pointing to our base class. + /// + /// This property is used to access members of a base class. + /// This is typically used when you call any of the Messaging + /// methods to invoke methods that were implemented in your base + /// class, instead of invoking the implementation in the current + /// class. + /// [EditorBrowsable (EditorBrowsableState.Never)] public NativeHandle SuperHandle { get { @@ -685,8 +740,8 @@ public NativeHandle SuperHandle { } /// Handle (pointer) to the unmanaged object representation. - /// A pointer - /// This IntPtr is a handle to the underlying unmanaged representation for this object. + /// A pointer. + /// This is a handle to the underlying unmanaged representation for this object. [EditorBrowsable (EditorBrowsableState.Never)] public NativeHandle Handle { get { return handle; } @@ -746,67 +801,72 @@ private bool AllocIfNeeded () return false; } - private void InvokeOnMainThread (Selector sel, NSObject obj, bool wait) + private void InvokeOnMainThread (Selector sel, NSObject? obj, bool wait) { Messaging.void_objc_msgSend_NativeHandle_NativeHandle_bool (this.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone), sel.Handle, obj.GetHandle (), wait ? (byte) 1 : (byte) 0); GC.KeepAlive (sel); GC.KeepAlive (obj); } + /// Invokes asynchronously the specified code on the main UI thread. /// Selector to invoke - /// Object in which the selector is invoked - /// Invokes asynchrously the specified code on the main UI thread. - /// - /// - /// You use this method from a thread to invoke the code in - /// the specified object that is exposed with the specified - /// selector in the UI thread. This is required for most - /// operations that affect UIKit or AppKit as neither one of - /// those APIs is thread safe. - /// - /// - /// The code is executed when the main thread goes back to its - /// main loop for processing events. - /// - /// - /// Unlike - /// this method merely queues the invocation and returns - /// immediately to the caller. - /// - /// - public void BeginInvokeOnMainThread (Selector sel, NSObject obj) + /// Object in which the selector is invoked + /// + /// + /// You use this method from a thread to invoke the code in + /// the specified object that is exposed with the specified + /// selector in the UI thread. This is required for most + /// operations that affect UIKit or AppKit as neither one of + /// those APIs is thread safe. + /// + /// + /// The code is executed when the main thread goes back to its + /// main loop for processing events. + /// + /// + /// Unlike + /// this method merely queues the invocation and returns + /// immediately to the caller. + /// + /// + public void BeginInvokeOnMainThread (Selector sel, NSObject? obj) { InvokeOnMainThread (sel, obj, false); } + /// Invokes synchronously the specified code on the main UI thread. /// Selector to invoke - /// Object in which the selector is invoked - /// Invokes synchrously the specified code on the main UI thread. - /// - /// - /// You use this method from a thread to invoke the code in - /// the specified object that is exposed with the specified - /// selector in the UI thread. This is required for most - /// operations that affect UIKit or AppKit as neither one of - /// those APIs is thread safe. - /// - /// - /// The code is executed when the main thread goes back to its - /// main loop for processing events. - /// - /// - /// Unlike - /// this method waits for the main thread to execute the method, and does not return until the code pointed by action has completed. - /// - /// - public void InvokeOnMainThread (Selector sel, NSObject obj) + /// Object in which the selector is invoked + /// + /// + /// You use this method from a thread to invoke the code in + /// the specified object that is exposed with the specified + /// selector in the UI thread. This is required for most + /// operations that affect UIKit or AppKit as neither one of + /// those APIs is thread safe. + /// + /// + /// The code is executed when the main thread goes back to its + /// main loop for processing events. + /// + /// + /// Unlike + /// this method waits for the main thread to execute the method, and does not return until the code pointed by action has completed. + /// + /// + public void InvokeOnMainThread (Selector sel, NSObject? obj) { InvokeOnMainThread (sel, obj, true); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Invokes the specified action asynchronously on the main UI thread. + /// + /// The action to invoke. + /// + /// This method queues the action to be executed when the main thread goes back to its + /// main loop for processing events. The method returns immediately to the caller. + /// public void BeginInvokeOnMainThread (Action action) { var d = new NSAsyncActionDispatcher (action); @@ -815,7 +875,7 @@ public void BeginInvokeOnMainThread (Action action) GC.KeepAlive (d); } - internal void BeginInvokeOnMainThread (System.Threading.SendOrPostCallback cb, object state) + internal void BeginInvokeOnMainThread (System.Threading.SendOrPostCallback cb, object? state) { var d = new NSAsyncSynchronizationContextDispatcher (cb, state); Messaging.void_objc_msgSend_NativeHandle_NativeHandle_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone), @@ -823,9 +883,13 @@ internal void BeginInvokeOnMainThread (System.Threading.SendOrPostCallback cb, o GC.KeepAlive (d); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Invokes the specified action synchronously on the main UI thread. + /// + /// The action to invoke. + /// + /// This method waits for the main thread to execute the action, and does not return until the action has completed. + /// public void InvokeOnMainThread (Action action) { using (var d = new NSActionDispatcher (action)) { @@ -834,7 +898,7 @@ public void InvokeOnMainThread (Action action) } } - internal void InvokeOnMainThread (System.Threading.SendOrPostCallback cb, object state) + internal void InvokeOnMainThread (System.Threading.SendOrPostCallback cb, object? state) { using (var d = new NSSynchronizationContextDispatcher (cb, state)) { Messaging.void_objc_msgSend_NativeHandle_NativeHandle_bool (d.Handle, Selector.GetHandle (Selector.PerformSelectorOnMainThreadWithObjectWaitUntilDone), @@ -843,13 +907,13 @@ internal void InvokeOnMainThread (System.Threading.SendOrPostCallback cb, object } /// - public static NSObject FromObject (object obj) + public static NSObject? FromObject (object? obj) { if (obj is null) return NSNull.Null; var t = obj.GetType (); - if (t == typeof (NSObject) || t.IsSubclassOf (typeof (NSObject))) - return (NSObject) obj; + if (obj is NSObject nsobj) + return nsobj; switch (Type.GetTypeCode (t)) { case TypeCode.Boolean: @@ -881,14 +945,12 @@ public static NSObject FromObject (object obj) default: if (t == typeof (NativeHandle)) return NSValue.ValueFromPointer ((NativeHandle) obj); -#if !NO_SYSTEM_DRAWING if (t == typeof (SizeF)) return NSValue.FromSizeF ((SizeF) obj); else if (t == typeof (RectangleF)) return NSValue.FromRectangleF ((RectangleF) obj); else if (t == typeof (PointF)) return NSValue.FromPointF ((PointF) obj); -#endif if (t == typeof (nint)) return NSNumber.FromNInt ((nint) obj); else if (t == typeof (nuint)) @@ -912,9 +974,9 @@ public static NSObject FromObject (object obj) #endif // last chance for types like CGPath, CGColor... that are not NSObject but are CFObject // see https://bugzilla.xamarin.com/show_bug.cgi?id=8458 - INativeObject native = (obj as INativeObject); + var native = (obj as INativeObject); if (native is not null) { - NSObject result = Runtime.GetNSObject (native.Handle); + var result = Runtime.GetNSObject (native.Handle); GC.KeepAlive (native); return result; } @@ -922,10 +984,19 @@ public static NSObject FromObject (object obj) } } + /// + /// Sets the value for the property identified by a given key path to a given value. + /// + /// A handle to the value to set. + /// A key path of the form relationship.property (with one or more relationships); for example "department.name" or "department.manager.lastName". + /// + /// This method is useful for setting a value for a property that can be reached by following a key path. + /// The key path is a series of property names separated by periods. + /// public void SetValueForKeyPath (NativeHandle handle, NSString keyPath) { if (keyPath is null) - throw new ArgumentNullException ("keyPath"); + throw new ArgumentNullException (nameof (keyPath)); if (IsDirectBinding) { ObjCRuntime.Messaging.void_objc_msgSend_NativeHandle_NativeHandle (this.Handle, Selector.GetHandle ("setValue:forKeyPath:"), handle, keyPath.Handle); GC.KeepAlive (keyPath); @@ -939,8 +1010,8 @@ public void SetValueForKeyPath (NativeHandle handle, NSString keyPath) // a correct implementation of GetHashCode / Equals. We default to Object.GetHashCode (like classic) /// Generates a hash code for the current instance. - /// A int containing the hash code for this instance. - /// The algorithm used to generate the hash code is unspecified. + /// A int containing the hash code for this instance. + /// The algorithm used to generate the hash code is unspecified. public override int GetHashCode () { if (!IsDirectBinding) @@ -949,11 +1020,16 @@ public override int GetHashCode () return GetNativeHash ().GetHashCode (); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public override bool Equals (object obj) + /// + /// Determines whether the specified object is equal to the current . + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + /// + /// For direct bindings, this method uses the Objective-C isEqual: method. + /// For non-direct bindings, this method uses reference equality. + /// + public override bool Equals (object? obj) { var o = obj as NSObject; if (o is null) @@ -969,38 +1045,41 @@ public override bool Equals (object obj) } // IEquatable - /// To be added. - /// To be added. - /// To be added. - /// To be added. - public bool Equals (NSObject obj) => Equals ((object) obj); + /// + /// Determines whether the specified is equal to the current . + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + /// + /// For direct bindings, this method uses the Objective-C isEqual: method. + /// For non-direct bindings, this method uses reference equality. + /// + public bool Equals (NSObject? obj) => Equals ((object?) obj); /// Returns a string representation of the value of the current instance. - /// - /// - /// - /// - public override string ToString () + public override string? ToString () { if (disposed) return base.ToString (); return Description ?? base.ToString (); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Invokes the specified action after the specified delay. + /// + /// The action to invoke. + /// The delay in seconds. public virtual void Invoke (Action action, double delay) { var d = new NSAsyncActionDispatcher (action); d.PerformSelector (NSDispatcher.Selector, null, delay); } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Invokes the specified action after the specified delay. + /// + /// The action to invoke. + /// The delay as a . public virtual void Invoke (Action action, TimeSpan delay) { var d = new NSAsyncActionDispatcher (action); @@ -1029,7 +1108,6 @@ protected virtual void Dispose (bool disposing) } } -#nullable enable void RecreateDataHandle () { // OK, this code is _weird_. @@ -1080,7 +1158,6 @@ void RecreateDataHandle () // Don't dispose previous_data, because another thread might be referencing it, and trying to access its pointer - which is still valid. // The GC will dispose of previous_data when its not accessible anymore. } -#nullable disable [Register ("__NSObject_Disposer")] [Preserve (AllMembers = true)] @@ -1155,8 +1232,8 @@ static void Drain (NSObject ctx) [Register ("__XamarinObjectObserver")] class Observer : NSObject { - WeakReference obj; - Action cback; + WeakReference? obj; + Action? cback; NSString key; public Observer (NSObject obj, NSString key, Action observer) @@ -1174,7 +1251,7 @@ public Observer (NSObject obj, NSString key, Action observer) public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context) { if (keyPath == key && context == Handle) - cback (new NSObservedChange (change)); + cback!.Invoke (new NSObservedChange (change)); else base.ObserveValue (keyPath, ofObject, change, context); } @@ -1182,9 +1259,8 @@ public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictio protected override void Dispose (bool disposing) { if (disposing) { - NSObject target; if (obj is not null) { - target = (NSObject) obj.Target; + var target = (NSObject?) obj.Target; if (target is not null) target.RemoveObserver (this, key, Handle); } @@ -1211,10 +1287,14 @@ public IDisposable AddObserver (NSString key, NSKeyValueObservingOptions options return o; } - /// To be added. - /// To be added. - /// To be added. - /// To be added. + /// + /// Allocates an uninitialized instance of the specified class. + /// + /// The class to allocate. + /// A new uninitialized instance. + /// + /// This method should typically be followed by a call to an init method to properly initialize the object. + /// [EditorBrowsable (EditorBrowsableState.Never)] public static NSObject Alloc (Class kls) { @@ -1223,8 +1303,12 @@ public static NSObject Alloc (Class kls) return new NSObject (h, true); } - /// To be added. - /// To be added. + /// + /// Initializes the object by calling the Objective-C init method. + /// + /// + /// This method should only be called on objects that have been allocated but not yet initialized. + /// [EditorBrowsable (EditorBrowsableState.Never)] public void Init () { @@ -1234,16 +1318,17 @@ public void Init () handle = Messaging.IntPtr_objc_msgSend (handle, Selector.GetHandle ("init")); } - /// To be added. - /// To be added. - /// To be added. + /// + /// Invokes the specified action on a background thread. + /// + /// The action to invoke. public static void InvokeInBackground (Action action) { // using the parameterized Thread.Start to avoid capturing // the 'action' parameter (it'll needlessly create an extra // object). new System.Threading.Thread ((v) => { - ((Action) v) (); + ((Action) v!) (); }) { IsBackground = true, }.Start (action); @@ -1252,34 +1337,56 @@ public static void InvokeInBackground (Action action) } #if !COREBUILD - /// - [SupportedOSPlatform ("ios")] - [SupportedOSPlatform ("maccatalyst")] - [SupportedOSPlatform ("macos")] - [SupportedOSPlatform ("tvos")] + /// + /// Changes that occurred to an object being observed by Key-Value-Observing. + /// + /// + /// This class exposes the various components that were changed in a Key-Value-Observed property. + /// These are merely accessors to the underlying that is provided to the method. + /// Instances of this class are provided to your callback methods that you provide to . + /// You can also create these objects if you have a dictionary that contains the keys from a key-value-observing change. For example if you override the method. + /// + /// + /// + /// public class NSObservedChange { NSDictionary dict; - /// To be added. - /// To be added. - /// To be added. + /// + /// Initializes a new instance of the class. + /// + /// The dictionary containing the change information. public NSObservedChange (NSDictionary source) { dict = source; } /// Records the kind of change that was done to the property. - /// The current state of the changes being reported. - /// You can use the value of this property to determine which information is available on the other properties of this class. + /// The current state of the changes being reported. + /// You can use the value of this property to determine which information is available on the other properties of this class. public NSKeyValueChange Change { get { - var n = (NSNumber) dict [NSObject.ChangeKindKey]; - return (NSKeyValueChange) n.Int32Value; + var n = (NSNumber?) dict [NSObject.ChangeKindKey]; + return (NSKeyValueChange) (n?.Int32Value ?? 0); } } /// The new value being set on the observed property. /// For this property to have a value, the options passed to method should contain the value New. - public NSObject NewValue { + public NSObject? NewValue { get { return dict [NSObject.ChangeNewKey]; } @@ -1288,18 +1395,18 @@ public NSObject NewValue { /// The previous value on the observed property. /// The old value. /// For this property to have a value, the options passed to method should contain the value . - public NSObject OldValue { + public NSObject? OldValue { get { return dict [NSObject.ChangeOldKey]; } } /// The indexes of the objects that were added, removed or changed. - /// To be added. - /// This value is set if the Change property is one of  - public NSIndexSet Indexes { + /// An containing the indexes, or if not applicable. + /// This value is set if the Change property is either , or . + public NSIndexSet? Indexes { get { - return (NSIndexSet) dict [NSObject.ChangeIndexesKey]; + return (NSIndexSet?) dict [NSObject.ChangeIndexesKey]; } } diff --git a/src/Foundation/NSOrderedSet.cs b/src/Foundation/NSOrderedSet.cs index bbd75dcf6459..96b016141687 100644 --- a/src/Foundation/NSOrderedSet.cs +++ b/src/Foundation/NSOrderedSet.cs @@ -219,9 +219,12 @@ public override int GetHashCode () /// Determines whether the ordered set contains the specified object. /// The object to locate in the ordered set. /// if the ordered set contains the specified object; otherwise, . - public bool Contains (object obj) + public bool Contains (object? obj) { - return Contains (NSObject.FromObject (obj)); + var nsobj = NSObject.FromObject (obj); + if (nsobj is null) + return false; + return Contains (nsobj); } } diff --git a/src/Foundation/NSSet.cs b/src/Foundation/NSSet.cs index bcdc81ea2c79..c24e2918bd16 100644 --- a/src/Foundation/NSSet.cs +++ b/src/Foundation/NSSet.cs @@ -168,9 +168,12 @@ IEnumerator IEnumerable.GetEnumerator () /// Determines whether the set contains the specified object. /// The object to locate in the set. /// if the set contains the specified object; otherwise, . - public bool Contains (object obj) + public bool Contains (object? obj) { - return Contains (NSObject.FromObject (obj)); + var nsobj = NSObject.FromObject (obj); + if (nsobj is null) + return false; + return Contains (nsobj); } } } diff --git a/src/Foundation/NSString.cs b/src/Foundation/NSString.cs index b918dd5cd818..c16bbc61d28b 100644 --- a/src/Foundation/NSString.cs +++ b/src/Foundation/NSString.cs @@ -264,7 +264,7 @@ public static NSString LocalizedFormat (NSString format, params object [] args) int argc = args.Length; var nso = new NSObject [argc]; for (int i = 0; i < argc; i++) - nso [i] = NSObject.FromObject (args [i]); + nso [i] = NSObject.FromObject (args [i])!; return LocalizedFormat (format, nso); } diff --git a/src/Foundation/NSUrl.cs b/src/Foundation/NSUrl.cs index 8a8094036084..b3196dc70bfb 100644 --- a/src/Foundation/NSUrl.cs +++ b/src/Foundation/NSUrl.cs @@ -100,7 +100,7 @@ public NSUrl MakeRelative (string url) /// /// /// - public override string ToString () + public override string? ToString () { return AbsoluteString ?? base.ToString (); } diff --git a/src/Foundation/NSUrlRequest.cs b/src/Foundation/NSUrlRequest.cs index d70b3a924422..b03b55bf8488 100644 --- a/src/Foundation/NSUrlRequest.cs +++ b/src/Foundation/NSUrlRequest.cs @@ -33,7 +33,7 @@ namespace Foundation { public partial class NSUrlRequest { /// Returns a string representation of the value of the current instance. /// The absolute string of the if it is not , otherwise the base class string representation. - public override string ToString () + public override string? ToString () { return Url?.AbsoluteString ?? base.ToString (); } diff --git a/src/Foundation/NSUrlSessionHandler.cs b/src/Foundation/NSUrlSessionHandler.cs index c12d535b6ce5..49a4aee1b1a3 100644 --- a/src/Foundation/NSUrlSessionHandler.cs +++ b/src/Foundation/NSUrlSessionHandler.cs @@ -93,10 +93,9 @@ public static string GetHeaderValue (this NSHttpCookie cookie) AppendSegment (header, NSHttpCookie.KeyExpires.ToString (), dateStr); } - if (cookie.Properties.ContainsKey (NSHttpCookie.KeyMaximumAge)) { - var timeStampString = (NSString) cookie.Properties [NSHttpCookie.KeyMaximumAge]; + var timeStampStringValue = cookie.Properties [NSHttpCookie.KeyMaximumAge]; + if (timeStampStringValue is NSString timeStampString) AppendSegment (header, NSHttpCookie.KeyMaximumAge.ToString (), timeStampString); - } if (cookie.IsSecure) AppendSegment (header, NSHttpCookie.KeySecure.ToString (), null); diff --git a/src/GLKit/GLKMesh.cs b/src/GLKit/GLKMesh.cs index a31fcfa2ae57..3b38e3d81682 100644 --- a/src/GLKit/GLKMesh.cs +++ b/src/GLKit/GLKMesh.cs @@ -13,11 +13,9 @@ public partial class GLKMesh { /// To be added. /// To be added. /// To be added. - public static GLKMesh []? FromAsset (MDLAsset asset, out MDLMesh [] sourceMeshes, out NSError error) + public static GLKMesh []? FromAsset (MDLAsset asset, out MDLMesh []? sourceMeshes, out NSError? error) { - NSArray aret; - - var ret = FromAsset (asset, out aret, out error); + var ret = FromAsset (asset, out NSArray? aret, out error); sourceMeshes = NSArray.FromArray (aret); return ret; } diff --git a/src/Makefile b/src/Makefile index cdc8cb9f9c8d..9ac7b1c03218 100644 --- a/src/Makefile +++ b/src/Makefile @@ -338,16 +338,16 @@ $($(2)_DOTNET_BUILD_DIR)/embed-files.rsp: $($(2)_DOTNET_BUILD_DIR)/$(3)-generate $$(Q) mv $$@.tmp $$@ $($(2)_DOTNET_BUILD_DIR)/ILLink.Substitutions.xml: $(TOP)/src/ILLink.Substitutions.$(1).xml | $($(2)_DOTNET_BUILD_DIR) - $(Q) $(CP) $$< $$@ + $$(Q) $(CP) $$< $$@ $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM)/Microsoft.$(1).dll: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll | $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM) - $(Q) $(CP) $$< $$@ + $$(Q) $(CP) $$< $$@ $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM)/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml | $(DOTNET_DESTDIR)/$($(2)_NUGET_REF_NAME)/ref/$(DOTNET_TFM) - $(Q) $(CP) $$< $$@ + $$(Q) $(CP) $$< $$@ $($(2)_DOTNET_BUILD_DIR)/doc/Microsoft.$(1).xml: $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll build/.build-adr-stamp | $($(2)_DOTNET_BUILD_DIR)/doc - $(TOP)/packages/appledocreader.$(ADR_RUNTIME_IDENTIFIER)/$(ADR_NUGET_VERSION)/tools/any/$(ADR_RUNTIME_IDENTIFIER)/AppleDocReader inject docs --assembly="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll)" --input="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml)" --output="$(abspath $$@)" --xcode="$(DEVELOPER_DIR)/../.." --runtimeDll="$(DOTNET_BCL_DIR)/System.Runtime.dll" -f + $$(Q_GEN) $(TOP)/packages/appledocreader.$(ADR_RUNTIME_IDENTIFIER)/$(ADR_NUGET_VERSION)/tools/any/$(ADR_RUNTIME_IDENTIFIER)/AppleDocReader inject docs --assembly="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).dll)" --input="$(abspath $($(2)_DOTNET_BUILD_DIR)/ref/Microsoft.$(1).xml)" --output="$(abspath $$@)" --xcode="$(DEVELOPER_DIR)/../.." --runtimeDll="$(DOTNET_BCL_DIR)/System.Runtime.dll" -f endef build/.build-adr-stamp: diff --git a/src/NaturalLanguage/NLLanguage.cs b/src/NaturalLanguage/NLLanguage.cs index 05eb9847c4ba..9052f9253878 100644 --- a/src/NaturalLanguage/NLLanguage.cs +++ b/src/NaturalLanguage/NLLanguage.cs @@ -10,8 +10,9 @@ public partial class NLLanguageExtensions { static internal Dictionary Convert (NSDictionary dict) { var result = new Dictionary ((int) dict.Count); - foreach (var k in dict.Keys) { - result [NLLanguageExtensions.GetValue (k)] = dict [k].DoubleValue; + var e = (IEnumerable>) dict; + foreach (var kvp in e) { + result [NLLanguageExtensions.GetValue (kvp.Key)] = kvp.Value.DoubleValue; } return result; } diff --git a/src/ObjCRuntime/Dlfcn.cs b/src/ObjCRuntime/Dlfcn.cs index baf3d14c00b7..48cc2ba31a39 100644 --- a/src/ObjCRuntime/Dlfcn.cs +++ b/src/ObjCRuntime/Dlfcn.cs @@ -32,14 +32,12 @@ #nullable enable using System.ComponentModel; +using System.Drawing; #if !COREBUILD using CoreFoundation; using CoreGraphics; using CoreMedia; #endif -#if !NO_SYSTEM_DRAWING -using System.Drawing; -#endif namespace ObjCRuntime { diff --git a/src/SceneKit/SCNParticleSystem.cs b/src/SceneKit/SCNParticleSystem.cs index 89beb77b049d..c98a04c8df20 100644 --- a/src/SceneKit/SCNParticleSystem.cs +++ b/src/SceneKit/SCNParticleSystem.cs @@ -40,11 +40,18 @@ public SCNPropertyControllers () internal void Set (NSString key, SCNParticlePropertyController? value) { + if (value is null && mutDict is null) + return; + if (mutDict is null) { mutDict = new NSMutableDictionary (dict); dict = mutDict; } - mutDict [key] = value; + if (value is null) { + mutDict.Remove (key); + } else { + mutDict [key] = value; + } } /// To be added. diff --git a/src/Security/Items.cs b/src/Security/Items.cs index 529a3684102b..341b65de1fb4 100644 --- a/src/Security/Items.cs +++ b/src/Security/Items.cs @@ -325,8 +325,11 @@ internal SecKeyChain (NativeHandle handle) copy.LowlevelSetObject (CFBoolean.TrueHandle, SecItem.ReturnAttributes); copy.LowlevelSetObject (CFBoolean.TrueHandle, SecItem.ReturnData); result = SecItem.SecItemCopyMatching (copy.Handle, out var ptr); - if (result == SecStatusCode.Success) - return new SecRecord (new NSMutableDictionary (ptr, true)); + if (result == SecStatusCode.Success) { + var dict = Runtime.GetNSObject (ptr, true); + if (dict is not null) + return new SecRecord (dict); + } return null; } } diff --git a/src/SpriteKit/SKKeyframeSequence.cs b/src/SpriteKit/SKKeyframeSequence.cs index 443dcdf44d30..f1962300d3cf 100644 --- a/src/SpriteKit/SKKeyframeSequence.cs +++ b/src/SpriteKit/SKKeyframeSequence.cs @@ -8,9 +8,7 @@ // using System.Collections.Generic; -#if !NO_SYSTEM_DRAWING using System.Drawing; -#endif #nullable enable diff --git a/src/VideoToolbox/VTVideoEncoder.cs b/src/VideoToolbox/VTVideoEncoder.cs index d9aac088c8bf..9f59b55d3201 100644 --- a/src/VideoToolbox/VTVideoEncoder.cs +++ b/src/VideoToolbox/VTVideoEncoder.cs @@ -136,7 +136,7 @@ internal VTVideoEncoder (NSDictionary dict) constant = VTVideoEncoderList.SupportedSelectionProperties; if (constant is not null) { - if (dict.TryGetValue (constant, out NSDictionary d)) // optional + if (dict.TryGetValue (constant, out var d)) // optional SupportedSelectionProperties = d; } diff --git a/src/WebKit/WebNavigationPolicyEventArgs.cs b/src/WebKit/WebNavigationPolicyEventArgs.cs index 24d4f6bb114c..6fdedb28efd7 100644 --- a/src/WebKit/WebNavigationPolicyEventArgs.cs +++ b/src/WebKit/WebNavigationPolicyEventArgs.cs @@ -36,7 +36,7 @@ partial class WebNavigationPolicyEventArgs { /// To be added. /// To be added. public WebNavigationType NavigationType { - get { return (WebNavigationType) ((NSNumber) ActionInformation [WebPolicyDelegate.WebActionNavigationTypeKey]).Int32Value; } + get { return (WebNavigationType) (((NSNumber?) ActionInformation [WebPolicyDelegate.WebActionNavigationTypeKey])?.Int32Value ?? 0); } } /// To be added. @@ -64,7 +64,7 @@ public WebActionMouseButton MouseButton { /// To be added. /// To be added. public uint Flags { - get { return ((NSNumber) ActionInformation [WebPolicyDelegate.WebActionModifierFlagsKey]).UInt32Value; } + get { return ((NSNumber?) ActionInformation [WebPolicyDelegate.WebActionModifierFlagsKey])?.UInt32Value ?? 0; } } /// To be added. diff --git a/src/authenticationservices.cs b/src/authenticationservices.cs index 066af5c84f55..7f9ebc2fedbf 100644 --- a/src/authenticationservices.cs +++ b/src/authenticationservices.cs @@ -1578,14 +1578,7 @@ interface ASAuthorizationPublicKeyCredentialAssertion : ASPublicKeyCredential { NSData Signature { get; } } -#if !XAMCORE_5_0 // Removed in Xcode 14.3 Beta 3 - [Obsoleted (PlatformName.iOS, 16, 4, message: Constants.ApiRemovedGeneral)] - [Obsoleted (PlatformName.MacCatalyst, 16, 4, message: Constants.ApiRemovedGeneral)] - [Obsoleted (PlatformName.TvOS, 16, 4, message: Constants.ApiRemovedGeneral)] [iOS (15, 0), MacCatalyst (15, 0), TV (16, 0)] -#else - [NoTV, NoiOS, NoMacCatalyst] -#endif [BaseType (typeof (ASAuthorizationRequest))] [DisableDefaultCtor] interface ASAuthorizationPlatformPublicKeyCredentialAssertionRequest : ASAuthorizationPublicKeyCredentialAssertionRequest { diff --git a/src/carplay.cs b/src/carplay.cs index e0a18f04a5d4..92b2640f946a 100644 --- a/src/carplay.cs +++ b/src/carplay.cs @@ -419,8 +419,6 @@ interface CPBarButtonProviding { interface CPGridButton : NSSecureCoding { [Export ("initWithTitleVariants:image:handler:")] - [Deprecated (PlatformName.iOS, 26, 0, message: "Use 'Constructor (string[], UIImage, CPMessageGridItemConfiguration, Action)' instead.")] - [Deprecated (PlatformName.MacCatalyst, 26, 0, message: "Use 'Constructor (string[], UIImage, CPMessageGridItemConfiguration, Action)' instead.")] NativeHandle Constructor (string [] titleVariants, UIImage image, [NullAllowed] Action handler); [iOS (26, 0), MacCatalyst (26, 0)] diff --git a/src/foundation.cs b/src/foundation.cs index c7d7ebcac07a..015d2662c208 100644 --- a/src/foundation.cs +++ b/src/foundation.cs @@ -6914,9 +6914,11 @@ interface NSLocale : NSSecureCoding, NSCopying { [Notification] NSString CurrentLocaleDidChangeNotification { get; } + [return: NullAllowed] [Export ("objectForKey:"), Internal] NSObject ObjectForKey (NSString key); + [return: NullAllowed] [Export ("displayNameForKey:value:"), Internal] NSString DisplayNameForKey (NSString key, string value); diff --git a/src/glkit.cs b/src/glkit.cs index 368d1a624dd4..6d9f1b57d428 100644 --- a/src/glkit.cs +++ b/src/glkit.cs @@ -433,7 +433,8 @@ interface GLKMesh { [Static] [Export ("newMeshesFromAsset:sourceMeshes:error:")] [return: NullAllowed] - GLKMesh [] FromAsset (MDLAsset asset, out NSArray sourceMeshes, out NSError error); + [return: Release] + GLKMesh [] FromAsset (MDLAsset asset, [NullAllowed] out NSArray sourceMeshes, [NullAllowed] out NSError error); /// To be added. /// To be added. diff --git a/src/scenekit.cs b/src/scenekit.cs index b37e091d8786..c6cb97b07c84 100644 --- a/src/scenekit.cs +++ b/src/scenekit.cs @@ -1989,12 +1989,14 @@ interface SCNMaterialProperty : SCNAnimatable, NSSecureCoding { /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] NSColor ContentColor { get; set; } /// Gets or sets the material property's image. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] NSImage ContentImage { get; set; } /// Gets or sets the material property's animation layer. @@ -2002,36 +2004,42 @@ interface SCNMaterialProperty : SCNAnimatable, NSSecureCoding { /// To be added. [MacCatalyst (13, 1)] [Wrap ("Contents")] + [NullAllowed] CALayer ContentLayer { get; set; } /// Gets or sets the path to the image that is used for the material property's contents. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] NSString ContentPath { get; set; } /// Gets or sets the URL that specifies the material property's image content. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] NSUrl ContentUrl { get; set; } /// Gets or sets the material property's scene. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] SKScene ContentScene { get; set; } /// Gets or sets the material property's texture. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] SKTexture ContentTexture { get; set; } /// Gets or sets the material property's image cube. /// To be added. /// To be added. [Wrap ("Contents")] + [NullAllowed] NSImage [] ContentImageCube { get; set; } [MacCatalyst (13, 1)] diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt index c04a990b5abd..c0bedcdbd785 100644 --- a/tests/cecil-tests/Documentation.KnownFailures.txt +++ b/tests/cecil-tests/Documentation.KnownFailures.txt @@ -11806,7 +11806,6 @@ M:Foundation.INSUrlSessionWebSocketDelegate.DidOpen(Foundation.NSUrlSession,Foun M:Foundation.INSXpcListenerDelegate.ShouldAcceptConnection(Foundation.NSXpcListener,Foundation.NSXpcConnection) M:Foundation.NSArray.ArrayFromHandle``1(ObjCRuntime.NativeHandle,System.Converter{ObjCRuntime.NativeHandle,``0},System.Boolean) M:Foundation.NSArray.EnumsFromHandle``1(ObjCRuntime.NativeHandle) -M:Foundation.NSArray.FromIntPtrs(ObjCRuntime.NativeHandle[]) M:Foundation.NSArray.FromNSObjects``1(``0[][]) M:Foundation.NSArray.FromNSObjects``1(``0[0:,0:]) M:Foundation.NSArray.FromStrings(System.Collections.Generic.IReadOnlyList{System.String}) @@ -11837,7 +11836,6 @@ M:Foundation.NSDataDetector.#ctor(Foundation.NSTextCheckingType,Foundation.NSErr M:Foundation.NSDataDetector.Create(Foundation.NSTextCheckingType,Foundation.NSError@) M:Foundation.NSDate.op_Explicit(Foundation.NSDate)~System.DateTime M:Foundation.NSDate.op_Explicit(System.DateTime)~Foundation.NSDate -M:Foundation.NSDictionary`2.FromObjectsAndKeys(`1[],`0[]) M:Foundation.NSEnumerator`1.NextObject M:Foundation.NSExceptionError.#ctor(System.Exception) M:Foundation.NSFileAttributes.#ctor @@ -11876,12 +11874,6 @@ M:Foundation.NSKeyValueSharedObserverRegistration_NSObject.SetSharedObservers(Fo M:Foundation.NSKeyValueSharedObservers.#ctor(System.Type) M:Foundation.NSMachPort.Dispose(System.Boolean) M:Foundation.NSMetadataQuery.Dispose(System.Boolean) -M:Foundation.NSMutableDictionary.LowlevelSetObject(System.String,System.IntPtr) -M:Foundation.NSMutableDictionary`2.FromObjectsAndKeys(`1[],`0[]) -M:Foundation.NSMutableSet.op_Addition(Foundation.NSMutableSet,Foundation.NSMutableSet) -M:Foundation.NSMutableSet.op_Subtraction(Foundation.NSMutableSet,Foundation.NSMutableSet) -M:Foundation.NSMutableSet`1.op_Addition(Foundation.NSMutableSet{`0},Foundation.NSMutableSet{`0}) -M:Foundation.NSMutableSet`1.op_Subtraction(Foundation.NSMutableSet{`0},Foundation.NSMutableSet{`0}) M:Foundation.NSNetService.add_AddressResolved(System.EventHandler) M:Foundation.NSNetService.add_DidAcceptConnection(System.EventHandler{Foundation.NSNetServiceConnectionEventArgs}) M:Foundation.NSNetService.add_Published(System.EventHandler) @@ -11952,7 +11944,6 @@ M:Foundation.NSObject.RemoveObserver(Foundation.NSObject,System.String) M:Foundation.NSObject.SetDefaultPlaceholder(Foundation.NSObject,Foundation.NSObject,Foundation.NSString) M:Foundation.NSObject.SetNilValueForKey(Foundation.NSString) M:Foundation.NSObject.SetValueForKeyPath(Foundation.NSObject,Foundation.NSString) -M:Foundation.NSObject.SetValueForKeyPath(ObjCRuntime.NativeHandle,Foundation.NSString) M:Foundation.NSObject.SetValueForUndefinedKey(Foundation.NSObject,Foundation.NSString) M:Foundation.NSObject.SetValuesForKeysWithDictionary(Foundation.NSDictionary) M:Foundation.NSObject.Unbind(Foundation.NSString) @@ -21066,7 +21057,6 @@ P:Foundation.NSAttributedStringDocumentAttributes.Title P:Foundation.NSAttributedStringDocumentAttributes.TopMargin P:Foundation.NSBundle.AllBundles P:Foundation.NSDateComponents.IsRepeatedDay -P:Foundation.NSDictionary`2.Item(`0) P:Foundation.NSExceptionError.Exception P:Foundation.NSFileHandleConnectionAcceptedEventArgs.NearSocketConnection P:Foundation.NSFileHandleConnectionAcceptedEventArgs.UnixErrorCode @@ -21080,10 +21070,6 @@ P:Foundation.NSMetadataItem.UbiquitousItemDownloadingStatus P:Foundation.NSMorphology.Unspecified P:Foundation.NSMutableArray`1.Item(System.UIntPtr) P:Foundation.NSMutableData.Item(System.IntPtr) -P:Foundation.NSMutableDictionary.Item(Foundation.NSObject) -P:Foundation.NSMutableDictionary.Item(Foundation.NSString) -P:Foundation.NSMutableDictionary.Item(System.String) -P:Foundation.NSMutableDictionary`2.Item(`0) P:Foundation.NSNetDomainEventArgs.Domain P:Foundation.NSNetDomainEventArgs.MoreComing P:Foundation.NSNetServiceConnectionEventArgs.InputStream diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs index 54acc20ef2aa..914cd28c1440 100644 --- a/tests/common/DotNet.cs +++ b/tests/common/DotNet.cs @@ -101,8 +101,8 @@ public static ExecutionResult AssertNew (string outputDirectory, string template var env = new Dictionary (); env ["MSBuildSDKsPath"] = null; env ["MSBUILD_EXE_PATH"] = null; - var output = new StringBuilder (); - var rv = Execution.RunWithStringBuildersAsync (Executable, args, env, output, output, Console.Out, workingDirectory: outputDirectory, timeout: TimeSpan.FromMinutes (10)).Result; + var rv = Execution.RunAsync (Executable, args, env, Console.Out, workingDirectory: outputDirectory, timeout: TimeSpan.FromMinutes (10)).Result; + var output = rv.Output.MergedOutput; if (rv.ExitCode != 0) { Console.WriteLine ($"'{Executable} {StringUtils.FormatArguments (args)}' failed with exit code {rv.ExitCode}."); Console.WriteLine (output); @@ -125,13 +125,13 @@ public static ExecutionResult InstallWorkload (params string [] workloads) env ["MSBuildSDKsPath"] = null; env ["MSBUILD_EXE_PATH"] = null; - var output = new StringBuilder (); - var rv = Execution.RunWithStringBuildersAsync (Executable, args, env, output, output, Console.Out, workingDirectory: Configuration.SourceRoot, timeout: TimeSpan.FromMinutes (10)).Result; + var rv = Execution.RunAsync (Executable, args, env, Console.Out, workingDirectory: Configuration.SourceRoot, timeout: TimeSpan.FromMinutes (10)).Result; + var output = rv.Output.MergedOutput; if (rv.ExitCode != 0) { var msg = new StringBuilder (); msg.AppendLine ($"'dotnet workload install' failed with exit code {rv.ExitCode}"); msg.AppendLine ($"Full command: {Executable} {StringUtils.FormatArguments (args)}"); - msg.AppendLine (output.ToString ()); + msg.AppendLine (output); Console.WriteLine (msg); Assert.Fail (msg.ToString ()); } @@ -174,14 +174,14 @@ public static string GetProperty (string projectPath, string propertyName, Dicti env ["MSBuildSDKsPath"] = null; env ["MSBUILD_EXE_PATH"] = null; - var output = new StringBuilder (); - var rv = Execution.RunWithStringBuildersAsync (Executable, args, env, output, output, null, workingDirectory: Path.GetDirectoryName (projectPath), timeout: TimeSpan.FromMinutes (2)).Result; + var rv = Execution.RunAsync (Executable, args, env, null, workingDirectory: Path.GetDirectoryName (projectPath), timeout: TimeSpan.FromMinutes (2)).Result; + var output = rv.Output.MergedOutput; if (rv.ExitCode != 0) throw new Exception ($"Failed to get property '{propertyName}' from project '{projectPath}'. Exit code: {rv.ExitCode}. Output: {output}"); // Extract the property value from the output - return output.ToString ().Trim (); + return output.Trim (); } public static ExecutionResult ExecuteCommand (string exe, params string [] args) @@ -195,8 +195,8 @@ public static ExecutionResult ExecuteCommand (string exe, Dictionary (); env ["MSBuildSDKsPath"] = null; env ["MSBUILD_EXE_PATH"] = null; - var output = new StringBuilder (); timeout ??= TimeSpan.FromMinutes (10); - var rv = Execution.RunWithStringBuildersAsync (Executable, args, env, output, output, Console.Out, workingDirectory: Path.GetDirectoryName (project), timeout: timeout).Result; + var rv = Execution.RunAsync (Executable, args, env, Console.Out, workingDirectory: Path.GetDirectoryName (project), timeout: timeout).Result; + var output = rv.Output.MergedOutput; if (assert_success && rv.ExitCode != 0) { - var outputStr = output.ToString (); Console.WriteLine ($"'{Executable} {StringUtils.FormatArguments (args)}' failed with exit code {rv.ExitCode}."); - Console.WriteLine (outputStr); + Console.WriteLine (output); if (rv.ExitCode != 0) { var msg = new StringBuilder (); if (rv.TimedOut) { @@ -494,13 +493,13 @@ public static void CompareApps (string old_app, string new_app) } public class ExecutionResult { - public StringBuilder StandardOutput; - public StringBuilder StandardError; + public string StandardOutput; + public string StandardError; public int ExitCode; public bool TimedOut; public string BinLogPath; - public ExecutionResult (StringBuilder stdout, StringBuilder stderr, int exitCode) + public ExecutionResult (string stdout, string stderr, int exitCode) { StandardOutput = stdout; StandardError = stderr; diff --git a/tests/common/ExecutionHelper.cs b/tests/common/ExecutionHelper.cs index efee93aaa5a0..16165517404a 100644 --- a/tests/common/ExecutionHelper.cs +++ b/tests/common/ExecutionHelper.cs @@ -74,7 +74,11 @@ public static int Execute (string fileName, IList arguments, out StringB public static int Execute (string fileName, IList arguments, out bool timed_out, string workingDirectory = null, Dictionary environment_variables = null, StringBuilder stdout = null, StringBuilder stderr = null, TimeSpan? timeout = null) { - var rv = Execution.RunWithStringBuildersAsync (fileName, arguments, workingDirectory: workingDirectory, environment: environment_variables, standardOutput: stdout, standardError: stderr, timeout: timeout).Result; + var rv = Execution.RunAsync (fileName, arguments, workingDirectory: workingDirectory, environment: environment_variables, timeout: timeout).Result; + if (stdout is not null) + stdout.Append (rv.Output.StandardOutput); + if (stderr is not null) + stderr.Append (rv.Output.StandardError); timed_out = rv.TimedOut; if (rv.TimedOut) Console.WriteLine ($"Command '{fileName} {StringUtils.FormatArguments (arguments)}' didn't finish in {timeout.Value.TotalMilliseconds} ms, and was killed.", timeout.Value.TotalMinutes); @@ -110,8 +114,8 @@ public static int Execute (string fileName, IList arguments, Dictionary< public static string Execute (string fileName, IList arguments, bool throwOnError = true, Dictionary environmentVariables = null, bool hide_output = false, TimeSpan? timeout = null) { - var rv = Execution.RunAsync (fileName, arguments, mergeOutput: true, environment: environmentVariables, timeout: timeout).Result; - var output = rv.StandardOutput.ToString (); + var rv = Execution.RunAsync (fileName, arguments, environment: environmentVariables, timeout: timeout).Result; + var output = rv.Output.MergedOutput; var throw_exc = throwOnError && rv.ExitCode != 0; if (!hide_output || throw_exc) { Console.WriteLine ($"{fileName} {StringUtils.FormatArguments (arguments)} (exit code: {rv.ExitCode})"); diff --git a/tests/dotnet/UnitTests/AssetsTest.cs b/tests/dotnet/UnitTests/AssetsTest.cs index b4d8af43051a..0f2655513ca4 100644 --- a/tests/dotnet/UnitTests/AssetsTest.cs +++ b/tests/dotnet/UnitTests/AssetsTest.cs @@ -125,11 +125,10 @@ void CopyAssets (string projectPath) void MakeSymlinks (string sourceDir, string destDir) { - var output = new StringBuilder (); var executable = "ln"; var arguments = new string [] { "-s", sourceDir, destDir }; - var rv = Execution.RunWithStringBuildersAsync (executable, arguments, standardOutput: output, standardError: output, timeout: TimeSpan.FromSeconds (60)).Result; - Assert.AreEqual (0, rv.ExitCode, $"Creating Symlink Error: {rv.StandardError}. Unexpected ExitCode"); + var rv = Execution.RunAsync (executable, arguments, timeout: TimeSpan.FromSeconds (60)).Result; + Assert.AreEqual (0, rv.ExitCode, $"Creating Symlink Error: {rv.Output.MergedOutput}. Unexpected ExitCode"); } public static string GetFullSdkVersion (ApplePlatform platform, string runtimeIdentifiers) @@ -159,7 +158,6 @@ public static string GetFullSdkVersion (ApplePlatform platform, string runtimeId // so we will touch the first (non-DS_Store) file the symlink points to in order to give them newer modified times void ProcessUpdateSymlink (string xcassetsDir) { - var output = new StringBuilder (); var assets = Directory.EnumerateFiles (xcassetsDir, "*.*", SearchOption.AllDirectories).ToArray (); // assets first value is a .DS_Store file that work trigger MSBuild recompile so we want the second value @@ -167,20 +165,18 @@ void ProcessUpdateSymlink (string xcassetsDir) var executable = "touch"; var arguments = new string [] { assets [1] }; - var rv = Execution.RunWithStringBuildersAsync (executable, arguments, standardOutput: output, standardError: output, timeout: TimeSpan.FromSeconds (120)).Result; - Assert.AreEqual (0, rv.ExitCode, $"Processing Update Symlink Error: {rv.StandardError}. Unexpected ExitCode"); + var rv = Execution.RunAsync (executable, arguments, timeout: TimeSpan.FromSeconds (120)).Result; + Assert.AreEqual (0, rv.ExitCode, $"Processing Update Symlink Error: {rv.Output.MergedOutput}. Unexpected ExitCode"); } public static JsonDocument ProcessAssets (string assetsPath, string sdkVersion) { - var output = new StringBuilder (); - var stderr = new StringBuilder (); var executable = "xcrun"; var tmpdir = Cache.CreateTemporaryDirectory (); var tmpfile = Path.Combine (tmpdir, "Assets.json"); var arguments = new string [] { "--sdk", sdkVersion, "assetutil", "--info", assetsPath, "-o", tmpfile }; - var rv = Execution.RunWithStringBuildersAsync (executable, arguments, standardOutput: output, standardError: stderr, timeout: TimeSpan.FromSeconds (120)).Result; - Assert.AreEqual (0, rv.ExitCode, $"Processing Assets Error: {stderr}. Unexpected ExitCode"); + var rv = Execution.RunAsync (executable, arguments, timeout: TimeSpan.FromSeconds (120)).Result; + Assert.AreEqual (0, rv.ExitCode, $"Processing Assets Error: {rv.Output.StandardError}. Unexpected ExitCode"); var s = File.ReadAllText (tmpfile); try { diff --git a/tests/dotnet/UnitTests/TestBaseClass.cs b/tests/dotnet/UnitTests/TestBaseClass.cs index 82b2cba2d1dd..fed8415f5fc5 100644 --- a/tests/dotnet/UnitTests/TestBaseClass.cs +++ b/tests/dotnet/UnitTests/TestBaseClass.cs @@ -410,7 +410,7 @@ protected string ExecuteWithMagicWordAndAssert (string executable, Dictionary? environment = null) + protected Execution Execute (string executable, out string output, out string magicWord, Dictionary? environment = null) { if (!File.Exists (executable)) throw new FileNotFoundException ($"The executable '{executable}' does not exists."); @@ -425,8 +425,9 @@ protected Execution Execute (string executable, out StringBuilder output, out st env [kvp.Key] = kvp.Value; } - output = new StringBuilder (); - return Execution.RunWithStringBuildersAsync (executable, Array.Empty (), environment: env, standardOutput: output, standardError: output, timeout: TimeSpan.FromSeconds (30)).Result; + var rv = Execution.RunAsync (executable, Array.Empty (), environment: env, timeout: TimeSpan.FromSeconds (30)).Result; + output = rv.Output.MergedOutput; + return rv; } public static StringBuilder AssertExecute (string executable, params string [] arguments) diff --git a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt index fcd2975f0d08..e3d240e0362f 100644 --- a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt @@ -82026,7 +82026,7 @@ Microsoft.iOS.dll:Foundation.NSMutableData/d__4.System.IDisposable.Dispose() Microsoft.iOS.dll:Foundation.NSMutableDictionary Microsoft.iOS.dll:Foundation.NSMutableDictionary CoreData.NSManagedObjectContext::UserInfo() -Microsoft.iOS.dll:Foundation.NSMutableDictionary Foundation.NSMutableDictionary/d__46::<>4__this +Microsoft.iOS.dll:Foundation.NSMutableDictionary Foundation.NSMutableDictionary/d__45::<>4__this Microsoft.iOS.dll:Foundation.NSMutableDictionary GameplayKit.GKRuleSystem::State() Microsoft.iOS.dll:Foundation.NSMutableDictionary SceneKit.SCNPropertyControllers::mutDict Microsoft.iOS.dll:Foundation.NSMutableDictionary Security.SecRecord::_queryDict @@ -82046,7 +82046,6 @@ Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSDictionary, Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSDictionary) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSObjectFlag) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSUrl) -Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(ObjCRuntime.NativeHandle, System.Boolean) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(System.String) Microsoft.iOS.dll:Foundation.NSMutableDictionary.Add(Foundation.NSObject, Foundation.NSObject) @@ -82099,13 +82098,13 @@ Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IDictionary. Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IDictionary.set_Item(System.Object, System.Object) Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IEnumerable.GetEnumerator() Microsoft.iOS.dll:Foundation.NSMutableDictionary.TryGetValue(Foundation.NSObject, out Foundation.NSObject&) -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46 -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46..ctor(System.Int32) -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.MoveNext() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.Generic.IEnumerator>.get_Current() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.IEnumerator.get_Current() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.IEnumerator.Reset() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.IDisposable.Dispose() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45 +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45..ctor(System.Int32) +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.MoveNext() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.Generic.IEnumerator>.get_Current() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.IEnumerator.get_Current() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.IEnumerator.Reset() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.IDisposable.Dispose() Microsoft.iOS.dll:Foundation.NSMutableDictionary`2 Microsoft.iOS.dll:Foundation.NSMutableDictionary`2._Xamarin_ConstructINativeObject(ObjCRuntime.NativeHandle, System.Boolean) Microsoft.iOS.dll:Foundation.NSMutableDictionary`2._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle) @@ -83906,7 +83905,7 @@ Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQuery::SearchScopes Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQuery::ValueListAttributes() Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQueryResultGroup::Results() Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQueryResultGroup::Subgroups() -Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMutableDictionary/d__46::<>7__wrap1 +Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMutableDictionary/d__45::<>7__wrap1 Microsoft.iOS.dll:Foundation.NSObject[] GameplayKit.GKRuleSystem::Facts() Microsoft.iOS.dll:Foundation.NSObject[] UIKit.UICollisionBehavior::BoundaryIdentifiers() Microsoft.iOS.dll:Foundation.NSObject[] UIKit.UIFontFeature::keys @@ -214991,8 +214990,8 @@ Microsoft.iOS.dll:System.Collections.Generic.IEqualityComparer`1 Microsoft.iOS.dll:System.Collections.Generic.IEqualityComparer`1 ObjCRuntime.IntPtrTypeValueTuple::item2Comparer Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary/d__64::<>2__current Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary/d__64::System.Collections.Generic.IEnumerator>.Current() -Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__46::<>2__current -Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__46::System.Collections.Generic.IEnumerator>.Current() +Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__45::<>2__current +Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__45::System.Collections.Generic.IEnumerator>.Current() Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary`2/>-GetEnumerator>d__48::<>2__current Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary`2/>-GetEnumerator>d__48::System.Collections.Generic.IEnumerator>.Current() Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>2__current @@ -218701,8 +218700,8 @@ Microsoft.iOS.dll:System.Int32 Foundation.NSLinguisticTagScheme::value__ Microsoft.iOS.dll:System.Int32 Foundation.NSMutableData/-GetEnumerator>d__5::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableData/d__4::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary::System.Collections.Generic.ICollection>.Count() -Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__46::<>1__state -Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__46::<>7__wrap2 +Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__45::<>1__state +Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__45::<>7__wrap2 Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2::System.Collections.Generic.ICollection>.Count() Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>7__wrap2 @@ -226438,7 +226437,7 @@ Microsoft.iOS.dll:System.Object Foundation.NSMutableData/d__4::System.Collections.Generic.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableData/d__4::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary::System.Collections.IDictionary.Item(System.Object) -Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary/d__46::System.Collections.IEnumerator.Current() +Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary/d__45::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSNetService::__mt_WeakDelegate_var Microsoft.iOS.dll:System.Object Foundation.NSNetServiceBrowser::__mt_WeakDelegate_var diff --git a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt index fcd2975f0d08..e3d240e0362f 100644 --- a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt +++ b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt @@ -82026,7 +82026,7 @@ Microsoft.iOS.dll:Foundation.NSMutableData/d__4.System.IDisposable.Dispose() Microsoft.iOS.dll:Foundation.NSMutableDictionary Microsoft.iOS.dll:Foundation.NSMutableDictionary CoreData.NSManagedObjectContext::UserInfo() -Microsoft.iOS.dll:Foundation.NSMutableDictionary Foundation.NSMutableDictionary/d__46::<>4__this +Microsoft.iOS.dll:Foundation.NSMutableDictionary Foundation.NSMutableDictionary/d__45::<>4__this Microsoft.iOS.dll:Foundation.NSMutableDictionary GameplayKit.GKRuleSystem::State() Microsoft.iOS.dll:Foundation.NSMutableDictionary SceneKit.SCNPropertyControllers::mutDict Microsoft.iOS.dll:Foundation.NSMutableDictionary Security.SecRecord::_queryDict @@ -82046,7 +82046,6 @@ Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSDictionary, Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSDictionary) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSObjectFlag) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(Foundation.NSUrl) -Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(ObjCRuntime.NativeHandle, System.Boolean) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(ObjCRuntime.NativeHandle) Microsoft.iOS.dll:Foundation.NSMutableDictionary..ctor(System.String) Microsoft.iOS.dll:Foundation.NSMutableDictionary.Add(Foundation.NSObject, Foundation.NSObject) @@ -82099,13 +82098,13 @@ Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IDictionary. Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IDictionary.set_Item(System.Object, System.Object) Microsoft.iOS.dll:Foundation.NSMutableDictionary.System.Collections.IEnumerable.GetEnumerator() Microsoft.iOS.dll:Foundation.NSMutableDictionary.TryGetValue(Foundation.NSObject, out Foundation.NSObject&) -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46 -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46..ctor(System.Int32) -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.MoveNext() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.Generic.IEnumerator>.get_Current() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.IEnumerator.get_Current() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.Collections.IEnumerator.Reset() -Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__46.System.IDisposable.Dispose() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45 +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45..ctor(System.Int32) +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.MoveNext() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.Generic.IEnumerator>.get_Current() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.IEnumerator.get_Current() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.Collections.IEnumerator.Reset() +Microsoft.iOS.dll:Foundation.NSMutableDictionary/d__45.System.IDisposable.Dispose() Microsoft.iOS.dll:Foundation.NSMutableDictionary`2 Microsoft.iOS.dll:Foundation.NSMutableDictionary`2._Xamarin_ConstructINativeObject(ObjCRuntime.NativeHandle, System.Boolean) Microsoft.iOS.dll:Foundation.NSMutableDictionary`2._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle) @@ -83906,7 +83905,7 @@ Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQuery::SearchScopes Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQuery::ValueListAttributes() Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQueryResultGroup::Results() Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMetadataQueryResultGroup::Subgroups() -Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMutableDictionary/d__46::<>7__wrap1 +Microsoft.iOS.dll:Foundation.NSObject[] Foundation.NSMutableDictionary/d__45::<>7__wrap1 Microsoft.iOS.dll:Foundation.NSObject[] GameplayKit.GKRuleSystem::Facts() Microsoft.iOS.dll:Foundation.NSObject[] UIKit.UICollisionBehavior::BoundaryIdentifiers() Microsoft.iOS.dll:Foundation.NSObject[] UIKit.UIFontFeature::keys @@ -214991,8 +214990,8 @@ Microsoft.iOS.dll:System.Collections.Generic.IEqualityComparer`1 Microsoft.iOS.dll:System.Collections.Generic.IEqualityComparer`1 ObjCRuntime.IntPtrTypeValueTuple::item2Comparer Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary/d__64::<>2__current Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary/d__64::System.Collections.Generic.IEnumerator>.Current() -Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__46::<>2__current -Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__46::System.Collections.Generic.IEnumerator>.Current() +Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__45::<>2__current +Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary/d__45::System.Collections.Generic.IEnumerator>.Current() Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary`2/>-GetEnumerator>d__48::<>2__current Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSDictionary`2/>-GetEnumerator>d__48::System.Collections.Generic.IEnumerator>.Current() Microsoft.iOS.dll:System.Collections.Generic.KeyValuePair`2 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>2__current @@ -218701,8 +218700,8 @@ Microsoft.iOS.dll:System.Int32 Foundation.NSLinguisticTagScheme::value__ Microsoft.iOS.dll:System.Int32 Foundation.NSMutableData/-GetEnumerator>d__5::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableData/d__4::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary::System.Collections.Generic.ICollection>.Count() -Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__46::<>1__state -Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__46::<>7__wrap2 +Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__45::<>1__state +Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary/d__45::<>7__wrap2 Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2::System.Collections.Generic.ICollection>.Count() Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>1__state Microsoft.iOS.dll:System.Int32 Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::<>7__wrap2 @@ -226438,7 +226437,7 @@ Microsoft.iOS.dll:System.Object Foundation.NSMutableData/d__4::System.Collections.Generic.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableData/d__4::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary::System.Collections.IDictionary.Item(System.Object) -Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary/d__46::System.Collections.IEnumerator.Current() +Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary/d__45::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSMutableDictionary`2/>-GetEnumerator>d__48::System.Collections.IEnumerator.Current() Microsoft.iOS.dll:System.Object Foundation.NSNetService::__mt_WeakDelegate_var Microsoft.iOS.dll:System.Object Foundation.NSNetServiceBrowser::__mt_WeakDelegate_var diff --git a/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs b/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs index f8077805850d..d984e094fdfc 100644 --- a/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs +++ b/tests/monotouch-test/CoreGraphics/BitmapContextTest.cs @@ -109,115 +109,194 @@ public void ToImage () } [Test] - public void CreateAdaptive () + public void CreateAdaptive_1 () { TestRuntime.AssertXcodeVersion (26, 0); nuint width = 256; nuint height = 256; - { + using (var pool = new NSAutoreleasePool ()) { using var context = CGBitmapContext.Create (width, height, (NSDictionary?) null, null, null, null, null); Assert.NotNull (context, "Context#1"); } + } + + [Test] + public void CreateAdaptive_2 () + { + TestRuntime.AssertXcodeVersion (26, 0); + + nuint width = 256; + nuint height = 256; + + var calledOnLockPointer = false; + var calledOnUnlockPointer = false; + var calledOnReleaseInfo = false; + const int renderingBufferProviderSize = 512; - { - var calledOnResolve = false; - var calledOnAllocate = false; - var calledOnFree = false; - var calledOnError = false; + var calledOnResolve = false; + var calledOnAllocate = false; + var calledOnFree = false; + var calledOnError = false; + + using (var pool = new NSAutoreleasePool ()) { using var context = CGBitmapContext.Create (width, height, (CGAdaptiveOptions?) null, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnResolve#2 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnResolve#2 info={info} parameters={parameters}"); calledOnResolve = true; return true; }, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#2 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#2 info={info} parameters={parameters}"); calledOnAllocate = true; - return null; + var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize, + lockPointer: (info) => { + calledOnLockPointer = true; + var rv = Marshal.AllocHGlobal (renderingBufferProviderSize); + // TestRuntime.NSLog ($"CreateAdaptive3 () OnLockPointer#2 (0x{info:x}) => 0x{rv:x}"); + return rv; + }, + unlockPointer: (info, pointer) => { + // TestRuntime.NSLog ($"CreateAdaptive3 () OnUnlockPointer#2 (0x{info:x}, 0x{pointer:x})"); + calledOnUnlockPointer = true; + Marshal.FreeHGlobal (pointer); + }, + releaseInfo: (info) => { + // TestRuntime.NSLog ($"CreateAdaptive3 () OnReleaseInfo#2 (0x{info:x})"); + calledOnReleaseInfo = true; + } + ); + return renderingBufferProvider; }, (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnFree#2 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnFree#2 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnFree = true; }, (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnError#2 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnError#2 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnError = true; }); Assert.NotNull (context, "Context#2"); - // This fails because onAllocate returns null using var img = context.ToImage (); - Assert.Null (img, "ToImage"); - - Assert.That (calledOnResolve, Is.True, "calledOnResolve#2"); - Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#2"); - Assert.That (calledOnFree, Is.False, "calledOnFree#2"); - Assert.That (calledOnError, Is.True, "calledOnError#2"); + Assert.NotNull (img, "ToImage"); } - { - var calledOnResolve = false; - var calledOnAllocate = false; - var calledOnFree = false; - var calledOnError = false; - var options = new CGAdaptiveOptions () { - MaximumBitDepth = CGComponent.Float16Bit, - }; + Assert.That (calledOnResolve, Is.True, "calledOnResolve#2"); + Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#2"); + Assert.That (calledOnFree, Is.True, "calledOnFree#2"); + Assert.That (calledOnError, Is.False, "calledOnError#2"); + + Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#2"); + Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#2"); + Assert.That (calledOnReleaseInfo, Is.False, "calledOnReleaseInfo#2"); + } + + [Test] + public void CreateAdaptive_3 () + { + TestRuntime.AssertXcodeVersion (26, 0); + + nuint width = 256; + nuint height = 256; + + var calledOnLockPointer = false; + var calledOnUnlockPointer = false; + var calledOnReleaseInfo = false; + const int renderingBufferProviderSize = 512; + + var calledOnResolve = false; + var calledOnAllocate = false; + var calledOnFree = false; + var calledOnError = false; + var options = new CGAdaptiveOptions () { + MaximumBitDepth = CGComponent.Float16Bit, + }; + + using (var pool = new NSAutoreleasePool ()) { using var context = CGBitmapContext.Create (width, height, options, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnResolve#3 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnResolve#3 info={info} parameters={parameters}"); calledOnResolve = true; return true; }, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#3 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#3 info={info} parameters={parameters}"); calledOnAllocate = true; - return null; + var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize, + lockPointer: (info) => { + calledOnLockPointer = true; + var rv = Marshal.AllocHGlobal (renderingBufferProviderSize); + // TestRuntime.NSLog ($"CreateAdaptive3 () OnLockPointer#3 (0x{info:x}) => 0x{rv:x}"); + return rv; + }, + unlockPointer: (info, pointer) => { + // TestRuntime.NSLog ($"CreateAdaptive3 () OnUnlockPointer#3 (0x{info:x}, 0x{pointer:x})"); + calledOnUnlockPointer = true; + Marshal.FreeHGlobal (pointer); + }, + releaseInfo: (info) => { + // TestRuntime.NSLog ($"CreateAdaptive3 () OnReleaseInfo#3 (0x{info:x})"); + calledOnReleaseInfo = true; + } + ); + return renderingBufferProvider; }, (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnFree#3 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnFree#3 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnFree = true; }, (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnError#3 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnError#3 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnError = true; }); Assert.NotNull (context, "Context#3"); - // This fails because onAllocate returns null using var img = context.ToImage (); - Assert.Null (img, "ToImage"); - - Assert.That (calledOnResolve, Is.True, "calledOnResolve#3"); - Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#3"); - Assert.That (calledOnFree, Is.False, "calledOnFree#3"); - Assert.That (calledOnError, Is.True, "calledOnError#3"); + Assert.NotNull (img, "ToImage"); } + Assert.That (calledOnResolve, Is.True, "calledOnResolve#3"); + Assert.That (calledOnAllocate, Is.True, "calledOnAllocate#3"); + Assert.That (calledOnFree, Is.True, "calledOnFree#3"); + Assert.That (calledOnError, Is.False, "calledOnError#3"); + + Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#3"); + Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#3"); + Assert.That (calledOnReleaseInfo, Is.False, "calledOnReleaseInfo#3"); + } + + [Test] + public void CreateAdaptive_4 () + { + TestRuntime.AssertXcodeVersion (26, 0); - { - var calledOnLockPointer = false; - var calledOnUnlockPointer = false; - var calledOnReleaseInfo = false; - const int renderingBufferProviderSize = 512; + nuint width = 256; + nuint height = 256; + + var calledOnLockPointer = false; + var calledOnUnlockPointer = false; + var calledOnReleaseInfo = false; + const int renderingBufferProviderSize = 512; + + using (var pool = new NSAutoreleasePool ()) { using (var renderingBufferProvider = CGRenderingBufferProvider.Create (IntPtr.Zero, renderingBufferProviderSize, lockPointer: (info) => { calledOnLockPointer = true; var rv = Marshal.AllocHGlobal (renderingBufferProviderSize); - // Console.WriteLine ($"CreateAdaptive () OnLockPointer#4 ({info}) => {rv}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnLockPointer#4 (0x{info:x}) => 0x{rv:x}"); return rv; }, unlockPointer: (info, pointer) => { - // Console.WriteLine ($"CreateAdaptive () OnUnlockPointer#4 ({info}, {pointer})"); + // TestRuntime.NSLog ($"CreateAdaptive () OnUnlockPointer#4 (0x{info:x}, 0x{pointer:x})"); calledOnUnlockPointer = true; Marshal.FreeHGlobal (pointer); }, releaseInfo: (info) => { - // Console.WriteLine ($"CreateAdaptive () OnReleaseInfo#4 ({info})"); + // TestRuntime.NSLog ($"CreateAdaptive () OnReleaseInfo#4 (0x{info:x})"); calledOnReleaseInfo = true; } )) { @@ -233,21 +312,21 @@ public void CreateAdaptive () using (var context = CGBitmapContext.Create (width, height, options, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnResolve#4 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnResolve#4 info={info} parameters={parameters}"); calledOnResolve = true; return true; }, (ref CGContentInfo info, ref CGBitmapParameters parameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#4 info={info} parameters={parameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnAllocate#4 info={info} parameters={parameters}"); calledOnAllocate = true; return renderingBufferProvider; }, (CGRenderingBufferProvider renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnFree#4 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnFree#4 renderingBufferProvider={renderingBufferProvider} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnFree = true; }, (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters) => { - TestRuntime.NSLog ($"CreateAdaptive () OnError#4 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); + // TestRuntime.NSLog ($"CreateAdaptive () OnError#4 error={error} contentInfo={contentInfo} bitmapParameters={bitmapParameters}"); calledOnError = true; })) { @@ -262,11 +341,11 @@ public void CreateAdaptive () Assert.That (calledOnFree, Is.True, "calledOnFree#4"); Assert.That (calledOnError, Is.False, "calledOnError#4"); } - - Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#4"); - Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#4"); - Assert.That (calledOnReleaseInfo, Is.False, "calledOnReleaseInfo#4"); } + + Assert.That (calledOnLockPointer, Is.True, "calledOnLockPointer#4"); + Assert.That (calledOnUnlockPointer, Is.True, "calledOnUnlockPointer#4"); + Assert.That (calledOnReleaseInfo, Is.True, "calledOnReleaseInfo#4"); } } } diff --git a/tests/monotouch-test/CoreWlan/CWKeychainTests.cs b/tests/monotouch-test/CoreWlan/CWKeychainTests.cs index 2c30925066ad..e65cf4ae13f3 100644 --- a/tests/monotouch-test/CoreWlan/CWKeychainTests.cs +++ b/tests/monotouch-test/CoreWlan/CWKeychainTests.cs @@ -94,10 +94,10 @@ public void TrySetWiFiEAPIdentityTest () var identity = IdentityTest.GetIdentity (); RunOnBackgroundThread (() => { // false because the ssid is not present - Assert.True (CWKeychain.TrySetWiFiEAPIdentity (domain, ssid, identity), "A"); + Assert.That (CWKeychain.TrySetWiFiEAPIdentity (domain, ssid, identity), Is.True.Or.False, "A"); - Assert.True (CWKeychain.TrySetWiFiEAPIdentity (domain, ssid, identity, out var status), "B"); - Assert.AreEqual (SecStatusCode.Success, (SecStatusCode) status, "Status B"); + Assert.That (CWKeychain.TrySetWiFiEAPIdentity (domain, ssid, identity, out var status), Is.True.Or.False, "B"); + Assert.That ((SecStatusCode) status, Is.EqualTo (SecStatusCode.Success).Or.EqualTo (SecStatusCode.Allocate), "Status B"); // remove it to clean behind Assert.False (CWKeychain.TryDeleteWiFiEAPUsernameAndPassword (domain, ssid), "C"); diff --git a/tests/monotouch-test/Foundation/NSArray1Test.cs b/tests/monotouch-test/Foundation/NSArray1Test.cs index 78e7b4b90745..3afb37a706a6 100644 --- a/tests/monotouch-test/Foundation/NSArray1Test.cs +++ b/tests/monotouch-test/Foundation/NSArray1Test.cs @@ -125,6 +125,38 @@ public void ToArray_T () } } + [Test] + public void FromIntPtrs_NativeHandle () + { + var str1 = (NSString) "1"; + var str2 = (NSString) "2"; + var str3 = (NSString) "3"; + + var handles = new NativeHandle [] { str1.Handle, str2.Handle, str3.Handle }; + using (var arr = NSArray.FromIntPtrs (handles)) { + Assert.AreEqual ((nuint) 3, arr.Count, "NSArray Count"); + Assert.AreEqual ("1", arr.GetItem (0).ToString (), "NSArray item 0"); + Assert.AreEqual ("2", arr.GetItem (1).ToString (), "NSArray item 1"); + Assert.AreEqual ("3", arr.GetItem (2).ToString (), "NSArray item 2"); + } + } + + [Test] + public void FromIntPtrs_NativeHandle_Null () + { + NativeHandle []? handles = null; + Assert.Throws (() => NSArray.FromIntPtrs (handles!), "Null array"); + } + + [Test] + public void FromIntPtrs_NativeHandle_Empty () + { + var handles = new NativeHandle [0]; + using (var arr = NSArray.FromIntPtrs (handles)) { + Assert.AreEqual ((nuint) 0, arr.Count, "NSArray Count"); + } + } + #if false // https://github.com/dotnet/macios/issues/15577 [Test] public void GetDifferenceFromArrayTest () diff --git a/tests/monotouch-test/Foundation/NSDictionary2Test.cs b/tests/monotouch-test/Foundation/NSDictionary2Test.cs index 877bb4982213..ee55050bc907 100644 --- a/tests/monotouch-test/Foundation/NSDictionary2Test.cs +++ b/tests/monotouch-test/Foundation/NSDictionary2Test.cs @@ -84,6 +84,98 @@ public void FromObjectsAndKeysGenericTest () Assert.AreEqual (dict [keys [i]], values [i], $"key lookup, Iteration: {i}"); } + [Test] + public void FromObjectsAndKeysGenericTest_NullValue () + { + var keys = new [] { + new NSString ("Key1"), + new NSString ("Key2"), + new NSString ("Key3"), + }; + var values = new NSNumber? [] { + NSNumber.FromByte (0x1), + null, + NSNumber.FromInt32 (42), + }; + + var dict = NSDictionary.FromObjectsAndKeys (values, keys, values.Length); + Assert.AreEqual (dict.Count, (nuint) 3, "count"); + Assert.AreEqual (dict [keys [0]], values [0], "key lookup 0"); + var baseDict = (NSDictionary) dict; + var rawValue = baseDict.ObjectForKey (keys [1]); + Assert.IsInstanceOf (rawValue, "Null value"); + Assert.AreEqual (dict [keys [2]], values [2], "key lookup 2"); + } + + [Test] + public void FromObjectsAndKeysGenericTest_NSObjects_NullValue () + { + var keys = new [] { + (NSObject) new NSString ("Key1"), + (NSObject) new NSString ("Key2"), + (NSObject) new NSString ("Key3"), + }; + var values = new NSObject? [] { + NSNumber.FromByte (0x1), + null, + NSNumber.FromInt32 (42), + }; + + var dict = NSDictionary.FromObjectsAndKeys (values, keys, values.Length); + Assert.AreEqual (dict.Count, (nuint) 3, "count"); + Assert.AreEqual (1, dict [(NSString) keys [0]].ByteValue, "key lookup 0"); + var baseDict = (NSDictionary) dict; + var rawValue = baseDict.ObjectForKey ((NSString) keys [1]); + Assert.IsInstanceOf (rawValue, "Null value"); + Assert.AreEqual (42, dict [(NSString) keys [2]].Int32Value, "key lookup 2"); + } + + [Test] + public void FromObjectsAndKeysGenericTest_NullValue_NoCount () + { + var keys = new [] { + new NSString ("Key1"), + new NSString ("Key2"), + new NSString ("Key3"), + }; + var values = new NSNumber? [] { + NSNumber.FromByte (0x1), + null, + NSNumber.FromInt32 (42), + }; + + var dict = NSDictionary.FromObjectsAndKeys (values, keys); + Assert.AreEqual (dict.Count, (nuint) 3, "count"); + Assert.AreEqual (dict [keys [0]], values [0], "key lookup 0"); + var baseDict = (NSDictionary) dict; + var rawValue = baseDict.ObjectForKey (keys [1]); + Assert.IsInstanceOf (rawValue, "Null value"); + Assert.AreEqual (dict [keys [2]], values [2], "key lookup 2"); + } + + [Test] + public void FromObjectsAndKeysGenericTest_NSObjects_NullValue_NoCount () + { + var keys = new [] { + (NSObject) new NSString ("Key1"), + (NSObject) new NSString ("Key2"), + (NSObject) new NSString ("Key3"), + }; + var values = new NSObject? [] { + NSNumber.FromByte (0x1), + null, + NSNumber.FromInt32 (42), + }; + + var dict = NSDictionary.FromObjectsAndKeys (values, keys); + Assert.AreEqual (dict.Count, (nuint) 3, "count"); + Assert.AreEqual (1, dict [(NSString) keys [0]].ByteValue, "key lookup 0"); + var baseDict = (NSDictionary) dict; + var rawValue = baseDict.ObjectForKey ((NSString) keys [1]); + Assert.IsInstanceOf (rawValue, "Null value"); + Assert.AreEqual (42, dict [(NSString) keys [2]].Int32Value, "key lookup 2"); + } + [Test] public void KeyValue_Autorelease () { @@ -361,6 +453,127 @@ public void IndexerTest () Assert.Throws (() => GC.KeepAlive (dict [(NSString) null]), "c"); } + [Test] + public void IndexerGetterKeyNotFoundBehaviorTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var key1 = new NSString ("key1"); + var keyMissing = new NSString ("missing"); + + var dict = new NSDictionary (key1, value1); + + // Accessing via the property indexer should return null for missing keys + Assert.IsNull (dict [keyMissing], "missing key"); + + // Accessing via IDictionary interface should also return null (NSDictionary behavior) + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "missing key via interface"); + } + + [Test] + public void MissingKeyAccessTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var value2 = NSDate.FromTimeIntervalSinceNow (2); + var key1 = new NSString ("key1"); + var key2 = new NSString ("key2"); + var keyMissing = new NSString ("missing"); + + var dict = new NSDictionary ( + new NSString [] { key1, key2 }, + new NSDate [] { value1, value2 } + ); + + // ObjectForKey should return null for missing keys + Assert.IsNull (dict.ObjectForKey (keyMissing), "ObjectForKey missing"); + + // TryGetValue should return false for missing keys + NSDate value; + Assert.IsFalse (dict.TryGetValue (keyMissing, out value), "TryGetValue missing"); + Assert.IsNull (value, "TryGetValue out value"); + + // ContainsKey should return false for missing keys + Assert.IsFalse (dict.ContainsKey (keyMissing), "ContainsKey missing"); + + // Indexer getter should return null for missing keys + Assert.IsNull (dict [keyMissing], "Indexer missing"); + + // IDictionary indexer should also return null for missing keys + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "IDictionary indexer missing"); + } + + [Test] + public void EmptyDictionaryMissingKeyTest () + { + var dict = new NSDictionary (); + var keyMissing = new NSString ("missing"); + + // All access methods should handle missing keys in empty dictionary + Assert.IsNull (dict.ObjectForKey (keyMissing), "ObjectForKey"); + Assert.IsFalse (dict.ContainsKey (keyMissing), "ContainsKey"); + + NSDate value; + Assert.IsFalse (dict.TryGetValue (keyMissing, out value), "TryGetValue"); + Assert.IsNull (value, "TryGetValue out"); + + Assert.IsNull (dict [keyMissing], "Indexer"); + + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "IDictionary indexer"); + } + + [Test] + public void ObjectsForKeysMissingKeysTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var value2 = NSDate.FromTimeIntervalSinceNow (2); + var marker = NSDate.FromTimeIntervalSinceNow (999); + var key1 = new NSString ("key1"); + var key2 = new NSString ("key2"); + var keyMissing1 = new NSString ("missing1"); + var keyMissing2 = new NSString ("missing2"); + + var dict = new NSDictionary ( + new NSString [] { key1, key2 }, + new NSDate [] { value1, value2 } + ); + + // Request mix of existing and missing keys - marker should replace missing values + var result = dict.ObjectsForKeys (new NSString [] { key1, keyMissing1, key2, keyMissing2 }, marker); + Assert.AreEqual (4, result.Length, "Length"); + Assert.AreSame (value1, result [0], "0 - existing"); + Assert.AreSame (marker, result [1], "1 - missing"); + Assert.AreSame (value2, result [2], "2 - existing"); + Assert.AreSame (marker, result [3], "3 - missing"); + + // Request all missing keys + result = dict.ObjectsForKeys (new NSString [] { keyMissing1, keyMissing2 }, marker); + Assert.AreEqual (2, result.Length, "All missing length"); + Assert.AreSame (marker, result [0], "All missing 0"); + Assert.AreSame (marker, result [1], "All missing 1"); + } + + [Test] + public void ReadOnlyDictionaryTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var key1 = new NSString ("key1"); + var key2 = new NSString ("key2"); + + var dict = new NSDictionary (key1, value1); + IDictionary idict = dict; + + // Verify it's read-only + Assert.IsTrue (idict.IsReadOnly, "IsReadOnly"); + + // Verify all mutating operations throw NotSupportedException + Assert.Throws (() => idict.Add (key2, value1), "Add"); + Assert.Throws (() => idict.Remove (key2), "Remove"); + Assert.Throws (() => idict [key2] = value1, "Indexer set"); + Assert.Throws (() => idict.Clear (), "Clear"); + } + [Test] public void IDictionary2Test () { diff --git a/tests/monotouch-test/Foundation/NSDictionaryTest.cs b/tests/monotouch-test/Foundation/NSDictionaryTest.cs index 45e379cbd192..57764bc937aa 100644 --- a/tests/monotouch-test/Foundation/NSDictionaryTest.cs +++ b/tests/monotouch-test/Foundation/NSDictionaryTest.cs @@ -154,6 +154,30 @@ public void FromObjectsAndKeysTest () } } + [Test] + public void FromObjectsAndKeysTest_NullValue () + { + var keys = new NSObject [] { new NSNumber (1), new NSNumber (2), new NSNumber (3) }; + var objs = new NSObject? [] { new NSNumber (1), null, new NSNumber (4) }; + NSDictionary ns = NSDictionary.FromObjectsAndKeys (objs, keys, 3); + Assert.AreEqual ((nuint) 3, ns.Count, "Count"); + Assert.AreEqual (1, ((NSNumber) ns [new NSNumber (1)]).Int32Value, "Value 1"); + Assert.IsInstanceOf (ns [new NSNumber (2)], "Null value"); + Assert.AreEqual (4, ((NSNumber) ns [new NSNumber (3)]).Int32Value, "Value 3"); + } + + [Test] + public void FromObjectsAndKeysTest_NullValue_NoCount () + { + var keys = new NSObject [] { new NSNumber (1), new NSNumber (2), new NSNumber (3) }; + var objs = new NSObject? [] { new NSNumber (1), null, new NSNumber (4) }; + NSDictionary ns = NSDictionary.FromObjectsAndKeys (objs, keys); + Assert.AreEqual ((nuint) 3, ns.Count, "Count"); + Assert.AreEqual (1, ((NSNumber) ns [new NSNumber (1)]).Int32Value, "Value 1"); + Assert.IsInstanceOf (ns [new NSNumber (2)], "Null value"); + Assert.AreEqual (4, ((NSNumber) ns [new NSNumber (3)]).Int32Value, "Value 3"); + } + [Test] public void Copy () { diff --git a/tests/monotouch-test/Foundation/NSMutableDictionary2Test.cs b/tests/monotouch-test/Foundation/NSMutableDictionary2Test.cs index a16867d26f8b..945c1c4d4e4b 100644 --- a/tests/monotouch-test/Foundation/NSMutableDictionary2Test.cs +++ b/tests/monotouch-test/Foundation/NSMutableDictionary2Test.cs @@ -357,6 +357,107 @@ public void IndexerTest () Assert.Throws (() => GC.KeepAlive (dict [(NSString) null]), "c"); } + [Test] + public void IndexerGetterKeyNotFoundBehaviorTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var key1 = new NSString ("key1"); + var keyMissing = new NSString ("missing"); + + var dict = new NSMutableDictionary (key1, value1); + + // Accessing via the indexer property should return null + Assert.IsNull (dict [keyMissing], "missing key"); + + // Accessing via IDictionary interface should return null too + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "missing key via interface"); + } + + [Test] + public void MissingKeyAccessTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var value2 = NSDate.FromTimeIntervalSinceNow (2); + var key1 = new NSString ("key1"); + var key2 = new NSString ("key2"); + var keyMissing = new NSString ("missing"); + + var dict = new NSMutableDictionary ( + new NSString [] { key1, key2 }, + new NSDate [] { value1, value2 } + ); + + // ObjectForKey should return null for missing keys + Assert.IsNull (dict.ObjectForKey (keyMissing), "ObjectForKey missing"); + + // TryGetValue should return false for missing keys + NSDate value; + Assert.IsFalse (dict.TryGetValue (keyMissing, out value), "TryGetValue missing"); + Assert.IsNull (value, "TryGetValue out value"); + + // ContainsKey should return false for missing keys + Assert.IsFalse (dict.ContainsKey (keyMissing), "ContainsKey missing"); + + // Indexer getter should return null + Assert.IsNull (dict [keyMissing], "Indexer missing"); + + // IDictionary indexer should also return null + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "IDictionary indexer missing"); + } + + [Test] + public void EmptyDictionaryMissingKeyTest () + { + var dict = new NSMutableDictionary (); + var keyMissing = new NSString ("missing"); + + // All access methods should handle missing keys in empty dictionary + Assert.IsNull (dict.ObjectForKey (keyMissing), "ObjectForKey"); + Assert.IsFalse (dict.ContainsKey (keyMissing), "ContainsKey"); + + NSDate value; + Assert.IsFalse (dict.TryGetValue (keyMissing, out value), "TryGetValue"); + Assert.IsNull (value, "TryGetValue out"); + + Assert.IsNull (dict [keyMissing], "Indexer"); + + IDictionary idict = dict; + Assert.IsNull (idict [keyMissing], "IDictionary indexer"); + } + + [Test] + public void ObjectsForKeysMissingKeysTest () + { + var value1 = NSDate.FromTimeIntervalSinceNow (1); + var value2 = NSDate.FromTimeIntervalSinceNow (2); + var marker = NSDate.FromTimeIntervalSinceNow (999); + var key1 = new NSString ("key1"); + var key2 = new NSString ("key2"); + var keyMissing1 = new NSString ("missing1"); + var keyMissing2 = new NSString ("missing2"); + + var dict = new NSMutableDictionary ( + new NSString [] { key1, key2 }, + new NSDate [] { value1, value2 } + ); + + // Request mix of existing and missing keys - marker should replace missing values + var result = dict.ObjectsForKeys (new NSString [] { key1, keyMissing1, key2, keyMissing2 }, marker); + Assert.AreEqual (4, result.Length, "Length"); + Assert.AreSame (value1, result [0], "0 - existing"); + Assert.AreSame (marker, result [1], "1 - missing"); + Assert.AreSame (value2, result [2], "2 - existing"); + Assert.AreSame (marker, result [3], "3 - missing"); + + // Request all missing keys + result = dict.ObjectsForKeys (new NSString [] { keyMissing1, keyMissing2 }, marker); + Assert.AreEqual (2, result.Length, "All missing length"); + Assert.AreSame (marker, result [0], "All missing 0"); + Assert.AreSame (marker, result [1], "All missing 1"); + } + [Test] public void IDictionary2Test () { diff --git a/tests/monotouch-test/Foundation/NSMutableDictionaryTest.cs b/tests/monotouch-test/Foundation/NSMutableDictionaryTest.cs index c319e8dd264f..af0c20d3d162 100644 --- a/tests/monotouch-test/Foundation/NSMutableDictionaryTest.cs +++ b/tests/monotouch-test/Foundation/NSMutableDictionaryTest.cs @@ -90,5 +90,119 @@ public void AddEntries () } } } + + [Test] + public void MissingKey_StringIndexer () + { + using (var dict = new NSMutableDictionary ()) { + dict ["existingKey"] = (NSString) "value"; + + // Accessing a missing key should return null + var result = dict ["missingKey"]; + Assert.IsNull (result, "Missing key should return null"); + + // Verify the existing key still works + Assert.IsNotNull (dict ["existingKey"], "Existing key should return value"); + } + } + + [Test] + public void MissingKey_NSObjectIndexer () + { + using (var dict = new NSMutableDictionary ()) { + var existingKey = NSDate.Now; + var missingKey = NSDate.DistantPast; + dict [existingKey] = NSDate.DistantFuture; + + // Accessing a missing key should return null + var result = dict [missingKey]; + Assert.IsNull (result, "Missing key should return null"); + + // Verify the existing key still works + Assert.IsNotNull (existingKey, "Existing key should return value"); + } + } + + [Test] + public void MissingKey_NSStringIndexer () + { + using (var dict = new NSMutableDictionary ()) { + dict [(NSString) "existingKey"] = (NSString) "value"; + + // Accessing a missing key should return null + var result = dict [(NSString) "missingKey"]; + Assert.IsNull (result, "Missing key should return null"); + + // Verify the existing key still works + Assert.IsNotNull (dict [(NSString) "existingKey"], "Existing key should return value"); + } + } + + [Test] + public void MissingKey_ObjectForKey () + { + using (var dict = new NSMutableDictionary ()) { + dict [(NSString) "existingKey"] = (NSString) "value"; + + // ObjectForKey with missing key should return null + var result = dict.ObjectForKey ((NSString) "missingKey"); + Assert.IsNull (result, "ObjectForKey with missing key should return null"); + + // Verify the existing key still works + Assert.IsNotNull (dict.ObjectForKey ((NSString) "existingKey"), "ObjectForKey with existing key should return value"); + } + } + + [Test] + public void MissingKey_TryGetValue () + { + using (var dict = new NSMutableDictionary ()) { + dict [(NSString) "existingKey"] = (NSString) "value"; + + // TryGetValue with missing key should return false + var found = dict.TryGetValue ((NSString) "missingKey", out var result); + Assert.IsFalse (found, "TryGetValue should return false for missing key"); + Assert.IsNull (result, "Output value should be null for missing key"); + + // Verify the existing key works + found = dict.TryGetValue ((NSString) "existingKey", out result); + Assert.IsTrue (found, "TryGetValue should return true for existing key"); + Assert.IsNotNull (result, "Output value should not be null for existing key"); + Assert.AreEqual ("value", result.ToString (), "Output value should match"); + } + } + + [Test] + public void MissingKey_IDictionaryIndexer () + { + using (var dict = new NSMutableDictionary ()) { + System.Collections.IDictionary idict = dict; + idict [(NSString) "existingKey"] = (NSString) "value"; + + // Accessing a missing key through IDictionary indexer returns IntPtr.Zero (not null) + // This is different from the typed indexers which return null + var result = idict [(NSString) "missingKey"]; + // The IDictionary indexer calls _ObjectForKey which returns IntPtr.Zero boxed + Assert.AreEqual (IntPtr.Zero, result, "IDictionary indexer with missing key returns IntPtr.Zero"); + + // Verify the existing key still works + Assert.IsNotNull (idict [(NSString) "existingKey"], "IDictionary indexer with existing key should return value"); + } + } + + [Test] + public void MissingKey_IDictionaryContains () + { + using (var dict = new NSMutableDictionary ()) { + System.Collections.IDictionary idict = dict; + idict [(NSString) "existingKey"] = (NSString) "value"; + + // Contains should return false for missing key + Assert.IsFalse (idict.Contains ((NSString) "missingKey"), "Contains should return false for missing key"); + + // Contains should return true for existing key + Assert.IsTrue (idict.Contains ((NSString) "existingKey"), "Contains should return true for existing key"); + } + } } } diff --git a/tests/monotouch-test/Foundation/NSMutableOrderedSet1Test.cs b/tests/monotouch-test/Foundation/NSMutableOrderedSet1Test.cs index 258c72a637b0..2f891c66dc3c 100644 --- a/tests/monotouch-test/Foundation/NSMutableOrderedSet1Test.cs +++ b/tests/monotouch-test/Foundation/NSMutableOrderedSet1Test.cs @@ -232,6 +232,77 @@ public void RemoveObjectsTest () Assert.IsTrue (oSet.Contains (str3), "RemoveObjectsTest Contains 3"); } + [Test] + public void AddObjectsTest_NullValue () + { + var str1 = (NSString) "1"; + NSString? str2 = null; + var str3 = (NSString) "3"; + var oSet = new NSMutableOrderedSet (); + oSet.AddObjects (str1, str2, str3); + + Assert.AreEqual ((nint) 3, oSet.Count, "AddObjectsTest_NullValue Count"); + Assert.IsTrue (oSet.Contains (str1), "AddObjectsTest_NullValue Contains 1"); + Assert.IsTrue (oSet.Contains (NSNull.Null), "AddObjectsTest_NullValue Contains NSNull"); + Assert.IsTrue (oSet.Contains (str3), "AddObjectsTest_NullValue Contains 3"); + } + + [Test] + public void InsertObjectsTest_NullValue () + { + var str1 = (NSString) "1"; + NSString? str2 = null; + var str3 = (NSString) "3"; + var str4 = (NSString) "4"; + var oSet = new NSMutableOrderedSet (str4); + oSet.InsertObjects (new NSString? [] { str1, str2, str3 }, NSIndexSet.FromNSRange (new NSRange (0, 3))); + + Assert.AreEqual ((nint) 4, oSet.Count, "InsertObjectsTest_NullValue Count"); + Assert.IsTrue (oSet.Contains (str1), "InsertObjectsTest_NullValue Contains 1"); + Assert.IsTrue (oSet.Contains (NSNull.Null), "InsertObjectsTest_NullValue Contains NSNull"); + Assert.IsTrue (oSet.Contains (str3), "InsertObjectsTest_NullValue Contains 3"); + Assert.IsTrue (oSet.Contains (str4), "InsertObjectsTest_NullValue Contains 4"); + Assert.AreSame (str1, oSet [0], "InsertObjectsTest_NullValue 1 == 1"); + Assert.AreSame (str4, oSet [3], "InsertObjectsTest_NullValue 4 == 4"); + } + + [Test] + public void ReplaceObjectsTest_NullValue () + { + var str1 = (NSString) "1"; + var str2 = (NSString) "2"; + NSString? str3 = null; + var str4 = (NSString) "4"; + + var oSet = new NSMutableOrderedSet (str1, str2); + Assert.AreEqual ((nint) 2, oSet.Count, "ReplaceObjectsTest_NullValue Count"); + Assert.AreSame (str1, oSet [0], "ReplaceObjectsTest_NullValue 1 == 1"); + Assert.AreSame (str2, oSet [1], "ReplaceObjectsTest_NullValue 2 == 2"); + + oSet.ReplaceObjects (NSIndexSet.FromNSRange (new NSRange (0, 2)), str3, str4); + var baseSet = (NSOrderedSet) oSet; + var item0 = baseSet [0]; + Assert.IsInstanceOf (item0, "ReplaceObjectsTest_NullValue NSNull"); + Assert.AreSame (str4, oSet [1], "ReplaceObjectsTest_NullValue 4 == 4"); + } + + [Test] + public void RemoveObjectsTest_NullValue () + { + var str1 = (NSString) "1"; + NSString? str2 = null; + var str3 = (NSString) "3"; + var oSet = new NSMutableOrderedSet (); + oSet.AddObjects (str1, str2, str3); + Assert.AreEqual ((nint) 3, oSet.Count, "RemoveObjectsTest_NullValue Count"); + + oSet.RemoveObjects (str1, str2); + Assert.AreEqual ((nint) 1, oSet.Count, "RemoveObjectsTest_NullValue Count After Remove"); + Assert.IsFalse (oSet.Contains (str1), "RemoveObjectsTest_NullValue must not contain 1"); + Assert.IsFalse (oSet.Contains (NSNull.Null), "RemoveObjectsTest_NullValue must not contain NSNull"); + Assert.IsTrue (oSet.Contains (str3), "RemoveObjectsTest_NullValue Contains 3"); + } + [Test] public void IEnumerable1Test () { diff --git a/tests/monotouch-test/Foundation/NSMutableSet1Test.cs b/tests/monotouch-test/Foundation/NSMutableSet1Test.cs index 68ee6f9c6145..c3014749dd10 100644 --- a/tests/monotouch-test/Foundation/NSMutableSet1Test.cs +++ b/tests/monotouch-test/Foundation/NSMutableSet1Test.cs @@ -266,5 +266,335 @@ public void OperatorPlusReferenceTest () Assert.AreNotEqual (IntPtr.Zero, one.Handle, "Handle must be != IntPtr.Zero"); Assert.AreNotEqual (IntPtr.Zero, two.Handle, "Handle must be != IntPtr.Zero"); } + + [Test] + public void OperatorPlus_BothNull () + { + NSMutableSet first = null; + NSMutableSet second = null; + var result = first + second; + Assert.IsNull (result, "Both null should return null"); + } + + [Test] + public void OperatorPlus_FirstNull () + { + NSMutableSet first = null; + using (var second = new NSMutableSet ((NSString) "1", (NSString) "2")) { + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + } + + [Test] + public void OperatorPlus_SecondNull () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) { + NSMutableSet second = null; + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + } + + [Test] + public void OperatorPlus_BothEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ()) + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 0, result.Count, "Count should be 0"); + } + } + + [Test] + public void OperatorPlus_FirstEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + + [Test] + public void OperatorPlus_SecondEmpty () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var second = new NSMutableSet ()) + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + + [Test] + public void OperatorPlus_Overlapping () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var second = new NSMutableSet ((NSString) "2", (NSString) "3")) + using (var result = first + second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 3, result.Count, "Count should be 3 (set union)"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + Assert.IsTrue (result.Contains ((NSString) "3"), "Contains 3"); + } + } + + [Test] + public void OperatorMinus_BothNull () + { + NSMutableSet first = null; + NSMutableSet second = null; + var result = first - second; + Assert.IsNull (result, "Both null should return null"); + } + + [Test] + public void OperatorMinus_FirstNull () + { + NSMutableSet first = null; + using (var second = new NSMutableSet ((NSString) "1", (NSString) "2")) { + var result = first - second; + Assert.IsNull (result, "First null should return null"); + } + } + + [Test] + public void OperatorMinus_SecondNull () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) { + NSMutableSet second = null; + using (var result = first - second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + } + + [Test] + public void OperatorMinus_FirstEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ((NSString) "1", (NSString) "2")) { + var result = first - second; + Assert.IsNull (result, "Empty first should return null"); + } + } + + [Test] + public void OperatorMinus_SecondEmpty () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var second = new NSMutableSet ()) + using (var result = first - second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + + [Test] + public void OperatorMinus_BothEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ()) { + var result = first - second; + Assert.IsNull (result, "Both empty should return null"); + } + } + + [Test] + public void OperatorMinus_NoOverlap () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var second = new NSMutableSet ((NSString) "3", (NSString) "4")) + using (var result = first - second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "2"), "Contains 2"); + } + } + + [Test] + public void OperatorMinus_PartialOverlap () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2", (NSString) "3")) + using (var second = new NSMutableSet ((NSString) "2", (NSString) "4")) + using (var result = first - second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 2, result.Count, "Count"); + Assert.IsTrue (result.Contains ((NSString) "1"), "Contains 1"); + Assert.IsTrue (result.Contains ((NSString) "3"), "Contains 3"); + Assert.IsFalse (result.Contains ((NSString) "2"), "Should not contain 2"); + } + } + + [Test] + public void OperatorMinus_CompleteOverlap () + { + using (var first = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var second = new NSMutableSet ((NSString) "1", (NSString) "2")) + using (var result = first - second) { + Assert.IsNotNull (result, "Result should not be null"); + Assert.AreEqual ((nuint) 0, result.Count, "Count should be 0"); + } + } + + [Test] + public void Ctor_Capacity () + { + using (var set = new NSMutableSet (10)) { + Assert.AreEqual ((nuint) 0, set.Count, "Empty with capacity"); + } + } + + [Test] + public void ToArray_Empty () + { + using (var set = new NSMutableSet ()) { + var arr = set.ToArray (); + Assert.IsNotNull (arr, "Array should not be null"); + Assert.AreEqual (0, arr.Length, "Length should be 0"); + } + } + + [Test] + public void ToArray_Multiple () + { + var v1 = (NSString) "1"; + var v2 = (NSString) "2"; + var v3 = (NSString) "3"; + + using (var set = new NSMutableSet (v1, v2, v3)) { + var arr = set.ToArray (); + Assert.AreEqual (3, arr.Length, "Length"); + Assert.Contains (v1, arr, "Contains v1"); + Assert.Contains (v2, arr, "Contains v2"); + Assert.Contains (v3, arr, "Contains v3"); + } + } + + [Test] + public void Add_Duplicate () + { + var v1 = (NSString) "1"; + + using (var set = new NSMutableSet ()) { + set.Add (v1); + Assert.AreEqual ((nuint) 1, set.Count, "Count after first add"); + + set.Add (v1); + Assert.AreEqual ((nuint) 1, set.Count, "Count after duplicate add"); + } + } + + [Test] + public void Remove_NonExistent () + { + var v1 = (NSString) "1"; + var v2 = (NSString) "2"; + + using (var set = new NSMutableSet (v1)) { + set.Remove (v2); + Assert.AreEqual ((nuint) 1, set.Count, "Count should remain 1"); + Assert.IsTrue (set.Contains (v1), "Should still contain v1"); + } + } + + [Test] + public void AddObjects_Empty () + { + using (var set = new NSMutableSet ()) { + set.AddObjects (); + Assert.AreEqual ((nuint) 0, set.Count, "Count should be 0"); + } + } + + [Test] + public void AddObjects_WithNullElement () + { + var v1 = (NSString) "1"; + + using (var set = new NSMutableSet ()) { + Assert.Throws (() => set.AddObjects (v1, null), "Should throw on null element"); + } + } + + [Test] + public void LookupMember_Empty () + { + var v1 = (NSString) "1"; + + using (var set = new NSMutableSet ()) { + var result = set.LookupMember (v1); + Assert.IsNull (result, "Should return null for empty set"); + } + } + + [Test] + public void Contains_Empty () + { + var v1 = (NSString) "1"; + + using (var set = new NSMutableSet ()) { + Assert.IsFalse (set.Contains (v1), "Empty set should not contain any element"); + } + } + + [Test] + public void Enumeration_Empty () + { + using (var set = new NSMutableSet ()) { + var count = 0; + foreach (var item in set) { + count++; + } + Assert.AreEqual (0, count, "Should not enumerate any items"); + } + } + + [Test] + public void Enumeration_Single () + { + var v1 = (NSString) "1"; + + using (var set = new NSMutableSet (v1)) { + var count = 0; + NSString found = null; + foreach (var item in set) { + count++; + found = item; + } + Assert.AreEqual (1, count, "Should enumerate one item"); + Assert.AreSame (v1, found, "Should find v1"); + } + } + + [Test] + public void Ctor_Params_Empty () + { + using (var set = new NSMutableSet ()) { + Assert.AreEqual ((nuint) 0, set.Count, "Empty params"); + } + } } } diff --git a/tests/monotouch-test/Foundation/NSMutableSetTest.cs b/tests/monotouch-test/Foundation/NSMutableSetTest.cs index 40d06675b086..e3050be3138c 100644 --- a/tests/monotouch-test/Foundation/NSMutableSetTest.cs +++ b/tests/monotouch-test/Foundation/NSMutableSetTest.cs @@ -64,5 +64,227 @@ public void OperatorPlusReferenceTest () Assert.AreNotEqual (IntPtr.Zero, one.Handle, "Handle must be != IntPtr.Zero"); Assert.AreNotEqual (IntPtr.Zero, two.Handle, "Handle must be != IntPtr.Zero"); } + + [Test] + public void OperatorAdd_BothNull () + { + NSMutableSet first = null; + NSMutableSet second = null; + var result = first + second; + Assert.IsNull (result, "BothNull should return null"); + } + + [Test] + public void OperatorAdd_FirstNull_SecondNonEmpty () + { + NSMutableSet first = null; + using (var second = new NSMutableSet ("1", "2")) + using (var result = first + second) { + Assert.IsNotNull (result, "FirstNull should return new set"); + Assert.AreEqual ((nuint) 2, result.Count, "FirstNull Count"); + Assert.IsTrue (result.Contains ("1"), "FirstNull Contains 1"); + Assert.IsTrue (result.Contains ("2"), "FirstNull Contains 2"); + } + } + + [Test] + public void OperatorAdd_FirstNull_SecondEmpty () + { + NSMutableSet first = null; + using (var second = new NSMutableSet ()) + using (var result = first + second) { + Assert.IsNotNull (result, "FirstNull SecondEmpty should return new set"); + Assert.AreEqual ((nuint) 0, result.Count, "FirstNull SecondEmpty Count"); + } + } + + [Test] + public void OperatorAdd_FirstNonEmpty_SecondNull () + { + using (var first = new NSMutableSet ("1", "2")) + using (var result = first + null) { + Assert.IsNotNull (result, "SecondNull should return new set"); + Assert.AreEqual ((nuint) 2, result.Count, "SecondNull Count"); + Assert.IsTrue (result.Contains ("1"), "SecondNull Contains 1"); + Assert.IsTrue (result.Contains ("2"), "SecondNull Contains 2"); + } + } + + [Test] + public void OperatorAdd_FirstEmpty_SecondNull () + { + using (var first = new NSMutableSet ()) + using (var result = first + null) { + Assert.IsNotNull (result, "FirstEmpty SecondNull should return new set"); + Assert.AreEqual ((nuint) 0, result.Count, "FirstEmpty SecondNull Count"); + } + } + + [Test] + public void OperatorAdd_FirstEmpty_SecondNonEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ("1", "2")) + using (var result = first + second) { + Assert.IsNotNull (result, "FirstEmpty should return copy of second"); + Assert.AreEqual ((nuint) 2, result.Count, "FirstEmpty Count"); + Assert.IsTrue (result.Contains ("1"), "FirstEmpty Contains 1"); + Assert.IsTrue (result.Contains ("2"), "FirstEmpty Contains 2"); + } + } + + [Test] + public void OperatorAdd_FirstNonEmpty_SecondEmpty () + { + using (var first = new NSMutableSet ("1", "2")) + using (var second = new NSMutableSet ()) + using (var result = first + second) { + Assert.IsNotNull (result, "SecondEmpty should return copy of first"); + Assert.AreEqual ((nuint) 2, result.Count, "SecondEmpty Count"); + Assert.IsTrue (result.Contains ("1"), "SecondEmpty Contains 1"); + Assert.IsTrue (result.Contains ("2"), "SecondEmpty Contains 2"); + } + } + + [Test] + public void OperatorAdd_BothEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ()) + using (var result = first + second) { + Assert.IsNotNull (result, "BothEmpty should return new empty set"); + Assert.AreEqual ((nuint) 0, result.Count, "BothEmpty Count"); + } + } + + [Test] + public void OperatorAdd_WithOverlappingElements () + { + using (var first = new NSMutableSet ("1", "2", "3")) + using (var second = new NSMutableSet ("2", "3", "4")) + using (var result = first + second) { + Assert.IsNotNull (result, "Overlapping should return new set"); + Assert.AreEqual ((nuint) 4, result.Count, "Overlapping Count"); + Assert.IsTrue (result.Contains ("1"), "Overlapping Contains 1"); + Assert.IsTrue (result.Contains ("2"), "Overlapping Contains 2"); + Assert.IsTrue (result.Contains ("3"), "Overlapping Contains 3"); + Assert.IsTrue (result.Contains ("4"), "Overlapping Contains 4"); + } + } + + [Test] + public void OperatorSubtract_FirstNull () + { + NSMutableSet first = null; + using (var second = new NSMutableSet ("1", "2")) { + var result = first - second; + Assert.IsNull (result, "FirstNull should return null"); + } + } + + [Test] + public void OperatorSubtract_SecondNull () + { + using (var first = new NSMutableSet ("1", "2")) + using (var result = first - null) { + Assert.IsNotNull (result, "SecondNull should return copy of first"); + Assert.AreEqual ((nuint) 2, result.Count, "SecondNull Count"); + Assert.IsTrue (result.Contains ("1"), "SecondNull Contains 1"); + Assert.IsTrue (result.Contains ("2"), "SecondNull Contains 2"); + } + } + + [Test] + public void OperatorSubtract_BothNull () + { + NSMutableSet first = null; + NSMutableSet second = null; + var result = first - second; + Assert.IsNull (result, "BothNull should return null"); + } + + [Test] + public void OperatorSubtract_FirstEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ("1", "2")) + using (var result = first - second) { + Assert.IsNotNull (result, "FirstEmpty should return empty set"); + Assert.AreEqual ((nuint) 0, result.Count, "FirstEmpty Count"); + } + } + + [Test] + public void OperatorSubtract_SecondEmpty () + { + using (var first = new NSMutableSet ("1", "2")) + using (var second = new NSMutableSet ()) + using (var result = first - second) { + Assert.IsNotNull (result, "SecondEmpty should return copy of first"); + Assert.AreEqual ((nuint) 2, result.Count, "SecondEmpty Count"); + Assert.IsTrue (result.Contains ("1"), "SecondEmpty Contains 1"); + Assert.IsTrue (result.Contains ("2"), "SecondEmpty Contains 2"); + } + } + + [Test] + public void OperatorSubtract_BothEmpty () + { + using (var first = new NSMutableSet ()) + using (var second = new NSMutableSet ()) + using (var result = first - second) { + Assert.IsNotNull (result, "BothEmpty should return empty set"); + Assert.AreEqual ((nuint) 0, result.Count, "BothEmpty Count"); + } + } + + [Test] + public void OperatorSubtract_NoOverlap () + { + using (var first = new NSMutableSet ("1", "2")) + using (var second = new NSMutableSet ("3", "4")) + using (var result = first - second) { + Assert.IsNotNull (result, "NoOverlap should return copy of first"); + Assert.AreEqual ((nuint) 2, result.Count, "NoOverlap Count"); + Assert.IsTrue (result.Contains ("1"), "NoOverlap Contains 1"); + Assert.IsTrue (result.Contains ("2"), "NoOverlap Contains 2"); + } + } + + [Test] + public void OperatorSubtract_PartialOverlap () + { + using (var first = new NSMutableSet ("1", "2", "3")) + using (var second = new NSMutableSet ("2", "3", "4")) + using (var result = first - second) { + Assert.IsNotNull (result, "PartialOverlap should return difference"); + Assert.AreEqual ((nuint) 1, result.Count, "PartialOverlap Count"); + Assert.IsTrue (result.Contains ("1"), "PartialOverlap Contains 1"); + Assert.IsFalse (result.Contains ("2"), "PartialOverlap Not Contains 2"); + Assert.IsFalse (result.Contains ("3"), "PartialOverlap Not Contains 3"); + } + } + + [Test] + public void OperatorSubtract_CompleteOverlap () + { + using (var first = new NSMutableSet ("1", "2", "3")) + using (var second = new NSMutableSet ("1", "2", "3")) + using (var result = first - second) { + Assert.IsNotNull (result, "CompleteOverlap should return empty set"); + Assert.AreEqual ((nuint) 0, result.Count, "CompleteOverlap Count"); + } + } + + [Test] + public void OperatorSubtract_SecondIsSupersetOfFirst () + { + using (var first = new NSMutableSet ("1", "2")) + using (var second = new NSMutableSet ("1", "2", "3", "4")) + using (var result = first - second) { + Assert.IsNotNull (result, "Superset should return empty set"); + Assert.AreEqual ((nuint) 0, result.Count, "Superset Count"); + } + } } } diff --git a/tests/monotouch-test/SceneKit/SCNParticleSystemTest.cs b/tests/monotouch-test/SceneKit/SCNParticleSystemTest.cs new file mode 100644 index 000000000000..ea4427448469 --- /dev/null +++ b/tests/monotouch-test/SceneKit/SCNParticleSystemTest.cs @@ -0,0 +1,537 @@ +// +// Unit tests for SCNParticleSystem +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright 2025 Microsoft Corp. +// + +using System; +using CoreAnimation; +using CoreGraphics; +using Foundation; +using SceneKit; +#if MONOMAC +using AppKit; +#else +using UIKit; +#endif +using Xamarin.Utils; + +namespace MonoTouchFixtures.SceneKit { + + [TestFixture] + [Preserve (AllMembers = true)] + public class SCNParticleSystemTest { + + [Test] + public void Create () + { + using (var ps = SCNParticleSystem.Create ()) { + Assert.IsNotNull (ps, "Create should return non-null"); + Assert.AreNotEqual (IntPtr.Zero, ps.Handle, "Handle should not be zero"); + } + } + + [Test] + public void CreateNamed_Null () + { + Assert.Throws (() => SCNParticleSystem.Create (null, null), "Create with null name should throw"); + } + + [Test] + public void CreateNamed_InvalidName () + { + var ps = SCNParticleSystem.Create ("nonexistent", null); + Assert.IsNull (ps, "Create with invalid name should return null"); + } + + [Test] + public void CreateNamed_NullDirectory () + { + var ps = SCNParticleSystem.Create ("test", null); + // Should not throw, just return null if not found + Assert.IsNull (ps, "Create with null directory should return null if not found"); + } + + [Test] + public void PropertyControllers_Get () + { + using (var ps = SCNParticleSystem.Create ()) { + var controllers = ps.PropertyControllers; + // PropertyControllers can be null initially + // If not null, verify it's a valid object + if (controllers is not null) { + Assert.IsNotNull (controllers, "PropertyControllers should be non-null or null"); + } + } + } + + [Test] + public void PropertyControllers_SetNull () + { + using (var ps = SCNParticleSystem.Create ()) { + ps.PropertyControllers = null; + Assert.IsNull (ps.PropertyControllers, "PropertyControllers should be null after setting to null"); + } + } + + [Test] + public void PropertyControllers_Set () + { + using (var ps = SCNParticleSystem.Create ()) { + var controllers = new SCNPropertyControllers (); + ps.PropertyControllers = controllers; + Assert.IsNotNull (ps.PropertyControllers, "PropertyControllers should be non-null after setting"); + } + } + + [Test] + public void PropertyControllers_EmptyConstructor () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNotNull (controllers, "Empty constructor should create valid object"); + } + + [Test] + public void PropertyControllers_Position () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Position, "Position should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Position = controller; + Assert.IsNotNull (controllers.Position, "Position should be non-null after setting"); + } + + controllers.Position = null; + Assert.IsNull (controllers.Position, "Position should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Angle () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Angle, "Angle should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Angle = controller; + Assert.IsNotNull (controllers.Angle, "Angle should be non-null after setting"); + } + + controllers.Angle = null; + Assert.IsNull (controllers.Angle, "Angle should be null after setting to null"); + } + + [Test] + public void PropertyControllers_RotationAxis () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.RotationAxis, "RotationAxis should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.RotationAxis = controller; + Assert.IsNotNull (controllers.RotationAxis, "RotationAxis should be non-null after setting"); + } + + controllers.RotationAxis = null; + Assert.IsNull (controllers.RotationAxis, "RotationAxis should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Velocity () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Velocity, "Velocity should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Velocity = controller; + Assert.IsNotNull (controllers.Velocity, "Velocity should be non-null after setting"); + } + + controllers.Velocity = null; + Assert.IsNull (controllers.Velocity, "Velocity should be null after setting to null"); + } + + [Test] + public void PropertyControllers_AngularVelocity () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.AngularVelocity, "AngularVelocity should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.AngularVelocity = controller; + Assert.IsNotNull (controllers.AngularVelocity, "AngularVelocity should be non-null after setting"); + } + + controllers.AngularVelocity = null; + Assert.IsNull (controllers.AngularVelocity, "AngularVelocity should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Life () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Life, "Life should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Life = controller; + Assert.IsNotNull (controllers.Life, "Life should be non-null after setting"); + } + + controllers.Life = null; + Assert.IsNull (controllers.Life, "Life should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Color () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Color, "Color should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Color = controller; + Assert.IsNotNull (controllers.Color, "Color should be non-null after setting"); + } + + controllers.Color = null; + Assert.IsNull (controllers.Color, "Color should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Opacity () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Opacity, "Opacity should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Opacity = controller; + Assert.IsNotNull (controllers.Opacity, "Opacity should be non-null after setting"); + } + + controllers.Opacity = null; + Assert.IsNull (controllers.Opacity, "Opacity should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Size () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Size, "Size should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Size = controller; + Assert.IsNotNull (controllers.Size, "Size should be non-null after setting"); + } + + controllers.Size = null; + Assert.IsNull (controllers.Size, "Size should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Frame () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Frame, "Frame should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Frame = controller; + Assert.IsNotNull (controllers.Frame, "Frame should be non-null after setting"); + } + + controllers.Frame = null; + Assert.IsNull (controllers.Frame, "Frame should be null after setting to null"); + } + + [Test] + public void PropertyControllers_FrameRate () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.FrameRate, "FrameRate should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.FrameRate = controller; + Assert.IsNotNull (controllers.FrameRate, "FrameRate should be non-null after setting"); + } + + controllers.FrameRate = null; + Assert.IsNull (controllers.FrameRate, "FrameRate should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Bounce () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Bounce, "Bounce should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Bounce = controller; + Assert.IsNotNull (controllers.Bounce, "Bounce should be non-null after setting"); + } + + controllers.Bounce = null; + Assert.IsNull (controllers.Bounce, "Bounce should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Charge () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Charge, "Charge should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Charge = controller; + Assert.IsNotNull (controllers.Charge, "Charge should be non-null after setting"); + } + + controllers.Charge = null; + Assert.IsNull (controllers.Charge, "Charge should be null after setting to null"); + } + + [Test] + public void PropertyControllers_Friction () + { + var controllers = new SCNPropertyControllers (); + Assert.IsNull (controllers.Friction, "Friction should be null initially"); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Friction = controller; + Assert.IsNotNull (controllers.Friction, "Friction should be non-null after setting"); + } + + controllers.Friction = null; + Assert.IsNull (controllers.Friction, "Friction should be null after setting to null"); + } + + [Test] + public void PropertyControllers_MultipleProperties () + { + var controllers = new SCNPropertyControllers (); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var posController = SCNParticlePropertyController.Create (animation)) + using (var colorController = SCNParticlePropertyController.Create (animation)) + using (var sizeController = SCNParticlePropertyController.Create (animation)) { + controllers.Position = posController; + controllers.Color = colorController; + controllers.Size = sizeController; + + Assert.IsNotNull (controllers.Position, "Position should be set"); + Assert.IsNotNull (controllers.Color, "Color should be set"); + Assert.IsNotNull (controllers.Size, "Size should be set"); + } + } + + [Test] + public void PropertyControllers_ReplaceProperty () + { + var controllers = new SCNPropertyControllers (); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller1 = SCNParticlePropertyController.Create (animation)) + using (var controller2 = SCNParticlePropertyController.Create (animation)) { + controllers.Position = controller1; + Assert.IsNotNull (controllers.Position, "Position should be set to first controller"); + + controllers.Position = controller2; + Assert.IsNotNull (controllers.Position, "Position should be set to second controller"); + + controllers.Position = null; + Assert.IsNull (controllers.Position, "Position should be null after clearing"); + } + } + + [Test] + public void AddAnimation () + { + using (var ps = SCNParticleSystem.Create ()) + using (var animation = CAAnimation.CreateAnimation ()) { + ps.AddAnimation (animation, (string) null); + ps.AddAnimation (animation, "key1"); + ps.RemoveAllAnimations (); + } + } + + [Test] + public void AddAnimation_NullAnimation () + { + using (var ps = SCNParticleSystem.Create ()) { + Assert.Throws (() => ps.AddAnimation ((CAAnimation) null, "key"), "AddAnimation with null should throw"); + } + } + + [Test] + public void GetAnimationKeys () + { + using (var ps = SCNParticleSystem.Create ()) { + var keys = ps.GetAnimationKeys (); + Assert.IsNotNull (keys, "GetAnimationKeys should return non-null"); + Assert.AreEqual (0, keys.Length, "Should have no animation keys initially"); + + using (var animation = CAAnimation.CreateAnimation ()) { + ps.AddAnimation (animation, "key1"); + keys = ps.GetAnimationKeys (); + Assert.AreEqual (1, keys.Length, "Should have one animation key"); + } + } + } + + [Test] + public void RemoveAllAnimations () + { + using (var ps = SCNParticleSystem.Create ()) + using (var animation = CAAnimation.CreateAnimation ()) { + ps.AddAnimation (animation, "key1"); + ps.AddAnimation (animation, "key2"); + var keys = ps.GetAnimationKeys (); + Assert.AreEqual (2, keys.Length, "Should have two animation keys"); + + ps.RemoveAllAnimations (); + keys = ps.GetAnimationKeys (); + Assert.AreEqual (0, keys.Length, "Should have no animation keys after removal"); + } + } + + [Test] + public void Copy () + { + using (var ps = SCNParticleSystem.Create ()) + using (var copy = ps.Copy (null)) { + Assert.IsNotNull (copy, "Copy should return non-null"); + Assert.AreNotEqual (ps.Handle, copy.Handle, "Copy should have different handle"); + } + } + + [Test] + public void NSCoding () + { + using (var ps = SCNParticleSystem.Create ()) { + // Test encoding/decoding + var data = NSKeyedArchiver.GetArchivedData (ps, true, out var error); + Assert.IsNotNull (data, "Encoding should produce data"); + Assert.IsNull (error, "Encoding should not produce error"); + + var decoded = NSKeyedUnarchiver.GetUnarchivedObject (typeof (SCNParticleSystem), data, out error); + Assert.IsNotNull (decoded, "Decoding should produce object"); + Assert.IsNull (error, "Decoding should not produce error"); + Assert.IsInstanceOf (decoded, "Decoded object should be SCNParticleSystem"); + } + } + + [Test] + public void AddModifier_NullProperties () + { + using (var ps = SCNParticleSystem.Create ()) { + Assert.Throws (() => ps.AddModifier (null, SCNParticleModifierStage.PreDynamics, (data, dataStride, start, end, deltaTime) => { }), "AddModifier with null properties should throw"); + } + } + + [Test] + public void AddModifier_NullHandler () + { + using (var ps = SCNParticleSystem.Create ()) { + var properties = new NSString [] { (NSString) "position" }; + Assert.Throws (() => ps.AddModifier (properties, SCNParticleModifierStage.PreDynamics, null), "AddModifier with null handler should throw"); + } + } + + [Test] + public void AddModifier_EmptyProperties () + { + using (var ps = SCNParticleSystem.Create ()) { + var properties = new NSString [0]; + // Should not throw with empty array + ps.AddModifier (properties, SCNParticleModifierStage.PreDynamics, (data, dataStride, start, end, deltaTime) => { }); + } + } + + [Test] + public void HandleEvent_NullProperties () + { + using (var ps = SCNParticleSystem.Create ()) { + Assert.Throws (() => ps.HandleEvent (SCNParticleEvent.Birth, null, (data, dataStride, indices, count) => { }), "HandleEvent with null properties should throw"); + } + } + + [Test] + public void HandleEvent_NullHandler () + { + using (var ps = SCNParticleSystem.Create ()) { + var properties = new NSString [] { (NSString) "position" }; + Assert.Throws (() => ps.HandleEvent (SCNParticleEvent.Birth, properties, null), "HandleEvent with null handler should throw"); + } + } + + [Test] + public void HandleEvent_EmptyProperties () + { + using (var ps = SCNParticleSystem.Create ()) { + var properties = new NSString [0]; + // Should not throw with empty array + ps.HandleEvent (SCNParticleEvent.Birth, properties, (data, dataStride, indices, count) => { }); + } + } + + [Test] + public void PropertyControllers_RoundTrip () + { + using (var ps = SCNParticleSystem.Create ()) { + var controllers = new SCNPropertyControllers (); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var posController = SCNParticlePropertyController.Create (animation)) { + controllers.Position = posController; + ps.PropertyControllers = controllers; + + var retrieved = ps.PropertyControllers; + Assert.IsNotNull (retrieved, "Retrieved PropertyControllers should not be null"); + Assert.IsNotNull (retrieved.Position, "Retrieved Position controller should not be null"); + } + } + } + + [Test] + public void PropertyControllers_ClearAllProperties () + { + var controllers = new SCNPropertyControllers (); + + using (var animation = CAAnimation.CreateAnimation ()) + using (var controller = SCNParticlePropertyController.Create (animation)) { + controllers.Position = controller; + controllers.Angle = controller; + controllers.Velocity = controller; + controllers.Color = controller; + + Assert.IsNotNull (controllers.Position, "Position should be set"); + Assert.IsNotNull (controllers.Angle, "Angle should be set"); + Assert.IsNotNull (controllers.Velocity, "Velocity should be set"); + Assert.IsNotNull (controllers.Color, "Color should be set"); + + controllers.Position = null; + controllers.Angle = null; + controllers.Velocity = null; + controllers.Color = null; + + Assert.IsNull (controllers.Position, "Position should be null"); + Assert.IsNull (controllers.Angle, "Angle should be null"); + Assert.IsNull (controllers.Velocity, "Velocity should be null"); + Assert.IsNull (controllers.Color, "Color should be null"); + } + } + } +} diff --git a/tests/monotouch-test/Security/IdentityTest.cs b/tests/monotouch-test/Security/IdentityTest.cs index f20f591f4366..a6e1084901a4 100644 --- a/tests/monotouch-test/Security/IdentityTest.cs +++ b/tests/monotouch-test/Security/IdentityTest.cs @@ -19,12 +19,7 @@ public class IdentityTest { static public SecIdentity GetIdentity () { - using (var options = NSDictionary.FromObjectAndKey (new NSString ("farscape"), SecImportExport.Passphrase)) { - NSDictionary [] array; - var rv = SecImportExport.ImportPkcs12 (ImportExportTest.farscape_pfx, options, out array); - Assert.That (rv, Is.EqualTo (SecStatusCode.Success), "ImportPkcs12"); - return Runtime.GetINativeObject (array [0].LowlevelObjectForKey (SecImportExport.Identity.Handle), false); - } + return SecIdentity.Import (ImportExportTest.farscape_pfx, "farscape"); } [Test] diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs index 2a6b2e271cbf..75f52139b7af 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ACToolTaskTest.cs @@ -25,8 +25,6 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i var sdk = Sdks.GetAppleSdk (platform); var version = AppleSdkVersion.UseDefault.ToString (); var root = sdk.GetSdkPath (version, false); - var usr = Path.Combine (sdk.DeveloperRoot, "usr"); - var bin = Path.Combine (usr, "bin"); string sdkPlatform; var uiDeviceFamily = ""; @@ -66,8 +64,6 @@ ACTool CreateACToolTask (ApplePlatform platform, string projectDir, out string i task.SdkDevPath = Configuration.xcode_root; task.SdkPlatform = sdkPlatform; task.SdkVersion = version.ToString (); - task.SdkUsrPath = usr; - task.SdkBinPath = bin; task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform).ToString (); task.UIDeviceFamily = uiDeviceFamily; return task; diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs index bcd3e301aa05..b52c18919861 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CreateBindingResourceTaskTests.cs @@ -94,9 +94,8 @@ void Extract (string zipArchive, string targetDirectory) unzipArguments.Add ("-d"); unzipArguments.Add (targetDirectory); unzipArguments.Add (zipArchive); - var output = new StringBuilder (); - var rv = Execution.RunWithStringBuildersAsync ("unzip", unzipArguments, standardOutput: output, standardError: output).Result; - Assert.AreEqual (0, rv.ExitCode, "ExitCode\n" + output.ToString ()); + var rv = Execution.RunAsync ("unzip", unzipArguments).Result; + Assert.AreEqual (0, rv.ExitCode, "ExitCode\n" + rv.Output.MergedOutput); } void AssertResourceDirectory (string directory, bool symlinks) diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs index e419c6de6cca..8c301b35e3c8 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/IBToolTaskTests.cs @@ -22,8 +22,6 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte var sdk = Sdks.GetSdk (framework); var version = AppleSdkVersion.GetDefault (sdk, false); var root = sdk.GetSdkPath (version, false); - var usr = Path.Combine (sdk.DeveloperRoot, "usr"); - var bin = Path.Combine (usr, "bin"); string platform; switch (framework) { @@ -50,8 +48,6 @@ IBTool CreateIBToolTask (ApplePlatform framework, string projectDir, string inte task.SdkDevPath = Configuration.xcode_root; task.SdkPlatform = platform; task.SdkVersion = version.ToString (); - task.SdkUsrPath = usr; - task.SdkBinPath = bin; task.SdkRoot = root; task.TargetFrameworkMoniker = TargetFramework.DotNet_iOS_String; return task; diff --git a/tests/xtro-sharpie/api-annotations-dotnet/common-Foundation.ignore b/tests/xtro-sharpie/api-annotations-dotnet/common-Foundation.ignore index 2fcae0dca80a..d285ab995faf 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/common-Foundation.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/common-Foundation.ignore @@ -1008,7 +1008,6 @@ !missing-null-allowed! 'Foundation.NSObject Foundation.NSKeyedArchiverDelegate::WillEncode(Foundation.NSKeyedArchiver,Foundation.NSObject)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSObject Foundation.NSKeyedUnarchiverDelegate::DecodedObject(Foundation.NSKeyedUnarchiver,Foundation.NSObject)' is missing an [NullAllowed] on parameter #1 !missing-null-allowed! 'Foundation.NSObject Foundation.NSKeyedUnarchiverDelegate::DecodedObject(Foundation.NSKeyedUnarchiver,Foundation.NSObject)' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSObject Foundation.NSLocale::ObjectForKey(Foundation.NSString)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSObject Foundation.NSMetadataItem::ValueForAttribute(System.String)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSObject Foundation.NSMetadataQuery::ValueOfAttribute(System.String,System.IntPtr)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSObject Foundation.NSMetadataQueryAttributeValueTuple::get_Value()' is missing an [NullAllowed] on return type @@ -1027,7 +1026,6 @@ !missing-null-allowed! 'Foundation.NSOrthography Foundation.NSTextCheckingResult::get_Orthography()' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSProgress Foundation.NSProgress::get_CurrentProgress()' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSRegularExpression Foundation.NSRegularExpression::Create(Foundation.NSString,Foundation.NSRegularExpressionOptions,Foundation.NSError&)' is missing an [NullAllowed] on return type -!missing-null-allowed! 'Foundation.NSString Foundation.NSLocale::DisplayNameForKey(Foundation.NSString,System.String)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSString Foundation.NSRunLoop::get_CurrentMode()' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSString Foundation.NSString::AppendPathExtension(Foundation.NSString)' is missing an [NullAllowed] on return type !missing-null-allowed! 'Foundation.NSString Foundation.NSUrlUtilities_NSString::CreateStringByAddingPercentEncoding(Foundation.NSString,Foundation.NSCharacterSet)' is missing an [NullAllowed] on return type diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-GLKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-GLKit.ignore index a53149aeb633..205372105779 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-GLKit.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-GLKit.ignore @@ -51,7 +51,6 @@ !missing-pinvoke! NSStringFromGLKVector4 is not bound # Initial result from new rule missing-release-attribute-on-return-value -!missing-release-attribute-on-return-value! GLKit.GLKMesh[] GLKit.GLKMesh::FromAsset(ModelIO.MDLAsset,Foundation.NSArray&,Foundation.NSError&)'s selector's ('newMeshesFromAsset:sourceMeshes:error:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferWithData:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:data:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,System.UIntPtr,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:length:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-GLKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-GLKit.ignore index a53149aeb633..205372105779 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-GLKit.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-GLKit.ignore @@ -51,7 +51,6 @@ !missing-pinvoke! NSStringFromGLKVector4 is not bound # Initial result from new rule missing-release-attribute-on-return-value -!missing-release-attribute-on-return-value! GLKit.GLKMesh[] GLKit.GLKMesh::FromAsset(ModelIO.MDLAsset,Foundation.NSArray&,Foundation.NSError&)'s selector's ('newMeshesFromAsset:sourceMeshes:error:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferWithData:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:data:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,System.UIntPtr,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:length:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. diff --git a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-GLKit.ignore b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-GLKit.ignore index a53149aeb633..205372105779 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/tvOS-GLKit.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/tvOS-GLKit.ignore @@ -51,7 +51,6 @@ !missing-pinvoke! NSStringFromGLKVector4 is not bound # Initial result from new rule missing-release-attribute-on-return-value -!missing-release-attribute-on-return-value! GLKit.GLKMesh[] GLKit.GLKMesh::FromAsset(ModelIO.MDLAsset,Foundation.NSArray&,Foundation.NSError&)'s selector's ('newMeshesFromAsset:sourceMeshes:error:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferWithData:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,Foundation.NSData,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:data:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. !missing-release-attribute-on-return-value! ModelIO.IMDLMeshBuffer GLKit.GLKMeshBufferAllocator::CreateBuffer(ModelIO.IMDLMeshBufferZone,System.UIntPtr,ModelIO.MDLMeshBufferType)'s selector's ('newBufferFromZone:length:type:') Objective-C method family ('new') indicates that the native method returns a retained object, and as such a '[return: Release]' attribute is required. diff --git a/tools/common/Execution.cs b/tools/common/Execution.cs index ec5e43ed4b38..bd136fae72f7 100644 --- a/tools/common/Execution.cs +++ b/tools/common/Execution.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; using System.Threading; @@ -18,6 +19,91 @@ #nullable enable namespace Xamarin.Utils { + public class ExecutionOutput { + public bool Complete { get; internal set; } + + List<(bool IsError, string Line)> lines = new (); + + void VerifyComplete () + { + if (!Complete) + throw new InvalidOperationException ("Cannot read output before execution is complete."); + } + + void VerifyNotComplete () + { + if (Complete) + throw new InvalidOperationException ("Cannot write output after execution is complete."); + } + + public IEnumerable StandardOutputLines { + get { + VerifyComplete (); + foreach (var (isError, line) in lines) { + if (!isError) + yield return line; + } + } + } + + public IEnumerable StandardErrorLines { + get { + VerifyComplete (); + foreach (var (isError, line) in lines) { + if (isError) + yield return line; + } + } + } + + public string StandardOutput { + get { + VerifyComplete (); + var sb = new StringBuilder (); + foreach (var line in StandardOutputLines) { + sb.AppendLine (line); + } + return sb.ToString (); + } + } + + public string StandardError { + get { + VerifyComplete (); + var sb = new StringBuilder (); + foreach (var line in StandardErrorLines) { + sb.AppendLine (line); + } + return sb.ToString (); + } + } + + public string MergedOutput { + get { + VerifyComplete (); + var sb = new StringBuilder (); + foreach (var (isError, line) in lines) { + sb.AppendLine (line); + } + return sb.ToString (); + } + } + + public void WriteStandardOutput (string line) + { + VerifyNotComplete (); + lock (lines) + lines.Add ((false, line)); + } + + public void WriteStandardError (string line) + { + VerifyNotComplete (); + lock (lines) + lines.Add ((true, line)); + } + } + public class Execution { public string? FileName; public IList? Arguments; @@ -30,18 +116,21 @@ public class Execution { public int ExitCode { get; private set; } public bool TimedOut { get; private set; } - public TextWriter? StandardOutput { get; private set; } - public TextWriter? StandardError { get; private set; } + + public Action? StandardOutputLineCallback; + public Action? StandardErrorLineCallback; + + public ExecutionOutput Output { get; private set; } = new ExecutionOutput (); public TimeSpan Duration { get; private set; } - static Thread StartOutputThread (TaskCompletionSource tcs, object lockobj, StreamReader reader, TextWriter writer, string thread_name) + static Thread StartOutputThread (TaskCompletionSource tcs, object lockobj, StreamReader reader, Action writer, string thread_name) { var thread = new Thread (() => { try { while (reader.ReadLine () is string line) { lock (lockobj) - writer.WriteLine (line); + writer (line); } } catch (Exception e) { tcs.TrySetException (e); @@ -91,8 +180,8 @@ public Task RunAsync () } } - StandardOutput ??= new StringWriter (); - StandardError ??= new StringWriter (); + StandardErrorLineCallback ??= Output.WriteStandardError; + StandardOutputLineCallback ??= Output.WriteStandardOutput; var thread = new Thread (() => { try { @@ -106,8 +195,8 @@ public Task RunAsync () p.Start (); var pid = p.Id; - var stdoutThread = StartOutputThread (tcs, lockobj, p.StandardOutput, StandardOutput, $"StandardOutput reader for {p.StartInfo.FileName} (PID: {pid})"); - var stderrThread = StartOutputThread (tcs, lockobj, p.StandardError, StandardError, $"StandardError reader for {p.StartInfo.FileName} (PID: {pid})"); + var stdoutThread = StartOutputThread (tcs, lockobj, p.StandardOutput, StandardOutputLineCallback, $"StandardOutput reader for {p.StartInfo.FileName} (PID: {pid})"); + var stderrThread = StartOutputThread (tcs, lockobj, p.StandardError, StandardErrorLineCallback, $"StandardError reader for {p.StartInfo.FileName} (PID: {pid})"); CancellationToken?.Register (() => { // Don't call tcs.TrySetCanceled, that won't return an Execution result to the caller. @@ -139,7 +228,7 @@ public Task RunAsync () stdoutThread.Join (TimeSpan.FromSeconds (1)); stderrThread.Join (TimeSpan.FromSeconds (1)); - + Output.Complete = true; tcs.TrySetResult (this); } catch (Exception e) { tcs.TrySetException (e); @@ -160,25 +249,27 @@ public Task RunAsync () public static Task RunWithCallbacksAsync (string filename, IList arguments, Dictionary? environment = null, Action? standardOutput = null, Action? standardError = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) { - CallbackWriter? outputCallback = null; - CallbackWriter? errorCallback = null; - if (standardOutput is not null) - outputCallback = new CallbackWriter { Callback = standardOutput }; - if (standardOutput == standardError) - errorCallback = outputCallback; - else if (standardError is not null) - errorCallback = new CallbackWriter { Callback = standardError }; - return RunAsync (filename, arguments, environment, outputCallback, errorCallback, log, workingDirectory, timeout, cancellationToken); + return new Execution { + FileName = filename, + Arguments = arguments, + Environment = environment, + StandardOutputLineCallback = standardOutput, + StandardErrorLineCallback = standardError, + WorkingDirectory = workingDirectory, + CancellationToken = cancellationToken, + Timeout = timeout, + Log = log, + }.RunAsync (); } - public static Task RunAsync (string filename, IList arguments, Dictionary? environment = null, TextWriter? standardOutput = null, TextWriter? standardError = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) + public static Task RunWithTextWritersAsync (string filename, IList arguments, Dictionary? environment = null, TextWriter? standardOutput = null, TextWriter? standardError = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) { return new Execution { FileName = filename, Arguments = arguments, Environment = environment, - StandardOutput = standardOutput, - StandardError = standardError, + StandardOutputLineCallback = standardOutput is null ? null : standardOutput.WriteLine, + StandardErrorLineCallback = standardError is null ? null : standardError.WriteLine, WorkingDirectory = workingDirectory, CancellationToken = cancellationToken, Timeout = timeout, @@ -186,29 +277,36 @@ public static Task RunAsync (string filename, IList arguments }.RunAsync (); } - public static Task RunAsync (string filename, IList arguments, Dictionary? environment = null, bool mergeOutput = false, string? workingDirectory = null, TextWriter? log = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) + public static Task RunAsync (string filename, IList arguments, Dictionary? environment = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) { - var standardOutput = new StringWriter (); - var standardError = mergeOutput ? standardOutput : new StringWriter (); - return RunAsync (filename, arguments, environment, standardOutput, standardError, log, workingDirectory, timeout, cancellationToken); + return new Execution { + FileName = filename, + Arguments = arguments, + Environment = environment, + WorkingDirectory = workingDirectory, + CancellationToken = cancellationToken, + Timeout = timeout, + Log = log, + }.RunAsync (); } - public static Task RunWithStringBuildersAsync (string filename, IList arguments, Dictionary? environment = null, StringBuilder? standardOutput = null, StringBuilder? standardError = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) + [Obsolete ("Use 'RunAsync' instead.")] + public static async Task RunWithStringBuildersAsync (string filename, IList arguments, Dictionary? environment = null, StringBuilder? standardOutput = null, StringBuilder? standardError = null, TextWriter? log = null, string? workingDirectory = null, TimeSpan? timeout = null, CancellationToken? cancellationToken = null) { - var stdout = standardOutput is null ? null : new StringWriter (standardOutput); - var stderr = standardError is null ? null : (standardOutput == standardError ? stdout : new StringWriter (standardError)); - return RunAsync (filename, arguments, environment, stdout, stderr, log, workingDirectory, timeout, cancellationToken); - } - - class CallbackWriter : TextWriter { - public Action? Callback; - public override void WriteLine (string? value) - { - if (value is not null) - Callback?.Invoke (value); + var rv = await RunAsync (filename, arguments, environment, log, workingDirectory, timeout, cancellationToken); + if (standardOutput is not null) { + if (standardError == standardOutput) { + standardOutput.Append (rv.Output.MergedOutput); + } else { + standardOutput.Append (rv.Output.StandardOutput); + if (standardError is not null) { + standardError.Append (rv.Output.StandardError); + } + } + } else if (standardError is not null) { + standardError.Append (rv.Output.StandardError); } - - public override Encoding Encoding => Encoding.UTF8; + return rv; } } }