Skip to content

Commit

Permalink
[generator] Generate more [SupportedOSPlatform] attributes (#868)
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
jpobst committed Aug 27, 2021
1 parent b7982e4 commit f359e73
Show file tree
Hide file tree
Showing 12 changed files with 37 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/BoundMethodStringOverload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions tools/generator/SourceWriters/BoundProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/BoundPropertyStringVariant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/ClassInvokerClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/InterfaceInvokerMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/InterfaceInvokerProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
10 changes: 7 additions & 3 deletions tools/generator/SourceWriters/InterfaceListenerEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(");
Expand All @@ -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)
Expand All @@ -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);");
}
}
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/MethodAsyncWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions tools/generator/SourceWriters/MethodCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions tools/generator/SourceWriters/MethodExtensionAsyncWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down

0 comments on commit f359e73

Please sign in to comment.