diff --git a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs index 41ea7cd22..97c34f0b1 100644 --- a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs +++ b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs @@ -232,10 +232,16 @@ static string GetPrimitiveClass (Type type) return "F"; if (type == typeof (int)) return "I"; + if (type == typeof (uint)) + return "I"; if (type == typeof (long)) return "J"; + if (type == typeof (ulong)) + return "J"; if (type == typeof (short)) return "S"; + if (type == typeof (ushort)) + return "S"; if (type == typeof (bool)) return "Z"; return null; diff --git a/src/Java.Interop/Java.Interop/JniArgumentValue.cs b/src/Java.Interop/Java.Interop/JniArgumentValue.cs index 86248e312..1e9a6dbda 100644 --- a/src/Java.Interop/Java.Interop/JniArgumentValue.cs +++ b/src/Java.Interop/Java.Interop/JniArgumentValue.cs @@ -34,6 +34,8 @@ public JniArgumentValue (sbyte value) b = value; } + public JniArgumentValue (byte value) : this ((sbyte)value) { } + public JniArgumentValue (char value) { this = new JniArgumentValue (); @@ -46,18 +48,24 @@ public JniArgumentValue (short value) s = value; } + public JniArgumentValue (ushort value) : this ((short)value) { } + public JniArgumentValue (int value) { this = new JniArgumentValue (); i = value; } + public JniArgumentValue (uint value) : this ((int)value) { } + public JniArgumentValue (long value) { this = new JniArgumentValue (); j = value; } + public JniArgumentValue (ulong value) : this ((long) value) { } + public JniArgumentValue (float value) { this = new JniArgumentValue (); diff --git a/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs b/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs index 61cd2dbca..877b7d58b 100644 --- a/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs +++ b/src/Xamarin.Android.Tools.ApiXmlAdjuster/JavaTypeReference.cs @@ -16,7 +16,11 @@ public class JavaTypeReference public static readonly JavaTypeReference Float; public static readonly JavaTypeReference Double; public static readonly JavaTypeReference GenericWildcard; - + public static readonly JavaTypeReference UInt; + public static readonly JavaTypeReference UShort; + public static readonly JavaTypeReference ULong; + public static readonly JavaTypeReference UByte; + internal static JavaTypeReference GetSpecialType (string name) { switch (name) { @@ -29,6 +33,10 @@ internal static JavaTypeReference GetSpecialType (string name) case "long": return Long; case "float": return Float; case "double": return Double; + case "uint": return UInt; + case "ushort": return UShort; + case "ulong": return ULong; + case "ubyte": return UByte; case "?": return GenericWildcard; } return null; @@ -46,8 +54,12 @@ static JavaTypeReference () Float = new JavaTypeReference ("float"); Double = new JavaTypeReference ("double"); GenericWildcard = new JavaTypeReference ("?"); + UInt = new JavaTypeReference ("uint"); + UShort = new JavaTypeReference ("ushort"); + ULong = new JavaTypeReference ("ulong"); + UByte = new JavaTypeReference ("ubyte"); } - + JavaTypeReference (string specialName) { SpecialName = specialName; diff --git a/src/Xamarin.Android.Tools.Bytecode/Fields.cs b/src/Xamarin.Android.Tools.Bytecode/Fields.cs index df316e3ac..28f9685e1 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Fields.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Fields.cs @@ -33,6 +33,7 @@ public sealed class FieldInfo { public ConstantPool ConstantPool {get; private set;} public FieldAccessFlags AccessFlags {get; private set;} public AttributeCollection Attributes {get; private set;} + public string KotlinType { get; set; } public FieldInfo (ConstantPool constantPool, Stream stream) { diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs index 901f5f8f5..1b395fecb 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinClassMetadata.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using org.jetbrains.kotlin.metadata.jvm; +using ProtoBuf; using Type = org.jetbrains.kotlin.metadata.jvm.Type; namespace Xamarin.Android.Tools.Bytecode { + // https://github.com/JetBrains/kotlin/blob/master/core/metadata.jvm/src/jvm_metadata.proto public class KotlinFile { public List Functions { get; set; } @@ -220,6 +223,8 @@ internal static KotlinExpression FromProtobuf (Expression exp, JvmNameResolver r public class KotlinFunction : KotlinMethodBase { public string Name { get; set; } + public string JvmName { get; set; } + public string JvmSignature { get; set; } public KotlinFunctionFlags Flags { get; set; } public KotlinType ReturnType { get; set; } public int ReturnTypeId { get; set; } @@ -235,9 +240,13 @@ internal static KotlinFunction FromProtobuf (Function f, JvmNameResolver resolve if (f is null) return null; + var sig = Extensible.GetValue (f, 100); + return new KotlinFunction { Flags = (KotlinFunctionFlags)f.Flags, Name = resolver.GetString (f.Name), + JvmName = resolver.GetString ((sig?.Name ?? 0) > 0 ? sig.Name : f.Name), + JvmSignature = sig is null ? null : resolver.GetString (sig.Desc), ReturnType = KotlinType.FromProtobuf (f.ReturnType, resolver), ReturnTypeId = f.ReturnTypeId, ReceiverType = KotlinType.FromProtobuf (f.ReceiverType, resolver), diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs index c205c06e0..edc893233 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs @@ -45,13 +45,15 @@ public static void Fixup (IList classes) FixupJavaMethods (c.Methods); foreach (var met in metadata.Functions) - FixupFunction (FindJavaMethod (class_metadata, met, c), met, class_metadata); + FixupFunction (FindJavaMethod (metadata, met, c), met, class_metadata); foreach (var prop in metadata.Properties) { - var getter = FindJavaPropertyGetter (class_metadata, prop, c); - var setter = FindJavaPropertySetter (class_metadata, prop, c); + var getter = FindJavaPropertyGetter (metadata, prop, c); + var setter = FindJavaPropertySetter (metadata, prop, c); FixupProperty (getter, setter, prop); + + FixupField (FindJavaFieldProperty (metadata, prop, c), prop); } } catch (Exception ex) { @@ -96,7 +98,6 @@ static void FixupConstructor (MethodInfo method, KotlinConstructor metadata) Log.Debug ($"Kotlin: Hiding internal constructor {method.DeclaringType?.ThisClass.Name.Value} - {metadata.GetSignature ()}"); method.AccessFlags = MethodAccessFlags.Private; } - } static void FixupFunction (MethodInfo method, KotlinFunction metadata, KotlinClass kotlinClass) @@ -111,18 +112,24 @@ static void FixupFunction (MethodInfo method, KotlinFunction metadata, KotlinCla return; } - // Kotlin provides actual parameter names var java_parameters = method.GetFilteredParameters (); for (var i = 0; i < java_parameters.Length; i++) { var java_p = java_parameters [i]; var kotlin_p = metadata.ValueParameters [i]; + // Kotlin provides actual parameter names if (TypesMatch (java_p.Type, kotlin_p.Type, kotlinClass) && java_p.IsUnnamedParameter () && !kotlin_p.IsUnnamedParameter ()) { Log.Debug ($"Kotlin: Renaming parameter {method.DeclaringType?.ThisClass.Name.Value} - {method.Name} - {java_p.Name} -> {kotlin_p.Name}"); java_p.Name = kotlin_p.Name; } + + // Handle erasure of Kotlin unsigned types + java_p.KotlinType = GetKotlinType (java_p.Type.TypeSignature, kotlin_p.Type.ClassName); } + + // Handle erasure of Kotlin unsigned types + method.KotlinReturnType = GetKotlinType (method.ReturnType.TypeSignature, metadata.ReturnType.ClassName); } static void FixupExtensionMethod (MethodInfo method) @@ -158,16 +165,32 @@ static void FixupProperty (MethodInfo getter, MethodInfo setter, KotlinProperty return; } + // Handle erasure of Kotlin unsigned types + if (getter != null) + getter.KotlinReturnType = GetKotlinType (getter.ReturnType.TypeSignature, metadata.ReturnType.ClassName); + if (setter != null) { var setter_parameter = setter.GetParameters ().First (); - if (setter_parameter.IsUnnamedParameter ()) { + if (setter_parameter.IsUnnamedParameter () || setter_parameter.Name == "") { Log.Debug ($"Kotlin: Renaming setter parameter {setter.DeclaringType?.ThisClass.Name.Value} - {setter.Name} - {setter_parameter.Name} -> value"); setter_parameter.Name = "value"; } + + // Handle erasure of Kotlin unsigned types + setter_parameter.KotlinType = GetKotlinType (setter_parameter.Type.TypeSignature, metadata.ReturnType.ClassName); } } + static void FixupField (FieldInfo field, KotlinProperty metadata) + { + if (field is null) + return; + + // Handle erasure of Kotlin unsigned types + field.KotlinType = GetKotlinType (field.Descriptor, metadata.ReturnType.ClassName); + } + static MethodInfo FindJavaConstructor (KotlinClass kotlinClass, KotlinConstructor constructor, ClassFile klass) { var all_constructors = klass.Methods.Where (method => method.Name == "" || method.Name == ""); @@ -181,16 +204,16 @@ static MethodInfo FindJavaConstructor (KotlinClass kotlinClass, KotlinConstructo return null; } - static MethodInfo FindJavaMethod (KotlinClass kotlinClass, KotlinFunction function, ClassFile klass) + static MethodInfo FindJavaMethod (KotlinFile kotlinFile, KotlinFunction function, ClassFile klass) { - var possible_methods = klass.Methods.Where (method => method.GetMethodNameWithoutSuffix () == function.Name && + var possible_methods = klass.Methods.Where (method => method.Name == function.JvmName && method.GetFilteredParameters ().Length == function.ValueParameters.Count); foreach (var method in possible_methods) { - if (!TypesMatch (method.ReturnType, function.ReturnType, kotlinClass)) + if (!TypesMatch (method.ReturnType, function.ReturnType, kotlinFile)) continue; - if (!ParametersMatch (kotlinClass, method, function.ValueParameters)) + if (!ParametersMatch (kotlinFile, method, function.ValueParameters)) continue; return method; @@ -199,7 +222,15 @@ static MethodInfo FindJavaMethod (KotlinClass kotlinClass, KotlinFunction functi return null; } - static MethodInfo FindJavaPropertyGetter (KotlinClass kotlinClass, KotlinProperty property, ClassFile klass) + static FieldInfo FindJavaFieldProperty (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) + { + var possible_methods = klass.Fields.Where (field => field.Name == property.Name && + TypesMatch (new TypeInfo (field.Descriptor, field.Descriptor), property.ReturnType, kotlinClass)); + + return possible_methods.FirstOrDefault (); + } + + static MethodInfo FindJavaPropertyGetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) { var possible_methods = klass.Methods.Where (method => (string.Compare (method.GetMethodNameWithoutSuffix (), $"get{property.Name}", true) == 0 || string.Compare (method.GetMethodNameWithoutSuffix (), property.Name, true) == 0) && @@ -209,7 +240,7 @@ static MethodInfo FindJavaPropertyGetter (KotlinClass kotlinClass, KotlinPropert return possible_methods.FirstOrDefault (); } - static MethodInfo FindJavaPropertySetter (KotlinClass kotlinClass, KotlinProperty property, ClassFile klass) + static MethodInfo FindJavaPropertySetter (KotlinFile kotlinClass, KotlinProperty property, ClassFile klass) { var possible_methods = klass.Methods.Where (method => string.Compare (method.GetMethodNameWithoutSuffix (), $"set{property.Name}", true) == 0 && property.ReturnType != null && @@ -219,7 +250,7 @@ static MethodInfo FindJavaPropertySetter (KotlinClass kotlinClass, KotlinPropert return possible_methods.FirstOrDefault (); } - static bool ParametersMatch (KotlinClass kotlinClass, MethodInfo method, List kotlinParameters) + static bool ParametersMatch (KotlinFile kotlinClass, MethodInfo method, List kotlinParameters) { var java_parameters = method.GetFilteredParameters (); @@ -237,13 +268,13 @@ static bool ParametersMatch (KotlinClass kotlinClass, MethodInfo method, List t.Id == type.TypeParameter); diff --git a/src/Xamarin.Android.Tools.Bytecode/Methods.cs b/src/Xamarin.Android.Tools.Bytecode/Methods.cs index 187138ef9..3add9fcdd 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Methods.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Methods.cs @@ -31,6 +31,7 @@ public sealed class MethodInfo { public ClassFile DeclaringType {get; private set;} public MethodAccessFlags AccessFlags {get; set;} public AttributeCollection Attributes {get; private set;} + public string KotlinReturnType {get; set;} public MethodInfo (ConstantPool constantPool, ClassFile declaringType, Stream stream) { @@ -290,6 +291,7 @@ public sealed class ParameterInfo : IEquatable { public string Name; public int Position; public TypeInfo Type = new TypeInfo (); + public string KotlinType; public MethodParameterAccessFlags AccessFlags; diff --git a/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj b/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj index 0f65a140b..b521d79b5 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj +++ b/src/Xamarin.Android.Tools.Bytecode/Xamarin.Android.Tools.Bytecode.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs b/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs index 32758428f..a5d5b35e8 100644 --- a/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs +++ b/src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs @@ -332,6 +332,8 @@ XElement GetMethod (string element, string name, MethodInfo method, string retur var ret = returns != null ? new XAttribute ("return", SignatureToGenericJavaTypeName (returns)) : null; + if (!string.IsNullOrWhiteSpace (method.KotlinReturnType)) + ret?.SetValue (method.KotlinReturnType); var jniRet = returns != null ? new XAttribute ("jni-return", returns) : null; @@ -400,6 +402,8 @@ IEnumerable GetMethodParameters (MethodInfo method) genericType = genericType.Substring (1); } genericType = SignatureToGenericJavaTypeName (genericType); + if (!string.IsNullOrWhiteSpace (p.KotlinType)) + genericType = p.KotlinType; if (varargArray) { type += "..."; genericType += "..."; @@ -480,6 +484,9 @@ IEnumerable GetFields () var visibility = GetVisibility (field.AccessFlags); if (visibility == "private" || visibility == "") continue; + var type = new XAttribute ("type", SignatureToJavaTypeName (field.Descriptor)); + if (!string.IsNullOrWhiteSpace (field.KotlinType)) + type.SetValue (field.KotlinType); yield return new XElement ("field", new XAttribute ("deprecated", GetDeprecatedValue (field.Attributes)), new XAttribute ("final", (field.AccessFlags & FieldAccessFlags.Final) != 0), @@ -487,7 +494,7 @@ IEnumerable GetFields () new XAttribute ("static", (field.AccessFlags & FieldAccessFlags.Static) != 0), new XAttribute ("synthetic", (field.AccessFlags & FieldAccessFlags.Synthetic) != 0), new XAttribute ("transient", (field.AccessFlags & FieldAccessFlags.Transient) != 0), - new XAttribute ("type", SignatureToJavaTypeName (field.Descriptor)), + type, new XAttribute ("type-generic-aware", GetGenericType (field)), new XAttribute ("jni-signature", field.Descriptor), GetNotNull (field), diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs index 2da9a3d35..dcfb774da 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs @@ -119,5 +119,122 @@ public void RenameSetterParameter () Assert.AreEqual ("value", p.Name); } + + [Test] + public void UnsignedMethods () + { + var klass = LoadClassFile ("UnsignedTypes.class"); + + var uint_method = klass.Methods.Single (m => m.Name.Contains ("foo_uint-")); + var ushort_method = klass.Methods.Single (m => m.Name.Contains ("foo_ushort-")); + var ulong_method = klass.Methods.Single (m => m.Name.Contains ("foo_ulong-")); + var ubyte_method = klass.Methods.Single (m => m.Name.Contains ("foo_ubyte-")); + var uintarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_uintarray-")); + var ushortarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ushortarray-")); + var ulongarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ulongarray-")); + var ubytearray_method = klass.Methods.Single (m => m.Name.Contains ("foo_ubytearray-")); + var uintarrayarray_method = klass.Methods.Single (m => m.Name.Contains ("foo_uintarrayarray")); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("uint", uint_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("uint", uint_method.KotlinReturnType); + + Assert.AreEqual ("ushort", ushort_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ushort", ushort_method.KotlinReturnType); + + Assert.AreEqual ("ulong", ulong_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ulong", ulong_method.KotlinReturnType); + + Assert.AreEqual ("ubyte", ubyte_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ubyte", ubyte_method.KotlinReturnType); + + Assert.AreEqual ("uint[]", uintarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("uint[]", uintarray_method.KotlinReturnType); + + Assert.AreEqual ("ushort[]", ushortarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ushort[]", ushortarray_method.KotlinReturnType); + + Assert.AreEqual ("ulong[]", ulongarray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ulong[]", ulongarray_method.KotlinReturnType); + + Assert.AreEqual ("ubyte[]", ubytearray_method.GetParameters () [0].KotlinType); + Assert.AreEqual ("ubyte[]", ubytearray_method.KotlinReturnType); + + // Kotlin's Array does not trigger this code because it is not + // encoded as Java's "[[I", instead it is exposed as "UIntArray[]", so + // we treat it as a normal class array. + Assert.Null (uintarrayarray_method.GetParameters () [0].KotlinType); + Assert.Null (uintarrayarray_method.KotlinReturnType); + } + + [Test] + public void UnsignedFields () + { + var klass = LoadClassFile ("UnsignedTypesKt.class"); + + var uint_field = klass.Fields.Single (m => m.Name == "UINT_CONST"); + var ushort_field = klass.Fields.Single (m => m.Name == "USHORT_CONST"); + var ulong_field = klass.Fields.Single (m => m.Name == "ULONG_CONST"); + var ubyte_field = klass.Fields.Single (m => m.Name == "UBYTE_CONST"); + + KotlinFixups.Fixup (new [] { klass }); + + Assert.AreEqual ("uint", uint_field.KotlinType); + Assert.AreEqual ("ushort", ushort_field.KotlinType); + Assert.AreEqual ("ulong", ulong_field.KotlinType); + Assert.AreEqual ("ubyte", ubyte_field.KotlinType); + } + + [Test] + public void UnsignedFieldsXml () + { + // Ensure Kotlin unsigned types end up in the xml + var klass = LoadClassFile ("UnsignedTypesKt.class"); + + KotlinFixups.Fixup (new [] { klass }); + + var xml = new XmlClassDeclarationBuilder (klass).ToXElement (); + + Assert.AreEqual ("uint", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "UINT_CONST").Attribute ("type").Value); + Assert.AreEqual ("ushort", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "USHORT_CONST").Attribute ("type").Value); + Assert.AreEqual ("ulong", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "ULONG_CONST").Attribute ("type").Value); + Assert.AreEqual ("ubyte", xml.Elements ("field").Single (f => f.Attribute ("name").Value == "UBYTE_CONST").Attribute ("type").Value); + } + + [Test] + public void UnsignedMethodsXml () + { + // Ensure Kotlin unsigned types end up in the xml + var klass = LoadClassFile ("UnsignedTypes.class"); + + KotlinFixups.Fixup (new [] { klass }); + + var xml = new XmlClassDeclarationBuilder (klass).ToXElement (); + + Assert.AreEqual ("uint", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uint-WZ4Q5Ns").Attribute ("return").Value); + Assert.AreEqual ("uint", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uint-WZ4Q5Ns").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ushort", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushort-xj2QHRw").Attribute ("return").Value); + Assert.AreEqual ("ushort", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushort-xj2QHRw").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ulong", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulong-VKZWuLQ").Attribute ("return").Value); + Assert.AreEqual ("ulong", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulong-VKZWuLQ").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ubyte", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubyte-7apg3OU").Attribute ("return").Value); + Assert.AreEqual ("ubyte", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubyte-7apg3OU").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("uint[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uintarray--ajY-9A").Attribute ("return").Value); + Assert.AreEqual ("uint[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_uintarray--ajY-9A").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ushort[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushortarray-rL5Bavg").Attribute ("return").Value); + Assert.AreEqual ("ushort[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ushortarray-rL5Bavg").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ulong[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulongarray-QwZRm1k").Attribute ("return").Value); + Assert.AreEqual ("ulong[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ulongarray-QwZRm1k").Element ("parameter").Attribute ("type").Value); + + Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Attribute ("return").Value); + Assert.AreEqual ("ubyte[]", xml.Elements ("method").Single (f => f.Attribute ("name").Value == "foo_ubytearray-GBYM_sE").Element ("parameter").Attribute ("type").Value); + } } } diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class new file mode 100644 index 000000000..b55f4c2bd Binary files /dev/null and b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.class differ diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt new file mode 100644 index 000000000..269d9c43a --- /dev/null +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypes.kt @@ -0,0 +1,28 @@ +@kotlin.ExperimentalUnsignedTypes +const val UINT_CONST: UInt = 3u + +@kotlin.ExperimentalUnsignedTypes +const val USHORT_CONST: UShort = 3u + +@kotlin.ExperimentalUnsignedTypes +const val ULONG_CONST: ULong = 3u + +@kotlin.ExperimentalUnsignedTypes +const val UBYTE_CONST: UByte = 3u + +@kotlin.ExperimentalUnsignedTypes +public class UnsignedTypes { + public fun foo_uint (value : Int) : Int { return value; } + public fun foo_uint (value : UInt) : UInt { return value; } + public fun foo_ushort (value : Short) : Short { return value; } + public fun foo_ushort (value : UShort) : UShort { return value; } + public fun foo_ulong (value : Long) : Long { return value; } + public fun foo_ulong (value : ULong) : ULong { return value; } + public fun foo_ubyte (value : Byte) : Byte { return value; } + public fun foo_ubyte (value : UByte) : UByte { return value; } + public fun foo_uintarray (value : UIntArray) : UIntArray { return value; } + public fun foo_ushortarray (value : UShortArray) : UShortArray { return value; } + public fun foo_ulongarray (value : ULongArray) : ULongArray { return value; } + public fun foo_ubytearray (value : UByteArray) : UByteArray { return value; } + public fun foo_uintarrayarray (value : Array) : Array { return value; } +} \ No newline at end of file diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class new file mode 100644 index 000000000..4140b0fe4 Binary files /dev/null and b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/UnsignedTypesKt.class differ diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt new file mode 100644 index 000000000..5339561af --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypeMethodsClass.txt @@ -0,0 +1,90 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint[]']]" + [Register ("Echo", "([I)[I", "")] + public unsafe uint[] Echo (uint[] value) + { + const string __id = "Echo.([I)[I"; + IntPtr native_value = JNIEnv.NewArray ((int[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (uint[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (uint)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + [Register ("Echo", "([S)[S", "")] + public unsafe ushort[] Echo (ushort[] value) + { + const string __id = "Echo.([S)[S"; + IntPtr native_value = JNIEnv.NewArray ((short[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (ushort[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ushort)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + [Register ("Echo", "([J)[J", "")] + public unsafe ulong[] Echo (ulong[] value) + { + const string __id = "Echo.([J)[J"; + IntPtr native_value = JNIEnv.NewArray ((long[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (ulong[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ulong)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + [Register ("Echo", "([B)[B", "")] + public unsafe byte[] Echo (byte[] value) + { + const string __id = "Echo.([B)[B"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args); + return (byte[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (byte)); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt new file mode 100644 index 000000000..a139a6768 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedArrayTypePropertiesClass.txt @@ -0,0 +1,130 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + public unsafe uint[] UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + [Register ("get_UIntProp", "()[I", "")] + get { + const string __id = "get_UIntProp.()[I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (uint[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (uint)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint[]']]" + [Register ("set_UIntProp", "([I)V", "")] + set { + const string __id = "set_UIntProp.([I)V"; + IntPtr native_value = JNIEnv.NewArray ((int[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + } + + public unsafe ushort[] UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + [Register ("get_UShortProp", "()[S", "")] + get { + const string __id = "get_UShortProp.()[S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (ushort[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ushort)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort[]']]" + [Register ("set_UShortProp", "([S)V", "")] + set { + const string __id = "set_UShortProp.([S)V"; + IntPtr native_value = JNIEnv.NewArray ((short[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + } + + public unsafe ulong[] ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + [Register ("get_ULongProp", "()[J", "")] + get { + const string __id = "get_ULongProp.()[J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (ulong[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (ulong)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong[]']]" + [Register ("set_ULongProp", "([J)V", "")] + set { + const string __id = "set_ULongProp.([J)V"; + IntPtr native_value = JNIEnv.NewArray ((long[])(object)value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + } + + public unsafe byte[] UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + [Register ("get_UByteProp", "()[B", "")] + get { + const string __id = "get_UByteProp.()[B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractObjectMethod (__id, this, null); + return (byte[]) JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof (byte)); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte[]']]" + [Register ("set_UByteProp", "([B)V", "")] + set { + const string __id = "set_UByteProp.([B)V"; + IntPtr native_value = JNIEnv.NewArray (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + if (value != null) { + JNIEnv.CopyArray (native_value, value); + JNIEnv.DeleteLocalRef (native_value); + } + } + } + } + +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt new file mode 100644 index 000000000..b03f98129 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypeMethodsClass.txt @@ -0,0 +1,70 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='uint']]" + [Register ("Echo", "(I)I", "")] + public unsafe uint Echo (uint value) + { + const string __id = "Echo.(I)I"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args); + return (uint)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ushort']]" + [Register ("Echo", "(S)S", "")] + public unsafe ushort Echo (ushort value) + { + const string __id = "Echo.(S)S"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, __args); + return (ushort)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ulong']]" + [Register ("Echo", "(J)J", "")] + public unsafe ulong Echo (ulong value) + { + const string __id = "Echo.(J)J"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, __args); + return (ulong)__rm; + } finally { + } + } + + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Echo' and count(parameter)=1 and parameter[1][@type='ubyte']]" + [Register ("Echo", "(B)B", "")] + public unsafe byte Echo (byte value) + { + const string __id = "Echo.(B)B"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, __args); + return (byte)__rm; + } finally { + } + } + +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt new file mode 100644 index 000000000..113e4c242 --- /dev/null +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteKotlinUnsignedTypePropertiesClass.txt @@ -0,0 +1,110 @@ +// Metadata.xml XPath class reference: path="/api/package[@name='java.code']/class[@name='MyClass']" +[global::Android.Runtime.Register ("java/code/MyClass", DoNotGenerateAcw=true)] +public partial class MyClass { + + static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/MyClass", typeof (MyClass)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + protected MyClass (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + public unsafe uint UIntProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UIntProp' and count(parameter)=0]" + [Register ("get_UIntProp", "()I", "")] + get { + const string __id = "get_UIntProp.()I"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, null); + return (uint)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UIntProp' and count(parameter)=1 and parameter[1][@type='uint']]" + [Register ("set_UIntProp", "(I)V", "")] + set { + const string __id = "set_UIntProp.(I)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ushort UShortProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UShortProp' and count(parameter)=0]" + [Register ("get_UShortProp", "()S", "")] + get { + const string __id = "get_UShortProp.()S"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt16Method (__id, this, null); + return (ushort)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UShortProp' and count(parameter)=1 and parameter[1][@type='ushort']]" + [Register ("set_UShortProp", "(S)V", "")] + set { + const string __id = "set_UShortProp.(S)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe ulong ULongProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_ULongProp' and count(parameter)=0]" + [Register ("get_ULongProp", "()J", "")] + get { + const string __id = "get_ULongProp.()J"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractInt64Method (__id, this, null); + return (ulong)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_ULongProp' and count(parameter)=1 and parameter[1][@type='ulong']]" + [Register ("set_ULongProp", "(J)V", "")] + set { + const string __id = "set_ULongProp.(J)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + + public unsafe byte UByteProp { + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_UByteProp' and count(parameter)=0]" + [Register ("get_UByteProp", "()B", "")] + get { + const string __id = "get_UByteProp.()B"; + try { + var __rm = _members.InstanceMethods.InvokeAbstractSByteMethod (__id, this, null); + return (byte)__rm; + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='set_UByteProp' and count(parameter)=1 and parameter[1][@type='ubyte']]" + [Register ("set_UByteProp", "(B)V", "")] + set { + const string __id = "set_UByteProp.(B)V"; + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (value); + _members.InstanceMethods.InvokeAbstractVoidMethod (__id, this, __args); + } finally { + } + } + } + +} diff --git a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs index 25ec4f0f8..8df7ff753 100644 --- a/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs +++ b/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs @@ -11,6 +11,94 @@ namespace generatortests class JavaInteropCodeGeneratorTests : CodeGeneratorTests { protected override CodeGenerationTarget Target => CodeGenerationTarget.JavaInterop1; + + [Test] + public void WriteKotlinUnsignedTypeMethodsClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "uint", false, false, new Parameter ("value", "uint", "uint", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ushort", false, false, new Parameter ("value", "ushort", "ushort", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ulong", false, false, new Parameter ("value", "ulong", "ulong", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ubyte", false, false, new Parameter ("value", "ubyte", "byte", false))); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Methods) + m.IsVirtual = false; + + generator.Context.ContextTypes.Push (@class); + generator.WriteClass (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteKotlinUnsignedTypeMethodsClass)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void WriteKotlinUnsignedTypePropertiesClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UIntProp", "uint", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UShortProp", "ushort", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "ULongProp", "ulong", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UByteProp", "ubyte", options, false, false)); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Properties) { + m.Getter.IsVirtual = false; + m.Setter.IsVirtual = false; + } + + generator.Context.ContextTypes.Push (@class); + generator.WriteClass (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteKotlinUnsignedTypePropertiesClass)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void WriteKotlinUnsignedArrayTypeMethodsClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "uint[]", false, false, new Parameter ("value", "uint[]", "uint[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ushort[]", false, false, new Parameter ("value", "ushort[]", "ushort[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ulong[]", false, false, new Parameter ("value", "ulong[]", "ulong[]", false))); + @class.AddMethod (SupportTypeBuilder.CreateMethod (@class, "Echo", options, "ubyte[]", false, false, new Parameter ("value", "ubyte[]", "byte[]", false))); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Methods) + m.IsVirtual = false; + + generator.Context.ContextTypes.Push (@class); + generator.WriteClass (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteKotlinUnsignedArrayTypeMethodsClass)), writer.ToString ().NormalizeLineEndings ()); + } + + [Test] + public void WriteKotlinUnsignedArrayTypePropertiesClass () + { + var @class = new TestClass ("Object", "java.code.MyClass"); + + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UIntProp", "uint[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UShortProp", "ushort[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "ULongProp", "ulong[]", options, false, false)); + @class.Properties.Add (SupportTypeBuilder.CreateProperty (@class, "UByteProp", "ubyte[]", options, false, false)); + + // Kotlin methods with unsigned types are name-mangled and don't support virtual + foreach (var m in @class.Properties) { + m.Getter.IsVirtual = false; + m.Setter.IsVirtual = false; + } + + generator.Context.ContextTypes.Push (@class); + generator.WriteClass (@class, string.Empty, new GenerationInfo ("", "", "MyAssembly")); + generator.Context.ContextTypes.Pop (); + + Assert.AreEqual (GetTargetedExpected (nameof (WriteKotlinUnsignedArrayTypePropertiesClass)), writer.ToString ().NormalizeLineEndings ()); + } } [TestFixture] diff --git a/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs b/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs index 1e4c90081..1c4ac1a89 100644 --- a/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs +++ b/tests/generator-Tests/Unit-Tests/KotlinFixupsTests.cs @@ -26,7 +26,7 @@ public void CreateMethod_EnsureKotlinImplFix () [Test] public void CreateMethod_EnsureKotlinHashcodeFix () { - var xml = XDocument.Parse (""); + var xml = XDocument.Parse (""); var klass = XmlApiImporter.CreateClass (xml.Root, xml.Root.Element ("class")); KotlinFixups.Fixup (new [] { (GenBase) klass }.ToList ()); diff --git a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs index f8b7c7005..a0a1d77ea 100644 --- a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs +++ b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs @@ -1212,7 +1212,7 @@ public void WriteMethodInvokerBody (Method method, string indent) writer.WriteLine ("{0}{1}", indent, prep); WriteParameterListCallArgs (method.Parameters, indent, invoker: true); string env_method = "Call" + method.RetVal.CallMethodPrefix + "Method"; - string call = "JNIEnv." + env_method + " (" + + string call = method.RetVal.ReturnCast + "JNIEnv." + env_method + " (" + Context.ContextType.GetObjectHandleProperty ("this") + ", " + method.EscapedIdName + method.Parameters.GetCallArgs (opt, invoker: true) + ")"; if (method.IsVoid) writer.WriteLine ("{0}{1};", indent, call); diff --git a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs index 5032a5085..7554007d7 100644 --- a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs +++ b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/JavaInteropCodeGenerator.cs @@ -19,6 +19,10 @@ static string GetInvokeType (string type) case "Short": return "Int16"; case "Long": return "Int64"; case "Float": return "Single"; + case "UInt": return "Int32"; + case "UShort": return "Int16"; + case "ULong": return "Int64"; + case "UByte": return "SByte"; default: return type; } } @@ -171,7 +175,7 @@ internal override void WriteMethodBody (Method method, string indent, GenBase ty if (!method.IsVoid) { var r = invokeType == "Object" ? "__rm.Handle" : "__rm"; - writer.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, r, true)); + writer.WriteLine ("{0}return {2}{1};", indent, method.RetVal.FromNative (opt, r, true), method.RetVal.ReturnCast); } indent = oldindent; @@ -196,19 +200,21 @@ internal override void WriteFieldGetBody (Field field, string indent, GenBase ty var invoke = "Get{0}Value"; invoke = string.Format (invoke, invokeType); - writer.WriteLine ("{0}var __v = _members.{1}.{2} (__id{3});", + writer.WriteLine ("{0}var __v = {4}_members.{1}.{2} (__id{3});", indent, indirect, invoke, - field.IsStatic ? "" : ", this"); + field.IsStatic ? "" : ", this", + field.Symbol.ReturnCast); if (field.Symbol.IsArray) { writer.WriteLine ("{0}return global::Android.Runtime.JavaArray<{1}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);", indent, opt.GetOutputName (field.Symbol.ElementType)); } else if (field.Symbol.NativeType != field.Symbol.FullName) { - writer.WriteLine ("{0}return {1};", + writer.WriteLine ("{0}return {2}{1};", indent, - field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true)); + field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true), + field.Symbol.ReturnCast); } else { writer.WriteLine ("{0}return __v;", indent); } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs index b74ba3d8a..3f5b51fac 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Field.cs @@ -23,7 +23,7 @@ public class Field : ApiVersionsSupport.IApiAvailability public string Value { get; set; } public string Visibility { get; set; } - internal string GetMethodPrefix => (Symbol is SimpleSymbol || Symbol.IsEnum) ? StringRocks.MemberToPascalCase (Symbol.JavaName) : "Object"; + internal string GetMethodPrefix => TypeNameUtilities.GetCallPrefix (Symbol); internal string ID => JavaName + "_jfieldId"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs index ec22211c1..a20d331f4 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBase.cs @@ -33,6 +33,8 @@ protected GenBase (GenBaseSupport support) public string DefaultValue { get; set; } public bool HasVirtualMethods { get; set; } + public string ReturnCast => string.Empty; + // This means Ctors/Methods/Properties/Fields has not been populated yet. // If this type is retrieved from the SymbolTable, it will call PopulateAction // to fill in members before returning it to the user. diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs index 67e857b92..60c84c6aa 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs @@ -108,7 +108,7 @@ internal string CalculateEventName (Func checkNameDuplicate) public string EscapedCallbackName => IdentifierValidator.CreateValidIdentifier ($"cb_{JavaName}{IDSignature}", true); - public string EscapedIdName => "id_" + JavaName.Replace ("<", "_x60_").Replace (">", "_x62_") + IDSignature; + public string EscapedIdName => IdentifierValidator.CreateValidIdentifier ($"id_{JavaName}{IDSignature}", true); internal void FillReturnType () { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs index 4a738d501..be0869f3a 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/MethodBase.cs @@ -87,10 +87,7 @@ public bool IsKotlinNameMangled { if (method.JavaName.IndexOf ("-impl") >= 0) return true; - var index = method.JavaName.IndexOf ('-'); - - // `add-V5j3Lk8` is always a 7 character hashcode - return index >= 0 && method.JavaName.Length - index == 8; + return method.JavaName.Length >= 8 && method.JavaName [method.JavaName.Length - 8] == '-'; } return false; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs index 8ee014132..bcdacec12 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/ReturnValue.cs @@ -22,14 +22,7 @@ public ReturnValue (Method owner, string java_type, string managed_type, bool is this.is_enumified = isEnumified; } - public string CallMethodPrefix { - get { - if (sym is SimpleSymbol || sym.IsEnum) - return StringRocks.MemberToPascalCase (sym.JavaName); - else - return "Object"; - } - } + public string CallMethodPrefix => TypeNameUtilities.GetCallPrefix (sym); public string DefaultValue { get { return sym.DefaultValue; } @@ -89,6 +82,8 @@ public string RawJavaType { get { return raw_type; } } + public string ReturnCast => sym?.ReturnCast ?? string.Empty; + public string FromNative (CodeGenerationOptions opt, string var_name, bool owned) { if (!string.IsNullOrEmpty (managed_type) && (sym is ClassGen || sym is InterfaceGen)) { diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs index cb59c5b16..deb5f82ad 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ArraySymbol.cs @@ -64,6 +64,8 @@ public bool IsArray { get { return true; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return sym.GetObjectHandleProperty (variable); @@ -120,10 +122,25 @@ public string[] PreCallback (CodeGenerationOptions opt, string var_name, bool ow public string[] PreCall (CodeGenerationOptions opt, string var_name) { - return new string[] { String.Format ("IntPtr {0} = JNIEnv.NewArray ({1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name)) }; + + return new string[] { String.Format ("IntPtr {0} = JNIEnv.NewArray ({2}{1});", opt.GetSafeIdentifier (TypeNameUtilities.GetNativeName (var_name)), opt.GetSafeIdentifier (var_name), GetPreCallCast ()) }; } public bool NeedsPrep { get { return true; } } + + string GetPreCallCast () + { + switch (sym.FullName) { + case "uint": + return "(int[])(object)"; + case "ushort": + return "(short[])(object)"; + case "ulong": + return "(long[])(object)"; + default: + return string.Empty; + } + } } } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs index 8a026cd4d..329e66eb3 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CharSequenceSymbol.cs @@ -41,6 +41,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs index 42ef65a5f..e97dabc92 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/CollectionSymbol.cs @@ -56,6 +56,8 @@ public bool MayHaveManagedGenericArguments { get { return true; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs index a404cbdd1..8782b556b 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/EnumSymbol.cs @@ -46,6 +46,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return null; 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 465d6be82..859a5f162 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/FormatSymbol.cs @@ -13,8 +13,9 @@ public class FormatSymbol : ISymbol { string native_type; string to_fmt; string type; + string return_cast; - public FormatSymbol (string default_value, string java_type, string jni_type, string native_type, string type, string from_fmt, string to_fmt) + public FormatSymbol (string default_value, string java_type, string jni_type, string native_type, string type, string from_fmt, string to_fmt, string returnCast) { this.default_value = default_value; this.java_type = java_type; @@ -23,6 +24,7 @@ public FormatSymbol (string default_value, string java_type, string jni_type, st this.type = type; this.from_fmt = from_fmt; this.to_fmt = to_fmt; + this.return_cast = returnCast ?? string.Empty; } public string DefaultValue { @@ -61,6 +63,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => return_cast; + public string GetObjectHandleProperty (string variable) { return null; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs index 09f61bd61..55638ddd0 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GeneratedEnumSymbol.cs @@ -77,6 +77,8 @@ public string ElementType { get { return enum_type; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return null; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs index 0865d333f..2c9fc2a47 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericSymbol.cs @@ -63,6 +63,8 @@ public ISymbol [] TypeParams { get { return type_params; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return gen.GetObjectHandleProperty (variable); diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs index b1642f290..d1f901910 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/GenericTypeParameter.cs @@ -63,6 +63,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return null; 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 c8831d722..c5182c83a 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/ISymbol.cs @@ -13,6 +13,7 @@ public interface ISymbol { bool IsEnum { get; } bool IsArray { get; } string ElementType { get; } + string ReturnCast { get; } string GetObjectHandleProperty (string variable); diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs index e5e04eca6..c8d3e9e2b 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SimpleSymbol.cs @@ -4,8 +4,8 @@ namespace MonoDroid.Generation { public class SimpleSymbol : FormatSymbol { - public SimpleSymbol (string default_value, string java_type, string type, string jni_type, string native_type = null, string from_fmt="{0}", string to_fmt="{0}") - : base (default_value, java_type, jni_type, native_type ?? type, type, from_fmt, to_fmt) + public SimpleSymbol (string default_value, string java_type, string type, string jni_type, string native_type = null, string from_fmt="{0}", string to_fmt="{0}", string returnCast = null) + : base (default_value, java_type, jni_type, native_type ?? type, type, from_fmt, to_fmt, returnCast) { } diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs index 78068e45e..bf660341d 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StreamSymbol.cs @@ -54,6 +54,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs index fe50266c2..d78799149 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/StringSymbol.cs @@ -44,6 +44,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; 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 5f6465209..8d3f279ec 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/SymbolTable.cs @@ -33,6 +33,10 @@ public class SymbolTable { "int", "long", "short", + "ubyte", + "uint", + "ulong", + "ushort", "void", }; @@ -55,6 +59,10 @@ public SymbolTable () AddType (new SimpleSymbol ("0", "int", "int", "I")); AddType (new SimpleSymbol ("0L", "long", "long", "J")); AddType (new SimpleSymbol ("0", "short", "short", "S")); + AddType (new SimpleSymbol ("0", "uint", "uint", "I", returnCast: "(uint)")); + AddType (new SimpleSymbol ("0", "ushort", "ushort", "S", returnCast: "(ushort)")); + AddType (new SimpleSymbol ("0", "ulong", "ulong", "J", returnCast: "(ulong)")); + AddType (new SimpleSymbol ("0", "ubyte", "byte", "B", returnCast: "(byte)")); AddType ("Android.Graphics.Color", new ColorSymbol ()); char_seq = new CharSequenceSymbol (); instream_sym = new StreamSymbol ("InputStream"); diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs index c497d31b3..aff529793 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlPullParserSymbol.cs @@ -41,6 +41,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs index 08a1b85b6..fa8df65f4 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Symbols/XmlResourceParserSymbol.cs @@ -41,6 +41,8 @@ public string ElementType { get { return null; } } + public string ReturnCast => string.Empty; + public string GetObjectHandleProperty (string variable) { return $"((global::Java.Lang.Object) {variable}).Handle"; diff --git a/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs b/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs index fc901fc5c..6545a0818 100644 --- a/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs +++ b/tools/generator/Java.Interop.Tools.Generator.Transformation/KotlinFixups.cs @@ -12,6 +12,8 @@ public static void Fixup (List gens) { foreach (var c in gens.OfType ()) FixupClass (c); + foreach (var i in gens.OfType ()) + FixupInterface (i); } private static void FixupClass (ClassGen c) @@ -20,9 +22,8 @@ private static void FixupClass (ClassGen c) // inaccessible from Java, like `add-impl` and `add-V5j3Lk8`. // We need to generate C# compatible names as well as prevent overriding // them as we cannot generate JCW for them. - var invalid_methods = c.Methods.Where (m => m.IsKotlinNameMangled).ToList (); - foreach (var method in invalid_methods) { + foreach (var method in c.Methods.Where (m => m.IsKotlinNameMangled)) { // If the method is virtual, mark it as !virtual as it can't be overridden in Java if (!method.IsFinal) @@ -31,15 +32,29 @@ private static void FixupClass (ClassGen c) if (method.IsVirtual) method.IsVirtual = false; - // Only run this if it's the default name (ie: not a user's "managedName") - if (method.Name == StringRocks.MemberToPascalCase (method.JavaName).Replace ('-', '_')) { - // We want to remove the hyphen and anything afterwards to fix mangled names, - // but a previous step converted it to an underscore. Remove the final - // underscore and anything after it. - var index = method.Name.LastIndexOf ('_'); + FixMethodName (method); + } + } + + private static void FixupInterface (InterfaceGen gen) + { + foreach (var method in gen.Methods.Where (m => m.IsKotlinNameMangled)) + FixMethodName (method); + } + + private static void FixMethodName (Method method) + { + // Only run this if it's the default name (ie: not a user's "managedName") + if (method.Name == StringRocks.MemberToPascalCase (method.JavaName).Replace ('-', '_')) { + // We want to remove the hyphen and anything afterwards to fix mangled names, + // but a previous step converted it to an underscore. Remove the final + // underscore and anything after it. + var index = method.Name.IndexOf ("_impl"); + if (index >= 0) method.Name = method.Name.Substring (0, index); - } + else + method.Name = method.Name.Substring (0, method.Name.Length - 8); } } } diff --git a/tools/generator/Utilities/TypeNameUtilities.cs b/tools/generator/Utilities/TypeNameUtilities.cs index 371ab068e..56a620f0a 100644 --- a/tools/generator/Utilities/TypeNameUtilities.cs +++ b/tools/generator/Utilities/TypeNameUtilities.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using MonoDroid.Utils; namespace MonoDroid.Generation { @@ -101,5 +102,27 @@ public static string StudlyCase (string name) } return builder.ToString (); } + + public static string GetCallPrefix (ISymbol symbol) + { + if (symbol is SimpleSymbol || symbol.IsEnum) { + var ret = StringRocks.MemberToPascalCase (symbol.JavaName); + + // We do not have unsigned versions of GetIntValue, etc. + // We use the signed versions and cast the result + if (ret == "Uint") + return "Int"; + if (ret == "Ushort") + return "Short"; + if (ret == "Ulong") + return "Long"; + if (ret == "Ubyte") + return "Byte"; + + return ret; + + } else + return "Object"; + } } }