diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs index 15612302e..7b6b2d484 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs @@ -28,6 +28,7 @@ // using System; +using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.IO; @@ -62,20 +63,28 @@ public class DirectoryAssemblyResolver : IAssemblyResolver { Dictionary cache; bool loadDebugSymbols; - Action logWarnings; + Action logger; ReaderParameters loadReaderParameters; static readonly ReaderParameters DefaultLoadReaderParameters = new ReaderParameters { }; + [Obsolete ("Use DirectoryAssemblyResolver(Action, bool, ReaderParameters)")] public DirectoryAssemblyResolver (Action logWarnings, bool loadDebugSymbols, ReaderParameters loadReaderParameters = null) + : this ((TraceLevel level, string value) => logWarnings?.Invoke ("{0}", new[]{value}), loadDebugSymbols, loadReaderParameters) { if (logWarnings == null) throw new ArgumentNullException (nameof (logWarnings)); + } + + public DirectoryAssemblyResolver (Action logger, bool loadDebugSymbols, ReaderParameters loadReaderParameters = null) + { + if (logger == null) + throw new ArgumentNullException (nameof (logger)); cache = new Dictionary (); this.loadDebugSymbols = loadDebugSymbols; - this.logWarnings = logWarnings; + this.logger = logger; SearchDirectories = new List (); this.loadReaderParameters = loadReaderParameters ?? DefaultLoadReaderParameters; } @@ -141,10 +150,10 @@ protected virtual AssemblyDefinition ReadAssembly (string file) try { return AssemblyDefinition.ReadAssembly (file, reader_parameters); } catch (Exception ex) { - logWarnings ( - "Failed to read '{0}' with debugging symbols. Retrying to load it without it. Error details are logged below.", - new [] { file }); - logWarnings ("{0}", new [] { ex.ToString () }); + logger ( + TraceLevel.Warning, + $"Failed to read '{file}' with debugging symbols. Retrying to load it without it. Error details are logged below."); + logger (TraceLevel.Warning, $"{ex.ToString ()}"); reader_parameters.ReadSymbols = false; return AssemblyDefinition.ReadAssembly (file, reader_parameters); } diff --git a/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs b/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs index 6b196d5e0..9f2e132dd 100644 --- a/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs +++ b/src/Java.Interop.Tools.Diagnostics/Java.Interop.Tools.Diagnostics/Diagnostic.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using Mono.Cecil.Cil; @@ -27,14 +28,14 @@ namespace Java.Interop.Tools.Diagnostics { // XA0013 Profiling support requires sgen to be enabled too // XA0014 iOS {0} does not support building applications targeting ARMv6 // XA0020 Could not launch mandroid daemon. - + // XA0100 EmbeddedNativeLibrary '{0}' is invalid in Android Application project. Please use AndroidNativeLibrary instead. // XA0101 @(Content) build action is not supported // XA0102 Lint Warning // XA0103 Lint Error // XA0104 Invalid Sequence Point mode // XA0105 The TargetFrameworkVersion for {0} (v{1}) is greater than the TargetFrameworkVersion for your project (v{2}). You need to increase the TargetFrameworkVersion for your project. - + // XA1xxx file copy / symlinks (project related) // XA10xx installer.cs / mtouch.cs // XA1001 Could not find an application at the specified directory @@ -101,6 +102,7 @@ namespace Java.Interop.Tools.Diagnostics { // XA4209 Failed to create JavaTypeInfo for class: {0} due to {1} // XA4210 "You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute." // XA4211 AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{1} for ACW compilation. + // XA4212 Type `{0}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported. // XA5xxx GCC and toolchain // XA32xx .apk generation // XA4300 Unsupported $(AndroidSupportedAbis) value '{0}'; ignoring. @@ -176,6 +178,17 @@ public static void WriteTo (System.IO.TextWriter destination, Exception message, destination.WriteLine ("monodroid: error XA0000: Unexpected error - Please file a bug report at http://bugzilla.xamarin.com. Reason: {0}", verbose ? message.Message : message.ToString ()); } + + public static Action CreateConsoleLogger () + { + Action logger = (level, value) => { + if (level == TraceLevel.Error) + Console.Error.WriteLine (value); + else + Console.WriteLine (value); + }; + return logger; + } } } diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs index 3e4d70b52..5613fa312 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using Mono.Cecil; @@ -10,10 +11,19 @@ namespace Java.Interop.Tools.JavaCallableWrappers { - public static class JavaTypeScanner + public class JavaTypeScanner { - // Returns all types for which we need to generate Java delegate types. - public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log) + public Action Logger { get; private set; } + public bool ErrorOnCustomJavaObject { get; set; } + + public JavaTypeScanner (Action logger) + { + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + Logger = logger; + } + + public List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver) { var javaTypes = new List (); @@ -22,7 +32,7 @@ public static List GetJavaTypes (IEnumerable assemblies, foreach (ModuleDefinition md in assm.Modules) { foreach (TypeDefinition td in md.Types) { - AddJavaTypes (javaTypes, td, log); + AddJavaTypes (javaTypes, td); } } } @@ -30,16 +40,18 @@ public static List GetJavaTypes (IEnumerable assemblies, return javaTypes; } - static void AddJavaTypes (List javaTypes, TypeDefinition type, Action log) + void AddJavaTypes (List javaTypes, TypeDefinition type) { if (type.IsSubclassOf ("Java.Lang.Object") || type.IsSubclassOf ("Java.Lang.Throwable")) { // For subclasses of e.g. Android.App.Activity. javaTypes.Add (type); } else if (type.IsClass && !type.IsSubclassOf ("System.Exception") && type.ImplementsInterface ("Android.Runtime.IJavaObject")) { - log ( - "Type '{0}' implements Android.Runtime.IJavaObject but does not inherit from Java.Lang.Object. It is not supported.", - new [] { type.FullName }); + var level = ErrorOnCustomJavaObject ? TraceLevel.Error : TraceLevel.Warning; + var prefix = ErrorOnCustomJavaObject ? "error" : "warning"; + Logger ( + level, + $"{prefix} XA412: Type `{type.FullName}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported."); return; } @@ -47,7 +59,7 @@ static void AddJavaTypes (List javaTypes, TypeDefinition type, A return; foreach (TypeDefinition nested in type.NestedTypes) - AddJavaTypes (javaTypes, nested, log); + AddJavaTypes (javaTypes, nested); } public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type) @@ -64,6 +76,11 @@ public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type) return false; } - + // Returns all types for which we need to generate Java delegate types. + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log) + { + Action l = (level, value) => log ("{0}", new string [] { value }); + return new JavaTypeScanner (l).GetJavaTypes (assemblies, resolver); + } } } diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs index c31834e81..c5b196b96 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Collections.Generic; using System.Linq; @@ -56,18 +57,27 @@ namespace Java.Interop.Tools.JavaCallableWrappers { */ public class TypeNameMapGenerator : IDisposable { - Action Log; + Action Log; List Types; DirectoryAssemblyResolver Resolver; + JavaTypeScanner Scanner; + [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action)")] public TypeNameMapGenerator (IEnumerable assemblies, Action logMessage) + : this (assemblies, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new[]{value})) { - if (assemblies == null) - throw new ArgumentNullException ("assemblies"); if (logMessage == null) throw new ArgumentNullException (nameof (logMessage)); + } - Log = logMessage; + public TypeNameMapGenerator (IEnumerable assemblies, Action logger) + { + if (assemblies == null) + throw new ArgumentNullException ("assemblies"); + if (logger == null) + throw new ArgumentNullException (nameof (logger)); + + Log = logger; var Assemblies = assemblies.ToList (); var rp = new ReaderParameters (); @@ -83,17 +93,28 @@ public TypeNameMapGenerator (IEnumerable assemblies, Action, Action)")] public TypeNameMapGenerator (IEnumerable types, Action logMessage) + : this (types, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new [] { value })) { - if (types == null) - throw new ArgumentNullException ("types"); if (logMessage == null) throw new ArgumentNullException (nameof (logMessage)); + } + + public TypeNameMapGenerator (IEnumerable types, Action logger) + { + if (types == null) + throw new ArgumentNullException ("types"); + if (logger == null) + throw new ArgumentNullException (nameof (logger)); - Log = logMessage; + Log = logger; Types = types.ToList (); } @@ -112,11 +133,6 @@ protected virtual void Dispose (bool disposing) Resolver = null; } - void LogWarning (string format, params object[] args) - { - Log (format, args); - } - public void WriteJavaToManaged (Stream output) { if (output == null) @@ -160,10 +176,10 @@ Dictionary GetTypeMapping (Func skipType, } } foreach (var e in aliases.OrderBy (e => e.Key)) { - LogWarning ("Mapping for type '{0}' is ambiguous between {1} types.", e.Key, e.Value.Count); - LogWarning (" Using: {0}", e.Value.First ()); + Log (TraceLevel.Warning, $"Mapping for type '{e.Key}' is ambiguous between {e.Value.Count} types."); + Log (TraceLevel.Warning, $" Using: {e.Value.First ()}"); foreach (var o in e.Value.Skip (1)) { - LogWarning (" Ignoring: {0}", o); + Log (TraceLevel.Info, $" Ignoring: {o}"); } } return typeMap.ToDictionary (e => e.Key, e => value (e.Value)); diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs index 1949e9b68..b9087f852 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Test/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGeneratorTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -9,6 +10,7 @@ using NUnit.Framework; using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; using Java.Interop.Tools.JavaCallableWrappers; using Android.App; @@ -24,16 +26,25 @@ public class TypeNameMapGeneratorTests public void ConstructorExceptions () { Action logger = (f, o) => { }; - Assert.Throws (() => new TypeNameMapGenerator ((string [])null, logger)); - Assert.Throws (() => new TypeNameMapGenerator ((TypeDefinition [])null, logger)); - Assert.Throws (() => new TypeNameMapGenerator (new string [0], null)); - Assert.Throws (() => new TypeNameMapGenerator (new TypeDefinition [0], null)); + Action nullLogger = null; + Action levelLogger = (l, v) => { }; + Action nullLevelLogger = null; + Assert.Throws (() => new TypeNameMapGenerator ((string []) null, levelLogger)); + Assert.Throws (() => new TypeNameMapGenerator ((TypeDefinition []) null, levelLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new string [0], nullLevelLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLevelLogger)); +#pragma warning disable 0618 + Assert.Throws (() => new TypeNameMapGenerator ((string []) null, logger)); + Assert.Throws (() => new TypeNameMapGenerator ((TypeDefinition []) null, logger)); + Assert.Throws (() => new TypeNameMapGenerator (new string [0], nullLogger)); + Assert.Throws (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLogger)); +#pragma warning restore 0618 } [Test] public void WriteJavaToManaged () { - var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logMessage: Console.WriteLine); + var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logger: Diagnostic.CreateConsoleLogger ()); var o = new MemoryStream (); v.WriteJavaToManaged (o); var a = ToArray (o); @@ -97,7 +108,7 @@ static string GetEntryPart (string value, int length) [Test] public void WriteManagedToJava () { - var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logMessage: Console.WriteLine); + var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logger: Diagnostic.CreateConsoleLogger ()); var o = new MemoryStream (); v.WriteManagedToJava (o); var a = ToArray (o); diff --git a/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml b/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml index 900383c77..9cc8523bc 100644 --- a/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml +++ b/src/Java.Interop/Documentation/Java.Interop/IJavaPeerable.xml @@ -314,7 +314,7 @@ partial class ExampleBinding { Set the value returned by PeerReference. - + A which contains the value that future invocations of the diff --git a/tools/jcw-gen/App.cs b/tools/jcw-gen/App.cs index 8de3ac526..a29adb2ab 100644 --- a/tools/jcw-gen/App.cs +++ b/tools/jcw-gen/App.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics; using System.Linq; using System.IO; using System.Threading.Tasks; using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.Diagnostics; using Java.Interop.Tools.JavaCallableWrappers; using Mono.Cecil; using Mono.Options; @@ -41,6 +43,7 @@ public static int Main (string [] args) "Show this message and exit", v => help = v != null }, }; + var scanner = new JavaTypeScanner (Diagnostic.CreateConsoleLogger ()); try { var assemblies = options.Parse (args); if (assemblies.Count == 0 || outputPath == null || help) { @@ -60,7 +63,7 @@ public static int Main (string [] args) resolver.SearchDirectories.Add (Path.GetDirectoryName (assembly)); resolver.Load (assembly); } - var types = JavaTypeScanner.GetJavaTypes (assemblies, resolver, log: Console.WriteLine) + var types = scanner.GetJavaTypes (assemblies, resolver) .Where (td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td)); foreach (var type in types) { GenerateJavaCallableWrapper (type, outputPath);