[generator] Do not inline duplicate attributes when processing protocols (#10683)

- this requires small (but tricky) generator changes
- duplicate availability attributes detection is tested by introspection
- it also requires removing dupes in manual bindings (which was the
  current, if not the _named_, goal for this PR)

Long story:

It's always been hard to detect and enforce removal of extraneous
availability attributes since the generator inlined them _freely_
when processing ObjC protocols.

That meant introspection could not report dupes and led to many
extra attributes. This was **not** a problem in binding files since we
could ignore them. IOW their presence (in the input) does not mean they
are _all_ dupes in generated code (output).

However dupes in manual bindings were also (forced to be) _ignored_ and
those were part of the assemblies we ship. Again it was not a big deal,
nor a source of much extra metadata/size, so it was ignored.

Forward to today, manual bindings needs to be updated for net6 [1] so any
extra we have requires more (manual) work. Cleaning this problem up in
the generator code reduce the (manual) work we need to do.

It also means introspection can detect dupes (in generated and manual
code) so we don't end up adding more (which would also require more
manual work to support both set of attributes).

[1] https://github.com/xamarin/xamarin-macios/pull/10580
This commit is contained in:
Sebastien Pouliot 2021-03-01 08:39:52 -05:00 коммит произвёл GitHub
Родитель ecccb8954e
Коммит 6992a5a10a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 121 добавлений и 112 удалений

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

@ -221,7 +221,6 @@ namespace AppKit
return NSArray.ArrayFromHandle<NSObject> (handle);
}
[Mac (10, 9)]
[DllImport (Constants.AppKitLibrary)]
static extern bool NSAccessibilitySetMayContainProtectedContent (bool flag);

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

@ -456,19 +456,19 @@ namespace CoreMedia {
return new CMClock (ptr, deprecated);
}
[iOS (9,0)][Mac (10,11), Watch (6,0)]
[iOS (9,0)][Mac (10,11)]
[DllImport(Constants.CoreMediaLibrary)]
static extern unsafe /* CMTimebaseRef */ IntPtr CMTimebaseCopyMasterTimebase (/* CMTimebaseRef */ IntPtr timebase);
[iOS (9,0)][Mac (10,11), Watch (6,0)]
[iOS (9,0)][Mac (10,11)]
[DllImport(Constants.CoreMediaLibrary)]
static extern unsafe /* CMClockRef */ IntPtr CMTimebaseCopyMasterClock (/* CMTimebaseRef */ IntPtr timebase);
[iOS (9,0)][Mac (10,11), Watch (6,0)]
[iOS (9,0)][Mac (10,11)]
[DllImport(Constants.CoreMediaLibrary)]
static extern unsafe IntPtr /* void* */ CMTimebaseCopyMaster (/* CMTimebaseRef */ IntPtr timebase);
[iOS (9,0)][Mac (10,11), Watch (6,0)]
[iOS (9,0)][Mac (10,11)]
[DllImport(Constants.CoreMediaLibrary)]
static extern unsafe /* CMClockRef */ IntPtr CMTimebaseCopyUltimateMasterClock (/* CMTimebaseRef */ IntPtr timebase);
#endif

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

