Skip to content

Commit

Permalink
[generator] Support using DIM to nest interface types. (#589)
Browse files Browse the repository at this point in the history
Context: #509

Consider the following Java code:

	package example;
	public interface Parent {
	    public interface Child {
	    }
	}

Before C#8, interfaces could not contain types.  To bind
`example.Parent.Child`, we had to "un-nest" the interface, *prefixing*
the interface name with the name of the enclosing type:

	namespace Example {
	    public interface IParent {
	    }
	    public interface IParentChild {
	    }
	}

With C#8, interfaces can now contain types.  We can now emit:

	namespace Example {
	    public interface IParent {
	        public interface IChild {
		}
	    }
	}

Enable this new style of binding when
`generator --lang-features=nested-interface-types` is used.  This is
*disabled* by default.

However, even when `nested-interface-types` is enabled, not all
interfaces should follow this new strategy.  In the case of
`Mono.Android.dll`, nested interface types should *only* be used for
types added in API-R/API-30.

Add support for a new `unnest` Metadata attribute which can be placed
on nested types to explicitly emit the C#7-compatible bindings:

	<attr path="/api/package[@name='example']/interface[@name='Parent.Child']" name="unnest">true</attr>

In a future integration with xamarin-android,
[`src/Mono.Android/metadata`][0] can be updated so that all APIs
prior to API-30 are unnested, and all APIs starting with API-30 are
nested:

	<!-- Handle everything that has always existed -->
	<attr api-since="30" path="/api/package/interface[not(@merge.SourceFile)]" name="unnest">true</attr>
	<attr api-since="30" path="/api/package/class[not(@merge.SourceFile)]" name="unnest">true</attr>

	<!-- Need these 2 for each platform prior to 30 -->
	<attr api-since="30" path="/api/package/interface[contains(@merge.SourceFile,'api-29.xml.in')]" 	name="unnest">true</attr>
	<attr api-since="30" path="/api/package/class[contains(@merge.SourceFile,'api-29.xml.in')]" name="unnest">true</attr>

This will ensure we preserve API compatibility.

[0]: https://github.com/xamarin/xamarin-android/blob/b366ac1e6d411dc052dc8711d881d71b7e967685/src/Mono.Android/metadata
  • Loading branch information
jpobst committed Mar 2, 2020
1 parent cdf840f commit 28b1fc9
Show file tree
Hide file tree
Showing 18 changed files with 833 additions and 34 deletions.
@@ -0,0 +1,179 @@
// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']"
[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")]
public partial interface IParent : IJavaObject, IJavaPeerable {

int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] get;
}

// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']"
[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParent/IChildInvoker")]
public partial interface IChild : IJavaObject, IJavaPeerable {

int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParent/IChildInvoker, MyAssembly")] get;
}

}

[global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)]
internal partial class IChildInvoker : global::Java.Lang.Object, IChild {

static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (IChildInvoker));

static IntPtr java_class_ref {
get { return _members.JniPeerType.PeerReference.Handle; }
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return class_ref; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

new IntPtr class_ref;

public static IChild GetObject (IntPtr handle, JniHandleOwnership transfer)
{
return global::Java.Lang.Object.GetObject<IChild> (handle, transfer);
}

static IntPtr Validate (IntPtr handle)
{
if (!JNIEnv.IsInstanceOf (handle, java_class_ref))
throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.",
JNIEnv.GetClassNameFromInstance (handle), "com.xamarin.android.Parent.Child"));
return handle;
}

protected override void Dispose (bool disposing)
{
if (this.class_ref != IntPtr.Zero)
JNIEnv.DeleteGlobalRef (this.class_ref);
this.class_ref = IntPtr.Zero;
base.Dispose (disposing);
}

public IChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer)
{
IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle);
this.class_ref = JNIEnv.NewGlobalRef (local_ref);
JNIEnv.DeleteLocalRef (local_ref);
}

static Delegate cb_getBar;
#pragma warning disable 0169
static Delegate GetGetBarHandler ()
{
if (cb_getBar == null)
cb_getBar = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, int>) n_GetBar);
return cb_getBar;
}

static int n_GetBar (IntPtr jnienv, IntPtr native__this)
{
Com.Xamarin.Android.IParent.IChild __this = global::Java.Lang.Object.GetObject<Com.Xamarin.Android.IParent.IChild> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return __this.Bar;
}
#pragma warning restore 0169

IntPtr id_getBar;
public unsafe int Bar {
get {
if (id_getBar == IntPtr.Zero)
id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I");
return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar);
}
}

}


}

[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)]
internal partial class IParentInvoker : global::Java.Lang.Object, IParent {

static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker));

static IntPtr java_class_ref {
get { return _members.JniPeerType.PeerReference.Handle; }
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return class_ref; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

new IntPtr class_ref;

public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer)
{
return global::Java.Lang.Object.GetObject<IParent> (handle, transfer);
}

static IntPtr Validate (IntPtr handle)
{
if (!JNIEnv.IsInstanceOf (handle, java_class_ref))
throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.",
JNIEnv.GetClassNameFromInstance (handle), "com.xamarin.android.Parent"));
return handle;
}

protected override void Dispose (bool disposing)
{
if (this.class_ref != IntPtr.Zero)
JNIEnv.DeleteGlobalRef (this.class_ref);
this.class_ref = IntPtr.Zero;
base.Dispose (disposing);
}

public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer)
{
IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle);
this.class_ref = JNIEnv.NewGlobalRef (local_ref);
JNIEnv.DeleteLocalRef (local_ref);
}

