Skip to content

Commit f359e73

Browse files
authored
[generator] Generate more [SupportedOSPlatform] attributes (#868)
Fixes: #863 In commits da12df4 and 412e974 (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`.
1 parent b7982e4 commit f359e73

12 files changed

+37
-11
lines changed

tools/generator/SourceWriters/BoundMethodExtensionStringOverload.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public BoundMethodExtensionStringOverload (Method method, CodeGenerationOptions
2929
if (method.Deprecated != null)
3030
Attributes.Add (new ObsoleteAttr (method.Deprecated.Replace ("\"", "\"\"").Trim ()));
3131

32+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
33+
3234
Parameters.Add (new MethodParameterWriter ("self", new TypeReferenceWriter (selfType)) { IsExtension = true });
3335
this.AddMethodParametersStringOverloads (method.Parameters, opt);
3436
}

tools/generator/SourceWriters/BoundMethodStringOverload.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public BoundMethodStringOverload (Method method, CodeGenerationOptions opt)
2727
if (method.Deprecated != null)
2828
Attributes.Add (new ObsoleteAttr (method.Deprecated.Replace ("\"", "\"\"").Trim ()));
2929

30+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
31+
3032
method.JavadocInfo?.AddJavadocs (Comments);
3133

3234
this.AddMethodParametersStringOverloads (method.Parameters, opt);

tools/generator/SourceWriters/BoundProperty.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ public BoundProperty (GenBase gen, Property property, CodeGenerationOptions opt,
6969
if (property.Getter.Deprecated != null && (property.Setter == null || property.Setter.Deprecated != null))
7070
Attributes.Add (new ObsoleteAttr (property.Getter.Deprecated.Replace ("\"", "\"\"").Trim () + (property.Setter != null && property.Setter.Deprecated != property.Getter.Deprecated ? " " + property.Setter.Deprecated.Replace ("\"", "\"\"").Trim () : null)));
7171

72+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt);
73+
7274
SourceWriterExtensions.AddMethodCustomAttributes (GetterAttributes, property.Getter);
7375

7476
if (gen.IsGeneratable)
7577
GetterComments.Add ($"// Metadata.xml XPath method reference: path=\"{gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\"");
7678

77-
SourceWriterExtensions.AddSupportedOSPlatform (GetterAttributes, property.Getter, opt);
78-
7979
GetterAttributes.Add (new RegisterAttr (property.Getter.JavaName, property.Getter.JniSignature, property.Getter.IsVirtual ? property.Getter.GetConnectorNameFull (opt) : string.Empty, additionalProperties: property.Getter.AdditionalAttributeString ()));
8080

8181
SourceWriterExtensions.AddMethodBody (GetBody, property.Getter, opt);

tools/generator/SourceWriters/BoundPropertyStringVariant.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public BoundPropertyStringVariant (Property property, CodeGenerationOptions opt)
2424

2525
SetVisibility ((property.Setter ?? property.Getter).Visibility);
2626

27+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt);
28+
2729
HasGet = true;
2830

2931
if (is_array)

tools/generator/SourceWriters/ClassInvokerClass.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public ClassInvokerClass (ClassGen klass, CodeGenerationOptions opt)
2626

2727
Attributes.Add (new RegisterAttr (klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString ()) { UseGlobal = true });
2828

29+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, klass, opt);
30+
2931
var ctor = new ConstructorWriter {
3032
Name = Name,
3133
IsPublic = true,

tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter
8585

8686
AddInterfaceListenerEventsAndProperties (tw, iface, target, name, setter,
8787
string.Format ("__v => {0} = __v", prop.Name),
88-
string.Format ("__v => {0} = null", prop.Name), opt);
88+
string.Format ("__v => {0} = null", prop.Name), opt, prop.Getter);
8989
} else {
9090
refs.Add (method.Name);
9191
string rm = null;
@@ -103,7 +103,7 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter
103103

104104
AddInterfaceListenerEventsAndProperties (tw, iface, target, name, method.Name,
105105
method.Name,
106-
remove, opt);
106+
remove, opt, method);
107107
}
108108
}
109109

@@ -113,7 +113,9 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter
113113
tw.Methods.Add (new CreateImplementorMethod (iface, opt));
114114
}
115115

