From 15040b6b81b4b94647611323880b305ee4706fd1 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 4 Mar 2020 14:18:55 -0600 Subject: [PATCH] [generator] Fix names of classes nested in an interface. --- .../WriteNestedInterfaceClass.txt | 116 ++++++++++++++++++ .../WriteNestedInterfaceClass.txt | 116 ++++++++++++++++++ .../DefaultInterfaceMethodsTests.cs | 30 +++++ .../InterfaceGen.cs | 15 ++- 4 files changed, 269 insertions(+), 8 deletions(-) create mode 100644 tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt create mode 100644 tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt new file mode 100644 index 000000000..ba32a9f79 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteNestedInterfaceClass.txt @@ -0,0 +1,116 @@ +// 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 class reference: path="/api/package[@name='com.xamarin.android']/class[@name='Parent.Child']" + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + public partial class Child : Java.Lang.Object { + + static readonly JniPeerMembers _members = new JniPeerMembers ("com/xamarin/android/Parent$Child", typeof (Child)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Child (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + } + +} + +[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 (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) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + Com.Xamarin.Android.IParent __this = global::Java.Lang.Object.GetObject (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); + } + } + +} + diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt new file mode 100644 index 000000000..d40713502 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteNestedInterfaceClass.txt @@ -0,0 +1,116 @@ +// 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 class reference: path="/api/package[@name='com.xamarin.android']/class[@name='Parent.Child']" + [global::Android.Runtime.Register ("com/xamarin/android/Parent$Child", DoNotGenerateAcw=true)] + public partial class Child : Java.Lang.Object { + + static readonly JniPeerMembers _members = new XAPeerMembers ("com/xamarin/android/Parent$Child", typeof (Child)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected Child (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + } + +} + +[global::Android.Runtime.Register ("com/xamarin/android/Parent", DoNotGenerateAcw=true)] +internal partial class IParentInvoker : global::Java.Lang.Object, IParent { + + static readonly JniPeerMembers _members = new XAPeerMembers ("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 (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) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + Com.Xamarin.Android.IParent __this = global::Java.Lang.Object.GetObject (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); + } + } + +} + diff --git a/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs b/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs index 2438d7328..761d64e2d 100644 --- a/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs +++ b/tests/generator-Tests/Unit-Tests/DefaultInterfaceMethodsTests.cs @@ -241,6 +241,18 @@ public void WriteStaticInterfaceProperty () "; + readonly string nested_class_api = @" + + + + + + + + + + "; + [Test] public void WriteUnnestedInterfaceTypes () { @@ -273,5 +285,23 @@ public void WriteNestedInterfaceTypes () Assert.AreEqual (GetTargetedExpected (nameof (WriteNestedInterfaceTypes)), writer.ToString ().NormalizeLineEndings ()); } + + [Test] + public void WriteNestedInterfaceClass () + { + // Traditionally this would have created namespace.IParent and namespace.IParentChild + // With nested types this creates namespace.IParent and namespace.IParent.IChild + options.SupportNestedInterfaceTypes = true; + + var gens = ParseApiDefinition (nested_class_api); + + var parent_iface = gens.OfType ().Single (); + + parent_iface.Validate (options, new GenericParameterDefinitionList (), new CodeGeneratorContext ()); + + generator.WriteInterface (parent_iface, string.Empty, new GenerationInfo (string.Empty, string.Empty, "MyAssembly")); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteNestedInterfaceClass)), writer.ToString ().NormalizeLineEndings ()); + } } } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs index e1c6f38f1..844cb5d17 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/InterfaceGen.cs @@ -20,15 +20,14 @@ public override void AddNestedType (GenBase gen) var nest_name = gen.JavaName.Substring (JavaName.Length + 1); if (nest_name.IndexOf (".") < 0) { - if (gen is InterfaceGen) { - - // We don't need to mangle the name if we support nested interface types - // ex: my.namespace.IParent.IChild - if (!gen.Unnest) { - gen.FullName = FullName + "." + gen.Name; - return; - } + // We don't need to mangle the name if we support nested interface types + // ex: my.namespace.IParent.IChild + if (!gen.Unnest) { + gen.FullName = FullName + "." + gen.Name; + return; + } + if (gen is InterfaceGen) { // ex: my.namespace.IParentChild gen.FullName = FullName + gen.Name.Substring (1); gen.Name = Name + gen.Name.Substring (1);