diff --git a/tools/generator/CodeGenerationOptions.cs b/tools/generator/CodeGenerationOptions.cs index d5085ff74..3afe374ed 100644 --- a/tools/generator/CodeGenerationOptions.cs +++ b/tools/generator/CodeGenerationOptions.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; - +using System.Text; using Java.Interop.Tools.JavaCallableWrappers; using Xamarin.Android.Binder; @@ -44,6 +44,9 @@ internal CodeGenerator CreateCodeGenerator (TextWriter writer) public SymbolTable SymbolTable { get; } = new SymbolTable (); + readonly SortedSet jni_marshal_delegates = new SortedSet (); + readonly object jni_marshal_delegates_lock = new object (); + public bool UseGlobal { get; set; } public bool IgnoreNonPublicType { get; set; } public string AssemblyName { get; set; } @@ -129,9 +132,10 @@ public string GetNullForgiveness (Parameter symbol) return string.Empty; } - string GetNullable (string s) + string GetNullable(string s) { - switch (s) { + switch (s) + { case "void": case "int": //case "int[]": @@ -156,6 +160,46 @@ string GetNullable (string s) return NullableOperator; } + // Encoding format: + // - Type name prefix: _JniMarshal_PP + // - Parameter types, using JNI encoding, e.g. Z is boolean, I is int, etc. Exception: Reference types, normally encoded as L…;, are instead just L. + // - Another _. + // - Return type, encoded as with parameters. A void return type is V. + internal string GetJniMarshalDelegate (Method method) + { + var sb = new StringBuilder ("_JniMarshal_PP"); + + foreach (var p in method.Parameters) + sb.Append (GetJniTypeCode (p.Symbol)); + + sb.Append ("_"); + + sb.Append (method.IsVoid ? "V" : GetJniTypeCode (method.RetVal.Symbol)); + + var result = sb.ToString (); + + lock (jni_marshal_delegates_lock) + jni_marshal_delegates.Add (result); + + return result; + } + + string GetJniTypeCode (ISymbol symbol) + { + var jni_name = symbol.JniName; + + if (jni_name.StartsWith ("L") || jni_name.StartsWith ("[")) + return "L"; + + return symbol.JniName; + } + + internal IEnumerable GetJniMarshalDelegates () + { + lock (jni_marshal_delegates_lock) + return jni_marshal_delegates; + } + public string GetOutputName (string s) { if (s == "System.Void") diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index cb7160f1f..54d189aeb 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -187,12 +187,12 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve if (mapping_file != null) GenerateMappingReportFile (gens, mapping_file); - new NamespaceMapping (gens).Generate (opt, gen_info); - foreach (IGeneratable gen in gens) if (gen.IsGeneratable) gen.Generate (opt, gen_info); + new NamespaceMapping (gens).Generate (opt, gen_info); + ClassGen.GenerateTypeRegistrations (opt, gen_info); ClassGen.GenerateEnumList (gen_info); diff --git a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs index 66d469ac0..2e4895c55 100644 --- a/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs +++ b/tools/generator/Java.Interop.Tools.Generator.CodeGeneration/CodeGenerator.cs @@ -1093,7 +1093,7 @@ public virtual void WriteMethodCallback (Method method, string indent, GenBase t { var is_private = method.IsInterfaceDefaultMethod ? "private " : string.Empty; - string delegate_type = method.GetDelegateType (); + string delegate_type = method.GetDelegateType (opt); writer.WriteLine ("{0}{2}static Delegate{3} {1};", indent, method.EscapedCallbackName, is_private, opt.NullableOperator); writer.WriteLine ("#pragma warning disable 0169"); if (method.Deprecated != null) diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs index 3632a9b01..6ad71a4e0 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/Method.cs @@ -128,15 +128,7 @@ internal string GetAdapterName (CodeGenerationOptions opt, string adapter) // Connectors for DIM are defined on the interface, not the implementing type public string GetConnectorNameFull (CodeGenerationOptions opt) => ConnectorName + (opt.SupportDefaultInterfaceMethods && IsInterfaceDefaultMethod ? $":{DeclaringType.FullName}, " + (AssemblyName ?? opt.AssemblyName) : string.Empty); - internal string GetDelegateType () - { - var parms = Parameters.DelegateTypeParams; - - if (IsVoid) - return $"Action"; - else - return $"Func"; - } + internal string GetDelegateType (CodeGenerationOptions opt) => opt.GetJniMarshalDelegate (this); public string GetMetadataXPathReference (GenBase declaringType) => $"{declaringType.MetadataXPathReference}/method[@name='{JavaName}'{Parameters.GetMethodXPathPredicate ()}]"; diff --git a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs index d4c7f519c..a3297d4ac 100644 --- a/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs +++ b/tools/generator/Java.Interop.Tools.Generator.ObjectModel/NamespaceMapping.cs @@ -19,9 +19,54 @@ public NamespaceMapping (IEnumerable gens) public void Generate (CodeGenerationOptions opt, GenerationInfo gen_info) { using (var sw = gen_info.OpenStream (opt.GetFileName ("__NamespaceMapping__"))) { + sw.WriteLine ("using System;"); + sw.WriteLine (); + foreach (var p in mappings) sw.WriteLine ("[assembly:global::Android.Runtime.NamespaceMapping (Java = \"{0}\", Managed=\"{1}\")]", p.Key, p.Value); + + sw.WriteLine (); + + // delegate bool _JniMarshal_PPL_Z (IntPtr jnienv, IntPtr klass, IntPtr a); + foreach (var jni in opt.GetJniMarshalDelegates ()) + sw.WriteLine ($"delegate {FromJniType (jni[jni.Length - 1])} {jni} (IntPtr jnienv, IntPtr klass{GetDelegateParameters (jni)});"); + } + } + + string GetDelegateParameters (string jni) + { + var parameters = new List (); + + jni = jni.Substring ("_JniMarshal_PP".Length); + + var index = 0; + + while (jni[index] != '_') { + parameters.Add ($"{FromJniType (jni [index])} p{index}"); + index++; + } + + if (parameters.Count == 0) + return string.Empty; + + return ", " + string.Join (", ", parameters); + } + + string FromJniType (char c) + { + switch (c) { + case 'B': return "sbyte"; + case 'C': return "char"; + case 'D': return "double"; + case 'F': return "float"; + case 'I': return "int"; + case 'J': return "long"; + case 'S': return "short"; + case 'Z': return "bool"; + case 'V': return "void"; + default: + return "IntPtr"; ; } } } diff --git a/tools/generator/generator.csproj b/tools/generator/generator.csproj index 3dc05c887..4b11352c6 100644 --- a/tools/generator/generator.csproj +++ b/tools/generator/generator.csproj @@ -1,9 +1,10 @@ - + - net472;netcoreapp3.1 + net472 Exe $(DefineConstants);GENERATOR;HAVE_CECIL;JCW_ONLY_TYPE_NAMES + 8.0 @@ -35,6 +36,7 @@ + diff --git a/tools/generator/generator.sln b/tools/generator/generator.sln index ce45e4310..2b5894e35 100644 --- a/tools/generator/generator.sln +++ b/tools/generator/generator.sln @@ -1,9 +1,12 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator", "generator.csproj", "{D14A1B5C-2060-4930-92BE-F7190256C735}" +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30013.7 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generator", "generator.csproj", "{D14A1B5C-2060-4930-92BE-F7190256C735}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "generator-Tests", "..\..\tests\generator-Tests\generator-Tests.csproj", "{4EEAB1A7-99C1-4302-9C18-01A7B481409B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "generator-Tests", "..\..\tests\generator-Tests\generator-Tests.csproj", "{4EEAB1A7-99C1-4302-9C18-01A7B481409B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.SourceWriter", "..\..\src\Xamarin.SourceWriter\Xamarin.SourceWriter.csproj", "{FD3882A4-2661-47C6-9C37-18FAFE5F7991}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,5 +22,15 @@ Global {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Debug|Any CPU.Build.0 = Debug|Any CPU {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4EEAB1A7-99C1-4302-9C18-01A7B481409B}.Release|Any CPU.Build.0 = Release|Any CPU + {FD3882A4-2661-47C6-9C37-18FAFE5F7991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD3882A4-2661-47C6-9C37-18FAFE5F7991}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD3882A4-2661-47C6-9C37-18FAFE5F7991}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD3882A4-2661-47C6-9C37-18FAFE5F7991}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EEBC7E77-8FA5-4C2C-8FFD-08F6CD0A5330} EndGlobalSection EndGlobal