From 79a8e1ee93673aa2f8ef9f2ea8cb9bebdc1394df Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 15 Sep 2017 10:58:24 -0400 Subject: [PATCH 1/2] [generator] Fix Formatted() overloads & parameter aliases (#185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=59472 Assume you have the following Java method: ```java class Example { public static CharSequence identity(CharSequence value) { return value; } } ``` When binding `Example.identity()`, we will *rename* it to have a `Formatted` suffix, and "overload" it with a `string` overload: ```csharp partial class Example { public static ICharSequence IdentityFormatted (ICharSequence value) { // ... } public static string Identity (string value) { // ... } } ``` The purpose of this overloading is to make it easier to call the method from C# code. It's not currently possible for interfaces to contain static methods, which in turn means it's not possible for interfaces to contain conversion operators. Thus, if a C# developer wants to do: Example.Identity ("value"); there would be no way to have this Just Work™ while having only `ICharSequence` running around. (Additionally, we rename the method so that we don't need to worry about return types. In the above example, the return type is converted, so if we didn't rename to `IdentityFormatted()`, we couldn't overload for many interesting use cases.) This feature has existed for quite some time, but there's a bug: `Example.Identity()` would do: ```csharp partial class Example { public static string Identity (string value) { var jls_value = value == null ? null : new Java.Lang.String (value) var __result = IdentityFormatted (jls_value); jls_value?.Dispose (); return __result?.ToString (); } } ``` This seems acceptable, but this will break when `Example.IdentityFormatted()` -- `Example.identity()` -- returns the parameter. When that happens, `jls_value` and `__result` are *the same instance*, and thus the `jls_value?.Dispose()` *also* disposes of `__result`. In this case, `__result.ToString()` will be `null`, which is *not* what is desired. The fix is to grab `__result.ToString()` *before* disposing of the temporary parameters: ```csharp partial class Example { public static string Identity (string value) { var jls_value = value == null ? null : new Java.Lang.String (value) var __result = IdentityFormatted (jls_value); var __rsval = __result?.ToString (); jls_value?.Dispose (); return __rsval; } } ``` This way we ensure that we get a copy before the source is disposed. --- tools/generator/Method.cs | 21 ++-- .../Android_Runtime_CharSequence.cs | 33 ++++++ .../SupportFiles/Java_Lang_ICharSequence.cs | 13 +++ .../Tests/SupportFiles/Java_Lang_String.cs | 43 ++++++++ .../TestInterface/Test.ME.ITestInterface.cs | 87 +++++++++++++++ .../Test.ME.TestInterfaceImplementation.cs | 99 +++++++++++++++++ .../TestInterface/Test.ME.ITestInterface.cs | 87 +++++++++++++++ .../Test.ME.TestInterfaceImplementation.cs | 103 ++++++++++++++++++ .../expected/TestInterface/TestInterface.xml | 9 ++ tools/generator/Tests/generator-Tests.csproj | 9 ++ 10 files changed, 495 insertions(+), 9 deletions(-) create mode 100644 tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs create mode 100644 tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs create mode 100644 tools/generator/Tests/SupportFiles/Java_Lang_String.cs diff --git a/tools/generator/Method.cs b/tools/generator/Method.cs index 3a17ec3f3..7f3365abe 100644 --- a/tools/generator/Method.cs +++ b/tools/generator/Method.cs @@ -687,25 +687,28 @@ void GenerateStringOverloadBody (StreamWriter sw, string indent, CodeGenerationO call.Append (pname); } sw.WriteLine ("{0}{1}{2}{3} ({4});", indent, RetVal.IsVoid ? String.Empty : opt.GetOutputName (RetVal.FullName) + " __result = ", haveSelf ? "self." : "", AdjustedName, call.ToString ()); - foreach (Parameter p in Parameters) { - if (p.Type == "Java.Lang.ICharSequence") - sw.WriteLine ("{0}if ({1} != null) {1}.Dispose ();", indent, p.GetName ("jls_")); - else if (p.Type == "Java.Lang.ICharSequence[]") - sw.WriteLine ("{0}if ({1} != null) foreach (global::Java.Lang.String s in {1}) if (s != null) s.Dispose ();", indent, p.GetName ("jlca_")); - } switch (RetVal.FullName) { case "void": break; case "Java.Lang.ICharSequence[]": - sw.WriteLine ("{0}return CharSequence.ArrayToStringArray (__result);", indent); + sw.WriteLine ("{0}var __rsval = CharSequence.ArrayToStringArray (__result);", indent); break; case "Java.Lang.ICharSequence": - sw.WriteLine ("{0}return __result == null ? null : __result.ToString ();", indent); + sw.WriteLine ("{0}var __rsval = __result?.ToString ();", indent); break; default: - sw.WriteLine ("{0}return __result;", indent); + sw.WriteLine ("{0}var __rsval = __result;", indent); break; } + foreach (Parameter p in Parameters) { + if (p.Type == "Java.Lang.ICharSequence") + sw.WriteLine ("{0}{1}?.Dispose ();", indent, p.GetName ("jls_")); + else if (p.Type == "Java.Lang.ICharSequence[]") + sw.WriteLine ("{0}if ({1} != null) foreach (global::Java.Lang.String s in {1}) s?.Dispose ();", indent, p.GetName ("jlca_")); + } + if (!RetVal.IsVoid) { + sw.WriteLine ($"{indent}return __rsval;"); + } } void GenerateStringOverload (StreamWriter sw, string indent, CodeGenerationOptions opt) diff --git a/tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs b/tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs new file mode 100644 index 000000000..7485a7df3 --- /dev/null +++ b/tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace Android.Runtime { + + public static class CharSequence + { + public static Java.Lang.ICharSequence [] ArrayFromStringArray (string [] val) + { + throw new NotImplementedException (); + } + + public static string [] ArrayToStringArray (Java.Lang.ICharSequence [] val) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (string value) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (Java.Lang.ICharSequence value) + { + throw new NotImplementedException (); + } + + public static IntPtr ToLocalJniHandle (IEnumerable value) + { + throw new NotImplementedException (); + } + } +} diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs b/tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs new file mode 100644 index 000000000..5011c3188 --- /dev/null +++ b/tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs @@ -0,0 +1,13 @@ +using System; +using Android.Runtime; + +namespace Java.Lang { + + public partial interface ICharSequence : IJavaObject + { + char CharAt (int index); + int Length (); + Java.Lang.ICharSequence SubSequenceFormatted (int start, int end); + string ToString (); + } +} diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_String.cs b/tools/generator/Tests/SupportFiles/Java_Lang_String.cs new file mode 100644 index 000000000..91bc36268 --- /dev/null +++ b/tools/generator/Tests/SupportFiles/Java_Lang_String.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Java.Lang { + + public sealed partial class String : global::Java.Lang.Object, Java.Lang.ICharSequence + { + public String (string value) + { + } + + public char CharAt (int index) + { + throw new NotImplementedException (); + } + + public int Length () + { + throw new NotImplementedException (); + } + + public Java.Lang.ICharSequence SubSequenceFormatted (int start, int end) + { + throw new NotImplementedException (); + } + + public override string ToString () + { + throw new NotImplementedException (); + } + + public IEnumerator GetEnumerator () + { + throw new NotImplementedException (); + } + + IEnumerator IEnumerable.GetEnumerator () + { + throw new NotImplementedException (); + } + } +} diff --git a/tools/generator/Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs b/tools/generator/Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs index 4ebe9d3dd..7ad9c9352 100644 --- a/tools/generator/Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs +++ b/tools/generator/Tests/expected.ji/TestInterface/Test.ME.ITestInterface.cs @@ -48,6 +48,33 @@ public partial interface ITestInterface : IJavaObject { [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] int GetSpanFlags (global::Java.Lang.Object tag); + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Append (global::Java.Lang.ICharSequence value); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + } + + public static partial class ITestInterfaceExtensions { + + public static void Append (this Test.ME.ITestInterface self, string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + self.Append (jls_value); + jls_value?.Dispose (); + } + + public static string Identity (this Test.ME.ITestInterface self, string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = self.IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } } [global::Android.Runtime.Register ("test/me/TestInterface", DoNotGenerateAcw=true)] @@ -130,6 +157,66 @@ public unsafe int GetSpanFlags (global::Java.Lang.Object tag) return __ret; } + static Delegate cb_append_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + if (cb_append_Ljava_lang_CharSequence_ == null) + cb_append_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Action) n_Append_Ljava_lang_CharSequence_); + return cb_append_Ljava_lang_CharSequence_; + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.ITestInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + IntPtr id_append_Ljava_lang_CharSequence_; + public unsafe void Append (global::Java.Lang.ICharSequence value) + { + if (id_append_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_append_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "append", "(Ljava/lang/CharSequence;)V"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_append_Ljava_lang_CharSequence_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + + static Delegate cb_identity_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + if (cb_identity_Ljava_lang_CharSequence_ == null) + cb_identity_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Func) n_Identity_Ljava_lang_CharSequence_); + return cb_identity_Ljava_lang_CharSequence_; + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.ITestInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_identity_Ljava_lang_CharSequence_; + public unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + if (id_identity_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_identity_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + global::Java.Lang.ICharSequence __ret = global::Java.Lang.Object.GetObject (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_identity_Ljava_lang_CharSequence_, __args), JniHandleOwnership.TransferLocalRef); + JNIEnv.DeleteLocalRef (native_value); + return __ret; + } + } } diff --git a/tools/generator/Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs b/tools/generator/Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs index eec041867..96b7c90c5 100644 --- a/tools/generator/Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs +++ b/tools/generator/Tests/expected.ji/TestInterface/Test.ME.TestInterfaceImplementation.cs @@ -92,6 +92,65 @@ static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] public abstract int GetSpanFlags (global::Java.Lang.Object tag); + static Delegate cb_append_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + if (cb_append_Ljava_lang_CharSequence_ == null) + cb_append_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Action) n_Append_Ljava_lang_CharSequence_); + return cb_append_Ljava_lang_CharSequence_; + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.TestInterfaceImplementation __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public abstract void Append (global::Java.Lang.ICharSequence value); + + public void Append (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + Append (jls_value); + jls_value?.Dispose (); + } + + static Delegate cb_identity_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + if (cb_identity_Ljava_lang_CharSequence_ == null) + cb_identity_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Func) n_Identity_Ljava_lang_CharSequence_); + return cb_identity_Ljava_lang_CharSequence_; + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.TestInterfaceImplementation __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public abstract global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + public string Identity (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + } [global::Android.Runtime.Register ("test/me/TestInterfaceImplementation", DoNotGenerateAcw=true)] @@ -123,6 +182,46 @@ public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) } } + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public override unsafe void Append (global::Java.Lang.ICharSequence value) + { + const string __id = "append.(Ljava/lang/CharSequence;)V"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public override unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + const string __id = "identity.(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"; + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return global::Java.Lang.Object.GetObject (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + + public string Identity (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + } } diff --git a/tools/generator/Tests/expected/TestInterface/Test.ME.ITestInterface.cs b/tools/generator/Tests/expected/TestInterface/Test.ME.ITestInterface.cs index 16016b7fc..88deed9f7 100644 --- a/tools/generator/Tests/expected/TestInterface/Test.ME.ITestInterface.cs +++ b/tools/generator/Tests/expected/TestInterface/Test.ME.ITestInterface.cs @@ -48,6 +48,33 @@ public partial interface ITestInterface : IJavaObject { [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] int GetSpanFlags (global::Java.Lang.Object tag); + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + void Append (global::Java.Lang.ICharSequence value); + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler:Test.ME.ITestInterfaceInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")] + global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + } + + public static partial class ITestInterfaceExtensions { + + public static void Append (this Test.ME.ITestInterface self, string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + self.Append (jls_value); + jls_value?.Dispose (); + } + + public static string Identity (this Test.ME.ITestInterface self, string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = self.IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } } [global::Android.Runtime.Register ("test/me/TestInterface", DoNotGenerateAcw=true)] @@ -122,6 +149,66 @@ public unsafe int GetSpanFlags (global::Java.Lang.Object tag) return __ret; } + static Delegate cb_append_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + if (cb_append_Ljava_lang_CharSequence_ == null) + cb_append_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Action) n_Append_Ljava_lang_CharSequence_); + return cb_append_Ljava_lang_CharSequence_; + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.ITestInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + IntPtr id_append_Ljava_lang_CharSequence_; + public unsafe void Append (global::Java.Lang.ICharSequence value) + { + if (id_append_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_append_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "append", "(Ljava/lang/CharSequence;)V"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_append_Ljava_lang_CharSequence_, __args); + JNIEnv.DeleteLocalRef (native_value); + } + + static Delegate cb_identity_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + if (cb_identity_Ljava_lang_CharSequence_ == null) + cb_identity_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Func) n_Identity_Ljava_lang_CharSequence_); + return cb_identity_Ljava_lang_CharSequence_; + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.ITestInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + IntPtr id_identity_Ljava_lang_CharSequence_; + public unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + if (id_identity_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_identity_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + global::Java.Lang.ICharSequence __ret = global::Java.Lang.Object.GetObject (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_identity_Ljava_lang_CharSequence_, __args), JniHandleOwnership.TransferLocalRef); + JNIEnv.DeleteLocalRef (native_value); + return __ret; + } + } } diff --git a/tools/generator/Tests/expected/TestInterface/Test.ME.TestInterfaceImplementation.cs b/tools/generator/Tests/expected/TestInterface/Test.ME.TestInterfaceImplementation.cs index 51abaf9ef..12b568ff6 100644 --- a/tools/generator/Tests/expected/TestInterface/Test.ME.TestInterfaceImplementation.cs +++ b/tools/generator/Tests/expected/TestInterface/Test.ME.TestInterfaceImplementation.cs @@ -98,6 +98,65 @@ static int n_GetSpanFlags_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this [Register ("getSpanFlags", "(Ljava/lang/Object;)I", "GetGetSpanFlags_Ljava_lang_Object_Handler")] public abstract int GetSpanFlags (global::Java.Lang.Object tag); + static Delegate cb_append_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetAppend_Ljava_lang_CharSequence_Handler () + { + if (cb_append_Ljava_lang_CharSequence_ == null) + cb_append_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Action) n_Append_Ljava_lang_CharSequence_); + return cb_append_Ljava_lang_CharSequence_; + } + + static void n_Append_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.TestInterfaceImplementation __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + __this.Append (value); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public abstract void Append (global::Java.Lang.ICharSequence value); + + public void Append (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + Append (jls_value); + jls_value?.Dispose (); + } + + static Delegate cb_identity_Ljava_lang_CharSequence_; +#pragma warning disable 0169 + static Delegate GetIdentity_Ljava_lang_CharSequence_Handler () + { + if (cb_identity_Ljava_lang_CharSequence_ == null) + cb_identity_Ljava_lang_CharSequence_ = JNINativeWrapper.CreateDelegate ((Func) n_Identity_Ljava_lang_CharSequence_); + return cb_identity_Ljava_lang_CharSequence_; + } + + static IntPtr n_Identity_Ljava_lang_CharSequence_ (IntPtr jnienv, IntPtr native__this, IntPtr native_value) + { + global::Test.ME.TestInterfaceImplementation __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Java.Lang.ICharSequence value = global::Java.Lang.Object.GetObject (native_value, JniHandleOwnership.DoNotTransfer); + IntPtr __ret = CharSequence.ToLocalJniHandle (__this.IdentityFormatted (value)); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public abstract global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value); + + public string Identity (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + } [global::Android.Runtime.Register ("test/me/TestInterfaceImplementation", DoNotGenerateAcw=true)] @@ -125,6 +184,50 @@ public override unsafe int GetSpanFlags (global::Java.Lang.Object tag) } } + static IntPtr id_append_Ljava_lang_CharSequence_; + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='append' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("append", "(Ljava/lang/CharSequence;)V", "GetAppend_Ljava_lang_CharSequence_Handler")] + public override unsafe void Append (global::Java.Lang.ICharSequence value) + { + if (id_append_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_append_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "append", "(Ljava/lang/CharSequence;)V"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + JNIEnv.CallVoidMethod (((global::Java.Lang.Object) this).Handle, id_append_Ljava_lang_CharSequence_, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + + static IntPtr id_identity_Ljava_lang_CharSequence_; + // Metadata.xml XPath method reference: path="/api/package[@name='test.me']/interface[@name='TestInterface']/method[@name='identity' and count(parameter)=1 and parameter[1][@type='java.lang.CharSequence']]" + [Register ("identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;", "GetIdentity_Ljava_lang_CharSequence_Handler")] + public override unsafe global::Java.Lang.ICharSequence IdentityFormatted (global::Java.Lang.ICharSequence value) + { + if (id_identity_Ljava_lang_CharSequence_ == IntPtr.Zero) + id_identity_Ljava_lang_CharSequence_ = JNIEnv.GetMethodID (class_ref, "identity", "(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;"); + IntPtr native_value = CharSequence.ToLocalJniHandle (value); + try { + JValue* __args = stackalloc JValue [1]; + __args [0] = new JValue (native_value); + global::Java.Lang.ICharSequence __ret = global::Java.Lang.Object.GetObject (JNIEnv.CallObjectMethod (((global::Java.Lang.Object) this).Handle, id_identity_Ljava_lang_CharSequence_, __args), JniHandleOwnership.TransferLocalRef); + return __ret; + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + + public string Identity (string value) + { + global::Java.Lang.String jls_value = value == null ? null : new global::Java.Lang.String (value); + global::Java.Lang.ICharSequence __result = IdentityFormatted (jls_value); + var __rsval = __result?.ToString (); + jls_value?.Dispose (); + return __rsval; + } + } } diff --git a/tools/generator/Tests/expected/TestInterface/TestInterface.xml b/tools/generator/Tests/expected/TestInterface/TestInterface.xml index b4905662d..c707d3ecf 100644 --- a/tools/generator/Tests/expected/TestInterface/TestInterface.xml +++ b/tools/generator/Tests/expected/TestInterface/TestInterface.xml @@ -18,6 +18,9 @@ default void defaultInterfaceMethod() { } + + void append(CharSequence value); + CharSequence identity(CharSequence value); } --> @@ -31,6 +34,12 @@ + + + + + +