static Delegate cb_getBar;
#pragma warning disable 0169
static Delegate GetGetBarHandler ()
{
if (cb_getBar == null)
cb_getBar = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, int>) n_GetBar);
return cb_getBar;
}

static int n_GetBar (IntPtr jnienv, IntPtr native__this)
{
Com.Xamarin.Android.IParent __this = global::Java.Lang.Object.GetObject<Com.Xamarin.Android.IParent> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return __this.Bar;
}
#pragma warning restore 0169

IntPtr id_getBar;
public unsafe int Bar {
get {
if (id_getBar == IntPtr.Zero)
id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I");
return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar);
}
}

}

@@ -0,0 +1,179 @@
// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']"
[Register ("com/xamarin/android/Parent$Child", "", "Com.Xamarin.Android.IParentChildInvoker")]
public partial interface IParentChild : IJavaObject, IJavaPeerable {

int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent.Child']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentChildInvoker, MyAssembly")] get;
}

}

[global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)]
internal partial class IParentChildInvoker : global::Java.Lang.Object, IParentChild {

static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (IParentChildInvoker));

static IntPtr java_class_ref {
get { return _members.JniPeerType.PeerReference.Handle; }
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return class_ref; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

new IntPtr class_ref;

public static IParentChild GetObject (IntPtr handle, JniHandleOwnership transfer)
{
return global::Java.Lang.Object.GetObject<IParentChild> (handle, transfer);
}

static IntPtr Validate (IntPtr handle)
{
if (!JNIEnv.IsInstanceOf (handle, java_class_ref))
throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.",
JNIEnv.GetClassNameFromInstance (handle), "com.xamarin.android.Parent.Child"));
return handle;
}

protected override void Dispose (bool disposing)
{
if (this.class_ref != IntPtr.Zero)
JNIEnv.DeleteGlobalRef (this.class_ref);
this.class_ref = IntPtr.Zero;
base.Dispose (disposing);
}

public IParentChildInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer)
{
IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle);
this.class_ref = JNIEnv.NewGlobalRef (local_ref);
JNIEnv.DeleteLocalRef (local_ref);
}

static Delegate cb_getBar;
#pragma warning disable 0169
static Delegate GetGetBarHandler ()
{
if (cb_getBar == null)
cb_getBar = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, int>) n_GetBar);
return cb_getBar;
}

static int n_GetBar (IntPtr jnienv, IntPtr native__this)
{
Com.Xamarin.Android.IParentChild __this = global::Java.Lang.Object.GetObject<Com.Xamarin.Android.IParentChild> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return __this.Bar;
}
#pragma warning restore 0169

IntPtr id_getBar;
public unsafe int Bar {
get {
if (id_getBar == IntPtr.Zero)
id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I");
return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar);
}
}

}


// Metadata.xml XPath interface reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']"
[Register ("com/xamarin/android/Parent", "", "Com.Xamarin.Android.IParentInvoker")]
public partial interface IParent : IJavaObject, IJavaPeerable {

int Bar {
// Metadata.xml XPath method reference: path="/api/package[@name='com.xamarin.android']/interface[@name='Parent']/method[@name='getBar' and count(parameter)=0]"
[Register ("getBar", "()I", "GetGetBarHandler:Com.Xamarin.Android.IParentInvoker, MyAssembly")] get;
}

}

[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)]
internal partial class IParentInvoker : global::Java.Lang.Object, IParent {

static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent", typeof (IParentInvoker));

static IntPtr java_class_ref {
get { return _members.JniPeerType.PeerReference.Handle; }
}

public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members; }
}

protected override IntPtr ThresholdClass {
get { return class_ref; }
}

protected override global::System.Type ThresholdType {
get { return _members.ManagedPeerType; }
}

new IntPtr class_ref;

public static IParent GetObject (IntPtr handle, JniHandleOwnership transfer)
{
return global::Java.Lang.Object.GetObject<IParent> (handle, transfer);
}

static IntPtr Validate (IntPtr handle)
{
if (!JNIEnv.IsInstanceOf (handle, java_class_ref))
throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.",
JNIEnv.GetClassNameFromInstance (handle), "com.xamarin.android.Parent"));
return handle;
}

protected override void Dispose (bool disposing)
{
if (this.class_ref != IntPtr.Zero)
JNIEnv.DeleteGlobalRef (this.class_ref);
this.class_ref = IntPtr.Zero;
base.Dispose (disposing);
}

public IParentInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer)
{
IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle);
this.class_ref = JNIEnv.NewGlobalRef (local_ref);
JNIEnv.DeleteLocalRef (local_ref);
}

static Delegate cb_getBar;
#pragma warning disable 0169
static Delegate GetGetBarHandler ()
{
if (cb_getBar == null)
cb_getBar = JNINativeWrapper.CreateDelegate ((Func<IntPtr, IntPtr, int>) n_GetBar);
return cb_getBar;
}

static int n_GetBar (IntPtr jnienv, IntPtr native__this)
{
Com.Xamarin.Android.IParent __this = global::Java.Lang.Object.GetObject<Com.Xamarin.Android.IParent> (jnienv, native__this, JniHandleOwnership.DoNotTransfer);
return __this.Bar;
}
#pragma warning restore 0169

IntPtr id_getBar;
public unsafe int Bar {
get {
if (id_getBar == IntPtr.Zero)
id_getBar = JNIEnv.GetMethodID (class_ref, "getBar", "()I");
return JNIEnv.CallIntMethod (((global::Java.Lang.Object) this).Handle, id_getBar);
}
}

}

0 comments on commit 28b1fc9

Please sign in to comment.