From 466f204d44e45a145716fb589c44e169e799ced2 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 28 Jun 2018 19:50:02 +0900 Subject: [PATCH 01/39] Initial default interface methods work. - Added simple test case that contains a DIM method and a DIM-based property. - CodeGenerator takes SupportDefaultInterfaceMethods property. - command line option --default-interface-methods is added. - DIMs in interface generates implementation, not declaration. - DIM-based properties in interface generates implementation, not declaration. --- tools/generator/ClassGen.cs | 20 +--- tools/generator/CodeGenerator.cs | 13 +- tools/generator/GenBase.cs | 29 ++++- tools/generator/InterfaceGen.cs | 20 +++- tools/generator/Property.cs | 2 +- .../DefaultInterfaceMethods.cs | 28 +++++ .../DefaultInterfaceMethods.xml | 15 +++ .../Xamarin.Test.ITheInterface.cs | 113 ++++++++++++++++++ tools/generator/Tests/generator-Tests.csproj | 10 ++ 9 files changed, 218 insertions(+), 32 deletions(-) create mode 100644 tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs create mode 100644 tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml create mode 100644 tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index 2cf25a106..9d63f449d 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -362,24 +362,6 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) } } - void GenProperties (StreamWriter sw, string indent, CodeGenerationOptions opt) - { - foreach (Property prop in Properties) { - bool get_virt = prop.Getter.IsVirtual; - bool set_virt = prop.Setter == null ? false : prop.Setter.IsVirtual; - prop.Getter.IsVirtual = !IsFinal && get_virt; - if (prop.Setter != null) - prop.Setter.IsVirtual = !IsFinal && set_virt; - if (prop.Getter.IsAbstract) - prop.GenerateAbstractDeclaration (sw, indent, opt, this); - else - prop.Generate (this, sw, indent, opt); - prop.Getter.IsVirtual = get_virt; - if (prop.Setter != null) - prop.Setter.IsVirtual = set_virt; - } - } - public override void Generate (StreamWriter sw, string indent, CodeGenerationOptions opt, GenerationInfo gen_info) { opt.ContextTypes.Push (this); @@ -476,7 +458,7 @@ public override void Generate (StreamWriter sw, string indent, CodeGenerationOpt GenConstructors (sw, indent + "\t", opt); - GenProperties (sw, indent + "\t", opt); + GenerateImplementedProperties (sw, indent + "\t", IsFinal, opt); GenMethods (sw, indent + "\t", opt); if (IsAbstract) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 67a5e0ccf..62a1a1089 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -57,6 +57,7 @@ public CodeGeneratorOptions () public string MappingReportFile { get; set; } public bool OnlyRunApiXmlAdjuster { get; set; } public string ApiXmlAdjusterOutput { get; set; } + public bool SupportDefaultInterfaceMethods { get; set; } public static CodeGeneratorOptions Parse (string[] args) { @@ -103,6 +104,9 @@ public static CodeGeneratorOptions Parse (string[] args) { "sdk-platform|api-level=", "SDK Platform {VERSION}/API level.", v => opts.ApiLevel = v }, + { "default-interface-methods", + "For internal use.", + v => opts.SupportDefaultInterfaceMethods = v != null }, { "preserve-enums", "For internal use.", v => opts.PreserveEnums = v != null }, @@ -242,7 +246,8 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve UseGlobal = options.GlobalTypeNames, IgnoreNonPublicType = true, UseShortFileNames = options.UseShortFileNames, - ProductVersion = options.ProductVersion + ProductVersion = options.ProductVersion, + SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods, }; // Load reference libraries @@ -313,7 +318,7 @@ static void Run (CodeGeneratorOptions options, DirectoryAssemblyResolver resolve // disable interface default methods here, especially before validation. gens = gens.Where (g => !g.IsObfuscated && g.Visibility != "private").ToList (); foreach (var gen in gens) { - gen.StripNonBindables (); + gen.StripNonBindables (opt); if (gen.IsGeneratable) AddTypeToTable (opt, gen); } @@ -624,6 +629,7 @@ public CodeGenerationTarget CodeGenerationTarget { public bool UseShortFileNames { get; set; } public IList Gens {get;set;} public int ProductVersion { get; set; } + public bool SupportDefaultInterfaceMethods { get; set; } public string GetOutputName (string s) { @@ -1084,7 +1090,8 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe writer.WriteLine ("{0}[Register (\"{1}\", \"{2}\", \"{3}\"{4})]", indent, method.JavaName, method.JniSignature, method.IsVirtual ? method.ConnectorName : String.Empty, method.AdditionalAttributeString ()); WriteMethodCustomAttributes (method, writer, indent); - writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6} ({7})", indent, method.Visibility, static_arg, virt_ov, seal, ret, method.AdjustedName, GenBase.GetSignature (method, opt)); + string visibility = type.IsInterface ? string.Empty : method.Visibility; + writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6} ({7})", indent, visibility, static_arg, virt_ov, seal, ret, method.AdjustedName, GenBase.GetSignature (method, opt)); writer.WriteLine ("{0}{{", indent); WriteMethodBody (method, writer, indent + "\t", opt); writer.WriteLine ("{0}}}", indent); diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 4ee3c62a7..474793322 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -64,6 +64,10 @@ public string DeprecatedComment { public bool IsGeneratable { get { return support.IsGeneratable; } } + + public virtual bool IsInterface { + get { return false; } + } public virtual ClassGen BaseGen { get { return null; } @@ -595,6 +599,24 @@ public List GetAllDerivedInterfaces () return result; } + protected void GenerateImplementedProperties (StreamWriter sw, string indent, bool isFinal, CodeGenerationOptions opt) + { + foreach (Property prop in Properties) { + bool get_virt = prop.Getter.IsVirtual; + bool set_virt = prop.Setter == null ? false : prop.Setter.IsVirtual; + prop.Getter.IsVirtual = !isFinal && get_virt; + if (prop.Setter != null) + prop.Setter.IsVirtual = !isFinal && set_virt; + if (prop.Getter.IsAbstract) + prop.GenerateAbstractDeclaration (sw, indent, opt, this); + else + prop.Generate (this, sw, indent, opt); + prop.Getter.IsVirtual = get_virt; + if (prop.Setter != null) + prop.Setter.IsVirtual = set_virt; + } + } + void GetAllDerivedInterfaces (List ifaces) { foreach (ISymbol isym in Interfaces) { @@ -716,15 +738,16 @@ protected virtual bool OnValidate (CodeGenerationOptions opt, GenericParameterDe bool property_filling; - public void StripNonBindables () + public void StripNonBindables (CodeGenerationOptions opt) { // As of now, if we generate bindings for interface default methods, that means users will // have to "implement" those methods because they are declared and you have to implement // any declared methods in C#. That is going to be problematic a lot. - methods = methods.Where (m => !m.IsInterfaceDefaultMethod).ToList (); + if (!opt.SupportDefaultInterfaceMethods) + methods = methods.Where (m => !m.IsInterfaceDefaultMethod).ToList (); nested_types = nested_types.Where (n => !n.IsObfuscated && n.Visibility != "private").ToList (); foreach (var n in nested_types) - n.StripNonBindables (); + n.StripNonBindables (opt); } public virtual void FixupAccessModifiers (CodeGenerationOptions opt) diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index dd58b64ad..8a279dd3c 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -9,6 +9,7 @@ using Xamarin.Android.Binder; using Xamarin.Android.Tools; +using System.Diagnostics; namespace MonoDroid.Generation { #if HAVE_CECIL @@ -105,6 +106,10 @@ public bool IsConstSugar { } } + public override bool IsInterface { + get { return true; } + } + public bool IsListener { // If there is a property it cannot generate valid implementor, so reject this at least so far. get { return Name.EndsWith ("Listener") && Properties.Count == 0 && Interfaces.Count == 0; } @@ -196,11 +201,13 @@ protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterD void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) { - foreach (Method m in Methods.Where (m => !m.IsStatic)) { + foreach (Method m in Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod)) { if (m.Name == Name || ContainsProperty (m.Name, true)) m.Name = "Invoke" + m.Name; opt.CodeGenerator.WriteMethodDeclaration (m, sw, indent, opt, this, AssemblyQualifiedName + "Invoker"); } + foreach (Method m in Methods.Where (m => m.IsInterfaceDefaultMethod)) + opt.CodeGenerator.WriteMethod (m, sw, indent, opt, this, true); } void GenExtensionMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) @@ -213,8 +220,9 @@ void GenExtensionMethods (StreamWriter sw, string indent, CodeGenerationOptions void GenProperties (StreamWriter sw, string indent, CodeGenerationOptions opt) { - foreach (Property prop in Properties.Where (p => !p.Getter.IsStatic)) + foreach (Property prop in Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod)) prop.GenerateDeclaration (sw, indent, opt, this, AssemblyQualifiedName + "Invoker"); + base.GenerateImplementedProperties (sw, indent, false, opt); } void GenerateInvoker (StreamWriter sw, string indent, CodeGenerationOptions opt) @@ -255,14 +263,14 @@ void GenerateInvoker (StreamWriter sw, string indent, CodeGenerationOptions opt) sw.WriteLine (); HashSet members = new HashSet (); - GenerateInvoker (sw, Properties.Where (p => !p.Getter.IsStatic), indent + "\t", opt, members); - GenerateInvoker (sw, Methods.Where (m => !m.IsStatic), indent + "\t", opt, members); + GenerateInvoker (sw, Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), indent + "\t", opt, members); + GenerateInvoker (sw, Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod), indent + "\t", opt, members); if (FullName == "Java.Lang.ICharSequence") GenCharSequenceEnumerator (sw, indent + "\t", opt); foreach (InterfaceGen iface in GetAllDerivedInterfaces ()) { - GenerateInvoker (sw, iface.Properties.Where (p => !p.Getter.IsStatic), indent + "\t", opt, members); - GenerateInvoker (sw, iface.Methods.Where (m => !m.IsStatic && !IsCovariantMethod (m) && !(iface.FullName.StartsWith ("Java.Lang.ICharSequence") && m.Name.EndsWith ("Formatted"))), indent + "\t", opt, members); + GenerateInvoker (sw, iface.Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), indent + "\t", opt, members); + GenerateInvoker (sw, iface.Methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod && !IsCovariantMethod (m) && !(iface.FullName.StartsWith ("Java.Lang.ICharSequence") && m.Name.EndsWith ("Formatted"))), indent + "\t", opt, members); if (iface.FullName == "Java.Lang.ICharSequence") GenCharSequenceEnumerator (sw, indent + "\t", opt); } diff --git a/tools/generator/Property.cs b/tools/generator/Property.cs index c896c1bff..d52a356a5 100644 --- a/tools/generator/Property.cs +++ b/tools/generator/Property.cs @@ -264,7 +264,7 @@ public void Generate (GenBase gen, StreamWriter sw, string indent, CodeGeneratio opt.CodeGenerator.WriteMethodIdField (Getter, sw, indent, opt); if (Setter != null) opt.CodeGenerator.WriteMethodIdField (Setter, sw, indent, opt); - string visibility = Getter.IsAbstract && Getter.RetVal.IsGeneric ? "protected" : (Setter ?? Getter).Visibility; + string visibility = gen.IsInterface ? string.Empty : Getter.IsAbstract && Getter.RetVal.IsGeneric ? "protected" : (Setter ?? Getter).Visibility; // Unlike [Register], mcs does not allow applying [Obsolete] on property accessors, so we can apply them only under limited condition... if (Getter.Deprecated != null && (Setter == null || Setter.Deprecated != null)) sw.WriteLine ("{0}[Obsolete (@\"{1}\")]", indent, Getter.Deprecated.Replace ("\"", "\"\"").Trim () + (Setter != null && Setter.Deprecated != Getter.Deprecated ? " " + Setter.Deprecated.Replace ("\"", "\"\"").Trim () : null)); diff --git a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs new file mode 100644 index 000000000..dcc3de838 --- /dev/null +++ b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; +using NUnit.Framework; +using Xamarin.Android.Binder; + +namespace generatortests +{ + [TestFixture] + public class DefaultInterfaceMethods : BaseGeneratorTest + { + [Test] + public void GeneratedOK () + { + Options.SupportDefaultInterfaceMethods = true; + RunAllTargets ( + outputRelativePath: "DefaultInterfaceMethods", + apiDescriptionFile: "expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml", + expectedRelativePath: "DefaultInterfaceMethods", + additionalSupportPaths: null); + } + + void RunAllTargets (string outputRelativePath, string apiDescriptionFile, string expectedRelativePath, string [] additionalSupportPaths) + { + Run (CodeGenerationTarget.JavaInterop1, Path.Combine ("out.ji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.ji", expectedRelativePath), additionalSupportPaths); + } + } +} + diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml new file mode 100644 index 000000000..13d32f0ef --- /dev/null +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs new file mode 100644 index 000000000..f684980a7 --- /dev/null +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; + +namespace Xamarin.Test { + + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']" + [Register ("xamarin/test/TheInterface", "", "Xamarin.Test.ITheInterfaceInvoker")] + public partial interface ITheInterface : IJavaObject { + + static Delegate cb_getBar; +#pragma warning disable 0169 + static Delegate GetGetBarHandler () + { + if (cb_getBar == null) + cb_getBar = JNINativeWrapper.CreateDelegate ((Func) n_GetBar); + return cb_getBar; + } + + static int n_GetBar (IntPtr jnienv, IntPtr native__this) + { + global::Xamarin.Test.TheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Bar; + } +#pragma warning restore 0169 + + public virtual unsafe int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TheInterface']/method[@name='getBar' and count(parameter)=0]" + [Register ("getBar", "()I", "GetGetBarHandler")] + get { + const string __id = "getBar.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + } + + static Delegate cb_foo; +#pragma warning disable 0169 + static Delegate GetFooHandler () + { + if (cb_foo == null) + cb_foo = JNINativeWrapper.CreateDelegate ((Func) n_Foo); + return cb_foo; + } + + static int n_Foo (IntPtr jnienv, IntPtr native__this) + { + global::Xamarin.Test.TheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return __this.Foo (); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TheInterface']/method[@name='foo' and count(parameter)=0]" + [Register ("foo", "()I", "GetFooHandler")] + public virtual unsafe int Foo () + { + const string __id = "foo.()I"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + return __rm; + } finally { + } + } + } + + [global::Android.Runtime.Register ("xamarin/test/TheInterface", DoNotGenerateAcw=true)] + internal class ITheInterfaceInvoker : global::Java.Lang.Object, ITheInterface { + + static IntPtr java_class_ref = JNIEnv.FindClass ("xamarin/test/TheInterface"); + + protected override IntPtr ThresholdClass { + get { return class_ref; } + } + + protected override global::System.Type ThresholdType { + get { return typeof (ITheInterfaceInvoker); } + } + + IntPtr class_ref; + + public static ITheInterface GetObject (IntPtr handle, JniHandleOwnership transfer) + { + return global::Java.Lang.Object.GetObject (handle, transfer); + } + + static IntPtr Validate (IntPtr handle) + { + if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) + throw new InvalidCastException (string.Format ("Unable to convert instance of type '{0}' to type '{1}'.", + JNIEnv.GetClassNameFromInstance (handle), "xamarin.test.TheInterface")); + return handle; + } + + protected override void Dispose (bool disposing) + { + if (this.class_ref != IntPtr.Zero) + JNIEnv.DeleteGlobalRef (this.class_ref); + this.class_ref = IntPtr.Zero; + base.Dispose (disposing); + } + + public ITheInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) + { + IntPtr local_ref = JNIEnv.GetObjectClass (((global::Java.Lang.Object) this).Handle); + this.class_ref = JNIEnv.NewGlobalRef (local_ref); + JNIEnv.DeleteLocalRef (local_ref); + } + } + +} diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index 760478073..80a748e3e 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -75,6 +75,7 @@ + @@ -167,6 +168,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + @@ -200,4 +207,7 @@ + + + From ab831c5f1157256a3682bcf889b6632f58a2f2df Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 28 Jun 2018 19:56:05 +0900 Subject: [PATCH 02/39] Forgot to limit property implementation generation only to DIM-based properties. --- tools/generator/ClassGen.cs | 2 +- tools/generator/GenBase.cs | 4 ++-- tools/generator/InterfaceGen.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index 9d63f449d..99cdfe900 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -458,7 +458,7 @@ public override void Generate (StreamWriter sw, string indent, CodeGenerationOpt GenConstructors (sw, indent + "\t", opt); - GenerateImplementedProperties (sw, indent + "\t", IsFinal, opt); + GenerateImplementedProperties (Properties, sw, indent + "\t", IsFinal, opt); GenMethods (sw, indent + "\t", opt); if (IsAbstract) diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 474793322..d64eafa01 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -599,9 +599,9 @@ public List GetAllDerivedInterfaces () return result; } - protected void GenerateImplementedProperties (StreamWriter sw, string indent, bool isFinal, CodeGenerationOptions opt) + protected void GenerateImplementedProperties (IEnumerable targetProperties, StreamWriter sw, string indent, bool isFinal, CodeGenerationOptions opt) { - foreach (Property prop in Properties) { + foreach (Property prop in targetProperties) { bool get_virt = prop.Getter.IsVirtual; bool set_virt = prop.Setter == null ? false : prop.Setter.IsVirtual; prop.Getter.IsVirtual = !isFinal && get_virt; diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index 8a279dd3c..81a6bf7ee 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -222,7 +222,7 @@ void GenProperties (StreamWriter sw, string indent, CodeGenerationOptions opt) { foreach (Property prop in Properties.Where (p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod)) prop.GenerateDeclaration (sw, indent, opt, this, AssemblyQualifiedName + "Invoker"); - base.GenerateImplementedProperties (sw, indent, false, opt); + base.GenerateImplementedProperties (Properties.Where (p => p.Getter.IsInterfaceDefaultMethod), sw, indent, false, opt); } void GenerateInvoker (StreamWriter sw, string indent, CodeGenerationOptions opt) From cd537ff13dd077eaab7df9f68926cf180a48959b Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 29 Jun 2018 19:19:18 +0900 Subject: [PATCH 03/39] generator unit tests now supports DIM-supported csc via nuget package. The idea is in the same mindset as existing Windows Roslyn support in terms of access to package contents (dll/exe). I couldn't enable this for ALL projects as java.lang.Object test somehow failed. We only need it only if DIM is required, so limit the usage to it. --- .../Tests/Integration-Tests/Compiler.cs | 42 +++++++++++++++++++ tools/generator/Tests/generator-Tests.csproj | 2 + tools/generator/Tests/packages.config | 1 + 3 files changed, 45 insertions(+) diff --git a/tools/generator/Tests/Integration-Tests/Compiler.cs b/tools/generator/Tests/Integration-Tests/Compiler.cs index 9c74b99e6..c9f027605 100644 --- a/tools/generator/Tests/Integration-Tests/Compiler.cs +++ b/tools/generator/Tests/Integration-Tests/Compiler.cs @@ -4,6 +4,8 @@ using System.IO; using System.Linq; using System.Collections.Generic; +using System.Diagnostics; +using System.Text; using NUnit.Framework; namespace generatortests @@ -67,6 +69,46 @@ public static Assembly Compile (Xamarin.Android.Binder.CodeGeneratorOptions opti parameters.IncludeDebugInformation = false; #endif + if (options.SupportDefaultInterfaceMethods) { + var sb = new StringBuilder (); + sb.Append (" /t:library") + .Append (" /unsafe") + .Append (" /langversion:latest") + .Append (' ').Append ($"/out:\"{assemblyFileName}\""); + foreach (var assembly in parameters.ReferencedAssemblies) + sb.Append ($" /r:\"{assembly}\""); + if (parameters.IncludeDebugInformation) + sb.Append (" /debug:portable"); + foreach (var sourceFile in sourceFiles) + sb.Append (' ').Append ($"\"{sourceFile}\""); + string compiler = Path.GetFullPath (Path.Combine (unitTestFrameworkAssemblyPath, "..", "..", "..", "packages", "xamarin.android.csc.dim.0.1.2", "tools", "csc.exe")); + var pinfo = new ProcessStartInfo () { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + pinfo.FileName = compiler; + pinfo.Arguments = sb.ToString (); + } else { + pinfo.FileName = "mono"; // SYSMONO + pinfo.Arguments = compiler + sb; + } + var results = new StringBuilder (); + var proc = new Process (); + proc.ErrorDataReceived += (o, e) => + results.Append (e.Data).Append (Environment.NewLine); + proc.OutputDataReceived += (o, e) => + results.Append (e.Data).Append (Environment.NewLine); + proc.StartInfo = pinfo; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + proc.WaitForExit (); + output = results.ToString (); + hasErrors = proc.ExitCode != 0; + return hasErrors ? null : Assembly.ReflectionOnlyLoadFrom (Path.GetFullPath (assemblyFileName)); + } using (var codeProvider = GetCodeDomProvider ()) { CompilerResults results = codeProvider.CompileAssemblyFromFile (parameters, sourceFiles.ToArray ()); diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index 80a748e3e..c15a2a528 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -210,4 +211,5 @@ + diff --git a/tools/generator/Tests/packages.config b/tools/generator/Tests/packages.config index 9f1bd4562..158b37758 100644 --- a/tools/generator/Tests/packages.config +++ b/tools/generator/Tests/packages.config @@ -3,4 +3,5 @@ + \ No newline at end of file From 60a950ee677449b7127a2f6480947b73b5d0da33 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 29 Jun 2018 22:45:01 +0900 Subject: [PATCH 04/39] "_members" field is needed inside InterfaceGen, whenever DIM bindings exist. --- tools/generator/InterfaceGen.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index 81a6bf7ee..e5f102d2f 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -744,6 +744,16 @@ public override void Generate (StreamWriter sw, string indent, CodeGenerationOpt } } + var defaultInterfaceMethods = Methods.Where (m => m.IsInterfaceDefaultMethod); + var defaultInterfaceProperties = Properties.Where (p => p.Getter != null && p.Getter.IsInterfaceDefaultMethod || p.Setter != null && p.Setter.IsInterfaceDefaultMethod); + if (defaultInterfaceMethods.Any () || defaultInterfaceProperties.Any ()) { + sw.WriteLine ("{0}partial interface {1} {{", indent, Name); + sw.WriteLine (); + opt.CodeGenerator.WriteClassHandle (this, sw, indent + "\t", opt, Name); + sw.WriteLine ("{0}}}", indent); + sw.WriteLine (); + } + if (IsConstSugar) return; From e027582871b2268aa443804e3d2852e6d76e028d Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 2 Jul 2018 17:49:24 +0900 Subject: [PATCH 05/39] Now generator generates missing (IPeerable) casts so that code compiles. CodeGenerator.WriteMethodBody() now takes CodeGen so that it can detect InterfaceGen and if it is for interface then it adds missing casts. It is also possible to simply add cast everywhere which makes code generation simple, but it will involve ALL the unit tests' expected output rewritten. It will be annoying work especially the branch development is going to take a while until merged, so I skip that for now. --- tools/generator/CodeGenerator.cs | 6 ++-- tools/generator/JavaInteropCodeGenerator.cs | 13 ++++--- tools/generator/Property.cs | 4 +-- .../JavaInteropCodeGeneratorTests.cs | 2 +- .../XamarinAndroidCodeGeneratorTests.cs | 2 +- .../Xamarin.Test.ITheInterface.cs | 36 +++++++++++++------ .../generator/XamarinAndroidCodeGenerator.cs | 2 +- 7 files changed, 43 insertions(+), 22 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 62a1a1089..81b239173 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -719,7 +719,7 @@ protected CodeGenerator () internal abstract void WriteConstructorBody (Ctor ctor, TextWriter writer, string indent, CodeGenerationOptions opt, StringCollection call_cleanup); internal abstract void WriteMethodIdField (Method method, TextWriter writer, string indent, CodeGenerationOptions opt); - internal abstract void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt); + internal abstract void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); internal abstract void WriteFieldIdField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt); internal abstract void WriteFieldGetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); @@ -828,7 +828,7 @@ public void WriteMethodExplicitInterfaceInvoker (Method method, TextWriter write writer.WriteLine ("{0}unsafe {1} {2}.{3} ({4})", indent, opt.GetOutputName (method.RetVal.FullName), opt.GetOutputName (iface.FullName), method.Name, GenBase.GetSignature (method, opt)); writer.WriteLine ("{0}{{", indent); - WriteMethodBody (method, writer, indent + "\t", opt); + WriteMethodBody (method, writer, indent + "\t", opt, iface); writer.WriteLine ("{0}}}", indent); writer.WriteLine (); } @@ -1093,7 +1093,7 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe string visibility = type.IsInterface ? string.Empty : method.Visibility; writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6} ({7})", indent, visibility, static_arg, virt_ov, seal, ret, method.AdjustedName, GenBase.GetSignature (method, opt)); writer.WriteLine ("{0}{{", indent); - WriteMethodBody (method, writer, indent + "\t", opt); + WriteMethodBody (method, writer, indent + "\t", opt, type); writer.WriteLine ("{0}}}", indent); writer.WriteLine (); diff --git a/tools/generator/JavaInteropCodeGenerator.cs b/tools/generator/JavaInteropCodeGenerator.cs index 635bf56fd..401ad7db6 100644 --- a/tools/generator/JavaInteropCodeGenerator.cs +++ b/tools/generator/JavaInteropCodeGenerator.cs @@ -139,7 +139,7 @@ internal override void WriteMethodIdField (Method method, TextWriter writer, str // No method id_ field required; it's now an `id` constant in the binding. } - internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) + internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { writer.WriteLine ("{0}const string __id = \"{1}.{2}\";", indent, method.JavaName, method.JniSignature); foreach (string prep in method.Parameters.GetCallPrep (opt)) @@ -156,21 +156,26 @@ internal override void WriteMethodBody (Method method, TextWriter writer, string writer.Write ("var __rm = "); } + string castToPeerable = type.IsInterface ? "(IJavaPeerable) " : string.Empty; + if (method.IsStatic) { writer.WriteLine ("_members.StaticMethods.Invoke{0}Method (__id{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); } else if (method.IsFinal) { - writer.WriteLine ("_members.InstanceMethods.InvokeNonvirtual{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeNonvirtual{0}Method (__id, {1}this{2});", invokeType, + castToPeerable, method.Parameters.GetCallArgs (opt, invoker: false)); } else if (method.IsVirtual && !method.IsAbstract) { - writer.WriteLine ("_members.InstanceMethods.InvokeVirtual{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeVirtual{0}Method (__id, {1}this{2});", invokeType, + castToPeerable, method.Parameters.GetCallArgs (opt, invoker: false)); } else { - writer.WriteLine ("_members.InstanceMethods.InvokeAbstract{0}Method (__id, this{1});", + writer.WriteLine ("_members.InstanceMethods.InvokeAbstract{0}Method (__id, {1}this{2});", invokeType, + castToPeerable, method.Parameters.GetCallArgs (opt, invoker: false)); } diff --git a/tools/generator/Property.cs b/tools/generator/Property.cs index d52a356a5..bc2ac8394 100644 --- a/tools/generator/Property.cs +++ b/tools/generator/Property.cs @@ -274,7 +274,7 @@ public void Generate (GenBase gen, StreamWriter sw, string indent, CodeGeneratio sw.WriteLine ("{0}\t// Metadata.xml XPath method reference: path=\"{1}/method[@name='{2}'{3}]\"", indent, gen.MetadataXPathReference, Getter.JavaName, Getter.Parameters.GetMethodXPathPredicate ()); sw.WriteLine ("{0}\t[Register (\"{1}\", \"{2}\", \"{3}\"{4})]", indent, Getter.JavaName, Getter.JniSignature, Getter.ConnectorName, Getter.AdditionalAttributeString ()); sw.WriteLine ("{0}\tget {{", indent); - opt.CodeGenerator.WriteMethodBody (Getter, sw, indent + "\t\t", opt); + opt.CodeGenerator.WriteMethodBody (Getter, sw, indent + "\t\t", opt, gen); sw.WriteLine ("{0}\t}}", indent); if (Setter != null) { if (gen.IsGeneratable) @@ -284,7 +284,7 @@ public void Generate (GenBase gen, StreamWriter sw, string indent, CodeGeneratio sw.WriteLine ("{0}\tset {{", indent); string pname = Setter.Parameters [0].Name; Setter.Parameters [0].Name = "value"; - opt.CodeGenerator.WriteMethodBody (Setter, sw, indent + "\t\t", opt); + opt.CodeGenerator.WriteMethodBody (Setter, sw, indent + "\t\t", opt, gen); Setter.Parameters [0].Name = pname; sw.WriteLine ("{0}\t}}", indent); } else if (GenerateDispatchingSetter) { diff --git a/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs b/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs index 8cc33ce4b..cc68c4dec 100644 --- a/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs +++ b/tools/generator/Tests/Unit-Tests/JavaInteropCodeGeneratorTests.cs @@ -220,7 +220,7 @@ public void WriteMethodBody () var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); var method = new TestMethod (@class, "bar"); Assert.IsTrue (method.Validate (options, new GenericParameterDefinitionList ()), "method.Validate failed!"); - generator.WriteMethodBody (method, writer, string.Empty, options); + generator.WriteMethodBody (method, writer, string.Empty, options, @class); Assert.AreEqual (@"const string __id = ""bar.()V""; try { diff --git a/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs b/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs index a70dccb2d..e54a2cebe 100644 --- a/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs +++ b/tools/generator/Tests/Unit-Tests/XamarinAndroidCodeGeneratorTests.cs @@ -216,7 +216,7 @@ public void WriteMethodBody () var @class = new TestClass ("java.lang.Object", "com.mypackage.foo"); var method = new TestMethod (@class, "bar"); Assert.IsTrue (method.Validate (options, new GenericParameterDefinitionList ()), "method.Validate failed!"); - generator.WriteMethodBody (method, writer, string.Empty, options); + generator.WriteMethodBody (method, writer, string.Empty, options, @class); Assert.AreEqual (@"if (id_bar == IntPtr.Zero) id_bar = JNIEnv.GetMethodID (class_ref, ""bar"", ""()V""); diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs index f684980a7..c881bb7ff 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs @@ -1,9 +1,15 @@ using System; using System.Collections.Generic; using Android.Runtime; +using Java.Interop; namespace Xamarin.Test { + partial interface ITheInterface { + + new static JniPeerMembers _members = new JniPeerMembers ("xamarin/test/TheInterface", typeof (ITheInterface)); + } + // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']" [Register ("xamarin/test/TheInterface", "", "Xamarin.Test.ITheInterfaceInvoker")] public partial interface ITheInterface : IJavaObject { @@ -19,18 +25,18 @@ static Delegate GetGetBarHandler () static int n_GetBar (IntPtr jnienv, IntPtr native__this) { - global::Xamarin.Test.TheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); return __this.Bar; } #pragma warning restore 0169 - public virtual unsafe int Bar { - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TheInterface']/method[@name='getBar' and count(parameter)=0]" + virtual unsafe int Bar { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='getBar' and count(parameter)=0]" [Register ("getBar", "()I", "GetGetBarHandler")] get { const string __id = "getBar.()I"; try { - var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, (IJavaPeerable) this, null); return __rm; } finally { } @@ -48,35 +54,44 @@ static Delegate GetFooHandler () static int n_Foo (IntPtr jnienv, IntPtr native__this) { - global::Xamarin.Test.TheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); return __this.Foo (); } #pragma warning restore 0169 - // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/class[@name='TheInterface']/method[@name='foo' and count(parameter)=0]" + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='foo' and count(parameter)=0]" [Register ("foo", "()I", "GetFooHandler")] - public virtual unsafe int Foo () + virtual unsafe int Foo () { const string __id = "foo.()I"; try { - var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, null); + var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, (IJavaPeerable) this, null); return __rm; } finally { } } + } [global::Android.Runtime.Register ("xamarin/test/TheInterface", DoNotGenerateAcw=true)] internal class ITheInterfaceInvoker : global::Java.Lang.Object, ITheInterface { - static IntPtr java_class_ref = JNIEnv.FindClass ("xamarin/test/TheInterface"); + internal new static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/TheInterface", typeof (ITheInterfaceInvoker)); + + static IntPtr java_class_ref { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } protected override IntPtr ThresholdClass { get { return class_ref; } } protected override global::System.Type ThresholdType { - get { return typeof (ITheInterfaceInvoker); } + get { return _members.ManagedPeerType; } } IntPtr class_ref; @@ -108,6 +123,7 @@ public ITheInterfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base this.class_ref = JNIEnv.NewGlobalRef (local_ref); JNIEnv.DeleteLocalRef (local_ref); } + } } diff --git a/tools/generator/XamarinAndroidCodeGenerator.cs b/tools/generator/XamarinAndroidCodeGenerator.cs index afa47aedc..b69c06149 100644 --- a/tools/generator/XamarinAndroidCodeGenerator.cs +++ b/tools/generator/XamarinAndroidCodeGenerator.cs @@ -118,7 +118,7 @@ void GenerateJNICall (Method method, TextWriter writer, string indent, CodeGener writer.WriteLine ("{0}return {1};", indent, method.RetVal.FromNative (opt, call, true)); } - internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt) + internal override void WriteMethodBody (Method method, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { writer.WriteLine ("{0}if ({1} == IntPtr.Zero)", indent, method.EscapedIdName); writer.WriteLine ("{0}\t{1} = JNIEnv.Get{2}MethodID (class_ref, \"{3}\", \"{4}\");", indent, method.EscapedIdName, method.IsStatic ? "Static" : String.Empty, method.JavaName, method.JniSignature); From 8de531305506df5c39218de0fe94310de37c8627 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 2 Jul 2018 18:11:43 +0900 Subject: [PATCH 06/39] Add a bit more complicated DIM tests: property setter, String, String[], params. --- .../DefaultInterfaceMethods.xml | 12 ++ .../Xamarin.Test.ITheInterface.cs | 139 ++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml index 13d32f0ef..25cc1eb24 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml @@ -10,6 +10,18 @@ + + + + + + + + + + + + diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs index c881bb7ff..a0a59b944 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs @@ -43,6 +43,65 @@ virtual unsafe int Bar { } } + static Delegate cb_getStringProp; +#pragma warning disable 0169 + static Delegate GetGetStringPropHandler () + { + if (cb_getStringProp == null) + cb_getStringProp = JNINativeWrapper.CreateDelegate ((Func) n_GetStringProp); + return cb_getStringProp; + } + + static IntPtr n_GetStringProp (IntPtr jnienv, IntPtr native__this) + { + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.StringProp); + } +#pragma warning restore 0169 + + static Delegate cb_setStringProp_Ljava_lang_String_; +#pragma warning disable 0169 + static Delegate GetSetStringProp_Ljava_lang_String_Handler () + { + if (cb_setStringProp_Ljava_lang_String_ == null) + cb_setStringProp_Ljava_lang_String_ = JNINativeWrapper.CreateDelegate ((Action) n_SetStringProp_Ljava_lang_String_); + return cb_setStringProp_Ljava_lang_String_; + } + + static void n_SetStringProp_Ljava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_v) + { + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + string v = JNIEnv.GetString (native_v, JniHandleOwnership.DoNotTransfer); + __this.StringProp = v; + } +#pragma warning restore 0169 + + virtual unsafe string StringProp { + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='getStringProp' and count(parameter)=0]" + [Register ("getStringProp", "()Ljava/lang/String;", "GetGetStringPropHandler")] + get { + const string __id = "getStringProp.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='setStringProp' and count(parameter)=1 and parameter[1][@type='java.lang.String']]" + [Register ("setStringProp", "(Ljava/lang/String;)V", "GetSetStringProp_Ljava_lang_String_Handler")] + set { + const string __id = "setStringProp.(Ljava/lang/String;)V"; + IntPtr native_value = JNIEnv.NewString (value); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [1]; + __args [0] = new JniArgumentValue (native_value); + _members.InstanceMethods.InvokeVirtualVoidMethod (__id, (IJavaPeerable) this, __args); + } finally { + JNIEnv.DeleteLocalRef (native_value); + } + } + } + static Delegate cb_foo; #pragma warning disable 0169 static Delegate GetFooHandler () @@ -71,6 +130,86 @@ virtual unsafe int Foo () } } + static Delegate cb_string1; +#pragma warning disable 0169 + static Delegate GetString1Handler () + { + if (cb_string1 == null) + cb_string1 = JNINativeWrapper.CreateDelegate ((Func) n_String1); + return cb_string1; + } + + static IntPtr n_String1 (IntPtr jnienv, IntPtr native__this) + { + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + return JNIEnv.NewString (__this.String1 ()); + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='string1' and count(parameter)=0]" + [Register ("string1", "()Ljava/lang/String;", "GetString1Handler")] + virtual unsafe string String1 () + { + const string __id = "string1.()Ljava/lang/String;"; + try { + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, null); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + } + } + + static Delegate cb_string1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_; +#pragma warning disable 0169 + static Delegate GetString1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_Handler () + { + if (cb_string1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_ == null) + cb_string1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_ = JNINativeWrapper.CreateDelegate ((Func) n_String1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_); + return cb_string1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_; + } + + static IntPtr n_String1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_ (IntPtr jnienv, IntPtr native__this, IntPtr native_p1, IntPtr native_p2, IntPtr native_p3) + { + global::Xamarin.Test.ITheInterface __this = global::Java.Lang.Object.GetObject (jnienv, native__this, JniHandleOwnership.DoNotTransfer); + string p1 = JNIEnv.GetString (native_p1, JniHandleOwnership.DoNotTransfer); + string[] p2 = (string[]) JNIEnv.GetArray (native_p2, JniHandleOwnership.DoNotTransfer, typeof (string)); + string[] p3 = (string[]) JNIEnv.GetArray (native_p3, JniHandleOwnership.DoNotTransfer, typeof (string)); + IntPtr __ret = JNIEnv.NewString (__this.String1 (p1, p2, p3)); + if (p2 != null) + JNIEnv.CopyArray (p2, native_p2); + if (p3 != null) + JNIEnv.CopyArray (p3, native_p3); + return __ret; + } +#pragma warning restore 0169 + + // Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']/method[@name='string1' and count(parameter)=3 and parameter[1][@type='java.lang.String'] and parameter[2][@type='java.lang.String[]'] and parameter[3][@type='java.lang.String...']]" + [Register ("string1", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;", "GetString1_Ljava_lang_String_arrayLjava_lang_String_arrayLjava_lang_String_Handler")] + virtual unsafe string String1 (string p1, string[] p2, params string[] p3) + { + const string __id = "string1.(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;"; + IntPtr native_p1 = JNIEnv.NewString (p1); + IntPtr native_p2 = JNIEnv.NewArray (p2); + IntPtr native_p3 = JNIEnv.NewArray (p3); + try { + JniArgumentValue* __args = stackalloc JniArgumentValue [3]; + __args [0] = new JniArgumentValue (native_p1); + __args [1] = new JniArgumentValue (native_p2); + __args [2] = new JniArgumentValue (native_p3); + var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, __args); + return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); + } finally { + JNIEnv.DeleteLocalRef (native_p1); + if (p2 != null) { + JNIEnv.CopyArray (native_p2, p2); + JNIEnv.DeleteLocalRef (native_p2); + } + if (p3 != null) { + JNIEnv.CopyArray (native_p3, p3); + JNIEnv.DeleteLocalRef (native_p3); + } + } + } + } [global::Android.Runtime.Register ("xamarin/test/TheInterface", DoNotGenerateAcw=true)] From 0e7592879eaa2ab875d82c78f254f072626f4f0b Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 3 Jul 2018 21:22:21 +0900 Subject: [PATCH 07/39] Add more test lines to ensure that the generated code actually loads and runs. So far the test fails because there isn't Java.Interop.dll in the loaded path... --- tools/generator/Tests/Integration-Tests/Compiler.cs | 2 +- .../Tests/Integration-Tests/DefaultInterfaceMethods.cs | 4 ++++ .../DefaultInterfaceMethods/DefaultInterfaceMethods.xml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/generator/Tests/Integration-Tests/Compiler.cs b/tools/generator/Tests/Integration-Tests/Compiler.cs index c9f027605..5dafd90e8 100644 --- a/tools/generator/Tests/Integration-Tests/Compiler.cs +++ b/tools/generator/Tests/Integration-Tests/Compiler.cs @@ -107,7 +107,7 @@ public static Assembly Compile (Xamarin.Android.Binder.CodeGeneratorOptions opti proc.WaitForExit (); output = results.ToString (); hasErrors = proc.ExitCode != 0; - return hasErrors ? null : Assembly.ReflectionOnlyLoadFrom (Path.GetFullPath (assemblyFileName)); + return hasErrors ? null : Assembly.LoadFrom (Path.GetFullPath (assemblyFileName)); } using (var codeProvider = GetCodeDomProvider ()) { CompilerResults results = codeProvider.CompileAssemblyFromFile (parameters, sourceFiles.ToArray ()); diff --git a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs index dcc3de838..533278592 100644 --- a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs +++ b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using NUnit.Framework; using Xamarin.Android.Binder; @@ -22,6 +23,9 @@ public void GeneratedOK () void RunAllTargets (string outputRelativePath, string apiDescriptionFile, string expectedRelativePath, string [] additionalSupportPaths) { Run (CodeGenerationTarget.JavaInterop1, Path.Combine ("out.ji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.ji", expectedRelativePath), additionalSupportPaths); + var type = BuiltAssembly.GetTypes ().First (t => t.FullName == "Xamarin.Test.TheImplementor"); + var instance = Activator.CreateInstance (type); + type.GetProperty ("Bar").GetValue (instance); } } } diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml index 25cc1eb24..9a3dda9c7 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/DefaultInterfaceMethods.xml @@ -23,5 +23,9 @@ + + + + From 2321d7907cd92d98afc776e18597aec09b6f2045 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 3 Jul 2018 22:50:24 +0900 Subject: [PATCH 08/39] Explicitly set JniRuntime(TestJVM) so that nunit can initialize JVM to load. To achieve this new references are added to generator-Tests.csproj. --- .../Integration-Tests/DefaultInterfaceMethods.cs | 3 +++ tools/generator/Tests/generator-Tests.csproj | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs index 533278592..fc7225305 100644 --- a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs +++ b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs @@ -23,6 +23,9 @@ public void GeneratedOK () void RunAllTargets (string outputRelativePath, string apiDescriptionFile, string expectedRelativePath, string [] additionalSupportPaths) { Run (CodeGenerationTarget.JavaInterop1, Path.Combine ("out.ji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.ji", expectedRelativePath), additionalSupportPaths); + + Java.Interop.JniRuntime.SetCurrent (new Java.InteropTests.TestJVM ()); + var type = BuiltAssembly.GetTypes ().First (t => t.FullName == "Xamarin.Test.TheImplementor"); var instance = Activator.CreateInstance (type); type.GetProperty ("Bar").GetValue (instance); diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index c15a2a528..7fedcdadd 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -92,6 +92,18 @@ {15945D4B-FF56-4BCC-B598-2718D199DD08} Xamarin.Android.Cecil + + {94BD81F7-B06F-4295-9636-F8A3B6BDC762} + Java.Interop + + + {5887B410-D448-4257-A46B-EAC03C80BE93} + Java.Runtime.Environment + + + {A76309AB-98AC-4AE2-BA30-75481420C52F} + TestJVM + From b7d00cf8baa540946e4bec8478566421f736d353 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 5 Jul 2018 22:06:54 +0900 Subject: [PATCH 09/39] Add binding-integration-Tests (ongoing work). context: https://github.com/xamarin/java.interop/pull/341#issuecomment-402346839 So far, it runs javac and jar to create input jars. --- Java.Interop.sln | 13 +- .../BindingBuilder.cs | 170 ++++++++++++++++++ .../BindingProject.cs | 50 ++++++ tests/binding-integrated-Tests/README.md | 26 +++ tests/binding-integrated-Tests/SampleTest.cs | 77 ++++++++ .../binding-integration-Tests.csproj | 15 ++ 6 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 tests/binding-integrated-Tests/BindingBuilder.cs create mode 100644 tests/binding-integrated-Tests/BindingProject.cs create mode 100644 tests/binding-integrated-Tests/README.md create mode 100644 tests/binding-integrated-Tests/SampleTest.cs create mode 100644 tests/binding-integrated-Tests/binding-integration-Tests.csproj diff --git a/Java.Interop.sln b/Java.Interop.sln index 22fc435d7..1a63f1196 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -17,7 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4C173212-3 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop", "src\Java.Interop\Java.Interop.csproj", "{94BD81F7-B06F-4295-9636-F8A3B6BDC762}" EndProject -Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Dynamic", "src\Java.Interop.Dynamic\Java.Interop.Dynamic.csproj", "{AD4468F8-8883-434B-9D4C-E1801BB3B52A}" EndProject @@ -99,6 +99,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.GenericMarshal EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.BootstrapTasks", "src\Java.Interop.BootstrapTasks\Java.Interop.BootstrapTasks.csproj", "{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "binding-integration-Tests", "tests\binding-integrated-Tests\binding-integration-Tests.csproj", "{D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -349,6 +351,14 @@ Global {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationRelease|Any CPU.ActiveCfg = Release|Any CPU {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationRelease|Any CPU.Build.0 = Release|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.Release|Any CPU.Build.0 = Release|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.XAIntegrationRelease|Any CPU.ActiveCfg = Release|Any CPU + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}.XAIntegrationRelease|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {0C001D50-4176-45AE-BDC8-BA626508B0CC} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} @@ -392,5 +402,6 @@ Global {C0487169-8F81-497F-919E-EB42B1D0243F} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF} = {4C173212-371D-45D8-BA83-9226194F48DC} {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A} = {172B608B-E6F3-41CC-9949-203A76BA247C} + {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} EndGlobalSection EndGlobal diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs new file mode 100644 index 000000000..bdeb422ff --- /dev/null +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -0,0 +1,170 @@ +using NUnit.Framework; +using System; +using System.Diagnostics; +using Java.Interop; +using System.IO; +using System.Linq; + +namespace BindingIntegrationTests +{ + public class BindingBuilder + { + [Flags] + public enum Steps + { + Javac, + Jar, + ClassParse, + ApiXmlAdjuster, + Generator, + Csc, + All = Javac | Jar | ClassParse | ApiXmlAdjuster | Generator | Csc + } + + public const string JavaSourcesSubDir = "java-sources"; + public const string ClassesSubDir = "classes"; + + public Steps ProcessSteps { get; set; } = Steps.All; + + // entire work (intermediate output) directory + public string IntermediateOutputPathRelative { get; set; } = "intermediate-output"; + + // Used to resolve javac and rt.jar + public string JdkPath { get; set; } + + static string ProbeJavaHome () + { + var env = Environment.GetEnvironmentVariable ("JAVA_HOME"); + if (!string.IsNullOrEmpty (env)) + return env; + return "/usr/lib/jvm/java-8-openjdk-amd64/"; + } + + public static BindingBuilder CreateBestBetDefault (BindingProject project) + { + return new BindingBuilder (project) { JdkPath = ProbeJavaHome () }; + } + + public BindingBuilder (BindingProject project) + { + this.project = project; + } + + readonly BindingProject project; + + public string IntermediateOutputPathAbsolute => Path.Combine (Path.GetDirectoryName (new Uri (GetType ().Assembly.CodeBase).LocalPath), IntermediateOutputPathRelative, project.Id); + + public void Clean () + { + if (Directory.Exists (IntermediateOutputPathAbsolute)) + Directory.Delete (IntermediateOutputPathAbsolute, true); + } + + public void Build () + { + Javac (); + Jar (); + ClassParse (); + AdjustApiXml (); + GenerateBindingSources (); + CompileBindings (); + } + + Action ensureDirectory = dir => { if (!Directory.Exists (dir)) Directory.CreateDirectory (dir); }; + + void Javac () + { + if ((ProcessSteps & Steps.Javac) != Steps.Javac) + return; + + if (JdkPath == null) + throw new InvalidOperationException ("JdkPath is not set."); + + var objDir = IntermediateOutputPathAbsolute; + ensureDirectory (objDir); + + string sourcesSaved = Path.Combine (objDir, JavaSourcesSubDir); + ensureDirectory (sourcesSaved); + foreach (var item in project.JavaSourceStrings) + File.WriteAllText (Path.Combine (sourcesSaved, item.FileName), item.Content); + var sourceFiles = project.JavaSourceFiles.Concat (project.JavaSourceStrings.Select (i => Path.Combine (sourcesSaved, i.FileName))); + + if (project.CompiledClassesDirectory == null) + project.CompiledClassesDirectory = Path.Combine (objDir, ClassesSubDir); + ensureDirectory (project.CompiledClassesDirectory); + + var psi = new ProcessStartInfo () { + UseShellExecute = false, + FileName = JdkPath != null ? Path.Combine (JdkPath, "bin", "javac") : "javac", + Arguments = $"{project.JavacOptions} -d \"{project.CompiledClassesDirectory}\" {string.Join (" ", sourceFiles.Select (s => '"' + s + '"'))}", + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + if (project.CustomRuntimeJar != null) + psi.Arguments += $" -bootclasspath {project.CustomRuntimeJar} -classpath {project.CustomRuntimeJar}"; + + project.JavacExecutionOutput = $"Execute javac as: {psi.FileName} {psi.Arguments}\n"; + + var proc = new Process () { StartInfo = psi }; + proc.OutputDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + proc.WaitForExit (); + if (proc.ExitCode != 0) + throw new Exception ("Javac failed: " + project.JavacExecutionOutput); + } + + void Jar () + { + if ((ProcessSteps & Steps.Jar) != Steps.Jar) + return; + + if (JdkPath == null) + throw new InvalidOperationException ("JdkPath is not set."); + + var objDir = IntermediateOutputPathAbsolute; + if (project.CompiledClassesDirectory == null) + project.CompiledClassesDirectory = Path.Combine (objDir, ClassesSubDir); + project.CompiledJarFile = Path.Combine (project.CompiledClassesDirectory, project.Id + ".jar"); + + var psi = new ProcessStartInfo () { + UseShellExecute = false, + FileName = JdkPath != null ? Path.Combine (JdkPath, "bin", "jar") : "jar", + Arguments = $"cvf \"{project.CompiledJarFile}\" -C \"{project.CompiledClassesDirectory}\" .", + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + project.JarExecutionOutput = $"Execute jar as: {psi.FileName} {psi.Arguments}\n"; + + var proc = new Process () { StartInfo = psi }; + proc.OutputDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + proc.WaitForExit (); + if (proc.ExitCode != 0) + throw new Exception ("Jar failed: " + project.JarExecutionOutput); + } + + void ClassParse () + { + } + + void AdjustApiXml () + { + } + + void GenerateBindingSources () + { + } + + void CompileBindings () + { + } + } +} + diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs new file mode 100644 index 000000000..90cdf6fba --- /dev/null +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; + +namespace BindingIntegrationTests +{ + public class JavaSource + { + public string FileName { get; set; } + public string Content { get; set; } + } + + public class BindingProject + { + public string Id { get; set; } + + // initial inputs + public IList JavaSourceFiles { get; set; } = new List (); + public IList JavaSourceStrings { get; set; } = new List (); + public string JavacOptions { get; set; } = "-g"; + // rt.jar, android.jar etc. + // If it is specified, then javac will run with -bootclasspath and -cp + public string CustomRuntimeJar { get; set; } + + public IList ApiXmlFiles { get; set; } = new List (); + public IList MetadataXmlFiles { get; set; } = new List (); + //public IList MetadataXmlStrings { get; set; } + public IList InputJarFiles { get; set; } = new List (); + public IList ReferenceJarFiles { get; set; } = new List (); + public IList CSharpSourceFiles { get; set; } = new List (); + //public IList CSharpSourceStrings { get; set; } = new List (); + public IList ReferenceDlls { get; set; } = new List (); + + public string JavacExecutionOutput { get; internal set; } + // Java classes directory generated by javac (Javac() method) + public string CompiledClassesDirectory { get; set; } + + public string JarExecutionOutput { get; internal set; } + // Java libraries archived by jar + public string CompiledJarFile { get; internal set; } + + // API XML description generated by class-parse + public string GeneratedClassParseXmlFile { get; internal set; } + // API XML description generated by api-xml-adjuster + public string GeneratedApiXmlFile { get; internal set; } + + // C# sources generated by generator + public IList GeneratedCSharpSourceFiles { get; internal set; } + // DLL built by C# compiler + public string GeneratedDllFile { get; internal set; } + } +} \ No newline at end of file diff --git a/tests/binding-integrated-Tests/README.md b/tests/binding-integrated-Tests/README.md new file mode 100644 index 000000000..5fbb17cf8 --- /dev/null +++ b/tests/binding-integrated-Tests/README.md @@ -0,0 +1,26 @@ +This directory contains a set of integration tests for binding infrastructure. + +The test fixtures make it possible to build binding Java library, export +API, generate binding sources, compile them and even execute it on JVM. + +### Input items + +- Java sources +- Metadata fixup +- input Java libraries +- reference Java libraries +- reference managed libraries + +### Tools + +- class-parse +- api-xml-adjuster +- generator +- csc + +### Build artifacts to test + +- jars +- dlls +- generated C# sources + diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs new file mode 100644 index 000000000..2282223b0 --- /dev/null +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using NUnit.Framework; + +namespace BindingIntegrationTests +{ + // Whenever we write complicated test foundation, we should ensure that it actually works. + public class SampleTest + { + [Test] + public void YouNeedJdkPath () + { + Assert.Throws (() => { + new BindingBuilder (new BindingProject ()).Build (); + }); + } + + [Test] + public void VerifyJavac () + { + // You don't even have to create a set of project files. They can be created on the fly. + var project = new BindingProject { Id = nameof (VerifyJavac) }; + string fooJavaFileName = "Foo.java"; + string fooJavaContent = "public class Foo {}"; + project.JavaSourceStrings.Add (new JavaSource { FileName = fooJavaFileName, Content = fooJavaContent }); + + // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. + var builder = BindingBuilder.CreateBestBetDefault (project); + builder.ProcessSteps = BindingBuilder.Steps.Javac; + builder.Clean (); + builder.Build (); + + var savedFooJavaFile = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.JavaSourcesSubDir, fooJavaFileName); + Assert.IsTrue (File.Exists (savedFooJavaFile), "Java source not saved"); + Assert.AreEqual (fooJavaContent, File.ReadAllText (savedFooJavaFile), "Saved java content mismatch."); + var classesDir = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.ClassesSubDir); + Assert.AreEqual (classesDir, project.CompiledClassesDirectory, "classes directory mismatch."); + var fooClassFile = Path.Combine (classesDir, "Foo.class"); + Assert.IsTrue (File.Exists (fooClassFile), "Compiled Foo.class not found"); + } + + [Test] + public void VerifyJavacWithRtJar () + { + var project = new BindingProject { Id = nameof (VerifyJavacWithRtJar) }; + string fooJavaFileName = "Foo.java"; + string fooJavaContent = "public class Foo {}"; + project.JavaSourceStrings.Add (new JavaSource { FileName = fooJavaFileName, Content = fooJavaContent }); + + var builder = BindingBuilder.CreateBestBetDefault (project); + project.CustomRuntimeJar = Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar"); + Assert.IsTrue (File.Exists (project.CustomRuntimeJar), "rt.jar exists"); + builder.ProcessSteps = BindingBuilder.Steps.Javac; + builder.Clean (); + builder.Build (); + } + + [Test] + public void VerifyJar () + { + // You don't even have to create a set of project files. They can be created on the fly. + var project = new BindingProject { Id = nameof (VerifyJar) }; + project.JavaSourceStrings.Add (new JavaSource { FileName = "Foo.java", Content = "public class Foo {}" }); + project.JavaSourceStrings.Add (new JavaSource { FileName = "Bar.java", Content = "public class Bar {}" }); + + // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. + var builder = BindingBuilder.CreateBestBetDefault (project); + builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar; + builder.Clean (); + builder.Build (); + + var jar = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.ClassesSubDir, project.Id + ".jar"); + Assert.AreEqual (jar, project.CompiledJarFile, "jar file path mismatch."); + Assert.IsTrue (File.Exists (project.CompiledJarFile), "Compiled jar not found"); + } + } +} diff --git a/tests/binding-integrated-Tests/binding-integration-Tests.csproj b/tests/binding-integrated-Tests/binding-integration-Tests.csproj new file mode 100644 index 000000000..4d3fce232 --- /dev/null +++ b/tests/binding-integrated-Tests/binding-integration-Tests.csproj @@ -0,0 +1,15 @@ + + + net461 + BindingIntegrationTests + + + + + + + + + + + From 4db1295e9ed76d7e3d370f8559bb685600fdee7b Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 6 Jul 2018 01:19:02 +0900 Subject: [PATCH 10/39] implement binding integration tests up to api-xml-adjuster. --- .../BindingBuilder.cs | 85 ++++++++++++++++--- .../BindingProject.cs | 15 +++- tests/binding-integrated-Tests/SampleTest.cs | 51 ++++++++++- 3 files changed, 130 insertions(+), 21 deletions(-) diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index bdeb422ff..32ae4e6fe 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -4,6 +4,8 @@ using Java.Interop; using System.IO; using System.Linq; +using Xamarin.Android.Tools.Bytecode; +using Xamarin.Android.Tools.ApiXmlAdjuster; namespace BindingIntegrationTests { @@ -12,17 +14,18 @@ public class BindingBuilder [Flags] public enum Steps { - Javac, - Jar, - ClassParse, - ApiXmlAdjuster, - Generator, - Csc, + Javac = 1, + Jar = 2, + ClassParse = 4, + ApiXmlAdjuster = 8, + Generator = 16, + Csc = 32, All = Javac | Jar | ClassParse | ApiXmlAdjuster | Generator | Csc } public const string JavaSourcesSubDir = "java-sources"; public const string ClassesSubDir = "classes"; + public const string ClassParseSubDir = "class-parse-xml"; public Steps ProcessSteps { get; set; } = Steps.All; @@ -70,28 +73,35 @@ public void Build () CompileBindings (); } - Action ensureDirectory = dir => { if (!Directory.Exists (dir)) Directory.CreateDirectory (dir); }; + void EnsureDirectory (string dir) + { + var parent = Path.GetDirectoryName (dir); + if (parent != Path.GetPathRoot (parent)) + EnsureDirectory (parent); + if (!Directory.Exists (dir)) + Directory.CreateDirectory (dir); + } void Javac () { - if ((ProcessSteps & Steps.Javac) != Steps.Javac) + if ((ProcessSteps & Steps.Javac) == 0) return; if (JdkPath == null) throw new InvalidOperationException ("JdkPath is not set."); var objDir = IntermediateOutputPathAbsolute; - ensureDirectory (objDir); + EnsureDirectory (objDir); string sourcesSaved = Path.Combine (objDir, JavaSourcesSubDir); - ensureDirectory (sourcesSaved); + EnsureDirectory (sourcesSaved); foreach (var item in project.JavaSourceStrings) File.WriteAllText (Path.Combine (sourcesSaved, item.FileName), item.Content); var sourceFiles = project.JavaSourceFiles.Concat (project.JavaSourceStrings.Select (i => Path.Combine (sourcesSaved, i.FileName))); if (project.CompiledClassesDirectory == null) project.CompiledClassesDirectory = Path.Combine (objDir, ClassesSubDir); - ensureDirectory (project.CompiledClassesDirectory); + EnsureDirectory (project.CompiledClassesDirectory); var psi = new ProcessStartInfo () { UseShellExecute = false, @@ -118,7 +128,7 @@ void Javac () void Jar () { - if ((ProcessSteps & Steps.Jar) != Steps.Jar) + if ((ProcessSteps & Steps.Jar) == 0) return; if (JdkPath == null) @@ -127,7 +137,8 @@ void Jar () var objDir = IntermediateOutputPathAbsolute; if (project.CompiledClassesDirectory == null) project.CompiledClassesDirectory = Path.Combine (objDir, ClassesSubDir); - project.CompiledJarFile = Path.Combine (project.CompiledClassesDirectory, project.Id + ".jar"); + if (project.CompiledJarFile == null) + project.CompiledJarFile = Path.Combine (project.CompiledClassesDirectory, project.Id + ".jar"); var psi = new ProcessStartInfo () { UseShellExecute = false, @@ -152,10 +163,58 @@ void Jar () void ClassParse () { + if ((ProcessSteps & Steps.ClassParse) == 0) + return; + + if (project.CompiledJarFile == null && !project.InputJarFiles.Any ()) + throw new InvalidOperationException ("Input Jar files are not set either at CompiledJarFile or InputJarFiles."); + + var objDir = IntermediateOutputPathAbsolute; + EnsureDirectory (objDir); + var cpDir = Path.Combine (objDir, ClassParseSubDir); + EnsureDirectory (cpDir); + if (project.GeneratedClassParseXmlFile == null) + project.GeneratedClassParseXmlFile = Path.Combine (cpDir, project.Id + ".class-parse"); + + // FIXME: logging + var cp = new ClassPath (); + cp.Load (project.CompiledJarFile); + foreach (var jar in project.InputJarFiles) + cp.Load (jar); + cp.SaveXmlDescription (project.GeneratedClassParseXmlFile); } void AdjustApiXml () { + if ((ProcessSteps & Steps.ApiXmlAdjuster) == 0) + return; + + if (project.GeneratedClassParseXmlFile == null) + throw new InvalidOperationException ("Input class-parse file is not set."); + + var objDir = IntermediateOutputPathAbsolute; + var cpDir = Path.Combine (objDir, ClassParseSubDir); + EnsureDirectory (cpDir); + if (project.GeneratedApiXmlFile == null) + project.GeneratedApiXmlFile = Path.Combine (objDir, "api.xml"); + foreach (var cpSource in project.ClassParseXmlStrings) + File.WriteAllText (Path.Combine (cpDir, cpSource.FileName), cpSource.Content); + var cpFiles = project.ClassParseXmlFiles.Concat (project.ClassParseXmlStrings.Select (i => Path.Combine (cpDir, i.FileName))); + + var writer = new StringWriter (); + Xamarin.Android.Tools.ApiXmlAdjuster.Log.DefaultWriter = writer; + var api = new JavaApi (); + api.Load (project.GeneratedClassParseXmlFile); + foreach (var apixml in cpFiles) + api.Load (apixml); + api.Resolve (); + api.CreateGenericInheritanceMapping (); + api.MarkOverrides (); + api.FindDefects (); + api.Save (project.GeneratedApiXmlFile); + project.ApiXmlAdjusterExecutionOutput = writer.ToString (); + if (project.ApiXmlAdjusterExecutionOutput != string.Empty) + throw new Exception ("api-xml-adjuster failed: " + project.ApiXmlAdjusterExecutionOutput); } void GenerateBindingSources () diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index 90cdf6fba..844d523c3 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -2,7 +2,7 @@ namespace BindingIntegrationTests { - public class JavaSource + public class SourceFile { public string FileName { get; set; } public string Content { get; set; } @@ -14,19 +14,23 @@ public class BindingProject // initial inputs public IList JavaSourceFiles { get; set; } = new List (); - public IList JavaSourceStrings { get; set; } = new List (); + public IList JavaSourceStrings { get; set; } = new List (); public string JavacOptions { get; set; } = "-g"; // rt.jar, android.jar etc. // If it is specified, then javac will run with -bootclasspath and -cp public string CustomRuntimeJar { get; set; } + public IList ClassParseXmlFiles { get; set; } = new List (); + public IList ClassParseXmlStrings { get; set; } = new List (); + public IList ApiXmlFiles { get; set; } = new List (); + public IList ApiXmlSources { get; set; } = new List (); public IList MetadataXmlFiles { get; set; } = new List (); - //public IList MetadataXmlStrings { get; set; } + public IList MetadataXmlStrings { get; set; } = new List (); public IList InputJarFiles { get; set; } = new List (); public IList ReferenceJarFiles { get; set; } = new List (); public IList CSharpSourceFiles { get; set; } = new List (); - //public IList CSharpSourceStrings { get; set; } = new List (); + public IList CSharpSourceStrings { get; set; } = new List (); public IList ReferenceDlls { get; set; } = new List (); public string JavacExecutionOutput { get; internal set; } @@ -37,8 +41,11 @@ public class BindingProject // Java libraries archived by jar public string CompiledJarFile { get; internal set; } + public string ClassParseExecutionOutput { get; internal set; } // API XML description generated by class-parse public string GeneratedClassParseXmlFile { get; internal set; } + + public string ApiXmlAdjusterExecutionOutput { get; internal set; } // API XML description generated by api-xml-adjuster public string GeneratedApiXmlFile { get; internal set; } diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 2282223b0..f5df188e1 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using System.Xml.Linq; +using System.Xml.XPath; using NUnit.Framework; namespace BindingIntegrationTests @@ -22,7 +24,7 @@ public void VerifyJavac () var project = new BindingProject { Id = nameof (VerifyJavac) }; string fooJavaFileName = "Foo.java"; string fooJavaContent = "public class Foo {}"; - project.JavaSourceStrings.Add (new JavaSource { FileName = fooJavaFileName, Content = fooJavaContent }); + project.JavaSourceStrings.Add (new SourceFile { FileName = fooJavaFileName, Content = fooJavaContent }); // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. var builder = BindingBuilder.CreateBestBetDefault (project); @@ -45,7 +47,7 @@ public void VerifyJavacWithRtJar () var project = new BindingProject { Id = nameof (VerifyJavacWithRtJar) }; string fooJavaFileName = "Foo.java"; string fooJavaContent = "public class Foo {}"; - project.JavaSourceStrings.Add (new JavaSource { FileName = fooJavaFileName, Content = fooJavaContent }); + project.JavaSourceStrings.Add (new SourceFile { FileName = fooJavaFileName, Content = fooJavaContent }); var builder = BindingBuilder.CreateBestBetDefault (project); project.CustomRuntimeJar = Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar"); @@ -60,8 +62,8 @@ public void VerifyJar () { // You don't even have to create a set of project files. They can be created on the fly. var project = new BindingProject { Id = nameof (VerifyJar) }; - project.JavaSourceStrings.Add (new JavaSource { FileName = "Foo.java", Content = "public class Foo {}" }); - project.JavaSourceStrings.Add (new JavaSource { FileName = "Bar.java", Content = "public class Bar {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "public class Bar {}" }); // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. var builder = BindingBuilder.CreateBestBetDefault (project); @@ -73,5 +75,46 @@ public void VerifyJar () Assert.AreEqual (jar, project.CompiledJarFile, "jar file path mismatch."); Assert.IsTrue (File.Exists (project.CompiledJarFile), "Compiled jar not found"); } + + [Test] + public void VerifyClassParse () + { + // You don't even have to create a set of project files. They can be created on the fly. + var project = new BindingProject { Id = nameof (VerifyClassParse) }; + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); + + // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. + var builder = BindingBuilder.CreateBestBetDefault (project); + builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar | BindingBuilder.Steps.ClassParse; + builder.Clean (); + builder.Build (); + + var cpxml = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.ClassParseSubDir, project.Id + ".class-parse"); + Assert.AreEqual (cpxml, project.GeneratedClassParseXmlFile, "class-parse output file path mismatch."); + Assert.IsTrue (File.Exists (project.GeneratedClassParseXmlFile), "class-parse output file not found"); + var doc = XDocument.Load (project.GeneratedClassParseXmlFile); + Assert.IsNotNull (doc.XPathSelectElement ("//class[@name='Foo']"), "Foo node does not exist"); + } + + [Test] + public void VerifyApiXmlAdjuster () + { + // You don't even have to create a set of project files. They can be created on the fly. + var project = new BindingProject { Id = nameof (VerifyApiXmlAdjuster) }; + project.JavaSourceStrings.Add (new SourceFile { FileName = "Object.java", Content = "package java.lang; public class Object {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); + + // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. + var builder = BindingBuilder.CreateBestBetDefault (project); + builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar | BindingBuilder.Steps.ClassParse | BindingBuilder.Steps.ApiXmlAdjuster; + builder.Clean (); + builder.Build (); + + var apixml = Path.Combine (builder.IntermediateOutputPathAbsolute, "api.xml"); + Assert.AreEqual (apixml, project.GeneratedApiXmlFile, "api.xml file path mismatch."); + Assert.IsTrue (File.Exists (project.GeneratedApiXmlFile), "api.xml file not found"); + } } } From ef578da27539cb65ca7a3d0f95d48bab939f7940 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 6 Jul 2018 13:25:29 +0900 Subject: [PATCH 11/39] Add generator verification in binding-integration-Tests. --- .../BindingBuilder.cs | 74 +++++++++++++++++-- .../BindingProject.cs | 26 ++++--- tests/binding-integrated-Tests/SampleTest.cs | 24 ++++-- .../binding-integration-Tests.csproj | 7 ++ 4 files changed, 111 insertions(+), 20 deletions(-) diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index 32ae4e6fe..fbaa001e3 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -11,6 +11,10 @@ namespace BindingIntegrationTests { public class BindingBuilder { + // This is required to get generator.exe deployed next to this assembly + // so that the default GeneratorPath can probe that it is right there. + static readonly Type dummy = typeof (MonoDroid.Generation.GenBase); + [Flags] public enum Steps { @@ -26,6 +30,9 @@ public enum Steps public const string JavaSourcesSubDir = "java-sources"; public const string ClassesSubDir = "classes"; public const string ClassParseSubDir = "class-parse-xml"; + public const string ApiXmlSubDir = "api-xml"; + public const string MetadataXmlSubDir = "metadata"; + public const string CSharpSourcesSubDir = "csharp"; public Steps ProcessSteps { get; set; } = Steps.All; @@ -35,6 +42,8 @@ public enum Steps // Used to resolve javac and rt.jar public string JdkPath { get; set; } + public string GeneratorPath { get; set; } = Path.Combine (Path.GetDirectoryName (new Uri (typeof (BindingBuilder).Assembly.CodeBase).LocalPath), "generator.exe"); + static string ProbeJavaHome () { var env = Environment.GetEnvironmentVariable ("JAVA_HOME"); @@ -188,23 +197,26 @@ void AdjustApiXml () { if ((ProcessSteps & Steps.ApiXmlAdjuster) == 0) return; - - if (project.GeneratedClassParseXmlFile == null) - throw new InvalidOperationException ("Input class-parse file is not set."); - + var objDir = IntermediateOutputPathAbsolute; var cpDir = Path.Combine (objDir, ClassParseSubDir); EnsureDirectory (cpDir); if (project.GeneratedApiXmlFile == null) project.GeneratedApiXmlFile = Path.Combine (objDir, "api.xml"); + if (!File.Exists (project.GeneratedClassParseXmlFile) && !project.ClassParseXmlFiles.Any () && !project.ClassParseXmlStrings.Any ()) + throw new InvalidOperationException ("Input class-parse file does not exist."); + foreach (var cpSource in project.ClassParseXmlStrings) File.WriteAllText (Path.Combine (cpDir, cpSource.FileName), cpSource.Content); var cpFiles = project.ClassParseXmlFiles.Concat (project.ClassParseXmlStrings.Select (i => Path.Combine (cpDir, i.FileName))); + // FIXME: this does not scale for parallel tasking. var writer = new StringWriter (); Xamarin.Android.Tools.ApiXmlAdjuster.Log.DefaultWriter = writer; + var api = new JavaApi (); - api.Load (project.GeneratedClassParseXmlFile); + if (File.Exists (project.GeneratedClassParseXmlFile)) + api.Load (project.GeneratedClassParseXmlFile); foreach (var apixml in cpFiles) api.Load (apixml); api.Resolve (); @@ -219,6 +231,58 @@ void AdjustApiXml () void GenerateBindingSources () { + if ((ProcessSteps & Steps.Generator) == 0) + return; + + if (GeneratorPath == null) + throw new InvalidOperationException ("GeneratorPath is not set."); + + var objDir = IntermediateOutputPathAbsolute; + EnsureDirectory (objDir); + + if (project.GeneratedApiXmlFile == null) + project.GeneratedApiXmlFile = Path.Combine (objDir, "api.xml"); + if (!File.Exists (project.GeneratedApiXmlFile) && !project.ApiXmlFiles.Any () && !project.ApiXmlStrings.Any ()) + throw new InvalidOperationException ("Input api xml file does not exist."); + if (project.GeneratedCSharpSourceDirectory == null) + project.GeneratedCSharpSourceDirectory = Path.Combine (objDir, CSharpSourcesSubDir); + + string apiXmlSaved = Path.Combine (objDir, ApiXmlSubDir); + EnsureDirectory (apiXmlSaved); + foreach (var item in project.ApiXmlStrings) + File.WriteAllText (Path.Combine (apiXmlSaved, item.FileName), item.Content); + var apiXmlFiles = project.ApiXmlFiles.Concat (project.ApiXmlStrings.Select (i => Path.Combine (apiXmlSaved, i.FileName))); + + string metadataSaved = Path.Combine (objDir, MetadataXmlSubDir); + EnsureDirectory (metadataSaved); + foreach (var item in project.MetadataXmlStrings) + File.WriteAllText (Path.Combine (metadataSaved, item.FileName), item.Content); + var metadataFiles = project.MetadataXmlFiles.Concat (project.MetadataXmlStrings.Select (i => Path.Combine (metadataSaved, i.FileName))); + + var psi = new ProcessStartInfo () { + UseShellExecute = false, + FileName = GeneratorPath, + Arguments = $"{project.GeneratorOptions}" + + $" {(File.Exists (project.GeneratedApiXmlFile) ? project.GeneratedApiXmlFile : string.Empty)}" + + $" {string.Join (" ", apiXmlFiles.Select (s => '"' + s + '"'))}" + + $" {string.Join (" ", metadataFiles.Select (s => " --fixup=\"" + s + '"'))}" + + $" {string.Join (" ", project.ReferenceDlls.Select (s => " -r \"" + s + '"'))}" + + $" --csdir=\"{project.GeneratedCSharpSourceDirectory}\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + project.GeneratorExecutionOutput = $"Execute generator as: {psi.FileName} {psi.Arguments}\n"; + + var proc = new Process () { StartInfo = psi }; + proc.OutputDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + proc.WaitForExit (); + if (proc.ExitCode != 0) + throw new Exception ("generator failed: " + project.GeneratorExecutionOutput); } void CompileBindings () diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index 844d523c3..206823d6f 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -12,45 +12,53 @@ public class BindingProject { public string Id { get; set; } - // initial inputs + public string JavacOptions { get; set; } = "-g"; + public string GeneratorOptions { get; internal set; } + public IList JavaSourceFiles { get; set; } = new List (); public IList JavaSourceStrings { get; set; } = new List (); - public string JavacOptions { get; set; } = "-g"; // rt.jar, android.jar etc. // If it is specified, then javac will run with -bootclasspath and -cp public string CustomRuntimeJar { get; set; } + public IList InputJarFiles { get; set; } = new List (); + public IList ReferenceJarFiles { get; set; } = new List (); + public IList ClassParseXmlFiles { get; set; } = new List (); public IList ClassParseXmlStrings { get; set; } = new List (); public IList ApiXmlFiles { get; set; } = new List (); - public IList ApiXmlSources { get; set; } = new List (); + public IList ApiXmlStrings { get; set; } = new List (); public IList MetadataXmlFiles { get; set; } = new List (); public IList MetadataXmlStrings { get; set; } = new List (); - public IList InputJarFiles { get; set; } = new List (); - public IList ReferenceJarFiles { get; set; } = new List (); + public IList ReferenceDlls { get; set; } = new List (); + public IList CSharpSourceFiles { get; set; } = new List (); public IList CSharpSourceStrings { get; set; } = new List (); - public IList ReferenceDlls { get; set; } = new List (); public string JavacExecutionOutput { get; internal set; } + public string JarExecutionOutput { get; internal set; } + public string ClassParseExecutionOutput { get; internal set; } + public string ApiXmlAdjusterExecutionOutput { get; internal set; } + public string GeneratorExecutionOutput { get; internal set; } + public string CscExecutionOutput { get; internal set; } + // Java classes directory generated by javac (Javac() method) public string CompiledClassesDirectory { get; set; } - public string JarExecutionOutput { get; internal set; } // Java libraries archived by jar public string CompiledJarFile { get; internal set; } - public string ClassParseExecutionOutput { get; internal set; } // API XML description generated by class-parse public string GeneratedClassParseXmlFile { get; internal set; } - public string ApiXmlAdjusterExecutionOutput { get; internal set; } // API XML description generated by api-xml-adjuster public string GeneratedApiXmlFile { get; internal set; } + public string GeneratedCSharpSourceDirectory { get; internal set; } // C# sources generated by generator public IList GeneratedCSharpSourceFiles { get; internal set; } + // DLL built by C# compiler public string GeneratedDllFile { get; internal set; } } diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index f5df188e1..55f599668 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -60,12 +60,10 @@ public void VerifyJavacWithRtJar () [Test] public void VerifyJar () { - // You don't even have to create a set of project files. They can be created on the fly. var project = new BindingProject { Id = nameof (VerifyJar) }; project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "public class Foo {}" }); project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "public class Bar {}" }); - // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. var builder = BindingBuilder.CreateBestBetDefault (project); builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar; builder.Clean (); @@ -79,12 +77,10 @@ public void VerifyJar () [Test] public void VerifyClassParse () { - // You don't even have to create a set of project files. They can be created on the fly. var project = new BindingProject { Id = nameof (VerifyClassParse) }; project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); - // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. var builder = BindingBuilder.CreateBestBetDefault (project); builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar | BindingBuilder.Steps.ClassParse; builder.Clean (); @@ -100,13 +96,11 @@ public void VerifyClassParse () [Test] public void VerifyApiXmlAdjuster () { - // You don't even have to create a set of project files. They can be created on the fly. var project = new BindingProject { Id = nameof (VerifyApiXmlAdjuster) }; project.JavaSourceStrings.Add (new SourceFile { FileName = "Object.java", Content = "package java.lang; public class Object {}" }); project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); - // Set up builder. Hopefully you don't have to provide JDK path, it will be probed. var builder = BindingBuilder.CreateBestBetDefault (project); builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar | BindingBuilder.Steps.ClassParse | BindingBuilder.Steps.ApiXmlAdjuster; builder.Clean (); @@ -115,6 +109,24 @@ public void VerifyApiXmlAdjuster () var apixml = Path.Combine (builder.IntermediateOutputPathAbsolute, "api.xml"); Assert.AreEqual (apixml, project.GeneratedApiXmlFile, "api.xml file path mismatch."); Assert.IsTrue (File.Exists (project.GeneratedApiXmlFile), "api.xml file not found"); + var doc = XDocument.Load (project.GeneratedApiXmlFile); + Assert.IsNotNull (doc.XPathSelectElement ("//class[@name='Foo']"), "Foo node does not exist"); + } + + [Test] + public void VerifyGenerator () + { + var project = new BindingProject { Id = nameof (VerifyGenerator) }; + project.JavaSourceStrings.Add (new SourceFile { FileName = "Object.java", Content = "package java.lang; public class Object {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); + + var builder = BindingBuilder.CreateBestBetDefault (project); + builder.ProcessSteps = BindingBuilder.Steps.Javac | BindingBuilder.Steps.Jar | BindingBuilder.Steps.ClassParse | BindingBuilder.Steps.ApiXmlAdjuster | BindingBuilder.Steps.Generator; + builder.Clean (); + builder.Build (); + + var csDir = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.CSharpSourcesSubDir); } } } diff --git a/tests/binding-integrated-Tests/binding-integration-Tests.csproj b/tests/binding-integrated-Tests/binding-integration-Tests.csproj index 4d3fce232..bfa6735f6 100644 --- a/tests/binding-integrated-Tests/binding-integration-Tests.csproj +++ b/tests/binding-integrated-Tests/binding-integration-Tests.csproj @@ -3,6 +3,12 @@ net461 BindingIntegrationTests + + ..\..\bin\TestDebug + + + ..\..\bin\TestRelease + @@ -11,5 +17,6 @@ + From f157e4c08bbaab601419873ebbfcacbca3204cd7 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 6 Jul 2018 13:27:16 +0900 Subject: [PATCH 12/39] default interface method run-time tests will not be done in generator-Tests. --- .../Tests/Integration-Tests/DefaultInterfaceMethods.cs | 6 ------ tools/generator/Tests/generator-Tests.csproj | 4 ---- 2 files changed, 10 deletions(-) diff --git a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs index fc7225305..b927500cf 100644 --- a/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs +++ b/tools/generator/Tests/Integration-Tests/DefaultInterfaceMethods.cs @@ -23,12 +23,6 @@ public void GeneratedOK () void RunAllTargets (string outputRelativePath, string apiDescriptionFile, string expectedRelativePath, string [] additionalSupportPaths) { Run (CodeGenerationTarget.JavaInterop1, Path.Combine ("out.ji", outputRelativePath), apiDescriptionFile, Path.Combine ("expected.ji", expectedRelativePath), additionalSupportPaths); - - Java.Interop.JniRuntime.SetCurrent (new Java.InteropTests.TestJVM ()); - - var type = BuiltAssembly.GetTypes ().First (t => t.FullName == "Xamarin.Test.TheImplementor"); - var instance = Activator.CreateInstance (type); - type.GetProperty ("Bar").GetValue (instance); } } } diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index 7fedcdadd..c4fc6df04 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -100,10 +100,6 @@ {5887B410-D448-4257-A46B-EAC03C80BE93} Java.Runtime.Environment - - {A76309AB-98AC-4AE2-BA30-75481420C52F} - TestJVM - From 8931d84fbb9372e2b719dce96ffd9fed562bfb72 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 14:49:36 +0900 Subject: [PATCH 13/39] Make generator support files common and add csc test in binding-integration-Tests. Though, the new csc test does NOT work. There is a complicated reason: what we will need is some *runnable* code that is unlike existing Java.Lang.Object stub etc. that are just to throw NotImplementedException. However, binding java.lang.Object requires either 1) have rt.jar fully bindable (which is not true, with current binding toolset) or 2) have api-xml-adjuster to be able to "reference" .jars (which is not true either, because it only processes DLLs as references, because any referenced library should have a binding). To make things testable, there are two possible approaches: 1) bind subset of rt.jar - this requies at least to pass all the binding steps, shrinking API by metadata fixup or even earlier (currently it is stuck at api-xml-adjuster due to some NREs). It takes so much time to resolve all the types at api-xml-adjuster, so some filtering system at api-xml-adjuster step will be useful. 2) "fix" api-xml-adjuster and let it generate huge api.xml, then filter API by metadata fixup, just like existing tooling. Until either of these happens, tests won't pass. --- Java.Interop.sln | 3 + src/Android.Interop/Android.Interop.csproj | 2 +- .../Tests/Android.Interop-Tests.csproj | 6 +- .../Tests/Dynamic-Tests.shproj | 2 + .../Tests/Export-Tests.shproj | 2 + src/Java.Interop/Tests/Interop-Tests.shproj | 2 + src/java-interop/java-interop.csproj | 26 +---- .../PerformanceTests/PerformanceTests.shproj | 2 + .../BindingBuilder.cs | 103 ++++++++++++++++-- .../BindingProject.cs | 10 +- tests/binding-integrated-Tests/SampleTest.cs | 39 +++++++ .../binding-integration-Tests.csproj | 1 + .../Android_Runtime_CharSequence.cs | 0 .../SupportFiles/GeneratedEnumAttribute.cs | 0 .../SupportFiles/IJavaObject.cs | 0 .../SupportFiles/IntDefinitionAttribute.cs | 0 .../SupportFiles/JNIEnv.cs | 0 .../SupportFiles/JNIEnv.g.cs | 0 .../SupportFiles/JObjectRefType.cs | 0 .../SupportFiles/JValue.cs | 0 .../SupportFiles/JavaArray.cs | 0 .../SupportFiles/JavaCollection.cs | 0 .../SupportFiles/JavaConvert.cs | 0 .../SupportFiles/JavaDictionary.cs | 0 .../JavaInterfaceDefaultMethodAttribute.cs | 0 .../SupportFiles/JavaObject.cs | 0 .../SupportFiles/JavaObjectExtensions.cs | 0 .../JavaTypeParametersAttribute.cs | 0 .../SupportFiles/Java_Lang_ICharSequence.cs | 0 .../SupportFiles/Java_Lang_Object.cs | 0 .../SupportFiles/Java_Lang_String.cs | 0 .../SupportFiles/Java_Lang_Throwable.cs | 0 .../SupportFiles/JniHandleOwnership.cs | 0 .../SupportFiles/NamespaceMappingAttribute.cs | 0 .../SupportFiles/PreserveAttribute.cs | 0 .../SupportFiles/RegisterAttribute.cs | 0 .../SupportFiles/TypeManager.cs | 0 .../binding-support-files.projitems | 95 ++++++++++++++++ .../binding-support-files.shproj | 13 +++ tools/generator/Tests/generator-Tests.csproj | 85 +-------------- 40 files changed, 274 insertions(+), 117 deletions(-) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/Android_Runtime_CharSequence.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/GeneratedEnumAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/IJavaObject.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/IntDefinitionAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JNIEnv.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JNIEnv.g.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JObjectRefType.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JValue.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaArray.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaCollection.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaConvert.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaDictionary.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaObject.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaObjectExtensions.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JavaTypeParametersAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/Java_Lang_ICharSequence.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/Java_Lang_Object.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/Java_Lang_String.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/Java_Lang_Throwable.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/JniHandleOwnership.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/NamespaceMappingAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/PreserveAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/RegisterAttribute.cs (100%) rename {tools/generator/Tests => tests/binding-support-files}/SupportFiles/TypeManager.cs (100%) create mode 100644 tests/binding-support-files/binding-support-files.projitems create mode 100644 tests/binding-support-files/binding-support-files.shproj diff --git a/Java.Interop.sln b/Java.Interop.sln index 1a63f1196..97ff87138 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -101,6 +101,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.BootstrapTasks EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "binding-integration-Tests", "tests\binding-integrated-Tests\binding-integration-Tests.csproj", "{D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "binding-support-files", "tests\binding-support-files\binding-support-files.shproj", "{AA1309A9-60BE-4BFD-802B-C44283669D58}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -403,5 +405,6 @@ Global {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF} = {4C173212-371D-45D8-BA83-9226194F48DC} {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A} = {172B608B-E6F3-41CC-9949-203A76BA247C} {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} + {AA1309A9-60BE-4BFD-802B-C44283669D58} = {271C9F30-F679-4793-942B-0D9527CB3E2F} EndGlobalSection EndGlobal diff --git a/src/Android.Interop/Android.Interop.csproj b/src/Android.Interop/Android.Interop.csproj index 6ea01dd5a..eaba12300 100644 --- a/src/Android.Interop/Android.Interop.csproj +++ b/src/Android.Interop/Android.Interop.csproj @@ -15,7 +15,7 @@ Assets True Android.Interop - v6.0 + v9.0 true diff --git a/src/Android.Interop/Tests/Android.Interop-Tests.csproj b/src/Android.Interop/Tests/Android.Interop-Tests.csproj index c75f4a018..7e9e0357e 100644 --- a/src/Android.Interop/Tests/Android.Interop-Tests.csproj +++ b/src/Android.Interop/Tests/Android.Interop-Tests.csproj @@ -16,7 +16,7 @@ True True Android.Interop-Tests - v5.0 + v9.0 Properties\AndroidManifest.xml @@ -75,7 +75,7 @@ - + BuildInteropTestJar; @@ -100,7 +100,7 @@ {0C001D50-4176-45AE-BDC8-BA626508B0CC} - Mono.Linq.Expressions-Android + Mono.Linq.Expressions {AD4468F8-8883-434B-9D4C-E1801BB3B52A} diff --git a/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj b/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj index 7fa179176..537efdf74 100644 --- a/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj +++ b/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj @@ -2,6 +2,8 @@ {8A190F28-74C7-45D8-A701-5864CDF4124A} + 8.0.30703 + 2.0 diff --git a/src/Java.Interop.Export/Tests/Export-Tests.shproj b/src/Java.Interop.Export/Tests/Export-Tests.shproj index 9cd3bb32d..d6432971c 100644 --- a/src/Java.Interop.Export/Tests/Export-Tests.shproj +++ b/src/Java.Interop.Export/Tests/Export-Tests.shproj @@ -2,6 +2,8 @@ {849ABEDC-6A9C-44F0-8543-5298C096A3FB} + 8.0.30703 + 2.0 diff --git a/src/Java.Interop/Tests/Interop-Tests.shproj b/src/Java.Interop/Tests/Interop-Tests.shproj index 8cd97918b..568c6ca11 100644 --- a/src/Java.Interop/Tests/Interop-Tests.shproj +++ b/src/Java.Interop/Tests/Interop-Tests.shproj @@ -2,6 +2,8 @@ {0ADB8D72-7479-49AF-8809-E03AE4A4EAE2} + 8.0.30703 + 2.0 diff --git a/src/java-interop/java-interop.csproj b/src/java-interop/java-interop.csproj index 1c7bf75ad..a1ad7adca 100644 --- a/src/java-interop/java-interop.csproj +++ b/src/java-interop/java-interop.csproj @@ -7,6 +7,7 @@ 8.0.30703 2.0 {BB0AB9F7-0979-41A7-B7A9-877260655F94} + Exe true @@ -60,27 +61,18 @@ mono - + - + <_Files>@(MacLibLipo -> '%(Identity)', ' ') - + <_FixedDefines>$(DefineSymbols.Split(' ')) @@ -99,10 +91,7 @@ - + <_FixedDefines>$(DefineSymbols.Split(' ')) @@ -122,10 +111,7 @@ - + diff --git a/tests/PerformanceTests/PerformanceTests.shproj b/tests/PerformanceTests/PerformanceTests.shproj index c1ce57fac..c241af725 100644 --- a/tests/PerformanceTests/PerformanceTests.shproj +++ b/tests/PerformanceTests/PerformanceTests.shproj @@ -2,6 +2,8 @@ {0FBECD2A-7C91-41AB-A4B4-B781E8EC8479} + 8.0.30703 + 2.0 diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index fbaa001e3..3d9e40c4c 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -34,6 +34,16 @@ public enum Steps public const string MetadataXmlSubDir = "metadata"; public const string CSharpSourcesSubDir = "csharp"; + public static string [] StubPartialSources => + Directory.GetFiles (Path.Combine (ThisAssemblyDirectory, "SupportFiles"), "*.cs") + .Where (cs => cs.IndexOf ("Java_Lang_", StringComparison.OrdinalIgnoreCase) < 0) + .Where (cs => !string.Equals (Path.GetFileName (cs), "JavaObject.cs", StringComparison.OrdinalIgnoreCase)) + .ToArray (); + public static string [] StubAllSources => + Directory.GetFiles (Path.Combine (ThisAssemblyDirectory, "SupportFiles"), "*.cs"); + + static string ThisAssemblyDirectory => Path.GetDirectoryName (new Uri (typeof (BindingBuilder).Assembly.CodeBase).LocalPath); + public Steps ProcessSteps { get; set; } = Steps.All; // entire work (intermediate output) directory @@ -42,7 +52,24 @@ public enum Steps // Used to resolve javac and rt.jar public string JdkPath { get; set; } - public string GeneratorPath { get; set; } = Path.Combine (Path.GetDirectoryName (new Uri (typeof (BindingBuilder).Assembly.CodeBase).LocalPath), "generator.exe"); + public string GeneratorPath { get; set; } = Path.Combine (ThisAssemblyDirectory, "generator.exe"); + + public bool UseSystemCsc { get; set; } // we don't have to default to csc-dim, but why "not" ? + + public string CscPath { get; set; } + + static string GetMscorlibPath () => new Uri (typeof (object).Assembly.CodeBase).LocalPath; + + static string ProbeCscDimPath () + { + // For Windows, use nuget package. For Mac/Linux, use SYSMONO dim/csc.exe. + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + return Path.Combine ("..", "..", "..", "packages", "xamarin.android.csc.dim.0.1.2", "tools", "csc.exe"); + // assume path relative to framework dll in the GAC. + return Path.GetFullPath (Path.Combine (GetMscorlibPath (), "..", "dim", "csc.exe")); + } + + static string GetSystemRuntimeDll () => Path.Combine (Path.GetDirectoryName (GetMscorlibPath ()), "Facades", "System.Runtime.dll"); static string ProbeJavaHome () { @@ -54,7 +81,10 @@ static string ProbeJavaHome () public static BindingBuilder CreateBestBetDefault (BindingProject project) { - return new BindingBuilder (project) { JdkPath = ProbeJavaHome () }; + return new BindingBuilder (project) { + JdkPath = ProbeJavaHome (), + CscPath = ProbeCscDimPath (), + }; } public BindingBuilder (BindingProject project) @@ -125,8 +155,8 @@ void Javac () project.JavacExecutionOutput = $"Execute javac as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; - proc.ErrorDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; + proc.OutputDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data + '\n'; + proc.ErrorDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data + '\n'; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -160,8 +190,8 @@ void Jar () project.JarExecutionOutput = $"Execute jar as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; - proc.ErrorDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; + proc.OutputDataReceived += (sender, e) => project.JarExecutionOutput += e.Data + '\n'; + proc.ErrorDataReceived += (sender, e) => project.JarExecutionOutput += e.Data + '\n'; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -275,8 +305,8 @@ void GenerateBindingSources () project.GeneratorExecutionOutput = $"Execute generator as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; - proc.ErrorDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; + proc.OutputDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data + '\n'; + proc.ErrorDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data + '\n'; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -287,6 +317,63 @@ void GenerateBindingSources () void CompileBindings () { + if ((ProcessSteps & Steps.Csc) == 0) + return; + + if (CscPath == null) + throw new InvalidOperationException ("CscPath is not set."); + + var objDir = IntermediateOutputPathAbsolute; + EnsureDirectory (objDir); + + if (project.GeneratedCSharpSourceFiles == null) + project.GeneratedCSharpSourceDirectory = Path.Combine (objDir, CSharpSourcesSubDir); + if (!Directory.GetFiles (project.GeneratedCSharpSourceDirectory, "*.cs").Any () && !project.CSharpSourceFiles.Any () && !project.CSharpSourceStrings.Any ()) + throw new InvalidOperationException ("No C# sources exist."); + if (project.GeneratedDllFile == null) + project.GeneratedDllFile = Path.Combine (objDir, project.Id + ".dll"); + + foreach (var item in project.CSharpSourceStrings) + File.WriteAllText (Path.Combine (project.GeneratedCSharpSourceDirectory, item.FileName), item.Content); + var csFiles = project.CSharpSourceFiles.AsEnumerable (); + + switch (project.CSharpStubUsage) { + case CSharpStubUsage.Partial: + csFiles = csFiles.Concat (StubPartialSources); + break; + case CSharpStubUsage.Full: + csFiles = csFiles.Concat (StubAllSources); + break; + } + + string localSystemRuntime = Path.Combine (ThisAssemblyDirectory, "System.Runtime.dll"); + if (!File.Exists (localSystemRuntime)) + File.Copy (GetSystemRuntimeDll (), localSystemRuntime); + + var psi = new ProcessStartInfo () { + UseShellExecute = false, + FileName = UseSystemCsc ? "csc" : CscPath, + Arguments = $" -t:library -unsafe" + + $" -out:\"{project.GeneratedDllFile}\" {project.GeneratedCSharpSourceDirectory}{Path.DirectorySeparatorChar}*.cs " + + $" {string.Join (" ", csFiles.Select (s => '"' + s + '"'))}" + + $" -r:{ThisAssemblyDirectory}{Path.DirectorySeparatorChar}System.Runtime.dll" + + $" -r:{ThisAssemblyDirectory}{Path.DirectorySeparatorChar}Java.Interop.dll" + + $" {string.Join (" ", project.ReferenceDlls.Select (s => " -r \"" + s + '"'))}", + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + project.CscExecutionOutput = $"Execute csc as: {psi.FileName} {psi.Arguments}\n"; + + var proc = new Process () { StartInfo = psi }; + proc.OutputDataReceived += (sender, e) => project.CscExecutionOutput += e.Data + '\n'; + proc.ErrorDataReceived += (sender, e) => project.CscExecutionOutput += e.Data + '\n'; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + proc.WaitForExit (); + if (proc.ExitCode != 0) + throw new Exception ("csc failed: " + project.CscExecutionOutput); } } } diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index 206823d6f..a8a270082 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -8,12 +8,20 @@ public class SourceFile public string Content { get; set; } } + public enum CSharpStubUsage + { + None, + Partial, + Full, + } + public class BindingProject { public string Id { get; set; } public string JavacOptions { get; set; } = "-g"; - public string GeneratorOptions { get; internal set; } + public string GeneratorOptions { get; internal set; } = " --codegen-target=XAJavaInterop1 --public"; + public CSharpStubUsage CSharpStubUsage { get; set; } = CSharpStubUsage.Full; public IList JavaSourceFiles { get; set; } = new List (); public IList JavaSourceStrings { get; set; } = new List (); diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 55f599668..098d3ffcb 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -127,6 +127,45 @@ public void VerifyGenerator () builder.Build (); var csDir = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.CSharpSourcesSubDir); + Assert.AreEqual (csDir, project.GeneratedCSharpSourceDirectory, "C# generated code directory path mismatch."); + Assert.IsTrue (File.Exists (Path.Combine (csDir, "Java.Lang.Object.cs")), "C# source not found"); + } + + [Test] + [Ignore ("rt.jar should be resolved at api-xml-adjuster step too, which is not part of its feature.")] + public void VerifyCsc () + { + var project = new BindingProject { Id = nameof (VerifyCsc) }; + var builder = BindingBuilder.CreateBestBetDefault (project); + project.ReferenceJarFiles.Add (Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar")); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); + project.CSharpStubUsage = CSharpStubUsage.Partial; + + builder.Clean (); + builder.Build (); + + var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); + Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); + Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); + } + + [Test] + public void BindRtJar () + { + var project = new BindingProject { Id = nameof (BindRtJar) }; + var builder = BindingBuilder.CreateBestBetDefault (project); + project.InputJarFiles.Add (Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar")); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); + project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); + project.CSharpStubUsage = CSharpStubUsage.None; + + builder.Clean (); + builder.Build (); + + var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); + Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); + Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); } } } diff --git a/tests/binding-integrated-Tests/binding-integration-Tests.csproj b/tests/binding-integrated-Tests/binding-integration-Tests.csproj index bfa6735f6..36a58fc09 100644 --- a/tests/binding-integrated-Tests/binding-integration-Tests.csproj +++ b/tests/binding-integrated-Tests/binding-integration-Tests.csproj @@ -19,4 +19,5 @@ + diff --git a/tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs b/tests/binding-support-files/SupportFiles/Android_Runtime_CharSequence.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs rename to tests/binding-support-files/SupportFiles/Android_Runtime_CharSequence.cs diff --git a/tools/generator/Tests/SupportFiles/GeneratedEnumAttribute.cs b/tests/binding-support-files/SupportFiles/GeneratedEnumAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/GeneratedEnumAttribute.cs rename to tests/binding-support-files/SupportFiles/GeneratedEnumAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/IJavaObject.cs b/tests/binding-support-files/SupportFiles/IJavaObject.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/IJavaObject.cs rename to tests/binding-support-files/SupportFiles/IJavaObject.cs diff --git a/tools/generator/Tests/SupportFiles/IntDefinitionAttribute.cs b/tests/binding-support-files/SupportFiles/IntDefinitionAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/IntDefinitionAttribute.cs rename to tests/binding-support-files/SupportFiles/IntDefinitionAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/JNIEnv.cs b/tests/binding-support-files/SupportFiles/JNIEnv.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JNIEnv.cs rename to tests/binding-support-files/SupportFiles/JNIEnv.cs diff --git a/tools/generator/Tests/SupportFiles/JNIEnv.g.cs b/tests/binding-support-files/SupportFiles/JNIEnv.g.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JNIEnv.g.cs rename to tests/binding-support-files/SupportFiles/JNIEnv.g.cs diff --git a/tools/generator/Tests/SupportFiles/JObjectRefType.cs b/tests/binding-support-files/SupportFiles/JObjectRefType.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JObjectRefType.cs rename to tests/binding-support-files/SupportFiles/JObjectRefType.cs diff --git a/tools/generator/Tests/SupportFiles/JValue.cs b/tests/binding-support-files/SupportFiles/JValue.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JValue.cs rename to tests/binding-support-files/SupportFiles/JValue.cs diff --git a/tools/generator/Tests/SupportFiles/JavaArray.cs b/tests/binding-support-files/SupportFiles/JavaArray.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaArray.cs rename to tests/binding-support-files/SupportFiles/JavaArray.cs diff --git a/tools/generator/Tests/SupportFiles/JavaCollection.cs b/tests/binding-support-files/SupportFiles/JavaCollection.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaCollection.cs rename to tests/binding-support-files/SupportFiles/JavaCollection.cs diff --git a/tools/generator/Tests/SupportFiles/JavaConvert.cs b/tests/binding-support-files/SupportFiles/JavaConvert.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaConvert.cs rename to tests/binding-support-files/SupportFiles/JavaConvert.cs diff --git a/tools/generator/Tests/SupportFiles/JavaDictionary.cs b/tests/binding-support-files/SupportFiles/JavaDictionary.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaDictionary.cs rename to tests/binding-support-files/SupportFiles/JavaDictionary.cs diff --git a/tools/generator/Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs b/tests/binding-support-files/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs rename to tests/binding-support-files/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/JavaObject.cs b/tests/binding-support-files/SupportFiles/JavaObject.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaObject.cs rename to tests/binding-support-files/SupportFiles/JavaObject.cs diff --git a/tools/generator/Tests/SupportFiles/JavaObjectExtensions.cs b/tests/binding-support-files/SupportFiles/JavaObjectExtensions.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaObjectExtensions.cs rename to tests/binding-support-files/SupportFiles/JavaObjectExtensions.cs diff --git a/tools/generator/Tests/SupportFiles/JavaTypeParametersAttribute.cs b/tests/binding-support-files/SupportFiles/JavaTypeParametersAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JavaTypeParametersAttribute.cs rename to tests/binding-support-files/SupportFiles/JavaTypeParametersAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs b/tests/binding-support-files/SupportFiles/Java_Lang_ICharSequence.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs rename to tests/binding-support-files/SupportFiles/Java_Lang_ICharSequence.cs diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_Object.cs b/tests/binding-support-files/SupportFiles/Java_Lang_Object.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/Java_Lang_Object.cs rename to tests/binding-support-files/SupportFiles/Java_Lang_Object.cs diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_String.cs b/tests/binding-support-files/SupportFiles/Java_Lang_String.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/Java_Lang_String.cs rename to tests/binding-support-files/SupportFiles/Java_Lang_String.cs diff --git a/tools/generator/Tests/SupportFiles/Java_Lang_Throwable.cs b/tests/binding-support-files/SupportFiles/Java_Lang_Throwable.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/Java_Lang_Throwable.cs rename to tests/binding-support-files/SupportFiles/Java_Lang_Throwable.cs diff --git a/tools/generator/Tests/SupportFiles/JniHandleOwnership.cs b/tests/binding-support-files/SupportFiles/JniHandleOwnership.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/JniHandleOwnership.cs rename to tests/binding-support-files/SupportFiles/JniHandleOwnership.cs diff --git a/tools/generator/Tests/SupportFiles/NamespaceMappingAttribute.cs b/tests/binding-support-files/SupportFiles/NamespaceMappingAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/NamespaceMappingAttribute.cs rename to tests/binding-support-files/SupportFiles/NamespaceMappingAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/PreserveAttribute.cs b/tests/binding-support-files/SupportFiles/PreserveAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/PreserveAttribute.cs rename to tests/binding-support-files/SupportFiles/PreserveAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/RegisterAttribute.cs b/tests/binding-support-files/SupportFiles/RegisterAttribute.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/RegisterAttribute.cs rename to tests/binding-support-files/SupportFiles/RegisterAttribute.cs diff --git a/tools/generator/Tests/SupportFiles/TypeManager.cs b/tests/binding-support-files/SupportFiles/TypeManager.cs similarity index 100% rename from tools/generator/Tests/SupportFiles/TypeManager.cs rename to tests/binding-support-files/SupportFiles/TypeManager.cs diff --git a/tests/binding-support-files/binding-support-files.projitems b/tests/binding-support-files/binding-support-files.projitems new file mode 100644 index 000000000..c9d9c712e --- /dev/null +++ b/tests/binding-support-files/binding-support-files.projitems @@ -0,0 +1,95 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {AA1309A9-60BE-4BFD-802B-C44283669D58} + + + binding-support-files + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + diff --git a/tests/binding-support-files/binding-support-files.shproj b/tests/binding-support-files/binding-support-files.shproj new file mode 100644 index 000000000..b348e2000 --- /dev/null +++ b/tests/binding-support-files/binding-support-files.shproj @@ -0,0 +1,13 @@ + + + + 8.0.30703 + 2.0 + {AA1309A9-60BE-4BFD-802B-C44283669D58} + + + + + + + \ No newline at end of file diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index c4fc6df04..143d0c800 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -1,5 +1,6 @@  + Debug @@ -68,7 +69,6 @@ - @@ -92,91 +92,8 @@ {15945D4B-FF56-4BCC-B598-2718D199DD08} Xamarin.Android.Cecil - - {94BD81F7-B06F-4295-9636-F8A3B6BDC762} - Java.Interop - - - {5887B410-D448-4257-A46B-EAC03C80BE93} - Java.Runtime.Environment - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest From 675707019380035ad669cc050f4c52758db47fce Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 18:35:50 +0900 Subject: [PATCH 14/39] Disable integration tests that has no possibility to work. as noted at https://github.com/xamarin/java.interop/pull/341#issuecomment-403418707 --- tests/binding-integrated-Tests/BindingBuilder.cs | 2 +- tests/binding-integrated-Tests/BindingProject.cs | 3 ++- tests/binding-integrated-Tests/SampleTest.cs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index 3d9e40c4c..b6d558843 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -255,7 +255,7 @@ void AdjustApiXml () api.FindDefects (); api.Save (project.GeneratedApiXmlFile); project.ApiXmlAdjusterExecutionOutput = writer.ToString (); - if (project.ApiXmlAdjusterExecutionOutput != string.Empty) + if (!project.IgnoreApiXmlAdjusterWarnings && project.ApiXmlAdjusterExecutionOutput != string.Empty) throw new Exception ("api-xml-adjuster failed: " + project.ApiXmlAdjusterExecutionOutput); } diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index a8a270082..9f4133db2 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -20,8 +20,9 @@ public class BindingProject public string Id { get; set; } public string JavacOptions { get; set; } = "-g"; - public string GeneratorOptions { get; internal set; } = " --codegen-target=XAJavaInterop1 --public"; + public string GeneratorOptions { get; set; } = " --codegen-target=XAJavaInterop1 --public"; public CSharpStubUsage CSharpStubUsage { get; set; } = CSharpStubUsage.Full; + public bool IgnoreApiXmlAdjusterWarnings { get; set; } public IList JavaSourceFiles { get; set; } = new List (); public IList JavaSourceStrings { get; set; } = new List (); diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 098d3ffcb..492c99e27 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -145,12 +145,13 @@ public void VerifyCsc () builder.Clean (); builder.Build (); - var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); + var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id + ".dll"); Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); } [Test] + [Ignore ("rt.jar should be resolved at api-xml-adjuster step too, which is not part of its feature.")] public void BindRtJar () { var project = new BindingProject { Id = nameof (BindRtJar) }; From 5899233385d5fbbb68d1c5536ad9c9fc2bd3a1f8 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 18:50:30 +0900 Subject: [PATCH 15/39] Revert "Disable integration tests that has no possibility to work." This reverts commit 28f11761923a919c7a8a30939f3d6184e32955b9. --- tests/binding-integrated-Tests/BindingBuilder.cs | 2 +- tests/binding-integrated-Tests/BindingProject.cs | 3 +-- tests/binding-integrated-Tests/SampleTest.cs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index b6d558843..3d9e40c4c 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -255,7 +255,7 @@ void AdjustApiXml () api.FindDefects (); api.Save (project.GeneratedApiXmlFile); project.ApiXmlAdjusterExecutionOutput = writer.ToString (); - if (!project.IgnoreApiXmlAdjusterWarnings && project.ApiXmlAdjusterExecutionOutput != string.Empty) + if (project.ApiXmlAdjusterExecutionOutput != string.Empty) throw new Exception ("api-xml-adjuster failed: " + project.ApiXmlAdjusterExecutionOutput); } diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index 9f4133db2..a8a270082 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -20,9 +20,8 @@ public class BindingProject public string Id { get; set; } public string JavacOptions { get; set; } = "-g"; - public string GeneratorOptions { get; set; } = " --codegen-target=XAJavaInterop1 --public"; + public string GeneratorOptions { get; internal set; } = " --codegen-target=XAJavaInterop1 --public"; public CSharpStubUsage CSharpStubUsage { get; set; } = CSharpStubUsage.Full; - public bool IgnoreApiXmlAdjusterWarnings { get; set; } public IList JavaSourceFiles { get; set; } = new List (); public IList JavaSourceStrings { get; set; } = new List (); diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 492c99e27..098d3ffcb 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -145,13 +145,12 @@ public void VerifyCsc () builder.Clean (); builder.Build (); - var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id + ".dll"); + var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); } [Test] - [Ignore ("rt.jar should be resolved at api-xml-adjuster step too, which is not part of its feature.")] public void BindRtJar () { var project = new BindingProject { Id = nameof (BindRtJar) }; From 18e62b345ca7a21ad16d115e46d92c63d21ae9a5 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 18:50:50 +0900 Subject: [PATCH 16/39] Revert "Make generator support files common and add csc test in binding-integration-Tests." This reverts commit fa5b016ae04bca0c041cd41fc3cfb24171283d04. --- Java.Interop.sln | 3 - src/Android.Interop/Android.Interop.csproj | 2 +- .../Tests/Android.Interop-Tests.csproj | 6 +- .../Tests/Dynamic-Tests.shproj | 2 - .../Tests/Export-Tests.shproj | 2 - src/Java.Interop/Tests/Interop-Tests.shproj | 2 - src/java-interop/java-interop.csproj | 26 ++++- .../PerformanceTests/PerformanceTests.shproj | 2 - .../BindingBuilder.cs | 103 ++---------------- .../BindingProject.cs | 10 +- tests/binding-integrated-Tests/SampleTest.cs | 39 ------- .../binding-integration-Tests.csproj | 1 - .../binding-support-files.projitems | 95 ---------------- .../binding-support-files.shproj | 13 --- .../Android_Runtime_CharSequence.cs | 0 .../SupportFiles/GeneratedEnumAttribute.cs | 0 .../Tests}/SupportFiles/IJavaObject.cs | 0 .../SupportFiles/IntDefinitionAttribute.cs | 0 .../generator/Tests}/SupportFiles/JNIEnv.cs | 0 .../generator/Tests}/SupportFiles/JNIEnv.g.cs | 0 .../Tests}/SupportFiles/JObjectRefType.cs | 0 .../generator/Tests}/SupportFiles/JValue.cs | 0 .../Tests}/SupportFiles/JavaArray.cs | 0 .../Tests}/SupportFiles/JavaCollection.cs | 0 .../Tests}/SupportFiles/JavaConvert.cs | 0 .../Tests}/SupportFiles/JavaDictionary.cs | 0 .../JavaInterfaceDefaultMethodAttribute.cs | 0 .../Tests}/SupportFiles/JavaObject.cs | 0 .../SupportFiles/JavaObjectExtensions.cs | 0 .../JavaTypeParametersAttribute.cs | 0 .../SupportFiles/Java_Lang_ICharSequence.cs | 0 .../Tests}/SupportFiles/Java_Lang_Object.cs | 0 .../Tests}/SupportFiles/Java_Lang_String.cs | 0 .../SupportFiles/Java_Lang_Throwable.cs | 0 .../Tests}/SupportFiles/JniHandleOwnership.cs | 0 .../SupportFiles/NamespaceMappingAttribute.cs | 0 .../Tests}/SupportFiles/PreserveAttribute.cs | 0 .../Tests}/SupportFiles/RegisterAttribute.cs | 0 .../Tests}/SupportFiles/TypeManager.cs | 0 tools/generator/Tests/generator-Tests.csproj | 85 ++++++++++++++- 40 files changed, 117 insertions(+), 274 deletions(-) delete mode 100644 tests/binding-support-files/binding-support-files.projitems delete mode 100644 tests/binding-support-files/binding-support-files.shproj rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/Android_Runtime_CharSequence.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/GeneratedEnumAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/IJavaObject.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/IntDefinitionAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JNIEnv.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JNIEnv.g.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JObjectRefType.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JValue.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaArray.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaCollection.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaConvert.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaDictionary.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaObject.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaObjectExtensions.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JavaTypeParametersAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/Java_Lang_ICharSequence.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/Java_Lang_Object.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/Java_Lang_String.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/Java_Lang_Throwable.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/JniHandleOwnership.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/NamespaceMappingAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/PreserveAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/RegisterAttribute.cs (100%) rename {tests/binding-support-files => tools/generator/Tests}/SupportFiles/TypeManager.cs (100%) diff --git a/Java.Interop.sln b/Java.Interop.sln index 97ff87138..1a63f1196 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -101,8 +101,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.BootstrapTasks EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "binding-integration-Tests", "tests\binding-integrated-Tests\binding-integration-Tests.csproj", "{D5CE4B09-C1D3-4647-B78B-6D2E89FE883E}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "binding-support-files", "tests\binding-support-files\binding-support-files.shproj", "{AA1309A9-60BE-4BFD-802B-C44283669D58}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -405,6 +403,5 @@ Global {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF} = {4C173212-371D-45D8-BA83-9226194F48DC} {3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A} = {172B608B-E6F3-41CC-9949-203A76BA247C} {D5CE4B09-C1D3-4647-B78B-6D2E89FE883E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} - {AA1309A9-60BE-4BFD-802B-C44283669D58} = {271C9F30-F679-4793-942B-0D9527CB3E2F} EndGlobalSection EndGlobal diff --git a/src/Android.Interop/Android.Interop.csproj b/src/Android.Interop/Android.Interop.csproj index eaba12300..6ea01dd5a 100644 --- a/src/Android.Interop/Android.Interop.csproj +++ b/src/Android.Interop/Android.Interop.csproj @@ -15,7 +15,7 @@ Assets True Android.Interop - v9.0 + v6.0 true diff --git a/src/Android.Interop/Tests/Android.Interop-Tests.csproj b/src/Android.Interop/Tests/Android.Interop-Tests.csproj index 7e9e0357e..c75f4a018 100644 --- a/src/Android.Interop/Tests/Android.Interop-Tests.csproj +++ b/src/Android.Interop/Tests/Android.Interop-Tests.csproj @@ -16,7 +16,7 @@ True True Android.Interop-Tests - v9.0 + v5.0 Properties\AndroidManifest.xml @@ -75,7 +75,7 @@ - + BuildInteropTestJar; @@ -100,7 +100,7 @@ {0C001D50-4176-45AE-BDC8-BA626508B0CC} - Mono.Linq.Expressions + Mono.Linq.Expressions-Android {AD4468F8-8883-434B-9D4C-E1801BB3B52A} diff --git a/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj b/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj index 537efdf74..7fa179176 100644 --- a/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj +++ b/src/Java.Interop.Dynamic/Tests/Dynamic-Tests.shproj @@ -2,8 +2,6 @@ {8A190F28-74C7-45D8-A701-5864CDF4124A} - 8.0.30703 - 2.0 diff --git a/src/Java.Interop.Export/Tests/Export-Tests.shproj b/src/Java.Interop.Export/Tests/Export-Tests.shproj index d6432971c..9cd3bb32d 100644 --- a/src/Java.Interop.Export/Tests/Export-Tests.shproj +++ b/src/Java.Interop.Export/Tests/Export-Tests.shproj @@ -2,8 +2,6 @@ {849ABEDC-6A9C-44F0-8543-5298C096A3FB} - 8.0.30703 - 2.0 diff --git a/src/Java.Interop/Tests/Interop-Tests.shproj b/src/Java.Interop/Tests/Interop-Tests.shproj index 568c6ca11..8cd97918b 100644 --- a/src/Java.Interop/Tests/Interop-Tests.shproj +++ b/src/Java.Interop/Tests/Interop-Tests.shproj @@ -2,8 +2,6 @@ {0ADB8D72-7479-49AF-8809-E03AE4A4EAE2} - 8.0.30703 - 2.0 diff --git a/src/java-interop/java-interop.csproj b/src/java-interop/java-interop.csproj index a1ad7adca..1c7bf75ad 100644 --- a/src/java-interop/java-interop.csproj +++ b/src/java-interop/java-interop.csproj @@ -7,7 +7,6 @@ 8.0.30703 2.0 {BB0AB9F7-0979-41A7-B7A9-877260655F94} - Exe true @@ -61,18 +60,27 @@ mono - + - + <_Files>@(MacLibLipo -> '%(Identity)', ' ') - + <_FixedDefines>$(DefineSymbols.Split(' ')) @@ -91,7 +99,10 @@ - + <_FixedDefines>$(DefineSymbols.Split(' ')) @@ -111,7 +122,10 @@ - + diff --git a/tests/PerformanceTests/PerformanceTests.shproj b/tests/PerformanceTests/PerformanceTests.shproj index c241af725..c1ce57fac 100644 --- a/tests/PerformanceTests/PerformanceTests.shproj +++ b/tests/PerformanceTests/PerformanceTests.shproj @@ -2,8 +2,6 @@ {0FBECD2A-7C91-41AB-A4B4-B781E8EC8479} - 8.0.30703 - 2.0 diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index 3d9e40c4c..fbaa001e3 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -34,16 +34,6 @@ public enum Steps public const string MetadataXmlSubDir = "metadata"; public const string CSharpSourcesSubDir = "csharp"; - public static string [] StubPartialSources => - Directory.GetFiles (Path.Combine (ThisAssemblyDirectory, "SupportFiles"), "*.cs") - .Where (cs => cs.IndexOf ("Java_Lang_", StringComparison.OrdinalIgnoreCase) < 0) - .Where (cs => !string.Equals (Path.GetFileName (cs), "JavaObject.cs", StringComparison.OrdinalIgnoreCase)) - .ToArray (); - public static string [] StubAllSources => - Directory.GetFiles (Path.Combine (ThisAssemblyDirectory, "SupportFiles"), "*.cs"); - - static string ThisAssemblyDirectory => Path.GetDirectoryName (new Uri (typeof (BindingBuilder).Assembly.CodeBase).LocalPath); - public Steps ProcessSteps { get; set; } = Steps.All; // entire work (intermediate output) directory @@ -52,24 +42,7 @@ public enum Steps // Used to resolve javac and rt.jar public string JdkPath { get; set; } - public string GeneratorPath { get; set; } = Path.Combine (ThisAssemblyDirectory, "generator.exe"); - - public bool UseSystemCsc { get; set; } // we don't have to default to csc-dim, but why "not" ? - - public string CscPath { get; set; } - - static string GetMscorlibPath () => new Uri (typeof (object).Assembly.CodeBase).LocalPath; - - static string ProbeCscDimPath () - { - // For Windows, use nuget package. For Mac/Linux, use SYSMONO dim/csc.exe. - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - return Path.Combine ("..", "..", "..", "packages", "xamarin.android.csc.dim.0.1.2", "tools", "csc.exe"); - // assume path relative to framework dll in the GAC. - return Path.GetFullPath (Path.Combine (GetMscorlibPath (), "..", "dim", "csc.exe")); - } - - static string GetSystemRuntimeDll () => Path.Combine (Path.GetDirectoryName (GetMscorlibPath ()), "Facades", "System.Runtime.dll"); + public string GeneratorPath { get; set; } = Path.Combine (Path.GetDirectoryName (new Uri (typeof (BindingBuilder).Assembly.CodeBase).LocalPath), "generator.exe"); static string ProbeJavaHome () { @@ -81,10 +54,7 @@ static string ProbeJavaHome () public static BindingBuilder CreateBestBetDefault (BindingProject project) { - return new BindingBuilder (project) { - JdkPath = ProbeJavaHome (), - CscPath = ProbeCscDimPath (), - }; + return new BindingBuilder (project) { JdkPath = ProbeJavaHome () }; } public BindingBuilder (BindingProject project) @@ -155,8 +125,8 @@ void Javac () project.JavacExecutionOutput = $"Execute javac as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data + '\n'; - proc.ErrorDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data + '\n'; + proc.OutputDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.JavacExecutionOutput += e.Data; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -190,8 +160,8 @@ void Jar () project.JarExecutionOutput = $"Execute jar as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.JarExecutionOutput += e.Data + '\n'; - proc.ErrorDataReceived += (sender, e) => project.JarExecutionOutput += e.Data + '\n'; + proc.OutputDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.JarExecutionOutput += e.Data; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -305,8 +275,8 @@ void GenerateBindingSources () project.GeneratorExecutionOutput = $"Execute generator as: {psi.FileName} {psi.Arguments}\n"; var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data + '\n'; - proc.ErrorDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data + '\n'; + proc.OutputDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; + proc.ErrorDataReceived += (sender, e) => project.GeneratorExecutionOutput += e.Data; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); @@ -317,63 +287,6 @@ void GenerateBindingSources () void CompileBindings () { - if ((ProcessSteps & Steps.Csc) == 0) - return; - - if (CscPath == null) - throw new InvalidOperationException ("CscPath is not set."); - - var objDir = IntermediateOutputPathAbsolute; - EnsureDirectory (objDir); - - if (project.GeneratedCSharpSourceFiles == null) - project.GeneratedCSharpSourceDirectory = Path.Combine (objDir, CSharpSourcesSubDir); - if (!Directory.GetFiles (project.GeneratedCSharpSourceDirectory, "*.cs").Any () && !project.CSharpSourceFiles.Any () && !project.CSharpSourceStrings.Any ()) - throw new InvalidOperationException ("No C# sources exist."); - if (project.GeneratedDllFile == null) - project.GeneratedDllFile = Path.Combine (objDir, project.Id + ".dll"); - - foreach (var item in project.CSharpSourceStrings) - File.WriteAllText (Path.Combine (project.GeneratedCSharpSourceDirectory, item.FileName), item.Content); - var csFiles = project.CSharpSourceFiles.AsEnumerable (); - - switch (project.CSharpStubUsage) { - case CSharpStubUsage.Partial: - csFiles = csFiles.Concat (StubPartialSources); - break; - case CSharpStubUsage.Full: - csFiles = csFiles.Concat (StubAllSources); - break; - } - - string localSystemRuntime = Path.Combine (ThisAssemblyDirectory, "System.Runtime.dll"); - if (!File.Exists (localSystemRuntime)) - File.Copy (GetSystemRuntimeDll (), localSystemRuntime); - - var psi = new ProcessStartInfo () { - UseShellExecute = false, - FileName = UseSystemCsc ? "csc" : CscPath, - Arguments = $" -t:library -unsafe" + - $" -out:\"{project.GeneratedDllFile}\" {project.GeneratedCSharpSourceDirectory}{Path.DirectorySeparatorChar}*.cs " + - $" {string.Join (" ", csFiles.Select (s => '"' + s + '"'))}" + - $" -r:{ThisAssemblyDirectory}{Path.DirectorySeparatorChar}System.Runtime.dll" + - $" -r:{ThisAssemblyDirectory}{Path.DirectorySeparatorChar}Java.Interop.dll" + - $" {string.Join (" ", project.ReferenceDlls.Select (s => " -r \"" + s + '"'))}", - RedirectStandardOutput = true, - RedirectStandardError = true, - }; - - project.CscExecutionOutput = $"Execute csc as: {psi.FileName} {psi.Arguments}\n"; - - var proc = new Process () { StartInfo = psi }; - proc.OutputDataReceived += (sender, e) => project.CscExecutionOutput += e.Data + '\n'; - proc.ErrorDataReceived += (sender, e) => project.CscExecutionOutput += e.Data + '\n'; - proc.Start (); - proc.BeginOutputReadLine (); - proc.BeginErrorReadLine (); - proc.WaitForExit (); - if (proc.ExitCode != 0) - throw new Exception ("csc failed: " + project.CscExecutionOutput); } } } diff --git a/tests/binding-integrated-Tests/BindingProject.cs b/tests/binding-integrated-Tests/BindingProject.cs index a8a270082..206823d6f 100644 --- a/tests/binding-integrated-Tests/BindingProject.cs +++ b/tests/binding-integrated-Tests/BindingProject.cs @@ -8,20 +8,12 @@ public class SourceFile public string Content { get; set; } } - public enum CSharpStubUsage - { - None, - Partial, - Full, - } - public class BindingProject { public string Id { get; set; } public string JavacOptions { get; set; } = "-g"; - public string GeneratorOptions { get; internal set; } = " --codegen-target=XAJavaInterop1 --public"; - public CSharpStubUsage CSharpStubUsage { get; set; } = CSharpStubUsage.Full; + public string GeneratorOptions { get; internal set; } public IList JavaSourceFiles { get; set; } = new List (); public IList JavaSourceStrings { get; set; } = new List (); diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 098d3ffcb..55f599668 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -127,45 +127,6 @@ public void VerifyGenerator () builder.Build (); var csDir = Path.Combine (builder.IntermediateOutputPathAbsolute, BindingBuilder.CSharpSourcesSubDir); - Assert.AreEqual (csDir, project.GeneratedCSharpSourceDirectory, "C# generated code directory path mismatch."); - Assert.IsTrue (File.Exists (Path.Combine (csDir, "Java.Lang.Object.cs")), "C# source not found"); - } - - [Test] - [Ignore ("rt.jar should be resolved at api-xml-adjuster step too, which is not part of its feature.")] - public void VerifyCsc () - { - var project = new BindingProject { Id = nameof (VerifyCsc) }; - var builder = BindingBuilder.CreateBestBetDefault (project); - project.ReferenceJarFiles.Add (Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar")); - project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); - project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); - project.CSharpStubUsage = CSharpStubUsage.Partial; - - builder.Clean (); - builder.Build (); - - var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); - Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); - Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); - } - - [Test] - public void BindRtJar () - { - var project = new BindingProject { Id = nameof (BindRtJar) }; - var builder = BindingBuilder.CreateBestBetDefault (project); - project.InputJarFiles.Add (Path.Combine (builder.JdkPath, "jre", "lib", "rt.jar")); - project.JavaSourceStrings.Add (new SourceFile { FileName = "Foo.java", Content = "package com.xamarin.test; public class Foo {}" }); - project.JavaSourceStrings.Add (new SourceFile { FileName = "Bar.java", Content = "package com.xamarin.test; public class Bar {}" }); - project.CSharpStubUsage = CSharpStubUsage.None; - - builder.Clean (); - builder.Build (); - - var dll = Path.Combine (builder.IntermediateOutputPathAbsolute, project.Id); - Assert.AreEqual (dll, project.GeneratedDllFile, "C# generated code directory path mismatch."); - Assert.IsTrue (File.Exists (dll), "gnerated dll not found"); } } } diff --git a/tests/binding-integrated-Tests/binding-integration-Tests.csproj b/tests/binding-integrated-Tests/binding-integration-Tests.csproj index 36a58fc09..bfa6735f6 100644 --- a/tests/binding-integrated-Tests/binding-integration-Tests.csproj +++ b/tests/binding-integrated-Tests/binding-integration-Tests.csproj @@ -19,5 +19,4 @@ - diff --git a/tests/binding-support-files/binding-support-files.projitems b/tests/binding-support-files/binding-support-files.projitems deleted file mode 100644 index c9d9c712e..000000000 --- a/tests/binding-support-files/binding-support-files.projitems +++ /dev/null @@ -1,95 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {AA1309A9-60BE-4BFD-802B-C44283669D58} - - - binding-support-files - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - diff --git a/tests/binding-support-files/binding-support-files.shproj b/tests/binding-support-files/binding-support-files.shproj deleted file mode 100644 index b348e2000..000000000 --- a/tests/binding-support-files/binding-support-files.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 8.0.30703 - 2.0 - {AA1309A9-60BE-4BFD-802B-C44283669D58} - - - - - - - \ No newline at end of file diff --git a/tests/binding-support-files/SupportFiles/Android_Runtime_CharSequence.cs b/tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/Android_Runtime_CharSequence.cs rename to tools/generator/Tests/SupportFiles/Android_Runtime_CharSequence.cs diff --git a/tests/binding-support-files/SupportFiles/GeneratedEnumAttribute.cs b/tools/generator/Tests/SupportFiles/GeneratedEnumAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/GeneratedEnumAttribute.cs rename to tools/generator/Tests/SupportFiles/GeneratedEnumAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/IJavaObject.cs b/tools/generator/Tests/SupportFiles/IJavaObject.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/IJavaObject.cs rename to tools/generator/Tests/SupportFiles/IJavaObject.cs diff --git a/tests/binding-support-files/SupportFiles/IntDefinitionAttribute.cs b/tools/generator/Tests/SupportFiles/IntDefinitionAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/IntDefinitionAttribute.cs rename to tools/generator/Tests/SupportFiles/IntDefinitionAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/JNIEnv.cs b/tools/generator/Tests/SupportFiles/JNIEnv.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JNIEnv.cs rename to tools/generator/Tests/SupportFiles/JNIEnv.cs diff --git a/tests/binding-support-files/SupportFiles/JNIEnv.g.cs b/tools/generator/Tests/SupportFiles/JNIEnv.g.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JNIEnv.g.cs rename to tools/generator/Tests/SupportFiles/JNIEnv.g.cs diff --git a/tests/binding-support-files/SupportFiles/JObjectRefType.cs b/tools/generator/Tests/SupportFiles/JObjectRefType.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JObjectRefType.cs rename to tools/generator/Tests/SupportFiles/JObjectRefType.cs diff --git a/tests/binding-support-files/SupportFiles/JValue.cs b/tools/generator/Tests/SupportFiles/JValue.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JValue.cs rename to tools/generator/Tests/SupportFiles/JValue.cs diff --git a/tests/binding-support-files/SupportFiles/JavaArray.cs b/tools/generator/Tests/SupportFiles/JavaArray.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaArray.cs rename to tools/generator/Tests/SupportFiles/JavaArray.cs diff --git a/tests/binding-support-files/SupportFiles/JavaCollection.cs b/tools/generator/Tests/SupportFiles/JavaCollection.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaCollection.cs rename to tools/generator/Tests/SupportFiles/JavaCollection.cs diff --git a/tests/binding-support-files/SupportFiles/JavaConvert.cs b/tools/generator/Tests/SupportFiles/JavaConvert.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaConvert.cs rename to tools/generator/Tests/SupportFiles/JavaConvert.cs diff --git a/tests/binding-support-files/SupportFiles/JavaDictionary.cs b/tools/generator/Tests/SupportFiles/JavaDictionary.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaDictionary.cs rename to tools/generator/Tests/SupportFiles/JavaDictionary.cs diff --git a/tests/binding-support-files/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs b/tools/generator/Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs rename to tools/generator/Tests/SupportFiles/JavaInterfaceDefaultMethodAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/JavaObject.cs b/tools/generator/Tests/SupportFiles/JavaObject.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaObject.cs rename to tools/generator/Tests/SupportFiles/JavaObject.cs diff --git a/tests/binding-support-files/SupportFiles/JavaObjectExtensions.cs b/tools/generator/Tests/SupportFiles/JavaObjectExtensions.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaObjectExtensions.cs rename to tools/generator/Tests/SupportFiles/JavaObjectExtensions.cs diff --git a/tests/binding-support-files/SupportFiles/JavaTypeParametersAttribute.cs b/tools/generator/Tests/SupportFiles/JavaTypeParametersAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JavaTypeParametersAttribute.cs rename to tools/generator/Tests/SupportFiles/JavaTypeParametersAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/Java_Lang_ICharSequence.cs b/tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/Java_Lang_ICharSequence.cs rename to tools/generator/Tests/SupportFiles/Java_Lang_ICharSequence.cs diff --git a/tests/binding-support-files/SupportFiles/Java_Lang_Object.cs b/tools/generator/Tests/SupportFiles/Java_Lang_Object.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/Java_Lang_Object.cs rename to tools/generator/Tests/SupportFiles/Java_Lang_Object.cs diff --git a/tests/binding-support-files/SupportFiles/Java_Lang_String.cs b/tools/generator/Tests/SupportFiles/Java_Lang_String.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/Java_Lang_String.cs rename to tools/generator/Tests/SupportFiles/Java_Lang_String.cs diff --git a/tests/binding-support-files/SupportFiles/Java_Lang_Throwable.cs b/tools/generator/Tests/SupportFiles/Java_Lang_Throwable.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/Java_Lang_Throwable.cs rename to tools/generator/Tests/SupportFiles/Java_Lang_Throwable.cs diff --git a/tests/binding-support-files/SupportFiles/JniHandleOwnership.cs b/tools/generator/Tests/SupportFiles/JniHandleOwnership.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/JniHandleOwnership.cs rename to tools/generator/Tests/SupportFiles/JniHandleOwnership.cs diff --git a/tests/binding-support-files/SupportFiles/NamespaceMappingAttribute.cs b/tools/generator/Tests/SupportFiles/NamespaceMappingAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/NamespaceMappingAttribute.cs rename to tools/generator/Tests/SupportFiles/NamespaceMappingAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/PreserveAttribute.cs b/tools/generator/Tests/SupportFiles/PreserveAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/PreserveAttribute.cs rename to tools/generator/Tests/SupportFiles/PreserveAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/RegisterAttribute.cs b/tools/generator/Tests/SupportFiles/RegisterAttribute.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/RegisterAttribute.cs rename to tools/generator/Tests/SupportFiles/RegisterAttribute.cs diff --git a/tests/binding-support-files/SupportFiles/TypeManager.cs b/tools/generator/Tests/SupportFiles/TypeManager.cs similarity index 100% rename from tests/binding-support-files/SupportFiles/TypeManager.cs rename to tools/generator/Tests/SupportFiles/TypeManager.cs diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index 143d0c800..c4fc6df04 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -1,6 +1,5 @@  - Debug @@ -69,6 +68,7 @@ + @@ -92,8 +92,91 @@ {15945D4B-FF56-4BCC-B598-2718D199DD08} Xamarin.Android.Cecil + + {94BD81F7-B06F-4295-9636-F8A3B6BDC762} + Java.Interop + + + {5887B410-D448-4257-A46B-EAC03C80BE93} + Java.Runtime.Environment + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest From 1d1c08582a665230e7450efa06d5ce4c0530c114 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 18:52:26 +0900 Subject: [PATCH 17/39] Revert most of the changes that are done only to get integration csc tests. And disabled those not-working csc tests. --- tests/binding-integrated-Tests/SampleTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/binding-integrated-Tests/SampleTest.cs b/tests/binding-integrated-Tests/SampleTest.cs index 55f599668..60cc51404 100644 --- a/tests/binding-integrated-Tests/SampleTest.cs +++ b/tests/binding-integrated-Tests/SampleTest.cs @@ -94,6 +94,7 @@ public void VerifyClassParse () } [Test] + [Ignore ("This won't run until we get a working partial Object.cs that exist only in xamarin-android.")] public void VerifyApiXmlAdjuster () { var project = new BindingProject { Id = nameof (VerifyApiXmlAdjuster) }; @@ -114,6 +115,7 @@ public void VerifyApiXmlAdjuster () } [Test] + [Ignore ("This won't run until we get a working partial Object.cs that exist only in xamarin-android.")] public void VerifyGenerator () { var project = new BindingProject { Id = nameof (VerifyGenerator) }; From 770d400dac0d19bf416e1cae08ddd745d20a9448 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Mon, 9 Jul 2018 19:03:26 +0900 Subject: [PATCH 18/39] remove unnecessary project references from generator-Tests made in dim branch. --- tools/generator/Tests/generator-Tests.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index c4fc6df04..c15a2a528 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -92,14 +92,6 @@ {15945D4B-FF56-4BCC-B598-2718D199DD08} Xamarin.Android.Cecil - - {94BD81F7-B06F-4295-9636-F8A3B6BDC762} - Java.Interop - - - {5887B410-D448-4257-A46B-EAC03C80BE93} - Java.Runtime.Environment - From 9775acbf807166597086c4899233cdd6268acbd7 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 10 Jul 2018 00:12:28 +0900 Subject: [PATCH 19/39] Futher removal of extraneous project references that causes build breakage. --- tests/binding-integrated-Tests/BindingBuilder.cs | 1 - tests/binding-integrated-Tests/binding-integration-Tests.csproj | 2 -- 2 files changed, 3 deletions(-) diff --git a/tests/binding-integrated-Tests/BindingBuilder.cs b/tests/binding-integrated-Tests/BindingBuilder.cs index fbaa001e3..a22232075 100644 --- a/tests/binding-integrated-Tests/BindingBuilder.cs +++ b/tests/binding-integrated-Tests/BindingBuilder.cs @@ -1,7 +1,6 @@ using NUnit.Framework; using System; using System.Diagnostics; -using Java.Interop; using System.IO; using System.Linq; using Xamarin.Android.Tools.Bytecode; diff --git a/tests/binding-integrated-Tests/binding-integration-Tests.csproj b/tests/binding-integrated-Tests/binding-integration-Tests.csproj index bfa6735f6..677fed851 100644 --- a/tests/binding-integrated-Tests/binding-integration-Tests.csproj +++ b/tests/binding-integrated-Tests/binding-integration-Tests.csproj @@ -13,8 +13,6 @@ - - From 8128a1b88c888d23ac196edd35c76fa4f1af1f8d Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 10 Jul 2018 18:18:18 +0900 Subject: [PATCH 20/39] Do not generate method implementations for DIM in ClassGen if DIM is enabled. They are required only in DIM-unsupported mode. Add test support file for generated implementation class. --- tools/generator/ClassGen.cs | 8 ++- .../Xamarin.Test.TheImplementor.cs | 52 +++++++++++++++++++ tools/generator/Tests/generator-Tests.csproj | 3 ++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.TheImplementor.cs diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index 99cdfe900..d4a4ebc5d 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -329,7 +329,7 @@ void GenerateAbstractMembers (StreamWriter sw, string indent, CodeGenerationOpti gen.GenerateAbstractMembers (this, sw, indent, opt); } - void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) + void GenerateDefaultInterfaceMethodsImplementationClassic (StreamWriter sw, string indent, CodeGenerationOptions opt) { // This does not exclude overrides (unlike virtual methods) because we're not sure // if calling the base interface default method via JNI expectedly dispatches to @@ -353,6 +353,12 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) opt.ContextGeneratedMethods.Add (m); m.IsVirtual = virt; } + } + + void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) + { + if (!opt.SupportDefaultInterfaceMethods) + GenerateDefaultInterfaceMethodsImplementationClassic (sw, indent, opt); var methods = Methods.Concat (Properties.Where (p => p.Setter != null).Select (p => p.Setter)); foreach (InterfaceGen type in methods.Where (m => m.IsListenerConnector && m.EventName != String.Empty).Select (m => m.ListenerType).Distinct ()) { diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.TheImplementor.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.TheImplementor.cs new file mode 100644 index 000000000..33b88457a --- /dev/null +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.TheImplementor.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Android.Runtime; +using Java.Interop; + +namespace Xamarin.Test { + + // Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='TheImplementor']" + [global::Android.Runtime.Register ("xamarin/test/TheImplementor", DoNotGenerateAcw=true)] + public partial class TheImplementor : global::Java.Lang.Object, global::Xamarin.Test.ITheInterface { + + internal new static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/TheImplementor", typeof (TheImplementor)); + internal static new IntPtr class_ref { + get { + return _members.JniPeerType.PeerReference.Handle; + } + } + + public override global::Java.Interop.JniPeerMembers JniPeerMembers { + get { return _members; } + } + + protected override IntPtr ThresholdClass { + get { return _members.JniPeerType.PeerReference.Handle; } + } + + protected override global::System.Type ThresholdType { + get { return _members.ManagedPeerType; } + } + + protected TheImplementor (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {} + + // Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='TheImplementor']/constructor[@name='TheImplementor' and count(parameter)=0]" + [Register (".ctor", "()V", "")] + public unsafe TheImplementor () + : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) + { + const string __id = "()V"; + + if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero) + return; + + try { + var __r = _members.InstanceMethods.StartCreateInstance (__id, ((object) this).GetType (), null); + SetHandle (__r.Handle, JniHandleOwnership.TransferLocalRef); + _members.InstanceMethods.FinishCreateInstance (__id, this, null); + } finally { + } + } + + } +} diff --git a/tools/generator/Tests/generator-Tests.csproj b/tools/generator/Tests/generator-Tests.csproj index c15a2a528..eedbe6647 100644 --- a/tools/generator/Tests/generator-Tests.csproj +++ b/tools/generator/Tests/generator-Tests.csproj @@ -175,6 +175,9 @@ PreserveNewest + + PreserveNewest + From 6b46e43b1046a44735321c4c0859c5b0846b5a70 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 12 Jul 2018 01:46:28 +0900 Subject: [PATCH 21/39] Fix t4 template for JniInstanceMethods. There was mismatch between the template and the generated (and checked in) code. The template was wrong. --- .../Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt index 5e5ae6994..0cfd669b5 100644 --- a/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt +++ b/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.tt @@ -44,7 +44,7 @@ namespace Java.Interop { JniPeerMembers.AssertSelf (self); var declaringType = DeclaringType; - if (Members.ShouldUseVirtualDispatch (self, declaringType)) { + if (Members.UsesVirtualDispatch (self, declaringType)) { var m = GetMethodInfo (encodedMember); <#= returnType.ReturnType != "void" ? "return " : "" #>JniEnvironment.InstanceMethods.Call<#= returnType.JniCallType #>Method (self.PeerReference, m, parameters); <#= returnType.ReturnType == "void" ? "return;" : "" #> From f5927afd51f74c85e266c89a42f6c44973a5b003 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 12 Jul 2018 01:47:36 +0900 Subject: [PATCH 22/39] For default interface methods, use CallNonvirtualXxxMethods(). It still throws AbstractMethodError, which is weird... --- tools/generator/JavaInteropCodeGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generator/JavaInteropCodeGenerator.cs b/tools/generator/JavaInteropCodeGenerator.cs index 401ad7db6..14b437906 100644 --- a/tools/generator/JavaInteropCodeGenerator.cs +++ b/tools/generator/JavaInteropCodeGenerator.cs @@ -162,7 +162,7 @@ internal override void WriteMethodBody (Method method, TextWriter writer, string writer.WriteLine ("_members.StaticMethods.Invoke{0}Method (__id{1});", invokeType, method.Parameters.GetCallArgs (opt, invoker: false)); - } else if (method.IsFinal) { + } else if (method.IsFinal || method.IsInterfaceDefaultMethod) { writer.WriteLine ("_members.InstanceMethods.InvokeNonvirtual{0}Method (__id, {1}this{2});", invokeType, castToPeerable, From a6e7d82ec7161528d8045d6c698de6b471c4870c Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 12 Jul 2018 15:48:57 +0900 Subject: [PATCH 23/39] Fix DIM test expected output C# code. Should emit "Nonvirtual" --- .../Xamarin.Test.ITheInterface.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs index a0a59b944..8e648f622 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs @@ -36,7 +36,7 @@ virtual unsafe int Bar { get { const string __id = "getBar.()I"; try { - var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, (IJavaPeerable) this, null); + var __rm = _members.InstanceMethods.InvokeNonvirtualInt32Method (__id, (IJavaPeerable) this, null); return __rm; } finally { } @@ -82,7 +82,7 @@ virtual unsafe string StringProp { get { const string __id = "getStringProp.()Ljava/lang/String;"; try { - var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, null); + var __rm = _members.InstanceMethods.InvokeNonvirtualObjectMethod (__id, (IJavaPeerable) this, null); return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); } finally { } @@ -95,7 +95,7 @@ virtual unsafe string StringProp { try { JniArgumentValue* __args = stackalloc JniArgumentValue [1]; __args [0] = new JniArgumentValue (native_value); - _members.InstanceMethods.InvokeVirtualVoidMethod (__id, (IJavaPeerable) this, __args); + _members.InstanceMethods.InvokeNonvirtualVoidMethod (__id, (IJavaPeerable) this, __args); } finally { JNIEnv.DeleteLocalRef (native_value); } @@ -124,7 +124,7 @@ virtual unsafe int Foo () { const string __id = "foo.()I"; try { - var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, (IJavaPeerable) this, null); + var __rm = _members.InstanceMethods.InvokeNonvirtualInt32Method (__id, (IJavaPeerable) this, null); return __rm; } finally { } @@ -152,7 +152,7 @@ virtual unsafe string String1 () { const string __id = "string1.()Ljava/lang/String;"; try { - var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, null); + var __rm = _members.InstanceMethods.InvokeNonvirtualObjectMethod (__id, (IJavaPeerable) this, null); return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); } finally { } @@ -195,7 +195,7 @@ virtual unsafe string String1 (string p1, string[] p2, params string[] p3) __args [0] = new JniArgumentValue (native_p1); __args [1] = new JniArgumentValue (native_p2); __args [2] = new JniArgumentValue (native_p3); - var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, (IJavaPeerable) this, __args); + var __rm = _members.InstanceMethods.InvokeNonvirtualObjectMethod (__id, (IJavaPeerable) this, __args); return JNIEnv.GetString (__rm.Handle, JniHandleOwnership.TransferLocalRef); } finally { JNIEnv.DeleteLocalRef (native_p1); From 92547eeb8f6cc36669ea5b0557cb6fe0188ea04a Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 12 Jul 2018 18:40:06 +0900 Subject: [PATCH 24/39] Partially revert Method generation switch for DIMs and non-DIMs. With the DIM mode, it was skipping some (or many!) method generation which resulted in huge API changes. Since it was a regression only in DIM mode, generator-Tests are now modified to run in both non-DIM mode and DIM mode. --- tools/generator/ClassGen.cs | 14 ++++++-------- tools/generator/Method.cs | 2 +- .../Tests/Integration-Tests/BaseGeneratorTest.cs | 13 ++++++++++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index d4a4ebc5d..179c14559 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -329,8 +329,10 @@ void GenerateAbstractMembers (StreamWriter sw, string indent, CodeGenerationOpti gen.GenerateAbstractMembers (this, sw, indent, opt); } - void GenerateDefaultInterfaceMethodsImplementationClassic (StreamWriter sw, string indent, CodeGenerationOptions opt) + void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) { + var methodsToDeclare = Methods.AsEnumerable (); + // This does not exclude overrides (unlike virtual methods) because we're not sure // if calling the base interface default method via JNI expectedly dispatches to // the derived method. @@ -343,7 +345,9 @@ void GenerateDefaultInterfaceMethodsImplementationClassic (StreamWriter sw, stri var overridens = defaultMethods.Where (m => overrides.Where (_ => _.Name == m.Name && _.JniSignature == m.JniSignature) .Any (mm => mm.DeclaringType.GetAllDerivedInterfaces ().Contains (m.DeclaringType))); - foreach (Method m in Methods.Concat (defaultMethods.Except (overridens)).Where (m => m.DeclaringType.IsGeneratable)) { + methodsToDeclare = opt.SupportDefaultInterfaceMethods ? methodsToDeclare : methodsToDeclare.Concat (defaultMethods.Except (overridens)).Where (m => m.DeclaringType.IsGeneratable); + + foreach (Method m in methodsToDeclare) { bool virt = m.IsVirtual; m.IsVirtual = !IsFinal && virt; if (m.IsAbstract && !m.IsInterfaceDefaultMethodOverride && !m.IsInterfaceDefaultMethod) @@ -353,12 +357,6 @@ void GenerateDefaultInterfaceMethodsImplementationClassic (StreamWriter sw, stri opt.ContextGeneratedMethods.Add (m); m.IsVirtual = virt; } - } - - void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) - { - if (!opt.SupportDefaultInterfaceMethods) - GenerateDefaultInterfaceMethodsImplementationClassic (sw, indent, opt); var methods = Methods.Concat (Properties.Where (p => p.Setter != null).Select (p => p.Setter)); foreach (InterfaceGen type in methods.Where (m => m.IsListenerConnector && m.EventName != String.Empty).Select (m => m.ListenerType).Distinct ()) { diff --git a/tools/generator/Method.cs b/tools/generator/Method.cs index 29a1cf19e..e22e80770 100644 --- a/tools/generator/Method.cs +++ b/tools/generator/Method.cs @@ -140,7 +140,7 @@ public XmlMethod (GenBase declaringType, XElement elem) name = StringRocks.MemberToPascalCase (JavaName); is_abstract = elem.XGetAttribute ("abstract") == "true"; - if (declaringType is InterfaceGen) + if (declaringType.IsInterface) is_interface_default_method = !is_abstract && !is_static; GenerateDispatchingSetter = elem.Attribute ("generateDispatchingSetter") != null; diff --git a/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs b/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs index 28a5dcb56..0b068ebc5 100644 --- a/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs +++ b/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs @@ -130,7 +130,18 @@ protected string FullPath (string path) return Path.Combine (dir, path.Replace ('/', Path.DirectorySeparatorChar)); } - protected void Run (CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string[] additionalSupportPaths = null) + protected void Run (CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string [] additionalSupportPaths = null) + { + // skip non-DIM mode if the test itself expects DIM mode. + if (!Options.SupportDefaultInterfaceMethods) + Run (false, target, outputPath, apiDescriptionFile, expectedPath, additionalSupportPaths); + var bak = Options.SupportDefaultInterfaceMethods; + Options.SupportDefaultInterfaceMethods = true; + Run (true, target, outputPath, apiDescriptionFile, expectedPath, additionalSupportPaths); + Options.SupportDefaultInterfaceMethods = bak; + } + + protected void Run (bool supportDefaultInterfaceMethods, CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string[] additionalSupportPaths = null) { Cleanup (outputPath); From fb6e911f1c9996db4a0f9b335aa4d1fb2b602565 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 17 Jul 2018 16:31:39 +0900 Subject: [PATCH 25/39] Revert previous changes to generator-Tests, it was not really doable. The thing is that the "expected*" files could vary depending on DIM options (only if DIMs exist in Java side), which makes this testing almost useless. --- .../Tests/Integration-Tests/BaseGeneratorTest.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs b/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs index 0b068ebc5..425c72c6b 100644 --- a/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs +++ b/tools/generator/Tests/Integration-Tests/BaseGeneratorTest.cs @@ -131,17 +131,6 @@ protected string FullPath (string path) } protected void Run (CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string [] additionalSupportPaths = null) - { - // skip non-DIM mode if the test itself expects DIM mode. - if (!Options.SupportDefaultInterfaceMethods) - Run (false, target, outputPath, apiDescriptionFile, expectedPath, additionalSupportPaths); - var bak = Options.SupportDefaultInterfaceMethods; - Options.SupportDefaultInterfaceMethods = true; - Run (true, target, outputPath, apiDescriptionFile, expectedPath, additionalSupportPaths); - Options.SupportDefaultInterfaceMethods = bak; - } - - protected void Run (bool supportDefaultInterfaceMethods, CodeGenerationTarget target, string outputPath, string apiDescriptionFile, string expectedPath, string[] additionalSupportPaths = null) { Cleanup (outputPath); From 5f8562b46c4a441d93f59fda8a5bf1d6a0d5a601 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 17 Jul 2018 21:39:53 +0900 Subject: [PATCH 26/39] [generator] generate appropriate JniPeerMembers for XAJavaInterop1. There were some code that generate XAPeerMembers, while some code generated JniPeerMembers. This change does not fix any bug but makes it consistent. --- tools/generator/JavaInteropCodeGenerator.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/generator/JavaInteropCodeGenerator.cs b/tools/generator/JavaInteropCodeGenerator.cs index 14b437906..2d3e68fd4 100644 --- a/tools/generator/JavaInteropCodeGenerator.cs +++ b/tools/generator/JavaInteropCodeGenerator.cs @@ -56,13 +56,14 @@ protected virtual string GetPeerMembersType () internal override void WriteClassHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - writer.WriteLine ("{0}new static JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));",indent, type.RawJniName, declaringType); + writer.WriteLine ("{0}new static JniPeerMembers _members = new {1} (\"{2}\", typeof ({3}));",indent, GetPeerMembersType (), type.RawJniName, declaringType); } internal override void WriteClassInvokerHandle (ClassGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", + writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new {1} (\"{2}\", typeof ({3}));", indent, + GetPeerMembersType (), type.RawJniName, declaringType); writer.WriteLine (); @@ -78,8 +79,9 @@ internal override void WriteClassInvokerHandle (ClassGen type, TextWriter writer internal override void WriteInterfaceInvokerHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { - writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new JniPeerMembers (\"{1}\", typeof ({2}));", + writer.WriteLine ("{0}internal new static readonly JniPeerMembers _members = new {1} (\"{2}\", typeof ({3}));", indent, + GetPeerMembersType (), type.RawJniName, declaringType); writer.WriteLine (); From 1ec65680c8165a9cd7ce49c641655e7ab0676b8e Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 17 Jul 2018 21:51:07 +0900 Subject: [PATCH 27/39] [generator] For DIM-supported mode, make interfaces implement IJavaPeerable. It is required to initialize JniPeerMembers. Since IJavaPeerable is supported only in JavaInteropCodeGenerator, implement it only in that codegen mode. Since I don't want to make huge changes in the expected test results, the generation change only applies to SupportDefaultInterfaceMethods mode. --- tools/generator/CodeGenerator.cs | 2 ++ tools/generator/InterfaceGen.cs | 2 +- tools/generator/JavaInteropCodeGenerator.cs | 5 +++++ .../DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 81b239173..49026c77b 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -725,6 +725,8 @@ protected CodeGenerator () internal abstract void WriteFieldGetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); internal abstract void WriteFieldSetBody (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type); + internal virtual string GetAllInterfaceImplements () => "IJavaObject"; + internal virtual void WriteField (Field field, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type) { if (field.IsEnumified) diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index e5f102d2f..01aa42f76 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -671,7 +671,7 @@ void GenerateDeclaration (StreamWriter sw, string indent, CodeGenerationOptions if (this.TypeParameters != null && this.TypeParameters.Any ()) sw.WriteLine ("{0}{1}", indent, TypeParameters.ToGeneratedAttributeString ()); sw.WriteLine ("{0}{1} partial interface {2} : {3} {{", indent, Visibility, Name, - Interfaces.Count == 0 || sb.Length == 0 ? "IJavaObject" : sb.ToString ()); + Interfaces.Count == 0 || sb.Length == 0 ? (opt.SupportDefaultInterfaceMethods ? opt.CodeGenerator.GetAllInterfaceImplements () : "IJavaObject") : sb.ToString ()); sw.WriteLine (); GenProperties (sw, indent + "\t", opt); GenMethods (sw, indent + "\t", opt); diff --git a/tools/generator/JavaInteropCodeGenerator.cs b/tools/generator/JavaInteropCodeGenerator.cs index 2d3e68fd4..d7365eae2 100644 --- a/tools/generator/JavaInteropCodeGenerator.cs +++ b/tools/generator/JavaInteropCodeGenerator.cs @@ -54,6 +54,11 @@ protected virtual string GetPeerMembersType () return "JniPeerMembers"; } + internal override string GetAllInterfaceImplements () + { + return "IJavaObject, IJavaPeerable"; + } + internal override void WriteClassHandle (InterfaceGen type, TextWriter writer, string indent, CodeGenerationOptions opt, string declaringType) { writer.WriteLine ("{0}new static JniPeerMembers _members = new {1} (\"{2}\", typeof ({3}));",indent, GetPeerMembersType (), type.RawJniName, declaringType); diff --git a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs index 8e648f622..af1137b35 100644 --- a/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs +++ b/tools/generator/Tests/expected.ji/DefaultInterfaceMethods/Xamarin.Test.ITheInterface.cs @@ -12,7 +12,7 @@ partial interface ITheInterface { // Metadata.xml XPath interface reference: path="/api/package[@name='xamarin.test']/interface[@name='TheInterface']" [Register ("xamarin/test/TheInterface", "", "Xamarin.Test.ITheInterfaceInvoker")] - public partial interface ITheInterface : IJavaObject { + public partial interface ITheInterface : IJavaObject, IJavaPeerable { static Delegate cb_getBar; #pragma warning disable 0169 From ea550793bb92ab7b6df21c1c5b86fc6e2fe33dbe Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 18 Jul 2018 12:29:29 +0900 Subject: [PATCH 28/39] [generator] fix bogus method code generation in interface Extensions class. It was generating code like this: ``` public static partial class IAdapterExtensions { public static string[] GetAutofillOptions (this Android.Widget.IAdapter self, ) ``` --- tools/generator/CodeGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 49026c77b..110ae06ad 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1016,9 +1016,9 @@ public void WriteMethodExtensionOverload (Method method, TextWriter writer, stri string ret = opt.GetOutputName (method.RetVal.FullName.Replace ("Java.Lang.ICharSequence", "string")); writer.WriteLine (); - writer.WriteLine ("{0}public static {1} {2} (this {3} self, {4})", - indent, ret, method.Name, selfType, - GenBase.GetSignature (method, opt).Replace ("Java.Lang.ICharSequence", "string").Replace ("global::string", "string")); + var parameters = GenBase.GetSignature (method, opt).Replace ("Java.Lang.ICharSequence", "string").Replace ("global::string", "string"); + writer.WriteLine ("{0}public static {1} {2} (this {3} self{4}{5})", + indent, ret, method.Name, selfType, parameters.Length > 0 ? ", " : "", parameters); writer.WriteLine ("{0}{{", indent); WriteMethodStringOverloadBody (method, writer, indent + "\t", opt, true); writer.WriteLine ("{0}}}", indent); From 36b57da76b63da4a70b73b88fcc050730966992e Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 18 Jul 2018 16:56:50 +0900 Subject: [PATCH 29/39] [generator] Fix and extend marking of "this is overriding DIM" step. DIMs were not correctly marked as expected - they should be marking only implementors of DIMs. What it was trying instead was just marking anything that matches the signature, in the interfaces. First this change expands the target of marking to class methods, therefore anything that implements DIMs are covered. Then limited the marking targets to only DIMs, not all the iface methods. (The change result for expanding them to classes was disasterous because of this problem.) --- tools/generator/CodeGenerator.cs | 2 +- tools/generator/GenBase.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 110ae06ad..b4f50e7ea 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1076,7 +1076,7 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe bool gen_string_overload = !method.IsOverride && method.Parameters.HasCharSequence && !type.ContainsMethod (name_and_jnisig); string static_arg = method.IsStatic ? " static" : String.Empty; - string virt_ov = method.IsOverride ? " override" : method.IsVirtual ? " virtual" : String.Empty; + string virt_ov = method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.IsInterfaceDefaultMethodOverride ? "/*DIM override*/" : " override") : method.IsVirtual ? " virtual" : String.Empty; if ((string.IsNullOrEmpty (virt_ov) || virt_ov == " virtual") && type.RequiresNew (method.AdjustedName)) { virt_ov = " new" + virt_ov; } diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index d64eafa01..aa558f92c 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -806,9 +806,10 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) } // Interface default methods can be overriden. We want to process them differently. - foreach (Method m in methods.Where (m => m.IsInterfaceDefaultMethod)) { + var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); + foreach (Method m in checkDimOverrideTargets) { foreach (var bt in this.GetAllDerivedInterfaces ()) { - var bm = bt.Methods.FirstOrDefault (mm => mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); + var bm = bt.Methods.FirstOrDefault (mm => !mm.IsAbstract && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); if (bm != null) { m.IsInterfaceDefaultMethodOverride = true; break; From 8eb0b0a1654f07d3eb9fdf1dc8762161c7c062bb Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 18 Jul 2018 20:01:44 +0900 Subject: [PATCH 30/39] [generator] change DIM override marking. For an DIM that overrides another method from its implementing interface, it must be declared explicitly overriding the base interface method (which can be either DIM or non-DIM). To achieve that, we need to store the name of the declaring type of the base method. Also, we cannot "override" static methods, so skip checking that. --- tools/generator/ClassGen.cs | 4 ++-- tools/generator/CodeGenerator.cs | 14 ++++++++++++-- tools/generator/GenBase.cs | 4 ++-- tools/generator/Method.cs | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index 179c14559..8b665f4c5 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -340,7 +340,7 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) .SelectMany (i => i.Methods) .Where (m => m.IsInterfaceDefaultMethod) .Where (m => !ContainsMethod (m, false, false)); - var overrides = defaultMethods.Where (m => m.IsInterfaceDefaultMethodOverride); + var overrides = defaultMethods.Where (m => m.OverriddenInterfaceMethod != null); var overridens = defaultMethods.Where (m => overrides.Where (_ => _.Name == m.Name && _.JniSignature == m.JniSignature) .Any (mm => mm.DeclaringType.GetAllDerivedInterfaces ().Contains (m.DeclaringType))); @@ -350,7 +350,7 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) foreach (Method m in methodsToDeclare) { bool virt = m.IsVirtual; m.IsVirtual = !IsFinal && virt; - if (m.IsAbstract && !m.IsInterfaceDefaultMethodOverride && !m.IsInterfaceDefaultMethod) + if (m.IsAbstract && m.OverriddenInterfaceMethod == null && !m.IsInterfaceDefaultMethod) opt.CodeGenerator.WriteMethodAbstractDeclaration (m, sw, indent, opt, null, this); else opt.CodeGenerator.WriteMethod (m, sw, indent, opt, this, true); diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index b4f50e7ea..ae8c50658 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1076,7 +1076,8 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe bool gen_string_overload = !method.IsOverride && method.Parameters.HasCharSequence && !type.ContainsMethod (name_and_jnisig); string static_arg = method.IsStatic ? " static" : String.Empty; - string virt_ov = method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.IsInterfaceDefaultMethodOverride ? "/*DIM override*/" : " override") : method.IsVirtual ? " virtual" : String.Empty; + bool is_explicit = opt.SupportDefaultInterfaceMethods && type.IsInterface && method.OverriddenInterfaceMethod != null; + string virt_ov = is_explicit ? string.Empty : method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.OverriddenInterfaceMethod != null ? "/*DIM override*/" : " override") : method.IsVirtual ? " virtual" : String.Empty; if ((string.IsNullOrEmpty (virt_ov) || virt_ov == " virtual") && type.RequiresNew (method.AdjustedName)) { virt_ov = " new" + virt_ov; } @@ -1093,7 +1094,16 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe indent, method.JavaName, method.JniSignature, method.IsVirtual ? method.ConnectorName : String.Empty, method.AdditionalAttributeString ()); WriteMethodCustomAttributes (method, writer, indent); string visibility = type.IsInterface ? string.Empty : method.Visibility; - writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6} ({7})", indent, visibility, static_arg, virt_ov, seal, ret, method.AdjustedName, GenBase.GetSignature (method, opt)); + writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6}{7} ({8})", + indent, + visibility, + static_arg, + virt_ov, + seal, + ret, + is_explicit ? method.OverriddenInterfaceMethod.DeclaringType.FullName + '.' : string.Empty, + method.AdjustedName, + GenBase.GetSignature (method, opt)); writer.WriteLine ("{0}{{", indent); WriteMethodBody (method, writer, indent + "\t", opt, type); writer.WriteLine ("{0}}}", indent); diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index aa558f92c..93577b437 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -807,11 +807,11 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) // Interface default methods can be overriden. We want to process them differently. var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); - foreach (Method m in checkDimOverrideTargets) { + foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { foreach (var bt in this.GetAllDerivedInterfaces ()) { var bm = bt.Methods.FirstOrDefault (mm => !mm.IsAbstract && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); if (bm != null) { - m.IsInterfaceDefaultMethodOverride = true; + m.OverriddenInterfaceMethod = bm; break; } } diff --git a/tools/generator/Method.cs b/tools/generator/Method.cs index e22e80770..5a900d552 100644 --- a/tools/generator/Method.cs +++ b/tools/generator/Method.cs @@ -363,7 +363,7 @@ public bool IsOverride { set { is_override = value; } } - public bool IsInterfaceDefaultMethodOverride { get; set; } + public Method OverriddenInterfaceMethod { get; set; } public bool IsVoid { get { return RetVal.JavaName == "void"; } From 74003698e85b2999f8d39355cddd2505642c58ad Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 18 Jul 2018 21:18:46 +0900 Subject: [PATCH 31/39] [generator] explicit DIM needs to specify exactly-declaring type. java.util.Set#spliterator() overrides java.util.Collection#spliterator(), which in turn overrides java.util.Iterator#spliterator(). What should ISet.Spliterator() be like? It used to be: `Java.Util.ISpliterator Java.Util.ICollection.Spliterator() { ... }` It is wrong. ICollection declares Spliterator() like: `Java.Util.ISpliterator Java.Util.IIterable.Spliterator() { ... }` ... so, ISet also has to declare it like this. That is, we have to track all the override chain up to non-overriding declaration. --- tools/generator/CodeGenerator.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index ae8c50658..bb5fa2386 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1063,6 +1063,13 @@ public void WriteMethodExtensionAsyncWrapper (Method method, TextWriter writer, writer.WriteLine (); } + static string GetDeclaringTypeOfExplicitInterfaceMethod (Method method) + { + return method.OverriddenInterfaceMethod != null ? + GetDeclaringTypeOfExplicitInterfaceMethod (method.OverriddenInterfaceMethod) : + method.DeclaringType.FullName; + } + public void WriteMethod (Method method, TextWriter writer, string indent, CodeGenerationOptions opt, GenBase type, bool generate_callbacks) { if (!method.IsValid) @@ -1101,7 +1108,7 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe virt_ov, seal, ret, - is_explicit ? method.OverriddenInterfaceMethod.DeclaringType.FullName + '.' : string.Empty, + is_explicit ? GetDeclaringTypeOfExplicitInterfaceMethod (method.OverriddenInterfaceMethod) + '.' : string.Empty, method.AdjustedName, GenBase.GetSignature (method, opt)); writer.WriteLine ("{0}{{", indent); From 24e0f456642bc984995513d89a1cf10ead70a38e Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 00:35:43 +0900 Subject: [PATCH 32/39] [generator] mark overriding method of non-DIMs in interfaces too. Unlike class methods that "implement" interface methods, interface methods that "override" their implementing interface methods need to be "explicitly" implemented. java.util.PrimitiveIterator.OfDouble#next() is a DIM and implements java.util.Iterator#next(), which then need to be generated as an explicit implementation of Iterator#next(), otherwise its Implementor will not have Iterator#next() implementation (the one from PrimitiveIterator.OfDouble is regarded as an irrelevant method). --- tools/generator/GenBase.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 93577b437..625d6369d 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -809,7 +809,9 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { foreach (var bt in this.GetAllDerivedInterfaces ()) { - var bm = bt.Methods.FirstOrDefault (mm => !mm.IsAbstract && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); + // We mark a method as an override if (1)it is declared in an interface, or (2) if the base method is DIM + // (i.e. we don't mark as override if a class method "implements" normal iface method.) + var bm = bt.Methods.FirstOrDefault (mm => (this.IsInterface || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); if (bm != null) { m.OverriddenInterfaceMethod = bm; break; From b85ecade9ba50b9b63cb7b77969c4b34e2967600 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 00:56:42 +0900 Subject: [PATCH 33/39] [generator] fix excess override marking from the previous change. Marking everything that overrides any base method AND is declared from an interface was too much. AsynchronousFileChannel#close() was regarded as a DIM and therefore its Invoker did not get any Close() method generated, resulting in missing IAsynchronousChannel.Close() implementation. --- tools/generator/GenBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 625d6369d..0ca6f911f 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -809,9 +809,9 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { foreach (var bt in this.GetAllDerivedInterfaces ()) { - // We mark a method as an override if (1)it is declared in an interface, or (2) if the base method is DIM + // We mark a method as an override if (1) it is a DIM, or (2) if the base method is DIM // (i.e. we don't mark as override if a class method "implements" normal iface method.) - var bm = bt.Methods.FirstOrDefault (mm => (this.IsInterface || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); + var bm = bt.Methods.FirstOrDefault (mm => (m.IsInterfaceDefaultMethod || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); if (bm != null) { m.OverriddenInterfaceMethod = bm; break; From 5ffada2925f7af5da4bcfffa054f00c268cac3a2 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 02:31:51 +0900 Subject: [PATCH 34/39] [generator] we need to check all the interfaces "of all the base types". java.util.concurrent.CopyOnWriteArraySet#removeIf() was not marked as overriding Collection#removeIf() because we didn't check the interfaces of all the base types, but only checking the declaring type's. By iterating all those relevant interfaces, now it is correctly marked as an override. --- tools/generator/GenBase.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 0ca6f911f..cbf58753a 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -807,8 +807,12 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) // Interface default methods can be overriden. We want to process them differently. var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); - foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { - foreach (var bt in this.GetAllDerivedInterfaces ()) { + var allIfaces = new List (); + // We need to check all the implemented interfaces of all the base types. + for (var gen = this; gen != null; gen = gen.BaseGen) + gen.GetAllDerivedInterfaces (allIfaces); + foreach (var bt in allIfaces.Distinct ()) { + foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { // We mark a method as an override if (1) it is a DIM, or (2) if the base method is DIM // (i.e. we don't mark as override if a class method "implements" normal iface method.) var bm = bt.Methods.FirstOrDefault (mm => (m.IsInterfaceDefaultMethod || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); From 0e9b0432c079393a26d3f60e85c273b7bef13cfb Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 03:49:50 +0900 Subject: [PATCH 35/39] [generator] fix DIM override lookup loop. The previous change introduced a stupid regression in method lookup loop (which will "break" in the middle, when iterating types for each method it's fine, but when iterating methods for each type it's not.) --- tools/generator/GenBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index cbf58753a..68609b92f 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -807,12 +807,12 @@ public void FixupMethodOverrides (CodeGenerationOptions opt) // Interface default methods can be overriden. We want to process them differently. var checkDimOverrideTargets = opt.SupportDefaultInterfaceMethods ? methods : methods.Where (m => m.IsInterfaceDefaultMethod); - var allIfaces = new List (); // We need to check all the implemented interfaces of all the base types. + var allIfaces = new List (); for (var gen = this; gen != null; gen = gen.BaseGen) gen.GetAllDerivedInterfaces (allIfaces); - foreach (var bt in allIfaces.Distinct ()) { - foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { + foreach (Method m in checkDimOverrideTargets.Where (m => !m.IsStatic)) { + foreach (var bt in allIfaces.Distinct ()) { // We mark a method as an override if (1) it is a DIM, or (2) if the base method is DIM // (i.e. we don't mark as override if a class method "implements" normal iface method.) var bm = bt.Methods.FirstOrDefault (mm => (m.IsInterfaceDefaultMethod || !mm.IsAbstract) && mm.Name == m.Name && ParameterList.Equals (mm.Parameters, m.Parameters)); From bc7400f648f46285711cc21bea00a37731b1bfef Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 16:13:00 +0900 Subject: [PATCH 36/39] [generator] reduce extraneous abstract methods and properties for DIM Invokers. There were cases that an abstract class generated abstract methods and properties for DIMs, which later caused missing implemented members in their Invokers. In Spliterators.AbstractSpliterator, `Comparator` and `ExactSizeIfKnown` properties were regarded as missing in the invoker. --- tools/generator/ClassGen.cs | 4 ++-- tools/generator/InterfaceGen.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/generator/ClassGen.cs b/tools/generator/ClassGen.cs index 8b665f4c5..474d09cd6 100644 --- a/tools/generator/ClassGen.cs +++ b/tools/generator/ClassGen.cs @@ -350,7 +350,7 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt) foreach (Method m in methodsToDeclare) { bool virt = m.IsVirtual; m.IsVirtual = !IsFinal && virt; - if (m.IsAbstract && m.OverriddenInterfaceMethod == null && !m.IsInterfaceDefaultMethod) + if (m.IsAbstract && m.OverriddenInterfaceMethod == null && (opt.SupportDefaultInterfaceMethods || !m.IsInterfaceDefaultMethod)) opt.CodeGenerator.WriteMethodAbstractDeclaration (m, sw, indent, opt, null, this); else opt.CodeGenerator.WriteMethod (m, sw, indent, opt, this, true); @@ -573,7 +573,7 @@ void GenerateInvokerMembers (StreamWriter sw, string indent, CodeGenerationOptio // if (iface.IsGeneric) // continue; GenerateInvoker (sw, iface.Properties.Where (p => !ContainsProperty (p.Name, false, false)), indent, opt, members); - GenerateInvoker (sw, iface.Methods.Where (m => !m.IsInterfaceDefaultMethod && !ContainsMethod (m, false, false) && !IsCovariantMethod (m) && !explicitly_implemented_iface_methods.Contains (m.GetSignature ())), indent, opt, members, iface); + GenerateInvoker (sw, iface.Methods.Where (m => (opt.SupportDefaultInterfaceMethods || !m.IsInterfaceDefaultMethod) && !ContainsMethod (m, false, false) && !IsCovariantMethod (m) && !explicitly_implemented_iface_methods.Contains (m.GetSignature ())), indent, opt, members, iface); } if (BaseGen != null && BaseGen.FullName != "Java.Lang.Object") diff --git a/tools/generator/InterfaceGen.cs b/tools/generator/InterfaceGen.cs index 01aa42f76..76b7c07ac 100644 --- a/tools/generator/InterfaceGen.cs +++ b/tools/generator/InterfaceGen.cs @@ -626,7 +626,7 @@ void GenerateProperty (StreamWriter sw, string indent, CodeGenerationOptions opt // For each interface, generate either an abstract method or an explicit implementation method. public void GenerateAbstractMembers (ClassGen gen, StreamWriter sw, string indent, CodeGenerationOptions opt) { - foreach (Method m in Methods.Where (m => !m.IsInterfaceDefaultMethod && !m.IsStatic)) { + foreach (Method m in Methods.Where (m => (!opt.SupportDefaultInterfaceMethods || !m.IsInterfaceDefaultMethod) && !m.IsStatic)) { bool mapped = false; string sig = m.GetSignature (); if (opt.ContextGeneratedMethods.Any (_ => _.Name == m.Name && _.JniSignature == m.JniSignature)) @@ -644,7 +644,7 @@ public void GenerateAbstractMembers (ClassGen gen, StreamWriter sw, string inden opt.CodeGenerator.WriteMethodAbstractDeclaration (m, sw, indent, opt, this, gen); opt.ContextGeneratedMethods.Add (m); } - foreach (Property prop in Properties.Where (p => !p.Getter.IsStatic)) { + foreach (Property prop in Properties.Where (p => (!opt.SupportDefaultInterfaceMethods || !p.Getter.IsInterfaceDefaultMethod) && !p.Getter.IsStatic)) { if (gen.ContainsProperty (prop.Name, false)) continue; prop.GenerateAbstractDeclaration (sw, indent, opt, gen); From a9145380e7d8a7286aa98d82ed9297087296eb62 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 18:17:39 +0900 Subject: [PATCH 37/39] [generator] add some code comment for future understanding. --- tools/generator/MethodBase.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/generator/MethodBase.cs b/tools/generator/MethodBase.cs index 5e64862bc..7914a551b 100644 --- a/tools/generator/MethodBase.cs +++ b/tools/generator/MethodBase.cs @@ -30,6 +30,10 @@ public abstract string Deprecated { get; } + // FIXME: this is semantically incorrect. A generic method should rather be evaluated as: + // GenericArguments != null && GenericArguments.Count > 0. + // However, changing this part like this causes various build errors especially with Java.Lang.Enum and other various generic parameter resolution, + // so we should leave this as is (maybe renaming this is an option, in case we want keep using this generator). public virtual bool IsGeneric { get { return parms.HasGeneric; } } From a6253f7a62ed0f194274d97810da7886941aedff Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 22:34:10 +0900 Subject: [PATCH 38/39] [generator] makr as DIM overrides as `virtual`. There were handful of ABI compatibility regressions that DIM overrides are marked as final. They are intended to be kept virtual, so explicitly mark them as virtual. Although they should be virtual (DIM specification-wise). --- tools/generator/CodeGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index bb5fa2386..8056a471c 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1084,7 +1084,7 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe string static_arg = method.IsStatic ? " static" : String.Empty; bool is_explicit = opt.SupportDefaultInterfaceMethods && type.IsInterface && method.OverriddenInterfaceMethod != null; - string virt_ov = is_explicit ? string.Empty : method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.OverriddenInterfaceMethod != null ? "/*DIM override*/" : " override") : method.IsVirtual ? " virtual" : String.Empty; + string virt_ov = is_explicit ? string.Empty : method.IsOverride ? (opt.SupportDefaultInterfaceMethods && method.OverriddenInterfaceMethod != null ? "/*DIM override*/ virtual" : " override") : method.IsVirtual ? " virtual" : String.Empty; if ((string.IsNullOrEmpty (virt_ov) || virt_ov == " virtual") && type.RequiresNew (method.AdjustedName)) { virt_ov = " new" + virt_ov; } From e6be186c23f0843a1774bafe450f535be7129128 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Thu, 19 Jul 2018 23:04:00 +0900 Subject: [PATCH 39/39] [generator] bring back static methods in the public API. We were marking interface methods too much as non-public. Static methods in the interfaces are generated in C# classes and they should remain public! --- tools/generator/CodeGenerator.cs | 2 +- tools/generator/GenBase.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/generator/CodeGenerator.cs b/tools/generator/CodeGenerator.cs index 8056a471c..e7f94c984 100644 --- a/tools/generator/CodeGenerator.cs +++ b/tools/generator/CodeGenerator.cs @@ -1100,7 +1100,7 @@ public void WriteMethod (Method method, TextWriter writer, string indent, CodeGe writer.WriteLine ("{0}[Register (\"{1}\", \"{2}\", \"{3}\"{4})]", indent, method.JavaName, method.JniSignature, method.IsVirtual ? method.ConnectorName : String.Empty, method.AdditionalAttributeString ()); WriteMethodCustomAttributes (method, writer, indent); - string visibility = type.IsInterface ? string.Empty : method.Visibility; + string visibility = type.IsInterface && !method.IsStatic ? string.Empty : method.Visibility; writer.WriteLine ("{0}{1}{2}{3}{4} unsafe {5} {6}{7} ({8})", indent, visibility, diff --git a/tools/generator/GenBase.cs b/tools/generator/GenBase.cs index 68609b92f..c29910d1a 100644 --- a/tools/generator/GenBase.cs +++ b/tools/generator/GenBase.cs @@ -795,7 +795,7 @@ protected virtual bool GetEnumMappedMemberInfo () public void FixupMethodOverrides (CodeGenerationOptions opt) { - foreach (Method m in methods.Where (m => !m.IsInterfaceDefaultMethod)) { + foreach (Method m in methods.Where (m => !m.IsStatic && !m.IsInterfaceDefaultMethod)) { for (var bt = this.GetBaseGen (opt); bt != null; bt = bt.GetBaseGen (opt)) { var bm = bt.Methods.FirstOrDefault (mm => mm.Name == m.Name && mm.Visibility == m.Visibility && ParameterList.Equals (mm.Parameters, m.Parameters)); if (bm != null && bm.RetVal.FullName == m.RetVal.FullName) { // if return type is different, it could be still "new", not "override".