From f359e7310225e333358e08f6549bbe79848af44f Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Fri, 27 Aug 2021 11:43:36 -0500 Subject: [PATCH] [generator] Generate more [SupportedOSPlatform] attributes (#868) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/xamarin/java.interop/issues/863 In commits da12df45 and 412e974b (and others) we added support to emit the `[SupportedOSPlatformAttribute]` custom attribute when targeting .NET 6+ builds, using the Android API-level that the member was introduced: [global::System.Runtime.Versioning.SupportedOSPlatformAttribute ("android23.0")] [global::Android.Runtime.Register ("android/telecom/InCallService", DoNotGenerateAcw=true, ApiSince = 23)] public abstract partial class InCallService : Android.App.Service { } However, our "invoke" machinery uses this API without having the same guards: [global::Android.Runtime.Register ("android/telecom/InCallService", DoNotGenerateAcw=true, ApiSince = 23)] internal partial class InCallServiceInvoker : InCallService { } This results in build warnings when building e.g. `xamarin-android/src/Mono.Android`: …/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-30/mcw/Android.Telecom.InCallService.cs(1287,76): warning CA1416: This call site is reachable on all platforms. 'InCallService' is only supported on: 'android' 23.0 and later. To fix these warnings, we need to emit the same `[SupportedOSPlatformAttribute]` for these members as well: [global::System.Runtime.Versioning.SupportedOSPlatformAttribute ("android23.0")] [global::Android.Runtime.Register ("android/telecom/InCallService", DoNotGenerateAcw=true, ApiSince = 23)] internal partial class InCallServiceInvoker : InCallService { } This change removes 4,699 `CA1416` warnings from our `Mono.Android.dll` build. The remaining 61 `CA1416` warnings are of the form: …\xamarin-android\src\Mono.Android\obj\Debug\net6.0\android-31\mcw\Java.Lang.Reflect.Method.cs(35,71): warning CA1416: This call site is reachable on all platforms. 'Executable' is only supported on: 'android' 26.0 and later. The problem here is that `Java.Lang.Reflect.Method` class is available since API-1, but it inherits from the `Java.Lang.Reflect.Executable` class which was added in API-26. See: - https://developer.android.com/reference/java/lang/reflect/Method - https://developer.android.com/reference/java/lang/reflect/Executable This seems like a `Mono.Android.dll` issue and not something we should attempt to fix in `generator`. --- .../BoundMethodExtensionStringOverload.cs | 2 ++ .../SourceWriters/BoundMethodStringOverload.cs | 2 ++ tools/generator/SourceWriters/BoundProperty.cs | 4 ++-- .../SourceWriters/BoundPropertyStringVariant.cs | 2 ++ tools/generator/SourceWriters/ClassInvokerClass.cs | 2 ++ .../Extensions/SourceWriterExtensions.cs | 14 ++++++++------ .../SourceWriters/InterfaceInvokerMethod.cs | 2 ++ .../SourceWriters/InterfaceInvokerProperty.cs | 2 ++ .../SourceWriters/InterfaceListenerEvent.cs | 10 +++++++--- .../generator/SourceWriters/MethodAsyncWrapper.cs | 2 ++ tools/generator/SourceWriters/MethodCallback.cs | 4 ++++ .../SourceWriters/MethodExtensionAsyncWrapper.cs | 2 ++ 12 files changed, 37 insertions(+), 11 deletions(-) diff --git a/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs b/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs index 7e0907192..284bdb3df 100644 --- a/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs +++ b/tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs @@ -29,6 +29,8 @@ public BoundMethodExtensionStringOverload (Method method, CodeGenerationOptions if (method.Deprecated != null) Attributes.Add (new ObsoleteAttr (method.Deprecated.Replace ("\"", "\"\"").Trim ())); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + Parameters.Add (new MethodParameterWriter ("self", new TypeReferenceWriter (selfType)) { IsExtension = true }); this.AddMethodParametersStringOverloads (method.Parameters, opt); } diff --git a/tools/generator/SourceWriters/BoundMethodStringOverload.cs b/tools/generator/SourceWriters/BoundMethodStringOverload.cs index 168e55ff7..463010012 100644 --- a/tools/generator/SourceWriters/BoundMethodStringOverload.cs +++ b/tools/generator/SourceWriters/BoundMethodStringOverload.cs @@ -27,6 +27,8 @@ public BoundMethodStringOverload (Method method, CodeGenerationOptions opt) if (method.Deprecated != null) Attributes.Add (new ObsoleteAttr (method.Deprecated.Replace ("\"", "\"\"").Trim ())); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + method.JavadocInfo?.AddJavadocs (Comments); this.AddMethodParametersStringOverloads (method.Parameters, opt); diff --git a/tools/generator/SourceWriters/BoundProperty.cs b/tools/generator/SourceWriters/BoundProperty.cs index 31e115aa4..24a627aff 100644 --- a/tools/generator/SourceWriters/BoundProperty.cs +++ b/tools/generator/SourceWriters/BoundProperty.cs @@ -69,13 +69,13 @@ public BoundProperty (GenBase gen, Property property, CodeGenerationOptions opt, if (property.Getter.Deprecated != null && (property.Setter == null || property.Setter.Deprecated != null)) Attributes.Add (new ObsoleteAttr (property.Getter.Deprecated.Replace ("\"", "\"\"").Trim () + (property.Setter != null && property.Setter.Deprecated != property.Getter.Deprecated ? " " + property.Setter.Deprecated.Replace ("\"", "\"\"").Trim () : null))); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + SourceWriterExtensions.AddMethodCustomAttributes (GetterAttributes, property.Getter); if (gen.IsGeneratable) GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); - SourceWriterExtensions.AddSupportedOSPlatform (GetterAttributes, property.Getter, opt); - GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.IsVirtual ? property.Getter.GetConnectorNameFull (opt) : string.Empty, additionalProperties: property.Getter.AdditionalAttributeString ())); SourceWriterExtensions.AddMethodBody (GetBody, property.Getter, opt); diff --git a/tools/generator/SourceWriters/BoundPropertyStringVariant.cs b/tools/generator/SourceWriters/BoundPropertyStringVariant.cs index 96a4899ad..26dd3f77f 100644 --- a/tools/generator/SourceWriters/BoundPropertyStringVariant.cs +++ b/tools/generator/SourceWriters/BoundPropertyStringVariant.cs @@ -24,6 +24,8 @@ public BoundPropertyStringVariant (Property property, CodeGenerationOptions opt) SetVisibility ((property.Setter ?? property.Getter).Visibility); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + HasGet = true; if (is_array) diff --git a/tools/generator/SourceWriters/ClassInvokerClass.cs b/tools/generator/SourceWriters/ClassInvokerClass.cs index d20bd63c5..9b767d760 100644 --- a/tools/generator/SourceWriters/ClassInvokerClass.cs +++ b/tools/generator/SourceWriters/ClassInvokerClass.cs @@ -26,6 +26,8 @@ public ClassInvokerClass (ClassGen klass, CodeGenerationOptions opt) Attributes.Add (new RegisterAttr (klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString ()) { UseGlobal = true }); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, klass, opt); + var ctor = new ConstructorWriter { Name = Name, IsPublic = true, diff --git a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs index fc7a94b86..917024e2e 100644 --- a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs +++ b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs @@ -85,7 +85,7 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter AddInterfaceListenerEventsAndProperties (tw, iface, target, name, setter, string.Format ("__v => {0} = __v", prop.Name), - string.Format ("__v => {0} = null", prop.Name), opt); + string.Format ("__v => {0} = null", prop.Name), opt, prop.Getter); } else { refs.Add (method.Name); string rm = null; @@ -103,7 +103,7 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter AddInterfaceListenerEventsAndProperties (tw, iface, target, name, method.Name, method.Name, - remove, opt); + remove, opt, method); } } @@ -113,7 +113,9 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter tw.Methods.Add (new CreateImplementorMethod (iface, opt)); } - public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt) + // Parameter 'setListenerMethod' refers to the method used to set the listener, like 'addOnRoutingChangedListener'/'setOnRoutingChangedListener'. + // This is used to determine what API level the listener setter is available on. + public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt, Method setListenerMethod) { if (!iface.IsValid) return; @@ -128,11 +130,11 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter if (target.ContainsName (nameUnique)) nameUnique += "Event"; - AddInterfaceListenerEventOrProperty (tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt); + AddInterfaceListenerEventOrProperty (tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt, setListenerMethod); } } - public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt) + public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt, Method setListenerMethod) { if (method.EventName == string.Empty) return; @@ -157,7 +159,7 @@ public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, Interface var mt = target.Methods.Where (method => string.Compare (method.Name, connector_fmt, StringComparison.OrdinalIgnoreCase) == 0 && method.IsListenerConnector).FirstOrDefault (); var hasHandlerArgument = mt != null && mt.IsListenerConnector && mt.Parameters.Count == 2 && mt.Parameters [1].Type == "Android.OS.Handler"; - tw.Events.Add (new InterfaceListenerEvent (iface, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt)); + tw.Events.Add (new InterfaceListenerEvent (iface, setListenerMethod, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt)); } } else { if (opt.GetSafeIdentifier (name) != name) { diff --git a/tools/generator/SourceWriters/InterfaceInvokerMethod.cs b/tools/generator/SourceWriters/InterfaceInvokerMethod.cs index 153ef3736..686ce6122 100644 --- a/tools/generator/SourceWriters/InterfaceInvokerMethod.cs +++ b/tools/generator/SourceWriters/InterfaceInvokerMethod.cs @@ -30,6 +30,8 @@ public InterfaceInvokerMethod (InterfaceGen iface, Method method, CodeGeneration method_callback = new MethodCallback (iface, method, opt, null, method.IsReturnCharSequence); context_this = context.ContextType.GetObjectHandleProperty ("this"); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + this.AddMethodParameters (method.Parameters, opt); } diff --git a/tools/generator/SourceWriters/InterfaceInvokerProperty.cs b/tools/generator/SourceWriters/InterfaceInvokerProperty.cs index f21dc9ac9..6da3e66f5 100644 --- a/tools/generator/SourceWriters/InterfaceInvokerProperty.cs +++ b/tools/generator/SourceWriters/InterfaceInvokerProperty.cs @@ -27,6 +27,8 @@ public InterfaceInvokerProperty (InterfaceGen iface, Property property, CodeGene IsPublic = true; IsUnsafe = true; + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt); + HasGet = property.Getter != null; if (property.Getter != null) { diff --git a/tools/generator/SourceWriters/InterfaceListenerEvent.cs b/tools/generator/SourceWriters/InterfaceListenerEvent.cs index a1b1af076..fb7a2cc4b 100644 --- a/tools/generator/SourceWriters/InterfaceListenerEvent.cs +++ b/tools/generator/SourceWriters/InterfaceListenerEvent.cs @@ -12,13 +12,15 @@ public class InterfaceListenerEvent : EventWriter { readonly InterfaceListenerEventHandlerHelper helper_method; - public InterfaceListenerEvent (InterfaceGen iface, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt) + public InterfaceListenerEvent (InterfaceGen iface, Method method, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt) { Name = name; EventType = new TypeReferenceWriter (opt.GetOutputName (fullDelegateName)); IsPublic = true; + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + HasAdd = true; AddBody.Add ($"global::Java.Interop.EventHelper.AddEventHandler<{opt.GetOutputName (iface.FullName)}, {opt.GetOutputName (iface.FullName)}Implementor>("); @@ -36,7 +38,7 @@ public InterfaceListenerEvent (InterfaceGen iface, string name, string nameSpec, RemoveBody.Add ($"__h => __h.{nameSpec}Handler -= value);"); if (hasHandlerArgument) - helper_method = new InterfaceListenerEventHandlerHelper (iface, add, opt); + helper_method = new InterfaceListenerEventHandlerHelper (iface, method, add, opt); } public override void Write (CodeWriter writer) @@ -49,12 +51,14 @@ public override void Write (CodeWriter writer) public class InterfaceListenerEventHandlerHelper : MethodWriter { - public InterfaceListenerEventHandlerHelper (InterfaceGen iface, string add, CodeGenerationOptions opt) + public InterfaceListenerEventHandlerHelper (InterfaceGen iface, Method method, string add, CodeGenerationOptions opt) { Name = add + "_Event_With_Handler_Helper"; Parameters.Add (new MethodParameterWriter ("value", new TypeReferenceWriter (opt.GetOutputName (iface.FullName)))); ReturnType = TypeReferenceWriter.Void; + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + Body.Add ($"{add} (value, null);"); } } diff --git a/tools/generator/SourceWriters/MethodAsyncWrapper.cs b/tools/generator/SourceWriters/MethodAsyncWrapper.cs index 89b55ede5..838fc368d 100644 --- a/tools/generator/SourceWriters/MethodAsyncWrapper.cs +++ b/tools/generator/SourceWriters/MethodAsyncWrapper.cs @@ -28,6 +28,8 @@ public MethodAsyncWrapper (Method method, CodeGenerationOptions opt) if (!method.IsVoid) ReturnType.Name += "<" + opt.GetTypeReferenceName (method.RetVal) + ">"; + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + Body.Add ($"return global::System.Threading.Tasks.Task.Run (() => {method.AdjustedName} ({method.Parameters.GetCall (opt)}));"); this.AddMethodParameters (method.Parameters, opt); diff --git a/tools/generator/SourceWriters/MethodCallback.cs b/tools/generator/SourceWriters/MethodCallback.cs index 84e6986a5..7563369bb 100644 --- a/tools/generator/SourceWriters/MethodCallback.cs +++ b/tools/generator/SourceWriters/MethodCallback.cs @@ -46,6 +46,8 @@ public MethodCallback (GenBase type, Method method, CodeGenerationOptions option if (!string.IsNullOrWhiteSpace (method.Deprecated)) Attributes.Add (new ObsoleteAttr ()); + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + Parameters.Add (new MethodParameterWriter ("jnienv", TypeReferenceWriter.IntPtr)); Parameters.Add (new MethodParameterWriter ("native__this", TypeReferenceWriter.IntPtr)); @@ -136,6 +138,8 @@ public GetDelegateHandlerMethod (Method method, CodeGenerationOptions opt) if (!string.IsNullOrWhiteSpace (method.Deprecated)) Attributes.Add (new ObsoleteAttr ()); + + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); } protected override void WriteBody (CodeWriter writer) diff --git a/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs b/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs index d62fa6cc6..f7d0cd551 100644 --- a/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs +++ b/tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs @@ -22,6 +22,8 @@ public MethodExtensionAsyncWrapper (Method method, CodeGenerationOptions opt, st if (!method.IsVoid) ReturnType.Name += "<" + opt.GetTypeReferenceName (method.RetVal) + ">"; + SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt); + Body.Add ($"return global::System.Threading.Tasks.Task.Run (() => self.{method.AdjustedName} ({method.Parameters.GetCall (opt)}));"); Parameters.Add (new MethodParameterWriter ("self", new TypeReferenceWriter (selfType)) { IsExtension = true });