Clarify usage of `[NullAllowed]` in our bindings (#5417)

First part to fix https://github.com/xamarin/xamarin-macios/issues/5416

We currently allow the `[NullAllowed]` attribute anywhere an attribute
can be used on metadata (i.e. no `AttributeUsage` is used).

However the generator only process the attribute in some specific cases,
*silently* ignoring others. This leads to situations such as

```csharp
[NullAllowed, Export ("setInputHandler:")]
void SetInputHandler (AUInputHandler handler);
```

where a `null` argument will throw an `ArgumentNullException` because
`[NullAllowed]` does not mean anything on a method declaration.

To avoid such confusion `[NullAllowed]` should be added on each parameter
(even if all of them requires it) and if a `null` return value is
possible then use `[return: NullAllowed]`.

This PR allows XI/XM bindings to be built, without error, when this
patch is applied.

```diff
diff --git a/src/generator-attributes.cs b/src/generator-attributes.cs
index 965d8469..77162253 100644
--- a/src/generator-attributes.cs
+++ b/src/generator-attributes.cs
@@ -250,6 +250,7 @@ public class IsThreadStaticAttribute : Attribute {

 // When applied to a member, generates the member as static
 // and passes IntPtr.Zero or null if the parameter is null
+[AttributeUsage (AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Parameter)]
 public class NullAllowedAttribute : Attribute {
        public NullAllowedAttribute () {}
 }
```

Note that it's unlikely we'll apply this patch _as-is_ to avoid breaking
existing projects. A better approach (in a future PR) is to have the
generator (instead of the C# compiler) issue a warning (instead of an
error) when a `NullAllowed` is ignored.
This commit is contained in:
Sebastien Pouliot 2019-01-16 09:42:45 -05:00 коммит произвёл GitHub
Родитель 34ca0496fc
Коммит 8757f36ca5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 103 добавлений и 67 удалений

Просмотреть файл

@ -608,7 +608,8 @@ namespace AppKit {
NSMenu MainMenu { get; set; }
[Export ("helpMenu", ArgumentSemantic.Retain)]
NSMenu HelpMenu { get; [NullAllowed] set; }
[NullAllowed]
NSMenu HelpMenu { get; set; }
[Export ("applicationIconImage", ArgumentSemantic.Retain)]
NSImage ApplicationIconImage { get; set; }
@ -1116,7 +1117,8 @@ namespace AppKit {
NSObject [] SortDescriptors { get; set; }
[Export ("filterPredicate", ArgumentSemantic.Retain)]
NSPredicate FilterPredicate { get; [NullAllowed] set; }
[NullAllowed]
NSPredicate FilterPredicate { get; set; }
[Export ("clearsFilterPredicateOnInsertion")]
bool ClearsFilterPredicateOnInsertion { get; set; }
@ -5511,7 +5513,8 @@ namespace AppKit {
void ShouldCloseWindowController (NSWindowController windowController, NSObject delegateObject, Selector shouldCloseSelector, IntPtr contextInfo);
[Export ("displayName")]
string DisplayName { get; [NullAllowed] set; }
[NullAllowed]
string DisplayName { get; set; }
[Export ("windowForSheet")]
NSWindow WindowForSheet { get; }
@ -8117,7 +8120,8 @@ namespace AppKit {
NSMenu Menu { get; set; }
[Export ("submenu", ArgumentSemantic.Retain)]
NSMenu Submenu { get; [NullAllowed] set; }
[NullAllowed]
NSMenu Submenu { get; set; }
[Export ("title")]
string Title { get; set; }
@ -10040,7 +10044,8 @@ namespace AppKit {
//Detected properties
[Export ("image", ArgumentSemantic.Retain)]
NSImage Image { get; [NullAllowed] set; }
[NullAllowed]
NSImage Image { get; set; }
[Export ("imageAlignment")]
NSImageAlignment ImageAlignment { get; set; }
@ -12738,7 +12743,7 @@ namespace AppKit {
interface NSResponder_NSTouchBarProvider : INSTouchBarProvider
{
[Mac (10, 12, 2)]
[NullAllowed, Export ("touchBar")]
[Export ("touchBar")]
NSTouchBar GetTouchBar ();
[Mac (10, 12, 2)]
@ -12746,7 +12751,7 @@ namespace AppKit {
void SetTouchBar ([NullAllowed]NSTouchBar bar);
[Mac (10, 12, 2)]
[NullAllowed, Export ("makeTouchBar")]
[Export ("makeTouchBar")]
NSTouchBar MakeTouchBar ();
}
@ -14808,7 +14813,8 @@ namespace AppKit {
[Availability (Deprecated = Platform.Mac_10_10, Message = "Soft-deprecation, forwards message to button, but will be gone in the future.")]
[Export ("view")]
NSView View { get; [NullAllowed] set; }
[NullAllowed]
NSView View { get; set; }
[Mac (10,10)]
[Export ("button", ArgumentSemantic.Retain)]
@ -20490,7 +20496,8 @@ namespace AppKit {
void MenuChanged (NSMenu menu);
[Export ("windowController")]
NSObject WindowController { get; [NullAllowed] set; }
[NullAllowed]
NSObject WindowController { get; set; }
[Export ("isSheet")]
bool IsSheet { get; }
@ -20555,7 +20562,8 @@ namespace AppKit {
NSSelectionDirection KeyViewSelectionDirection ();
[Export ("defaultButtonCell")]
NSButtonCell DefaultButtonCell { get; [NullAllowed] set; }
[NullAllowed]
NSButtonCell DefaultButtonCell { get; set; }
[Export ("disableKeyEquivalentForDefaultButtonCell")]
void DisableKeyEquivalentForDefaultButtonCell ();
@ -25763,7 +25771,7 @@ namespace AppKit {
interface NSView_NSCandidateListTouchBarItem
{
[Mac (10, 12, 2)]
[NullAllowed, Export ("candidateListTouchBarItem")]
[Export ("candidateListTouchBarItem")]
NSCandidateListTouchBarItem GetCandidateListTouchBarItem ();
}

Просмотреть файл

@ -311,11 +311,11 @@ namespace AudioUnit {
[Export ("setOutputEnabled:")]
bool SetOutputEnabled (bool enabled);
[NullAllowed, Export ("inputHandler", ArgumentSemantic.Copy)]
[Export ("inputHandler", ArgumentSemantic.Copy)]
AUInputHandler GetInputHandler ();
[NullAllowed, Export ("setInputHandler:")]
void SetInputHandler (AUInputHandler handler);
[Export ("setInputHandler:")]
void SetInputHandler ([NullAllowed] AUInputHandler handler);
[Export ("startHardwareAndReturnError:")]
bool StartHardware ([NullAllowed] out NSError outError);
@ -323,11 +323,11 @@ namespace AudioUnit {
[Export ("stopHardware")]
void StopHardware ();
[NullAllowed, Export ("outputProvider", ArgumentSemantic.Copy)]
[Export ("outputProvider", ArgumentSemantic.Copy)]
AURenderPullInputBlock GetOutputProvider ();
[NullAllowed, Export ("setOutputProvider:")]
void SetOutputProvider (AURenderPullInputBlock provider);
[Export ("setOutputProvider:")]
void SetOutputProvider ([NullAllowed] AURenderPullInputBlock provider);
// the following are properties but we cannot have properties in Categories.
[Mac (10, 13), NoWatch, NoiOS, NoTV]

Просмотреть файл

@ -13226,7 +13226,8 @@ namespace Foundation
bool LockBeforeDate (NSDate limit);
[Export ("name")]
string Name { get; [NullAllowed] set; }
[NullAllowed]
string Name { get; set; }
}
[BaseType (typeof(NSObject))]
@ -13258,7 +13259,8 @@ namespace Foundation
bool LockWhenCondition (nint condition, NSDate limit);
[Export ("name")]
string Name { get; [NullAllowed] set; }
[NullAllowed]
string Name { get; set; }
}
[BaseType (typeof(NSObject))]
@ -13271,7 +13273,8 @@ namespace Foundation
bool LockBeforeDate (NSDate limit);
[Export ("name")]
string Name { get; [NullAllowed] set; }
[NullAllowed]
string Name { get; set; }
}
[BaseType (typeof(NSObject))]
@ -13290,7 +13293,8 @@ namespace Foundation
void Broadcast ();
[Export ("name")]
string Name { get; [NullAllowed] set; }
[NullAllowed]
string Name { get; set; }
}
// Not yet, the IntPtr[] argument isn't handled correctly by the generator (it tries to convert to NSArray, while the native method expects a C array).

Просмотреть файл

@ -500,7 +500,7 @@ namespace GameKit {
[NoWatch]
[Deprecated (PlatformName.iOS, 7, 0, message : "Use 'InitWithLeaderboardIdentifier' instead.")]
[Deprecated (PlatformName.MacOSX, 10, 10, message : "Use 'InitWithLeaderboardIdentifier' instead.")]
[Internal][NullAllowed]
[Internal]
[Export ("initWithCategory:")]
IntPtr InitWithCategory ([NullAllowed] string category);
@ -515,7 +515,7 @@ namespace GameKit {
IntPtr Constructor (string identifier, string playerID);
[iOS (7,0)][Mac (10,10)]
[Internal][NullAllowed]
[Internal]
[Export ("initWithLeaderboardIdentifier:")]
IntPtr InitWithLeaderboardIdentifier (string identifier);

Просмотреть файл

@ -1385,7 +1385,7 @@ namespace GameplayKit {
IGKRandom RandomSource { get; set; }
[Abstract]
[NullAllowed, Export ("bestMoveForActivePlayer")]
[Export ("bestMoveForActivePlayer")]
IGKGameModelUpdate GetBestMoveForActivePlayer ();
}

Просмотреть файл

@ -223,7 +223,6 @@ namespace iAd {
void SetCanDisplayBannerAds (bool value);
[iOS (7,0), Export ("originalContentView")]
[NullAllowed]
UIView GetOriginalContentView ();
[iOS (7,0), Export ("isPresentingFullScreenAd")]

Просмотреть файл

@ -2980,7 +2980,7 @@ namespace Intents {
INImage GetImage (string parameterName);
[Watch (5,0), Mac (10,14, onlyOn64: true), iOS (12,0)]
[NullAllowed, Export ("keyImage")]
[Export ("keyImage")]
INImage GetKeyImage ();
}
@ -6340,7 +6340,7 @@ namespace Intents {
[BaseType (typeof (NSUserActivity))]
interface NSUserActivity_IntentsAdditions {
[NullAllowed, Export ("interaction")]
[Export ("interaction")]
INInteraction GetInteraction ();
}

Просмотреть файл

@ -116,10 +116,11 @@ namespace MapKit {
[Export ("annotation", ArgumentSemantic.Retain)]
[ThreadSafe] // Sometimes iOS will request the annotation from a non-UI thread (see https://bugzilla.xamarin.com/show_bug.cgi?27609)
[NullAllowed]
#if XAMCORE_2_0
IMKAnnotation Annotation { get; [NullAllowed] set; }
IMKAnnotation Annotation { get; set; }
#else
NSObject Annotation { get; [NullAllowed] set; }
NSObject Annotation { get; set; }
#endif
[Export ("image", ArgumentSemantic.Retain)]

Просмотреть файл

@ -2214,11 +2214,11 @@ namespace MediaPlayer {
[TV (10,0,1)][iOS (10,1)]
[NoWatch][NoMac]
interface NSUserActivity_MediaPlayerAdditions {
[NullAllowed, Export ("externalMediaContentIdentifier")]
[Export ("externalMediaContentIdentifier")]
NSString GetExternalMediaContentIdentifier ();
[NullAllowed, Export ("setExternalMediaContentIdentifier:")]
void SetExternalMediaContentIdentifier (NSString identifier);
[Export ("setExternalMediaContentIdentifier:")]
void SetExternalMediaContentIdentifier ([NullAllowed] NSString identifier);
}
#endif
[iOS (9,0)][TV (9,0)]
@ -2227,7 +2227,7 @@ namespace MediaPlayer {
[Category]
[BaseType (typeof (AVMediaSelectionOption))]
interface AVMediaSelectionOption_MPNowPlayingInfoLanguageOptionAdditions {
[NullAllowed, Export ("makeNowPlayingInfoLanguageOption")]
[Export ("makeNowPlayingInfoLanguageOption")]
MPNowPlayingInfoLanguageOption CreateNowPlayingInfoLanguageOption ();
}

Просмотреть файл

@ -1040,14 +1040,16 @@ namespace Metal {
#if XAMCORE_4_0
[Abstract]
#endif
[NullAllowed, Export ("newEvent")]
[return: NullAllowed]
[Export ("newEvent")]
IMTLEvent CreateEvent ();
[Mac (10, 14, onlyOn64: true), iOS (12, 0), TV (12,0)]
#if XAMCORE_4_0
[Abstract]
#endif
[NullAllowed, Export ("newSharedEvent")]
[return: NullAllowed]
[Export ("newSharedEvent")]
IMTLSharedEvent CreateSharedEvent ();
[Mac (10,14, onlyOn64: true), iOS (12,0), TV (12,0)]
@ -1307,7 +1309,8 @@ namespace Metal {
#if XAMCORE_4_0
[Abstract]
#endif
[NullAllowed, Export ("newSharedTextureHandle")]
[return: NullAllowed]
[Export ("newSharedTextureHandle")]
MTLSharedTextureHandle CreateSharedTextureHandle ();
}

Просмотреть файл

@ -124,7 +124,7 @@ namespace ModelIO {
bool ExportAssetToUrl (NSUrl url, out NSError error);
[TV (11,0), Mac (10,13, onlyOn64: true), iOS (11,0)]
[Export ("objectAtPath:"), NullAllowed]
[Export ("objectAtPath:")]
MDLObject GetObject (string atPath);
[Static]
@ -1715,10 +1715,12 @@ namespace ModelIO {
[return: NullAllowed]
CGImage GetImageFromTexture (nuint level);
[NullAllowed, Export ("texelDataWithTopLeftOrigin")]
[Export ("texelDataWithTopLeftOrigin")]
[return: NullAllowed]
NSData GetTexelDataWithTopLeftOrigin ();
[NullAllowed, Export ("texelDataWithBottomLeftOrigin")]
[Export ("texelDataWithBottomLeftOrigin")]
[return: NullAllowed]
NSData GetTexelDataWithBottomLeftOrigin ();
[Export ("texelDataWithTopLeftOriginAtMipLevel:create:")]

Просмотреть файл

@ -1716,7 +1716,8 @@ namespace SceneKit {
SCNCamera Camera { get; set; }
[Export ("geometry", ArgumentSemantic.Retain)]
SCNGeometry Geometry { get; [NullAllowed] set; }
[NullAllowed]
SCNGeometry Geometry { get; set; }
[NullAllowed] // by default this property is null
[Export ("name", ArgumentSemantic.Copy)]
@ -1782,7 +1783,8 @@ namespace SceneKit {
[Mac (10,9)]
[Export ("constraints", ArgumentSemantic.Copy)]
SCNConstraint [] Constraints { get; [NullAllowed] set; }
[NullAllowed]
SCNConstraint [] Constraints { get; set; }
[NoWatch, Mac (10, 9)]
[NullAllowed] // by default this property is null
@ -3897,7 +3899,8 @@ namespace SceneKit {
[Abstract]
[Mac (10,10), iOS (8,0)]
[Export ("technique", ArgumentSemantic.Copy)]
SCNTechnique Technique { get; [NullAllowed] set; }
[NullAllowed]
SCNTechnique Technique { get; set; }
}
[Watch (3,0)]

Просмотреть файл

@ -311,11 +311,11 @@ namespace StoreKit {
[BaseType (typeof (NSObject), Delegates=new string [] {"WeakDelegate"}, Events=new Type [] {typeof (SKRequestDelegate)})]
interface SKRequest {
[Export ("delegate", ArgumentSemantic.Weak)][NullAllowed]
NSObject WeakDelegate { get; [NullAllowed] set; }
NSObject WeakDelegate { get; set; }
[Wrap ("WeakDelegate")]
[Protocolize]
SKRequestDelegate Delegate { get; [NullAllowed] set; }
SKRequestDelegate Delegate { get; set; }
[Export ("cancel")]
void Cancel ();
@ -372,11 +372,11 @@ namespace StoreKit {
IntPtr Constructor (NSSet productIdentifiersStringSet);
[Export ("delegate", ArgumentSemantic.Weak)][NullAllowed][New]
NSObject WeakDelegate { get; [NullAllowed] set; }
NSObject WeakDelegate { get; set; }
[Wrap ("WeakDelegate")][New]
[Protocolize]
SKProductsRequestDelegate Delegate { get; [NullAllowed] set; }
SKProductsRequestDelegate Delegate { get; set; }
}
[BaseType (typeof (NSObject))]

Просмотреть файл

@ -591,7 +591,7 @@ namespace UIKit {
IntPtr _FirstAnchor<AnchorType> ();
[iOS (10,0), TV (10,0)]
[NullAllowed, Export ("secondAnchor", ArgumentSemantic.Copy)]
[Export ("secondAnchor", ArgumentSemantic.Copy)]
[Internal]
IntPtr _SecondAnchor<AnchorType> ();
#endif
@ -3690,7 +3690,8 @@ namespace UIKit {
UICollectionViewDataSource DataSource { get; set; }
[Export ("backgroundView", ArgumentSemantic.Retain)]
UIView BackgroundView { get; [NullAllowed] set; }
[NullAllowed]
UIView BackgroundView { get; set; }
[Export ("allowsSelection")]
bool AllowsSelection { get; set; }
@ -7359,7 +7360,8 @@ namespace UIKit {
UIBezierPath FromRoundedRect (CGRect rect, nfloat cornerRadius);
[Export ("CGPath")]
CGPath CGPath { get; [NullAllowed] set; }
[NullAllowed]
CGPath CGPath { get; set; }
[Export ("moveToPoint:")]
void MoveTo (CGPoint point);
@ -7760,13 +7762,16 @@ namespace UIKit {
UIDatePickerMode Mode { get; set; }
[Export ("locale", ArgumentSemantic.Retain)]
NSLocale Locale { get; [NullAllowed] set; }
[NullAllowed]
NSLocale Locale { get; set; }
[Export ("timeZone", ArgumentSemantic.Retain)]
NSTimeZone TimeZone { get; [NullAllowed] set; }
[NullAllowed]
NSTimeZone TimeZone { get; set; }
[Export ("calendar", ArgumentSemantic.Copy)]
NSCalendar Calendar { get; [NullAllowed] set; }
[NullAllowed]
NSCalendar Calendar { get; set; }
// not fully clear from docs but null is not allowed:
// Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Invalid parameter not satisfying: date
@ -7774,10 +7779,12 @@ namespace UIKit {
NSDate Date { get; set; }
[Export ("minimumDate", ArgumentSemantic.Retain)]
NSDate MinimumDate { get; [NullAllowed] set; }
[NullAllowed]
NSDate MinimumDate { get; set; }
[Export ("maximumDate", ArgumentSemantic.Retain)]
NSDate MaximumDate { get; [NullAllowed] set; }
[NullAllowed]
NSDate MaximumDate { get; set; }
[Export ("countDownDuration")]
double CountDownDuration { get; set; }
@ -8414,7 +8421,7 @@ namespace UIKit {
UIBarButtonItem BackBarButtonItem { get; set; }
[Export ("titleView", ArgumentSemantic.Retain), NullAllowed]
UIView TitleView { get; [NullAllowed] set; }
UIView TitleView { get; set; }
[NoTV]
[Export ("prompt", ArgumentSemantic.Copy), NullAllowed]
@ -10890,7 +10897,8 @@ namespace UIKit {
[NoTV]
[Export ("customizableViewControllers", ArgumentSemantic.Copy)]
UIViewController [] CustomizableViewControllers { get; [NullAllowed] set; }
[NullAllowed]
UIViewController [] CustomizableViewControllers { get; set; }
[Export ("tabBar")]
UITabBar TabBar { get; }
@ -11685,7 +11693,7 @@ namespace UIKit {
UITableViewCellAccessory Accessory { get; set; }
[Export ("accessoryView", ArgumentSemantic.Retain)][NullAllowed]
UIView AccessoryView { get; [NullAllowed] set; }
UIView AccessoryView { get; set; }
[Export ("editingAccessoryType")]
UITableViewCellAccessory EditingAccessory { get; set; }
@ -12030,13 +12038,16 @@ namespace UIKit {
IntPtr Constructor (CGRect frame);
[Export ("text", ArgumentSemantic.Copy)]
string Text { get; [NullAllowed] set; }
[NullAllowed]
string Text { get; set; }
[Export ("textColor", ArgumentSemantic.Retain)]
UIColor TextColor { get; [NullAllowed] set; }
[NullAllowed]
UIColor TextColor { get; set; }
[Export ("font", ArgumentSemantic.Retain)]
UIFont Font { get; [NullAllowed] set; }
[NullAllowed]
UIFont Font { get; set; }
[Export ("textAlignment")]
UITextAlignment TextAlignment { get; set; }
@ -12045,7 +12056,8 @@ namespace UIKit {
UITextBorderStyle BorderStyle { get; set; }
[Export ("placeholder", ArgumentSemantic.Copy)]
string Placeholder { get; [NullAllowed] set; }
[NullAllowed]
string Placeholder { get; set; }
[Export ("clearsOnBeginEditing")]
bool ClearsOnBeginEditing { get; set; }
@ -12057,17 +12069,19 @@ namespace UIKit {
nfloat MinimumFontSize { get; set; }
[Export ("delegate", ArgumentSemantic.Assign)][NullAllowed]
NSObject WeakDelegate { get; [NullAllowed] set; }
NSObject WeakDelegate { get; set; }
[Wrap ("WeakDelegate")]
[Protocolize]
UITextFieldDelegate Delegate { get; [NullAllowed] set; }
UITextFieldDelegate Delegate { get; set; }
[Export ("background", ArgumentSemantic.Retain)]
UIImage Background { get; [NullAllowed] set; }
[NullAllowed]
UIImage Background { get; set; }
[Export ("disabledBackground", ArgumentSemantic.Retain)]
UIImage DisabledBackground { get; [NullAllowed] set; }
[NullAllowed]
UIImage DisabledBackground { get; set; }
[Export ("isEditing")]
bool IsEditing { get; }
@ -13473,7 +13487,8 @@ namespace UIKit {
// These come from @interface UIViewController (UINavigationControllerContextualToolbarItems)
[Export ("toolbarItems", ArgumentSemantic.Retain)]
UIBarButtonItem [] ToolbarItems { get; [NullAllowed] set; }
[NullAllowed]
UIBarButtonItem [] ToolbarItems { get; set; }
[NoTV]
[Export ("setToolbarItems:animated:")][PostGet ("ToolbarItems")]
@ -16278,7 +16293,8 @@ namespace UIKit {
NSAttributedString GetAccessibilityAttributedContent (nint lineNumber);
[TV (11,0), iOS (11,0)]
[NullAllowed, Export ("accessibilityAttributedPageContent")]
[Export ("accessibilityAttributedPageContent")]
[return: NullAllowed]
NSAttributedString GetAccessibilityAttributedPageContent ();
}