@ -6,28 +6,24 @@ namespace CoreTelephony {
public partial class CTCall {
#if !COREBUILD
[Deprecated (PlatformName.iOS, 10, 0, message : Constants.UseCallKitInstead)]
public string StateDialing {
get {
return Dlfcn.SlowGetStringConstant (Constants.CoreTelephonyLibrary, "CTCallStateDialing");
}
}
[Deprecated (PlatformName.iOS, 10, 0, message : Constants.UseCallKitInstead)]
public string StateIncoming {
get {
return Dlfcn.SlowGetStringConstant (Constants.CoreTelephonyLibrary, "CTCallStateIncoming");
}
}
[Deprecated (PlatformName.iOS, 10, 0, message : Constants.UseCallKitInstead)]
public string StateConnected {
get {
return Dlfcn.SlowGetStringConstant (Constants.CoreTelephonyLibrary, "CTCallStateConnected");
}
}
[Deprecated (PlatformName.iOS, 10, 0, message : Constants.UseCallKitInstead)]
public string StateDisconnected {
get {
return Dlfcn.SlowGetStringConstant (Constants.CoreTelephonyLibrary, "CTCallStateDisconnected");

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

@ -115,9 +115,6 @@ namespace GameController {
[TV (12, 2), Mac (10, 14, 4), iOS (12, 2)]
bool RightThumbstickButton;
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[DllImport (Constants.GameControllerLibrary)]
[TV (12, 2), Mac (10, 14, 4), iOS (12, 2)]
static extern /* NSData * __nullable */ IntPtr NSDataFromGCExtendedGamepadSnapshotData (
@ -134,28 +131,17 @@ namespace GameController {
public partial class GCExtendedGamepadSnapshot {
// GCExtendedGamepadSnapshot.h
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[DllImport (Constants.GameControllerLibrary)]
static extern bool GCExtendedGamepadSnapShotDataV100FromNSData (
/* GCExtendedGamepadSnapShotDataV100 * __nullable */ out GCExtendedGamepadSnapShotDataV100 snapshotData,
/* NSData * __nullable */ IntPtr data);
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCController.GetExtendedGamepadController()' instead.")]
[DllImport (Constants.GameControllerLibrary)]
[TV (12, 2), Mac (10, 14, 4), iOS (12, 2)]
static extern bool GCExtendedGamepadSnapshotDataFromNSData (
/* GCExtendedGamepadSnapshotData * __nullable */ out GCExtendedGamepadSnapshotData snapshotData,
/* NSData * __nullable */ IntPtr data);
[Deprecated (PlatformName.iOS, 12, 2, message: "Use 'TryGetExtendedSnapShotData' instead.")]
[Deprecated (PlatformName.MacOSX, 10, 14, 4, message: "Use 'TryGetExtendedSnapShotData' instead.")]
[Deprecated (PlatformName.TvOS, 12, 2, message: "Use 'TryGetExtendedSnapShotData' instead.")]
public static bool TryGetSnapShotData (NSData data, out GCExtendedGamepadSnapShotDataV100 snapshotData)
{
return GCExtendedGamepadSnapShotDataV100FromNSData (out snapshotData, data == null ? IntPtr.Zero : data.Handle);

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

@ -40,9 +40,6 @@ namespace GameController {
public float /* float_t = float */ LeftShoulder;
public float /* float_t = float */ RightShoulder;
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCExtendedGamepad' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCExtendedGamepad' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCExtendedGamepad' instead.")]
[DllImport (Constants.GameControllerLibrary)]
static extern /* NSData * __nullable */ IntPtr NSDataFromGCGamepadSnapShotDataV100 (
/* GCGamepadSnapShotDataV100 * __nullable */ ref GCGamepadSnapShotDataV100 snapshotData);
@ -57,9 +54,6 @@ namespace GameController {
public partial class GCGamepadSnapshot {
// GCGamepadSnapshot.h
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCExtendedGamepad' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCExtendedGamepad' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCExtendedGamepad' instead.")]
[DllImport (Constants.GameControllerLibrary)]
static extern bool GCGamepadSnapShotDataV100FromNSData (
/* GCGamepadSnapShotDataV100 * __nullable */ out GCGamepadSnapShotDataV100 snapshotData,

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

@ -67,9 +67,6 @@ namespace GameController {
public float /* float_t = float */ ButtonA;
public float /* float_t = float */ ButtonX;
[Deprecated (PlatformName.MacOSX, 10, 15, message: "Use 'GCController.GetMicroGamepadController()' instead.")]
[Deprecated (PlatformName.iOS, 13, 0, message: "Use 'GCController.GetMicroGamepadController()' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Use 'GCController.GetMicroGamepadController()' instead.")]
[DllImport (Constants.GameControllerLibrary)]
[TV (12, 2), Mac (10, 14, 4), iOS (12, 2)]
static extern /* NSData * __nullable */ IntPtr NSDataFromGCMicroGamepadSnapshotData (

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

@ -26,7 +26,6 @@ namespace MediaPlayer {
#if !XAMCORE_4_0
public partial class MPPlayableContentDataSource : NSObject {
[Unavailable (PlatformName.MacOSX, PlatformArchitecture.All)]
[iOS (10, 0)]
[Obsolete ("Use 'MPPlayableContentDataSource_Extensions.GetContentItemAsync' instead.")]
public unsafe virtual Task<MPContentItem> GetContentItemAsync (string identifier)

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

@ -16,7 +16,7 @@ namespace Metal {
public static partial class MTLResourceStateCommandEncoder_Extensions {
[NoMac, NoTV, iOS (13,0)]
[NoMac, NoTV]
public static void Update (this IMTLResourceStateCommandEncoder This, IMTLTexture texture, MTLSparseTextureMappingMode mode, MTLRegion[] regions, nuint[] mipLevels, nuint[] slices)
{
if (texture == null)

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

@ -20,11 +20,9 @@ namespace MetalPerformanceShaders {
}
[DllImport (Constants.MetalPerformanceShadersLibrary)]
[Introduced (PlatformName.MacCatalyst, 13, 0)]
[TV (13,0), Mac (10,15), iOS (13,0)]
static extern /* id<MTLDevice> _Nullable */ IntPtr MPSGetPreferredDevice (nuint options);
[Introduced (PlatformName.MacCatalyst, 13, 0)]
[TV (13,0), Mac (10,15), iOS (13,0)]
public static IMTLDevice GetPreferredDevice (MPSDeviceOptions options)
{
@ -72,11 +70,11 @@ namespace MetalPerformanceShaders {
#if !COREBUILD
public partial class MPSImage {
[iOS (13,0), TV (12,0), Mac (10,15)][Introduced (PlatformName.MacCatalyst, 13, 0)]
[iOS (13,0), TV (12,0), Mac (10,15)]
[DllImport (Constants.MetalPerformanceShadersLibrary)]
static extern MPSImageType MPSGetImageType (IntPtr image);
[iOS (13,0), TV (12,0), Mac (10,15)][Introduced (PlatformName.MacCatalyst, 13, 0)]
[iOS (13,0), TV (12,0), Mac (10,15)]
public MPSImageType ImageType => MPSGetImageType (Handle);
}

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

@ -44,13 +44,11 @@ namespace MetalPerformanceShaders {
MPSStateBatchSynchronize (stateBatch.Handle, commandBuffer.Handle);
}
[Introduced (PlatformName.MacCatalyst, 13, 0)]
[iOS (12,0), TV (12,0), Mac (10,14)]
[DllImport (Constants.MetalPerformanceShadersLibrary)]
static extern nuint MPSStateBatchResourceSize (IntPtr batch);
// Using 'NSArray<MPSState>' instead of `MPSState[]` because array 'Handle' matters.
[Introduced (PlatformName.MacCatalyst, 13, 0)]
[iOS (12,0), TV (12,0), Mac (10,14)]
public static nuint GetResourceSize (NSArray<MPSState> stateBatch)
{

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

@ -91,7 +91,7 @@ namespace Network {
[TV (13,0), Mac (10,15), iOS (13,0)]
public static NWProtocolDefinition CreateWebSocketDefinition () => new NWProtocolDefinition (nw_protocol_copy_ws_definition (), owns: true);
[Watch (6,0), TV (13,0), Mac (10,15)]
[TV (13,0), Mac (10,15)]
[DllImport (Constants.NetworkLibrary)]
static extern unsafe OS_nw_protocol_definition nw_framer_create_definition (string identifier, NWFramerCreateFlags flags, ref BlockLiteral start_handler);
delegate NWFramerStartResult nw_framer_create_definition_t (IntPtr block, IntPtr framer);

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

@ -115,7 +115,6 @@ namespace QTKit {
get { return default(Foundation.NSString); }
}
[ObjCRuntime.Obsoleted (ObjCRuntime.PlatformName.MacOSX, 10,15, message: ObjCRuntime.Constants.MacOS32bitsUnavailable)]
public static class Notifications : System.Object {
public static Foundation.NSObject ObserveAttributeDidChange (System.EventHandler<Foundation.NSNotificationEventArgs> handler)
{
@ -353,7 +352,6 @@ namespace QTKit {
get { return default(Foundation.NSString); }
}
[ObjCRuntime.Obsoleted (ObjCRuntime.PlatformName.MacOSX, 10,15, message: ObjCRuntime.Constants.MacOS32bitsUnavailable)]
public static class Notifications : System.Object {
public static Foundation.NSObject ObserveAttributeDidChange (System.EventHandler<Foundation.NSNotificationEventArgs> handler)
{
@ -1786,7 +1784,6 @@ namespace QTKit {
get { return default(Foundation.NSString); }
}
[ObjCRuntime.Obsoleted (ObjCRuntime.PlatformName.MacOSX, 10,15, message: ObjCRuntime.Constants.MacOS32bitsUnavailable)]
public static class Notifications : System.Object {
public static Foundation.NSObject ObserveApertureModeDidChange (System.EventHandler<Foundation.NSNotificationEventArgs> handler)
{
@ -2884,7 +2881,6 @@ namespace QTKit {
get { return default(Foundation.NSString); }
}
[ObjCRuntime.Obsoleted (ObjCRuntime.PlatformName.MacOSX, 10,15, message: ObjCRuntime.Constants.MacOS32bitsUnavailable)]
public static class Notifications : System.Object {
public static Foundation.NSObject ObserveRuntimeError (System.EventHandler<Foundation.NSNotificationEventArgs> handler)
{

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

@ -123,7 +123,6 @@ namespace Security {
public SecAccessible Accessible { get; private set; }
public SecAccessControlCreateFlags Flags { get; private set; }
[Mac (10,10)][iOS (8,0)]
[DllImport (Constants.SecurityLibrary)]
extern static IntPtr SecAccessControlCreateWithFlags (IntPtr allocator, /* CFTypeRef */ IntPtr protection, /* SecAccessControlCreateFlags */ nint flags, out IntPtr error);
#endif

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

@ -13,7 +13,6 @@ namespace Security {
public static partial class SecSharedCredential {
[DllImport (Constants.SecurityLibrary)]
[Introduced (PlatformName.MacCatalyst, 14, 0)]
extern static void SecAddSharedWebCredential (IntPtr /* CFStringRef */ fqdn, IntPtr /* CFStringRef */ account, IntPtr /* CFStringRef */ password,
IntPtr /* void (^completionHandler)( CFErrorRef error) ) */ completionHandler);
@ -34,7 +33,6 @@ namespace Security {
}
}
[Introduced (PlatformName.MacCatalyst, 14, 0)]
[BindingImpl (BindingImplOptions.Optimizable)]
public static void AddSharedWebCredential (string domainName, string account, string password, Action<NSError> handler)
{
@ -137,11 +135,9 @@ namespace Security {
}
}
[Introduced (PlatformName.MacCatalyst, 14, 0)]
[DllImport (Constants.SecurityLibrary)]
extern static IntPtr /* CFStringRef */ SecCreateSharedWebCredentialPassword ();
[Introduced (PlatformName.MacCatalyst, 14, 0)]
public static string CreateSharedWebCredentialPassword ()
{
var handle = SecCreateSharedWebCredentialPassword ();

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

@ -32,7 +32,6 @@ namespace StoreKit {
protected internal SKAdNetwork (IntPtr handle) : base (handle) { }
[Obsolete ("Throws a 'NotSupportedException'.")]
[Unavailable (PlatformName.TvOS)]
public static void RegisterAppForAdNetworkAttribution () => throw new NotSupportedException ();
}
}

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

@ -49,9 +49,15 @@ namespace AuthenticationServices {
}
[Partial]
#if TVOS || WATCH
// The associated enum is not generated (which is normal)
// without this define the attributes would be duplicated
// on other platforms (where the enum exists)
[NoTV][NoWatch]
#endif
interface ASExtensionErrorCodeExtensions {
[NoWatch, NoTV, NoMac, iOS (14,0)]
[NoMac, iOS (14,0)]
[Field ("ASExtensionLocalizedFailureReasonErrorKey")]
NSString LocalizedFailureReasonErrorKey { get; }
}

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

@ -13500,7 +13500,6 @@ namespace AVFoundation {
[Export ("processContentKeyResponseError:")]
void Process (NSError error);
[NoWatch]
[Deprecated (PlatformName.iOS, 11, 2, message: "Use the 'NSError' overload instead.")]
[Export ("respondByRequestingPersistableContentKeyRequest"), NoWatch, NoTV, NoMac]
void RespondByRequestingPersistableContentKeyRequest ();

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

@ -4004,7 +4004,6 @@ namespace Foundation
#if !XAMCORE_3_0
// now exposed with the corresponding EABluetoothAccessoryPickerError enum
[NoMac, NoTV, NoWatch]
[NoTV]
[Field ("EABluetoothAccessoryPickerErrorDomain", "ExternalAccessory")]
NSString EABluetoothAccessoryPickerErrorDomain { get; }
@ -6536,35 +6535,35 @@ namespace Foundation
string AsString ();
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfScheme"), Mac(10,11)]
[Export ("rangeOfScheme")]
NSRange RangeOfScheme { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfUser"), Mac(10,11)]
[Export ("rangeOfUser")]
NSRange RangeOfUser { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfPassword"), Mac(10,11)]
[Export ("rangeOfPassword")]
NSRange RangeOfPassword { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfHost"), Mac(10,11)]
[Export ("rangeOfHost")]
NSRange RangeOfHost { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfPort"), Mac(10,11)]
[Export ("rangeOfPort")]
NSRange RangeOfPort { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfPath"), Mac(10,11)]
[Export ("rangeOfPath")]
NSRange RangeOfPath { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfQuery"), Mac(10,11)]
[Export ("rangeOfQuery")]
NSRange RangeOfQuery { get; }
[iOS (9,0), Mac(10,11)]
[Export ("rangeOfFragment"), Mac(10,11)]
[Export ("rangeOfFragment")]
NSRange RangeOfFragment { get; }
[Watch (4, 0), TV (11, 0), Mac (10, 13), iOS (11, 0)]

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

@ -117,7 +117,7 @@ public partial class Generator {
}
// properties
GenerateProperties (type);
GenerateProperties (type, type);
// protocols
GenerateProtocolProperties (type, new HashSet<string> ());
@ -146,14 +146,14 @@ public partial class Generator {
print ("");
print ($"// {pname} protocol members ");
GenerateProperties (i, type);
GenerateProperties (i, type, fromProtocol: true);
// also include base interfaces/protocols
GenerateProtocolProperties (i, processed);
}
}
void GenerateProperties (Type type, Type originalType = null)
void GenerateProperties (Type type, Type originalType = null, bool fromProtocol = false)
{
foreach (var p in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
if (p.IsUnavailable (this))
@ -162,7 +162,13 @@ public partial class Generator {
continue;
print ("");
PrintPropertyAttributes (p, originalType);
// an export will be present (only) if it's defined in a protocol
var export = AttributeManager.GetCustomAttribute<ExportAttribute> (p);
// this is a bit special since CoreImage filter protocols are much newer than the our generated, key-based bindings
// so we do not want to advertise the protocol versions since most properties would be incorrectly advertised
PrintPropertyAttributes (p, originalType, skipTypeInjection: export != null);
print_generated_code ();
var ptype = p.PropertyType.Name;
@ -189,7 +195,7 @@ public partial class Generator {
case "CIColor":
case "CIImage":
// protocol-based bindings have annotations - but the older, key-based, versions did not
if (originalType == null)
if (!fromProtocol)
nullable = true;
break;
}
@ -198,9 +204,6 @@ public partial class Generator {
print ("public {0}{1} {2} {{", ptype, nullable ? "?" : "", p.Name);
indent++;
// an export will be present (only) if it's defined in a protocol
var export = AttributeManager.GetCustomAttribute<ExportAttribute> (p);
var name = AttributeManager.GetCustomAttribute<CoreImageFilterPropertyAttribute> (p)?.Name;
// we can skip the name when it's identical to a protocol selector
if (name == null) {

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

@ -3217,40 +3217,41 @@ public partial class Generator : IMemberGatherer {
return false;
}
public void PrintPlatformAttributes (MemberInfo mi, Type type = null)
public bool PrintPlatformAttributes (MemberInfo mi, Type type = null)
{
bool printed = false;
if (mi == null)
return;
return printed;
AvailabilityBaseAttribute[] type_ca = null;
AvailabilityBaseAttribute [] type_ca = null;
foreach (var availability in AttributeManager.GetCustomAttributes<AvailabilityBaseAttribute> (mi)) {
var t = type ?? (mi as TypeInfo) ?? mi.DeclaringType;
if (type_ca == null) {
if (mi.DeclaringType != null)
type_ca = AttributeManager.GetCustomAttributes<AvailabilityBaseAttribute> (type ?? mi.DeclaringType);
if (t != null)
type_ca = AttributeManager.GetCustomAttributes<AvailabilityBaseAttribute> (t);
else
type_ca = Array.Empty<AvailabilityBaseAttribute> ();
}
// type has nothing, anything on member should be generated
if (type_ca.Length == 0) {
print (availability.ToString ());
continue;
}
if (Duplicated (availability, type_ca))
// if we're comparing to something else (than ourself) then don't generate duplicate attributes
if ((mi != t) && Duplicated (availability, type_ca))
continue;
switch (availability.AvailabilityKind) {
case AvailabilityKind.Unavailable:
// an unavailable member can override type-level attribute
print (availability.ToString ());
printed = true;
break;
default:
// can't introduce or deprecate/obsolete a member on a type that is not available
if (IsUnavailable (type_ca, availability.Platform))
continue;
print (availability.ToString ());
printed = true;
break;
}
}
return printed;
}
static bool IsUnavailable (IEnumerable<AvailabilityBaseAttribute> customAttributes, PlatformName platform)
@ -3312,23 +3313,6 @@ public partial class Generator : IMemberGatherer {
}
}
public void PrintPlatformAttributesIfInlined (MemberInformation minfo)
{
if (minfo == null)
return;
// check if it is an inlined property (e.g. from a protocol)
bool isInlined = minfo.type != minfo.property.DeclaringType;
// we must avoid duplication of availability so we will only print
// if the property has no Availability
bool propHasNoInfo = !AttributeManager.HasAttribute<AvailabilityBaseAttribute> (minfo.property)
&& (minfo.property.GetGetMethod () == null || !AttributeManager.HasAttribute<AvailabilityBaseAttribute> (minfo.property.GetGetMethod ()));
if (isInlined && propHasNoInfo)
PrintPlatformAttributes (minfo.property.DeclaringType);
}
public string SelectorField (string s, bool ignore_inline_directive = false)
{
string name;
@ -4740,7 +4724,7 @@ public partial class Generator : IMemberGatherer {
}
}
void PrintPropertyAttributes (PropertyInfo pi, Type type = null)
void PrintPropertyAttributes (PropertyInfo pi, Type type, bool skipTypeInjection = false)
{
foreach (var oa in AttributeManager.GetCustomAttributes<ObsoleteAttribute> (pi)) {
print ("[Obsolete (\"{0}\", {1})]", oa.Message, oa.IsError ? "true" : "false");
@ -4759,7 +4743,17 @@ public partial class Generator : IMemberGatherer {
print ("[DebuggerBrowsable (DebuggerBrowsableState.Never)]");
}
PrintPlatformAttributes (pi, type);
// if we inline properties (e.g. from a protocol)
// we must look if the type has an [Availability] attribute
if (type != pi.DeclaringType) {
// print, if not duplicated from the type (being inlined into), the property availability
if (!PrintPlatformAttributes (pi, type) && !skipTypeInjection) {
// print, if not duplicated from the type (being inlined into), the property declaring type (protocol) availability
PrintPlatformAttributes (pi.DeclaringType, type);
}
} else {
PrintPlatformAttributes (pi, type);
}
foreach (var sa in AttributeManager.GetCustomAttributes<ThreadSafeAttribute> (pi))
print (sa.Safe ? "[ThreadSafe]" : "[ThreadSafe (false)]");
@ -4802,7 +4796,7 @@ public partial class Generator : IMemberGatherer {
if (wrap != null){
print_generated_code ();
PrintPropertyAttributes (pi);
PrintPropertyAttributes (pi, minfo.type);
PrintAttributes (pi, preserve:true, advice:true);
print ("{0} {1}{2}{3} {4}{5} {{",
mod,
@ -4881,11 +4875,7 @@ public partial class Generator : IMemberGatherer {
}
print_generated_code ();
PrintPropertyAttributes (pi);
// when we inline properties (e.g. from a protocol)
// we must look if the type has an [Availability] attribute
PrintPlatformAttributesIfInlined (minfo);
PrintPropertyAttributes (pi, minfo.type);
PrintAttributes (pi, preserve:true, advice:true, bindAs:true);
@ -4950,7 +4940,9 @@ public partial class Generator : IMemberGatherer {
var ba = GetBindAttribute (getter);
string sel = ba != null ? ba.Selector : export.Selector;
PrintAttributes (pi, platform:true);
// print availability separately since we could be inlining
PrintPlatformAttributes (pi, type);
PrintAttributes (pi, platform:false);
if (!minfo.is_sealed || !minfo.is_wrapper) {
PrintDelegateProxy (pi.GetGetMethod ());
@ -5014,7 +5006,10 @@ public partial class Generator : IMemberGatherer {
}
PrintBlockProxy (pi.PropertyType);
PrintAttributes (pi, platform:true);
// print availability separately since we could be inlining
PrintPlatformAttributes (pi, type);
PrintAttributes (pi, platform: false);
if (not_implemented_attr == null && (!minfo.is_sealed || !minfo.is_wrapper))
PrintExport (minfo, sel, export.ArgumentSemantic);
@ -5839,7 +5834,6 @@ public partial class Generator : IMemberGatherer {
var mod = string.Empty;
PrintMethodAttributes (minfo);
PrintPlatformAttributes (mi);
print_generated_code ();
PrintDelegateProxy (minfo);
PrintExport (minfo);

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

@ -404,7 +404,7 @@ namespace SceneKit {
[Mac (10,9)]
[Export ("projectionTransform")]
SCNMatrix4 ProjectionTransform { get; [Mac (10,9)] set; }
SCNMatrix4 ProjectionTransform { get; set; }
[Mac (10,9)]
[Export ("automaticallyAdjustsZRange")]

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

@ -936,7 +936,6 @@ namespace UIKit {
[Deprecated (PlatformName.iOS, 13, 0, message: "Please use 'UsesDefaultHyphenation' or 'NSParagraphStyle.HyphenationFactor' instead.")]
[Deprecated (PlatformName.WatchOS, 6, 0, message: "Please use 'UsesDefaultHyphenation' or 'NSParagraphStyle.HyphenationFactor' instead.")]
[Deprecated (PlatformName.TvOS, 13, 0, message: "Please use 'UsesDefaultHyphenation' or 'NSParagraphStyle.HyphenationFactor' instead.")]
[Unavailable (PlatformName.MacCatalyst)]
[Advice ("This API is not available when using UIKit on macOS.")]
[NoMacCatalyst]
[Export ("hyphenationFactor")]

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

@ -220,7 +220,7 @@ namespace GeneratorTests
.Union (allTypes.SelectMany ((type) => type.Properties));
var preserves = allMembers.Sum ((v) => v.CustomAttributes.Count ((ca) => ca.AttributeType.Name == "IntroducedAttribute"));
Assert.AreEqual (8, preserves, "Introduced attribute count"); // If you modified code that generates IntroducedAttributes please update the attribute count
Assert.AreEqual (10, preserves, "Introduced attribute count"); // If you modified code that generates IntroducedAttributes please update the attribute count
}
[Test]

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

@ -20,6 +20,7 @@
//
using System;
using System.Collections.Generic;
using System.Reflection;
using NUnit.Framework;
using ObjCRuntime;
@ -259,5 +260,56 @@ namespace Introspection {
}
AssertIfErrors ("{0} API with mixed [Unavailable] and availability attributes", Errors);
}
static HashSet<string> member_level = new HashSet<string> ();
void CheckDupes (MemberInfo m, Type t, ISet<string> type_level)
{
member_level.Clear ();
foreach (var a in m.GetCustomAttributes (false)) {
var s = String.Empty;
if (a is AvailabilityBaseAttribute aa)
s = aa.ToString ();
if (s.Length > 0) {
if (type_level.Contains (s))
AddErrorLine ($"[FAIL] Both '{t}' and '{m}' are marked with `{s}`.");
if (member_level.Contains (s))
AddErrorLine ($"[FAIL] '{m}' is decorated more than once with `{s}`.");
else
member_level.Add (s);
}
}
}
[Test]
public void Duplicates ()
{
HashSet<string> type_level = new HashSet<string> ();
//LogProgress = true;
Errors = 0;
foreach (Type t in Assembly.GetTypes ()) {
if (LogProgress)
Console.WriteLine ($"T: {t}");
type_level.Clear ();
foreach (var a in t.GetCustomAttributes (false)) {
if (a is AvailabilityBaseAttribute aa)
type_level.Add (aa.ToString ());
}
foreach (var p in t.GetProperties (BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
if (LogProgress)
Console.WriteLine ($"P: {p}");
CheckDupes (p, t, type_level);
}
foreach (var m in t.GetMembers (BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) {
if (LogProgress)
Console.WriteLine ($"M: {m}");
CheckDupes (m, t, type_level);
}
}
AssertIfErrors ("{0} API with members duplicating type-level attributes", Errors);
}
}
}