diff --git a/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs b/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs new file mode 100644 index 000000000..11b49c10d --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/BlittableTypeTests.cs @@ -0,0 +1,142 @@ +using System; +using MonoDroid.Generation; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests; + +[TestFixture] +class BlittableTypeTests : CodeGeneratorTestBase +{ + protected override CodeGenerationTarget Target => CodeGenerationTarget.XAJavaInterop1; + + [Test] + public void MethodWithBoolReturnType () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "IsEmpty", options, "boolean"); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Return type should be byte + Assert.That (actual, Contains.Substring ("static sbyte n_IsEmpty")); + + // Return statement should convert to 0 or 1 + Assert.That (actual, Contains.Substring ("return __this.IsEmpty () ? (sbyte)1 : (sbyte)0")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_B")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_Z")); + } + + [Test] + public void MethodWithBoolParameter () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "SetEmpty", options, "void", parameters: new Parameter ("value", "boolean", "bool", false)); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Method parameter should be byte + Assert.That (actual, Contains.Substring ("static void n_SetEmpty_Z (IntPtr jnienv, IntPtr native__this, sbyte native_value)")); + + // Method should convert from 0 or 1 + Assert.That (actual, Contains.Substring ("var value = native_value != 0;")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PPB_V")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PPZ_V")); + } + + [Test] + public void BoolProperty () + { + var klass = SupportTypeBuilder.CreateClassWithProperty ("MyClass", "com.example.myClass", "IsEmpty", "boolean", options); + var actual = GetGeneratedTypeOutput (klass); + + // Getter return type should be byte + Assert.That (actual, Contains.Substring ("static sbyte n_get_IsEmpty")); + + // Getter return statement should convert to 0 or 1 + Assert.That (actual, Contains.Substring ("return __this.IsEmpty ? (sbyte)1 : (sbyte)0")); + + // Setter parameter should be byte + Assert.That (actual, Contains.Substring ("static void n_set_IsEmpty_Z (IntPtr jnienv, IntPtr native__this, sbyte native_value)")); + + // Setter should convert from 0 or 1 + Assert.That (actual, Contains.Substring ("var value = native_value != 0;")); + + // Ensure the marshal delegate is byte + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_B")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_Z")); + } + + [Test] + public void MethodWithCharReturnType () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "GetFirstLetter", options, "char"); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Return type should be ushort + Assert.That (actual, Contains.Substring ("static ushort n_GetFirstLetter")); + + // Return statement should convert to ushort + Assert.That (actual, Contains.Substring ("return (ushort)__this.GetFirstLetter ()")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_s")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_C")); + } + + [Test] + public void MethodWithCharParameter () + { + var klass = new TestClass ("Object", "java.code.MyClass"); + var method = SupportTypeBuilder.CreateMethod (klass, "SetFirstLetter", options, "void", parameters: new Parameter ("value", "char", "char", false)); + + klass.Methods.Add (method); + + var actual = GetGeneratedTypeOutput (klass); + + // Method parameter should be ushort + Assert.That (actual, Contains.Substring ("static void n_SetFirstLetter_C (IntPtr jnienv, IntPtr native__this, ushort native_value)")); + + // Method should convert from ushort to char + Assert.That (actual, Contains.Substring ("var value = (char)native_value;")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PPs_V")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PPC_V")); + } + + [Test] + public void CharProperty () + { + var klass = SupportTypeBuilder.CreateClassWithProperty ("MyClass", "com.example.myClass", "FirstLetter", "char", options); + var actual = GetGeneratedTypeOutput (klass); + + // Getter return type should be ushort + Assert.That (actual, Contains.Substring ("static ushort n_get_FirstLetter")); + + // Getter return statement should convert to ushort + Assert.That (actual, Contains.Substring ("return (ushort)__this.FirstLetter")); + + // Setter parameter should be ushort + Assert.That (actual, Contains.Substring ("static void n_set_FirstLetter_C (IntPtr jnienv, IntPtr native__this, ushort native_value)")); + + // Setter should convert from ushort to char + Assert.That (actual, Contains.Substring ("var value = (char)native_value;")); + + // Ensure the marshal delegate is ushort + Assert.That (actual, Contains.Substring ("new _JniMarshal_PP_s")); + Assert.That (actual, Does.Not.Contains ("new _JniMarshal_PP_C")); + } +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt index 1a00e3a9e..22e295d12 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/Common/WriteDuplicateInterfaceEventArgs.txt @@ -70,18 +70,18 @@ internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, Anima #pragma warning disable 0169 static Delegate GetOnAnimationEnd_IHandler () { - return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_Z (n_OnAnimationEnd_I); + return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_B (n_OnAnimationEnd_I); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) + static sbyte n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); - return __this.OnAnimationEnd (param1); + return __this.OnAnimationEnd (param1) ? (sbyte)1 : (sbyte)0; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); return default; @@ -105,18 +105,18 @@ internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, Anima #pragma warning disable 0169 static Delegate GetOnAnimationEnd_IIHandler () { - return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_Z (n_OnAnimationEnd_II); + return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_B (n_OnAnimationEnd_II); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) + static sbyte n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); - return __this.OnAnimationEnd (param1, param2); + return __this.OnAnimationEnd (param1, param2) ? (sbyte)1 : (sbyte)0; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); return default; diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt index 1a00e3a9e..22e295d12 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/XAJavaInterop1/WriteDuplicateInterfaceEventArgs.txt @@ -70,18 +70,18 @@ internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, Anima #pragma warning disable 0169 static Delegate GetOnAnimationEnd_IHandler () { - return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_Z (n_OnAnimationEnd_I); + return cb_OnAnimationEnd_OnAnimationEnd_I_Z ??= new _JniMarshal_PPI_B (n_OnAnimationEnd_I); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) + static sbyte n_OnAnimationEnd_I (IntPtr jnienv, IntPtr native__this, int param1) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); - return __this.OnAnimationEnd (param1); + return __this.OnAnimationEnd (param1) ? (sbyte)1 : (sbyte)0; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); return default; @@ -105,18 +105,18 @@ internal partial class AnimatorListenerInvoker : global::Java.Lang.Object, Anima #pragma warning disable 0169 static Delegate GetOnAnimationEnd_IIHandler () { - return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_Z (n_OnAnimationEnd_II); + return cb_OnAnimationEnd_OnAnimationEnd_II_Z ??= new _JniMarshal_PPII_B (n_OnAnimationEnd_II); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) + static sbyte n_OnAnimationEnd_II (IntPtr jnienv, IntPtr native__this, int param1, int param2) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); - return __this.OnAnimationEnd (param1, param2); + return __this.OnAnimationEnd (param1, param2) ? (sbyte)1 : (sbyte)0; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); return default; diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs index 65ea9d8a4..5709772e5 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTestBase.cs @@ -131,5 +131,14 @@ protected static string GetAssertionMessage (string header, string expected, str $"Expected:\n```\n{expected}\n```\n" + $"Actual:\n```\n{actual}\n```"; } + + protected string GetGeneratedTypeOutput (GenBase gen) + { + generator.Context.ContextTypes.Push (gen); + generator.WriteType (gen, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + return writer.ToString (); + } } } diff --git a/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs b/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs index 52ec10374..6a6d14288 100644 --- a/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs +++ b/tests/generator-Tests/expected.xaji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaCrypto.cs @@ -48,11 +48,11 @@ public IExoMediaCryptoInvoker (IntPtr handle, JniHandleOwnership transfer) : bas #pragma warning disable 0169 static Delegate GetRequiresSecureDecoderComponent_Ljava_lang_String_Handler () { - return cb_requiresSecureDecoderComponent_RequiresSecureDecoderComponent_Ljava_lang_String__Z ??= new _JniMarshal_PPL_Z (n_RequiresSecureDecoderComponent_Ljava_lang_String_); + return cb_requiresSecureDecoderComponent_RequiresSecureDecoderComponent_Ljava_lang_String__Z ??= new _JniMarshal_PPL_B (n_RequiresSecureDecoderComponent_Ljava_lang_String_); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_RequiresSecureDecoderComponent_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) + static sbyte n_RequiresSecureDecoderComponent_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p0) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; @@ -60,7 +60,7 @@ static bool n_RequiresSecureDecoderComponent_Ljava_lang_String_ (IntPtr jnienv, try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); var p0 = JNIEnv.GetString (native_p0, JniHandleOwnership.DoNotTransfer); - bool __ret = __this.RequiresSecureDecoderComponent (p0); + sbyte __ret = __this.RequiresSecureDecoderComponent (p0) ? (sbyte)1 : (sbyte)0; return __ret; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); diff --git a/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs b/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs index 35c4547b6..5c1d44a86 100644 --- a/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs +++ b/tests/generator-Tests/expected.xaji/GenericArguments/__NamespaceMapping__.cs @@ -4,9 +4,9 @@ [assembly:global::Android.Runtime.NamespaceMapping (Java = "com.google.android.exoplayer.drm", Managed="Com.Google.Android.Exoplayer.Drm")] [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] -delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); +delegate sbyte _JniMarshal_PPL_B (IntPtr jnienv, IntPtr klass, IntPtr p0); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] -delegate bool _JniMarshal_PPL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0); +delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate void _JniMarshal_PPLLIIL_V (IntPtr jnienv, IntPtr klass, IntPtr p0, IntPtr p1, int p2, int p3, IntPtr p4); #if !NET diff --git a/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs b/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs index b785e84ae..fe6c29655 100644 --- a/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs +++ b/tests/generator-Tests/expected.xaji/Streams/Java.IO.InputStream.cs @@ -176,18 +176,18 @@ public virtual unsafe void Mark (int readlimit) #pragma warning disable 0169 static Delegate GetMarkSupportedHandler () { - return cb_markSupported_MarkSupported_Z ??= new _JniMarshal_PP_Z (n_MarkSupported); + return cb_markSupported_MarkSupported_Z ??= new _JniMarshal_PP_B (n_MarkSupported); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_MarkSupported (IntPtr jnienv, IntPtr native__this) + static sbyte n_MarkSupported (IntPtr jnienv, IntPtr native__this) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); - return __this.MarkSupported (); + return __this.MarkSupported () ? (sbyte)1 : (sbyte)0; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); return default; diff --git a/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs b/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs index ce368cc40..12d463858 100644 --- a/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs +++ b/tests/generator-Tests/expected.xaji/Streams/__NamespaceMapping__.cs @@ -3,6 +3,8 @@ [assembly:global::Android.Runtime.NamespaceMapping (Java = "java.lang", Managed="Java.Lang")] [assembly:global::Android.Runtime.NamespaceMapping (Java = "java.io", Managed="Java.IO")] +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate sbyte _JniMarshal_PP_B (IntPtr jnienv, IntPtr klass); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate int _JniMarshal_PP_I (IntPtr jnienv, IntPtr klass); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] @@ -10,8 +12,6 @@ [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] -delegate bool _JniMarshal_PP_Z (IntPtr jnienv, IntPtr klass); -[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate void _JniMarshal_PPI_V (IntPtr jnienv, IntPtr klass, int p0); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate long _JniMarshal_PPJ_J (IntPtr jnienv, IntPtr klass, long p0); diff --git a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs index 14f70b75d..7e73eb5bd 100644 --- a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs +++ b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.ICollection.cs @@ -53,11 +53,11 @@ public ICollectionInvoker (IntPtr handle, JniHandleOwnership transfer) : base (h #pragma warning disable 0169 static Delegate GetAdd_Ljava_lang_Object_Handler () { - return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_Z (n_Add_Ljava_lang_Object_); + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; @@ -65,7 +65,7 @@ static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); - bool __ret = __this.Add (e); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; return __ret; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); diff --git a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs index 51deba137..af1bf8cab 100644 --- a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs +++ b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IDeque.cs @@ -53,11 +53,11 @@ public IDequeInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle #pragma warning disable 0169 static Delegate GetAdd_Ljava_lang_Object_Handler () { - return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_Z (n_Add_Ljava_lang_Object_); + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; @@ -65,7 +65,7 @@ static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); - bool __ret = __this.Add (e); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; return __ret; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); diff --git a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs index f17456d61..cce3be5d3 100644 --- a/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs +++ b/tests/generator-Tests/expected.xaji/TestInterface/Java.Util.IQueue.cs @@ -51,11 +51,11 @@ public IQueueInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle #pragma warning disable 0169 static Delegate GetAdd_Ljava_lang_Object_Handler () { - return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_Z (n_Add_Ljava_lang_Object_); + return cb_add_Add_Ljava_lang_Object__Z ??= new _JniMarshal_PPL_B (n_Add_Ljava_lang_Object_); } [global::System.Diagnostics.DebuggerDisableUserUnhandledExceptions] - static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) + static sbyte n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr native_e) { if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return default; @@ -63,7 +63,7 @@ static bool n_Add_Ljava_lang_Object_ (IntPtr jnienv, IntPtr native__this, IntPtr try { var __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); var e = global::Java.Lang.Object.GetObject (native_e, JniHandleOwnership.DoNotTransfer); - bool __ret = __this.Add (e); + sbyte __ret = __this.Add (e) ? (sbyte)1 : (sbyte)0; return __ret; } catch (global::System.Exception __e) { __r.OnUserUnhandledException (ref __envp, __e); diff --git a/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs b/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs index 825ceb91a..046b83dd1 100644 --- a/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs +++ b/tests/generator-Tests/expected.xaji/TestInterface/__NamespaceMapping__.cs @@ -10,13 +10,13 @@ [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate void _JniMarshal_PP_V (IntPtr jnienv, IntPtr klass); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] +delegate sbyte _JniMarshal_PPL_B (IntPtr jnienv, IntPtr klass, IntPtr p0); +[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate int _JniMarshal_PPL_I (IntPtr jnienv, IntPtr klass, IntPtr p0); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate IntPtr _JniMarshal_PPL_L (IntPtr jnienv, IntPtr klass, IntPtr p0); [global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] delegate void _JniMarshal_PPL_V (IntPtr jnienv, IntPtr klass, IntPtr p0); -[global::System.Runtime.InteropServices.UnmanagedFunctionPointer (global::System.Runtime.InteropServices.CallingConvention.Winapi)] -delegate bool _JniMarshal_PPL_Z (IntPtr jnienv, IntPtr klass, IntPtr p0); #if !NET namespace System.Runtime.Versioning { [System.Diagnostics.Conditional("NEVER")] diff --git a/tools/generator/CodeGenerationOptions.cs b/tools/generator/CodeGenerationOptions.cs index 51f244451..d3c50a254 100644 --- a/tools/generator/CodeGenerationOptions.cs +++ b/tools/generator/CodeGenerationOptions.cs @@ -217,6 +217,8 @@ string GetJniTypeCode (ISymbol symbol) case "uint": return "i"; case "ulong": return "j"; case "ushort": return "s"; + case "boolean": return "B"; // We marshal boolean (Z) as byte (B) + case "char": return "s"; // We marshal char (C) as ushort (s) } var jni_name = symbol.JniName; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs index 57a629485..3f3bb13f4 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs @@ -97,7 +97,7 @@ public string RawJavaType { public ISymbol Symbol => sym; - public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned, bool isMarshal = false) { if (!string.IsNullOrEmpty (managed_type) && (sym is ClassGen || sym is InterfaceGen)) { if (opt.CodeGenerationTarget == Xamarin.Android.Binder.CodeGenerationTarget.JavaInterop1) { @@ -108,7 +108,7 @@ public string FromNative (CodeGenerationOptions opt, string var_name, bool owned return string.Format ("global::Java.Lang.Object.GetObject<{0}> ({1}, {2})", opt.GetOutputName (managed_type), var_name, owned ? "JniHandleOwnership.TransferLocalRef" : "JniHandleOwnership.DoNotTransfer"); } - return sym.FromNative (opt, var_name, owned); + return sym.FromNative (opt, var_name, owned, isMarshal); } public string ToNative (CodeGenerationOptions opt, string var_name) diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs index a6aaa4f0e..abbb5cfe9 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs @@ -116,6 +116,8 @@ public string[] PostCall (CodeGenerationOptions opt, string var_name) } public bool NeedsPrep { get { return false; } } + + public bool OnlyFormatOnMarshal { get; set; } } } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs index 5b1566a31..15ff68daf 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs @@ -15,10 +15,23 @@ public interface ISymbol { string ElementType { get; } string ReturnCast { get; } + // Only apply ToNative/FromNative for marshal methods. This is used when + // we want to change the marshal type to be blittable, like bool -> byte. + // But it will not be used for normal invocations, like InvokeVirtualBooleanMethod, etc. + bool OnlyFormatOnMarshal { get => false; } + string GetObjectHandleProperty (CodeGenerationOptions opt, string variable); string GetGenericType (Dictionary mappings); + string FromNative (CodeGenerationOptions opt, string var_name, bool owned, bool isMarshal = true) + { + if (OnlyFormatOnMarshal && !isMarshal) + return var_name; + + return FromNative (opt, var_name, owned); + } + string FromNative (CodeGenerationOptions opt, string var_name, bool owned); string ToNative (CodeGenerationOptions opt, string var_name, Dictionary mappings = null); diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs index 259e8c0f1..3d9353563 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs @@ -57,9 +57,9 @@ public SymbolTable (CodeGenerationTarget target) this.target = target; AddType (new SimpleSymbol ("IntPtr.Zero", "void", "void", "V")); - AddType (new SimpleSymbol ("false", "boolean", "bool", "Z")); + AddType (new SimpleSymbol ("false", "boolean", "bool", "Z", "sbyte", from_fmt: "{0} != 0", to_fmt: "{0} ? (sbyte)1 : (sbyte)0") { OnlyFormatOnMarshal = true }); AddType (new SimpleSymbol ("0", "byte", "sbyte", "B")); - AddType (new SimpleSymbol ("(char)0", "char", "char", "C")); + AddType (new SimpleSymbol ("(char)0", "char", "char", "C", "ushort", from_fmt: "(char){0}", to_fmt: "(ushort){0}") { OnlyFormatOnMarshal = true }); AddType (new SimpleSymbol ("0.0", "double", "double", "D")); AddType (new SimpleSymbol ("0.0F", "float", "float", "F")); AddType (new SimpleSymbol ("0", "int", "int", "I")); diff --git a/tools/generator/SourceWriters/BoundFieldAsProperty.cs b/tools/generator/SourceWriters/BoundFieldAsProperty.cs index c7f2560cd..5ebe97f95 100644 --- a/tools/generator/SourceWriters/BoundFieldAsProperty.cs +++ b/tools/generator/SourceWriters/BoundFieldAsProperty.cs @@ -94,7 +94,7 @@ protected override void WriteGetterBody (CodeWriter writer) writer.WriteLine ($"var __v = {field.Symbol.ReturnCast}_members.{indirect}.{invoke} (__id{(field.IsStatic ? "" : ", this")});"); if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { - if (field.Symbol.NativeType == field.Symbol.FullName) { + if (field.Symbol.NativeType == field.Symbol.FullName || field.Symbol.OnlyFormatOnMarshal) { writer.WriteLine ("return __v;"); return; } @@ -107,8 +107,8 @@ protected override void WriteGetterBody (CodeWriter writer) if (field.Symbol.IsArray) { writer.WriteLine ($"return global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);"); - } else if (field.Symbol.NativeType != field.Symbol.FullName) { - writer.WriteLine ($"return {field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true) + opt.GetNullForgiveness (field))};"); + } else if (field.Symbol.NativeType != field.Symbol.FullName && !field.Symbol.OnlyFormatOnMarshal) { + writer.WriteLine ($"return {field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true, false) + opt.GetNullForgiveness (field))};"); } else { writer.WriteLine ("return __v;"); } @@ -155,7 +155,10 @@ protected override void WriteSetterBody (CodeWriter writer) if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { if (invokeType != "Object" || have_prep) { - writer.Write (arg); + if (field.SetParameters [0].Symbol.OnlyFormatOnMarshal) + writer.Write (opt.GetSafeIdentifier (field.SetParameters [0].Name)); + else + writer.Write (arg); } else { writer.Write ($"{arg}?.PeerReference ?? default"); } diff --git a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs index 610dca21e..7170f74d0 100644 --- a/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs +++ b/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs @@ -284,7 +284,7 @@ public static void AddMethodBodyTryBlock (List body, Method method, Code if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1 && invokeType == "Object") { r += ".Handle"; } - body.Add ($"\treturn {method.RetVal.ReturnCast}{method.RetVal.FromNative (opt, r, true) + opt.GetNullForgiveness (method.RetVal)};"); + body.Add ($"\treturn {method.RetVal.ReturnCast}{method.RetVal.FromNative (opt, r, true, false) + opt.GetNullForgiveness (method.RetVal)};"); } }