116-
public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt)
116+
// Parameter 'setListenerMethod' refers to the method used to set the listener, like 'addOnRoutingChangedListener'/'setOnRoutingChangedListener'.
117+
// This is used to determine what API level the listener setter is available on.
118+
public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, InterfaceGen iface, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt, Method setListenerMethod)
117119
{
118120
if (!iface.IsValid)
119121
return;
@@ -128,11 +130,11 @@ public static void AddInterfaceListenerEventsAndProperties (TypeWriter tw, Inter
128130
if (target.ContainsName (nameUnique))
129131
nameUnique += "Event";
130132

131-
AddInterfaceListenerEventOrProperty (tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt);
133+
AddInterfaceListenerEventOrProperty (tw, iface, method, target, nameUnique, connector_fmt, add, remove, opt, setListenerMethod);
132134
}
133135
}
134136

135-
public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt)
137+
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)
136138
{
137139
if (method.EventName == string.Empty)
138140
return;
@@ -157,7 +159,7 @@ public static void AddInterfaceListenerEventOrProperty (TypeWriter tw, Interface
157159
var mt = target.Methods.Where (method => string.Compare (method.Name, connector_fmt, StringComparison.OrdinalIgnoreCase) == 0 && method.IsListenerConnector).FirstOrDefault ();
158160
var hasHandlerArgument = mt != null && mt.IsListenerConnector && mt.Parameters.Count == 2 && mt.Parameters [1].Type == "Android.OS.Handler";
159161

160-
tw.Events.Add (new InterfaceListenerEvent (iface, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt));
162+
tw.Events.Add (new InterfaceListenerEvent (iface, setListenerMethod, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt));
161163
}
162164
} else {
163165
if (opt.GetSafeIdentifier (name) != name) {

tools/generator/SourceWriters/InterfaceInvokerMethod.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public InterfaceInvokerMethod (InterfaceGen iface, Method method, CodeGeneration
3030
method_callback = new MethodCallback (iface, method, opt, null, method.IsReturnCharSequence);
3131
context_this = context.ContextType.GetObjectHandleProperty ("this");
3232

33+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
34+
3335
this.AddMethodParameters (method.Parameters, opt);
3436
}
3537

tools/generator/SourceWriters/InterfaceInvokerProperty.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public InterfaceInvokerProperty (InterfaceGen iface, Property property, CodeGene
2727
IsPublic = true;
2828
IsUnsafe = true;
2929

30+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, property.Getter, opt);
31+
3032
HasGet = property.Getter != null;
3133

3234
if (property.Getter != null) {

tools/generator/SourceWriters/InterfaceListenerEvent.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ public class InterfaceListenerEvent : EventWriter
1212
{
1313
readonly InterfaceListenerEventHandlerHelper helper_method;
1414

15-
public InterfaceListenerEvent (InterfaceGen iface, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt)
15+
public InterfaceListenerEvent (InterfaceGen iface, Method method, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt)
1616
{
1717
Name = name;
1818
EventType = new TypeReferenceWriter (opt.GetOutputName (fullDelegateName));
1919

2020
IsPublic = true;
2121

22+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
23+
2224
HasAdd = true;
2325

2426
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,
3638
RemoveBody.Add ($"__h => __h.{nameSpec}Handler -= value);");
3739

3840
if (hasHandlerArgument)
39-
helper_method = new InterfaceListenerEventHandlerHelper (iface, add, opt);
41+
helper_method = new InterfaceListenerEventHandlerHelper (iface, method, add, opt);
4042
}
4143

4244
public override void Write (CodeWriter writer)
@@ -49,12 +51,14 @@ public override void Write (CodeWriter writer)
4951

5052
public class InterfaceListenerEventHandlerHelper : MethodWriter
5153
{
52-
public InterfaceListenerEventHandlerHelper (InterfaceGen iface, string add, CodeGenerationOptions opt)
54+
public InterfaceListenerEventHandlerHelper (InterfaceGen iface, Method method, string add, CodeGenerationOptions opt)
5355
{
5456
Name = add + "_Event_With_Handler_Helper";
5557
Parameters.Add (new MethodParameterWriter ("value", new TypeReferenceWriter (opt.GetOutputName (iface.FullName))));
5658
ReturnType = TypeReferenceWriter.Void;
5759

60+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
61+
5862
Body.Add ($"{add} (value, null);");
5963
}
6064
}

tools/generator/SourceWriters/MethodAsyncWrapper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public MethodAsyncWrapper (Method method, CodeGenerationOptions opt)
2828
if (!method.IsVoid)
2929
ReturnType.Name += "<" + opt.GetTypeReferenceName (method.RetVal) + ">";
3030

31+
SourceWriterExtensions.AddSupportedOSPlatform (Attributes, method, opt);
32+
3133
Body.Add ($"return global::System.Threading.Tasks.Task.Run (() => {method.AdjustedName} ({method.Parameters.GetCall (opt)}));");
3234

3335
this.AddMethodParameters (method.Parameters, opt);

0 commit comments

Comments
 (0)