From 5f8d44d662fd1f67dc562ee39452be0d79b7457c Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 18 May 2021 20:25:24 -0400 Subject: [PATCH] [Java.Interop.Tools.*] IMetadataResolver not TypeDefinitionCache Context: b81cfbb9ab8efa647a3bfcc2b2b97a5f1b1fa71e Context: https://github.com/xamarin/xamarin-android/pull/5748 Context: https://github.com/xamarin/xamarin-android/pull/5748#discussion_r634716239 Commit b81cfbb9 introduced `TypeDefinitionCache`, which caches `TypeReference.Resolve()` invocations so as to speed things up. Enter xamarin/xamarin-android#5748: we want to adopt some linker API changes, and mono/linker's [`LinkContext` API][0] *also* has a `TypeDefinition` cache construct. Consequently, to "fully embrace" the new `LinkContext` API changes, *large portions* of `Java.Interop.Tools.Cecil.dll` are copied so that `LinkContext`'s caching can be used instead of `TypeDefinitionCache`'s caching, because mono/linker doesn't use Java.Interop, and thus can't use `TypeDefinitionCache`. Clean this up and split the difference: "duplicate" the APIs in `Java.Interop.Tools.Cecil.dll`, `Java.Interop.Tools.JavaCallableWrappers.dll`, and `src/Java.Interop.Tools.TypeNameMappings` so that instead of optionally using `TypeDefinitionCache`, we instead permit the use of the [`Mono.Cecil.IMetadataResolver` interface][1], which is a "superset" of `TypeDefinitionCache` functionality. Update `TypeDefinitionCache` to implement the `IMetadataResolver` interface, implementing `IMetadataResolver.Resolve()` so that previous caching functionality is preserved. This *should* result in no breakage of existing xamarin-android code, while allowing for a reasonable integration point between `Java.Interop.Tools.Cecil.dll` and mono/linker, by way of `IMetadataResolver`. [0]: https://github.com/mono/linker/blob/30f2498c2a3de1f7e236d5793f5f1aca6e5ba456/src/linker/Linker/LinkContext.cs [1]: https://github.com/mono/cecil/blob/e069cd8d25d5b61b0e28fe65e75959c20af7aa80/Mono.Cecil/MetadataResolver.cs#L22-L26 --- .../MethodDefinitionRocks.cs | 37 ++++--- .../TypeDefinitionCache.cs | 28 ++++- .../TypeDefinitionRocks.cs | 86 +++++++++------ .../JavaCallableWrapperGenerator.cs | 23 ++-- .../JavaTypeScanner.cs | 27 +++-- .../TypeNameMapGenerator.cs | 27 +++-- .../JavaNativeTypeManager.cs | 100 ++++++++++++------ 7 files changed, 224 insertions(+), 104 deletions(-) diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs index 74855f52e..9b9ae0974 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs @@ -11,19 +11,22 @@ public static class MethodDefinitionRocks { [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => - GetBaseDefinition (method, cache: null); + GetBaseDefinition (method, resolver: null); - public static MethodDefinition GetBaseDefinition (this MethodDefinition method, TypeDefinitionCache? cache) + public static MethodDefinition GetBaseDefinition (this MethodDefinition method, TypeDefinitionCache? cache) => + GetBaseDefinition (method, (IMetadataResolver?) cache); + + public static MethodDefinition GetBaseDefinition (this MethodDefinition method, IMetadataResolver? resolver) { if (method.IsStatic || method.IsNewSlot || !method.IsVirtual) return method; - foreach (var baseType in method.DeclaringType.GetBaseTypes (cache)) { + foreach (var baseType in method.DeclaringType.GetBaseTypes (resolver)) { foreach (var m in baseType.Methods) { if (!m.IsConstructor && m.Name == method.Name && (m.IsVirtual || m.IsAbstract) && - AreParametersCompatibleWith (m.Parameters, method.Parameters, cache)) { + AreParametersCompatibleWith (m.Parameters, method.Parameters, resolver)) { return m; } } @@ -33,14 +36,17 @@ public static MethodDefinition GetBaseDefinition (this MethodDefinition method, [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit) => - GetOverriddenMethods (method, inherit, cache: null); + GetOverriddenMethods (method, inherit, resolver: null); + + public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit, TypeDefinitionCache? cache) => + GetOverriddenMethods (method, inherit, (IMetadataResolver?) cache); - public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit, TypeDefinitionCache? cache) + public static IEnumerable GetOverriddenMethods (MethodDefinition method, bool inherit, IMetadataResolver? resolver) { yield return method; if (inherit) { MethodDefinition baseMethod = method; - while ((baseMethod = method.GetBaseDefinition (cache)) != null && baseMethod != method) { + while ((baseMethod = method.GetBaseDefinition (resolver)) != null && baseMethod != method) { yield return method; method = baseMethod; } @@ -49,9 +55,12 @@ public static IEnumerable GetOverriddenMethods (MethodDefiniti [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool AreParametersCompatibleWith (this Collection a, Collection b) => - AreParametersCompatibleWith (a, b, cache: null); + AreParametersCompatibleWith (a, b, resolver: null); + + public static bool AreParametersCompatibleWith (this Collection a, Collection b, TypeDefinitionCache? cache) => + AreParametersCompatibleWith (a, b, (IMetadataResolver?) cache); - public static bool AreParametersCompatibleWith (this Collection a, Collection b, TypeDefinitionCache? cache) + public static bool AreParametersCompatibleWith (this Collection a, Collection b, IMetadataResolver? resolver) { if (a.Count != b.Count) return false; @@ -60,13 +69,13 @@ public static bool AreParametersCompatibleWith (this Collection /// A class for caching lookups from TypeReference -> TypeDefinition. /// Generally its lifetime should match an AssemblyResolver instance. /// - public class TypeDefinitionCache + public class TypeDefinitionCache : IMetadataResolver { - readonly Dictionary cache = new Dictionary (); + readonly Dictionary types = new Dictionary (); + readonly Dictionary fields = new Dictionary (); + readonly Dictionary methods = new Dictionary (); - public virtual TypeDefinition Resolve (TypeReference typeReference) + public virtual TypeDefinition? Resolve (TypeReference typeReference) { - if (cache.TryGetValue (typeReference, out var typeDefinition)) + if (types.TryGetValue (typeReference, out var typeDefinition)) return typeDefinition; - return cache [typeReference] = typeReference.Resolve (); + return types [typeReference] = typeReference.Resolve (); + } + + public virtual FieldDefinition? Resolve (FieldReference field) + { + if (fields.TryGetValue (field, out var fieldDefinition)) + return fieldDefinition; + return fields [field] = field.Resolve (); + } + + public virtual MethodDefinition? Resolve (MethodReference method) + { + if (methods.TryGetValue (method, out var methodDefinition)) + return methodDefinition; + return methods [method] = method.Resolve (); } } } diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs index 962912a6a..681d4efbb 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs @@ -9,62 +9,74 @@ public static class TypeDefinitionRocks { [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static TypeDefinition? GetBaseType (this TypeDefinition type) => - GetBaseType (type, cache: null); + GetBaseType (type, resolver: null); - public static TypeDefinition? GetBaseType (this TypeDefinition type, TypeDefinitionCache? cache) + public static TypeDefinition? GetBaseType (this TypeDefinition type, TypeDefinitionCache? cache) => + GetBaseType (type, (IMetadataResolver?) cache); + + public static TypeDefinition? GetBaseType (this TypeDefinition type, IMetadataResolver? resolver) { var bt = type.BaseType; if (bt == null) return null; - if (cache != null) - return cache.Resolve (bt); + if (resolver != null) + return resolver.Resolve (bt); return bt.Resolve (); } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type) => - GetTypeAndBaseTypes (type, cache: null); + GetTypeAndBaseTypes (type, resolver: null); + + public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type, TypeDefinitionCache? cache) => + GetTypeAndBaseTypes (type, (IMetadataResolver?) cache); - public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type, TypeDefinitionCache? cache) + public static IEnumerable GetTypeAndBaseTypes (this TypeDefinition type, IMetadataResolver? resolver) { TypeDefinition? t = type; while (t != null) { yield return t; - t = t.GetBaseType (cache); + t = t.GetBaseType (resolver); } } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static IEnumerable GetBaseTypes (this TypeDefinition type) => - GetBaseTypes (type, cache: null); + GetBaseTypes (type, resolver: null); - public static IEnumerable GetBaseTypes (this TypeDefinition type, TypeDefinitionCache? cache) + public static IEnumerable GetBaseTypes (this TypeDefinition type, TypeDefinitionCache? cache) => + GetBaseTypes (type, (IMetadataResolver?) cache); + + public static IEnumerable GetBaseTypes (this TypeDefinition type, IMetadataResolver? resolver) { TypeDefinition? t = type; - while ((t = t.GetBaseType (cache)) != null) { + while ((t = t.GetBaseType (resolver)) != null) { yield return t; } } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool IsAssignableFrom (this TypeReference type, TypeReference c) => - IsAssignableFrom (type, c, cache: null); + IsAssignableFrom (type, c, resolver: null); + + public static bool IsAssignableFrom (this TypeReference type, TypeReference c, TypeDefinitionCache? cache) => + IsAssignableFrom (type, c, (IMetadataResolver?) cache); - public static bool IsAssignableFrom (this TypeReference type, TypeReference c, TypeDefinitionCache? cache) + public static bool IsAssignableFrom (this TypeReference type, TypeReference c, IMetadataResolver? resolver) { if (type.FullName == c.FullName) return true; - var d = c.Resolve (); + var d = (resolver?.Resolve (c)) ?? c.Resolve (); if (d == null) return false; - foreach (var t in d.GetTypeAndBaseTypes (cache)) { + foreach (var t in d.GetTypeAndBaseTypes (resolver)) { if (type.FullName == t.FullName) return true; foreach (var ifaceImpl in t.Interfaces) { var i = ifaceImpl.InterfaceType; - if (IsAssignableFrom (type, i, cache)) + if (IsAssignableFrom (type, i, resolver)) return true; } } @@ -73,11 +85,13 @@ public static bool IsAssignableFrom (this TypeReference type, TypeReference c, T [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool IsSubclassOf (this TypeDefinition type, string typeName) => - IsSubclassOf (type, typeName, cache: null); + IsSubclassOf (type, typeName, resolver: null); - public static bool IsSubclassOf (this TypeDefinition type, string typeName, TypeDefinitionCache? cache) + public static bool IsSubclassOf (this TypeDefinition type, string typeName, TypeDefinitionCache? cache) => + IsSubclassOf (type, typeName, (IMetadataResolver?) cache); + public static bool IsSubclassOf (this TypeDefinition type, string typeName, IMetadataResolver? resolver) { - foreach (var t in type.GetTypeAndBaseTypes (cache)) { + foreach (var t in type.GetTypeAndBaseTypes (resolver)) { if (t.FullName == typeName) { return true; } @@ -87,11 +101,14 @@ public static bool IsSubclassOf (this TypeDefinition type, string typeName, Type [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool ImplementsInterface (this TypeDefinition type, string interfaceName) => - ImplementsInterface (type, interfaceName, cache: null); + ImplementsInterface (type, interfaceName, resolver: null); - public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, TypeDefinitionCache? cache) + public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, TypeDefinitionCache? cache) => + ImplementsInterface (type, interfaceName, (IMetadataResolver?) cache); + + public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, IMetadataResolver? resolver) { - foreach (var t in type.GetTypeAndBaseTypes (cache)) { + foreach (var t in type.GetTypeAndBaseTypes (resolver)) { foreach (var i in t.Interfaces) { if (i.InterfaceType.FullName == interfaceName) { return true; @@ -103,34 +120,43 @@ public static bool ImplementsInterface (this TypeDefinition type, string interfa [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string GetPartialAssemblyName (this TypeReference type) => - GetPartialAssemblyName (type, cache: null); + GetPartialAssemblyName (type, resolver: null); + + public static string GetPartialAssemblyName (this TypeReference type, TypeDefinitionCache? cache) => + GetPartialAssemblyName (type, (IMetadataResolver?) cache); - public static string GetPartialAssemblyName (this TypeReference type, TypeDefinitionCache? cache) + public static string GetPartialAssemblyName (this TypeReference type, IMetadataResolver? resolver) { - TypeDefinition def = cache != null ? cache.Resolve (type) : type.Resolve (); + TypeDefinition? def = (resolver?.Resolve (type)) ?? type.Resolve (); return (def ?? type).Module.Assembly.Name.Name; } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string GetPartialAssemblyQualifiedName (this TypeReference type) => - GetPartialAssemblyQualifiedName (type, cache: null); + GetPartialAssemblyQualifiedName (type, resolver: null); - public static string GetPartialAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache? cache) + public static string GetPartialAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache? cache) => + GetPartialAssemblyQualifiedName (type, (IMetadataResolver?) cache); + + public static string GetPartialAssemblyQualifiedName (this TypeReference type, IMetadataResolver? resolver) { return string.Format ("{0}, {1}", // Cecil likes to use '/' as the nested type separator, while // Reflection uses '+' as the nested type separator. Use Reflection. type.FullName.Replace ('/', '+'), - type.GetPartialAssemblyName (cache)); + type.GetPartialAssemblyName (resolver)); } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string GetAssemblyQualifiedName (this TypeReference type) => - GetAssemblyQualifiedName (type, cache: null); + GetAssemblyQualifiedName (type, resolver: null); + + public static string GetAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache? cache) => + GetAssemblyQualifiedName (type, (IMetadataResolver?) cache); - public static string GetAssemblyQualifiedName (this TypeReference type, TypeDefinitionCache? cache) + public static string GetAssemblyQualifiedName (this TypeReference type, IMetadataResolver? resolver) { - TypeDefinition def = cache != null ? cache.Resolve (type) : type.Resolve (); + TypeDefinition? def = (resolver?.Resolve (type)) ?? type.Resolve (); return string.Format ("{0}, {1}", // Cecil likes to use '/' as the nested type separator, while // Reflection uses '+' as the nested type separator. Use Reflection. diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs index c2207e3b1..7b0cea79f 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs @@ -23,11 +23,11 @@ namespace Java.Interop.Tools.JavaCallableWrappers { public class JavaCallableWrapperGenerator { class JavaFieldInfo { - public JavaFieldInfo (MethodDefinition method, string fieldName, TypeDefinitionCache cache) + public JavaFieldInfo (MethodDefinition method, string fieldName, IMetadataResolver resolver) { this.FieldName = fieldName; InitializerName = method.Name; - TypeName = JavaNativeTypeManager.ReturnTypeFromSignature (GetJniSignature (method, cache)).Type; + TypeName = JavaNativeTypeManager.ReturnTypeFromSignature (GetJniSignature (method, resolver)).Type; IsStatic = method.IsStatic; Access = method.Attributes & MethodAttributes.MemberAccessMask; Annotations = GetAnnotationsString ("\t", method.CustomAttributes); @@ -54,15 +54,20 @@ public string GetJavaAccess () List methods = new List (); List ctors = new List (); List children; - readonly TypeDefinitionCache cache; + readonly IMetadataResolver cache; [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public JavaCallableWrapperGenerator (TypeDefinition type, Action log) - : this (type, null, log, cache: null) + : this (type, null, log, resolver: null) { } public JavaCallableWrapperGenerator (TypeDefinition type, Action log, TypeDefinitionCache cache) - : this (type, null, log, cache) + : this (type, log, (IMetadataResolver) cache) + { + } + + public JavaCallableWrapperGenerator (TypeDefinition type, Action log, IMetadataResolver resolver) + : this (type, null, log, resolver) { if (type.HasNestedTypes) { children = new List (); @@ -103,11 +108,11 @@ void AddNestedTypes (TypeDefinition type) HasExport |= children.Any (t => t.HasExport); } - JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action log, TypeDefinitionCache cache) + JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action log, IMetadataResolver resolver) { this.type = type; this.log = log; - this.cache = cache ?? new TypeDefinitionCache (); + this.cache = resolver ?? new TypeDefinitionCache (); if (type.IsEnum || type.IsInterface || type.IsValueType) Diagnostic.Error (4200, LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4200, type.FullName); @@ -655,7 +660,7 @@ public Signature (MethodDefinition method, RegisterAttribute register, string ma Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes); } - public Signature (MethodDefinition method, ExportAttribute export, TypeDefinitionCache cache) + public Signature (MethodDefinition method, ExportAttribute export, IMetadataResolver cache) : this (method.Name, GetJniSignature (method, cache), "__export__", null, null, export.SuperArgumentsString) { IsExport = true; @@ -666,7 +671,7 @@ public Signature (MethodDefinition method, ExportAttribute export, TypeDefinitio Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes); } - public Signature (MethodDefinition method, ExportFieldAttribute exportField, TypeDefinitionCache cache) + public Signature (MethodDefinition method, ExportFieldAttribute exportField, IMetadataResolver cache) : this (method.Name, GetJniSignature (method, cache), "__export__", null, null, null) { if (method.HasParameters) 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 23694b7a3..18f34d435 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 @@ -16,14 +16,19 @@ public class JavaTypeScanner public Action Logger { get; private set; } public bool ErrorOnCustomJavaObject { get; set; } - readonly TypeDefinitionCache cache; + readonly IMetadataResolver cache; [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public JavaTypeScanner (Action logger) - : this (logger, cache: null) + : this (logger, resolver: null) { } public JavaTypeScanner (Action logger, TypeDefinitionCache cache) + : this (logger, (IMetadataResolver) cache) + { + } + + public JavaTypeScanner (Action logger, IMetadataResolver resolver) { if (logger == null) throw new ArgumentNullException (nameof (logger)); @@ -73,11 +78,14 @@ void AddJavaTypes (List javaTypes, TypeDefinition type) [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type) => - ShouldSkipJavaCallableWrapperGeneration (type, cache: null); + ShouldSkipJavaCallableWrapperGeneration (type, resolver: null); - public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, TypeDefinitionCache cache) + public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, TypeDefinitionCache cache) => + ShouldSkipJavaCallableWrapperGeneration (type, (IMetadataResolver) cache); + + public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, IMetadataResolver resolver) { - if (JavaNativeTypeManager.IsNonStaticInnerClass (type, cache)) + if (JavaNativeTypeManager.IsNonStaticInnerClass (type, resolver)) return true; foreach (var r in type.GetCustomAttributes (typeof (global::Android.Runtime.RegisterAttribute))) { @@ -92,13 +100,16 @@ public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type, [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log) => - GetJavaTypes (assemblies, resolver, log, cache: null); + GetJavaTypes (assemblies, resolver, log, metadataResolver: null); // Returns all types for which we need to generate Java delegate types. - public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log, TypeDefinitionCache cache) + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log, TypeDefinitionCache cache) => + GetJavaTypes (assemblies, resolver, log, (IMetadataResolver) cache); + + public static List GetJavaTypes (IEnumerable assemblies, IAssemblyResolver resolver, Action log, IMetadataResolver metadataResolver) { Action l = (level, value) => log ("{0}", new string [] { value }); - return new JavaTypeScanner (l, cache).GetJavaTypes (assemblies, resolver); + return new JavaTypeScanner (l, metadataResolver).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 8c3009337..4ad4c92a5 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 @@ -61,11 +61,11 @@ public class TypeNameMapGenerator : IDisposable { List Types; DirectoryAssemblyResolver Resolver; JavaTypeScanner Scanner; - readonly TypeDefinitionCache Cache; + readonly IMetadataResolver Cache; [Obsolete ("Use TypeNameMapGenerator(IEnumerable, Action, TypeDefinitionCache)")] public TypeNameMapGenerator (IEnumerable assemblies, Action logMessage) - : this (assemblies, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new[]{value}), cache: null) + : this (assemblies, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new[]{value}), resolver: null) { if (logMessage == null) throw new ArgumentNullException (nameof (logMessage)); @@ -73,17 +73,22 @@ public TypeNameMapGenerator (IEnumerable assemblies, Action, Action, TypeDefinitionCache)")] public TypeNameMapGenerator (IEnumerable assemblies, Action logger) - : this (assemblies, logger, cache: null) + : this (assemblies, logger, resolver: null) { } public TypeNameMapGenerator (IEnumerable assemblies, Action logger, TypeDefinitionCache cache) + : this (assemblies, logger, (IMetadataResolver) cache) + { + } + + public TypeNameMapGenerator (IEnumerable assemblies, Action logger, IMetadataResolver resolver) { if (assemblies == null) throw new ArgumentNullException ("assemblies"); if (logger == null) throw new ArgumentNullException (nameof (logger)); - Cache = cache ?? new TypeDefinitionCache (); + Cache = resolver ?? new TypeDefinitionCache (); Log = logger; var Assemblies = assemblies.ToList (); var rp = new ReaderParameters (); @@ -100,7 +105,7 @@ public TypeNameMapGenerator (IEnumerable assemblies, Action assemblies, Action, Action, TypeDefinitionCache)")] public TypeNameMapGenerator (IEnumerable types, Action logMessage) - : this (types, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new [] { value }), cache: null) + : this (types, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new [] { value }), resolver: null) { if (logMessage == null) throw new ArgumentNullException (nameof (logMessage)); @@ -116,16 +121,22 @@ public TypeNameMapGenerator (IEnumerable types, Action, Action, TypeDefinitionCache)")] public TypeNameMapGenerator (IEnumerable types, Action logger) - : this (types, logger, cache: null) + : this (types, logger, resolver: null) { } public TypeNameMapGenerator (IEnumerable types, Action logger, TypeDefinitionCache cache) + : this (types, logger, (IMetadataResolver) cache) + { + } + + public TypeNameMapGenerator (IEnumerable types, Action logger, IMetadataResolver resolver) { if (types == null) throw new ArgumentNullException ("types"); if (logger == null) throw new ArgumentNullException (nameof (logger)); - Cache = cache ?? new TypeDefinitionCache (); + + Cache = resolver ?? new TypeDefinitionCache (); Log = logger; Types = types.ToList (); diff --git a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs index 5ec2e9007..f6e97e82f 100644 --- a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs +++ b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs @@ -408,28 +408,37 @@ internal static ExportParameterAttribute ToExportParameterAttribute (CustomAttri [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool IsApplication (TypeDefinition type) => - IsApplication (type, cache: null); + IsApplication (type, resolver: null); - public static bool IsApplication (TypeDefinition type, TypeDefinitionCache? cache) + public static bool IsApplication (TypeDefinition type, TypeDefinitionCache? cache) => + IsApplication (type, (IMetadataResolver?) cache); + + public static bool IsApplication (TypeDefinition type, IMetadataResolver? resolver) { - return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Application"); + return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Application"); } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static bool IsInstrumentation (TypeDefinition type) => - IsInstrumentation (type, cache: null); + IsInstrumentation (type, resolver: null); + + public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? cache) => + IsInstrumentation (type, (IMetadataResolver?) cache); - public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? cache) + public static bool IsInstrumentation (TypeDefinition type, IMetadataResolver? resolver) { - return type.GetBaseTypes (cache).Any (b => b.FullName == "Android.App.Instrumentation"); + return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Instrumentation"); } // moved from JavaTypeInfo [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string? GetJniSignature (MethodDefinition method) => - GetJniSignature (method, cache: null); + GetJniSignature (method, resolver: null); - public static string? GetJniSignature (MethodDefinition method, TypeDefinitionCache? cache) + public static string? GetJniSignature (MethodDefinition method, TypeDefinitionCache? cache) => + GetJniSignature (method, (IMetadataResolver?) cache); + + public static string? GetJniSignature (MethodDefinition method, IMetadataResolver? resolver) { return GetJniSignature ( method.Parameters, @@ -437,21 +446,24 @@ public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? p => GetExportKind (p), method.ReturnType, GetExportKind (method.MethodReturnType), - (t, k) => GetJniTypeName (t, k, cache), + (t, k) => GetJniTypeName (t, k, resolver), method.IsConstructor); } // moved from JavaTypeInfo [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string? GetJniTypeName (TypeReference typeRef) => - GetJniTypeName (typeRef, cache: null); + GetJniTypeName (typeRef, resolver: null); + + public static string? GetJniTypeName (TypeReference typeRef, TypeDefinitionCache? cache) => + GetJniTypeName (typeRef, (IMetadataResolver?) cache); - public static string? GetJniTypeName (TypeReference typeRef, TypeDefinitionCache? cache) + public static string? GetJniTypeName (TypeReference typeRef, IMetadataResolver? resolver) { - return GetJniTypeName (typeRef, ExportParameterKind.Unspecified, cache); + return GetJniTypeName (typeRef, ExportParameterKind.Unspecified, resolver); } - internal static string? GetJniTypeName (TypeReference typeRef, ExportParameterKind exportKind, TypeDefinitionCache? cache) + internal static string? GetJniTypeName (TypeReference typeRef, ExportParameterKind exportKind, IMetadataResolver? cache) { return GetJniTypeName (typeRef, exportKind, t => t.Resolve (), t => { TypeReference etype; @@ -462,11 +474,21 @@ public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache? [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string ToCompatJniName (TypeDefinition type) => - ToCompatJniName (type, cache: null); + ToCompatJniName (type, resolver: null); - public static string ToCompatJniName (TypeDefinition type, TypeDefinitionCache? cache) + public static string ToCompatJniName (TypeDefinition type, TypeDefinitionCache? cache) => + ToCompatJniName (type, (IMetadataResolver?) cache); + + public static string ToCompatJniName (TypeDefinition type, IMetadataResolver? resolver) { - return ToJniName (type, t => t.DeclaringType, t => t.Name, ToCompatPackageName, ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); + return ToJniName ( + type: type, + decl: t => t.DeclaringType, + name: t => t.Name, + ns: ToCompatPackageName, + overrideName: t => ToJniNameFromAttributes (t, resolver), + shouldUpdateName: t => IsNonStaticInnerClass (t as TypeDefinition, resolver) + ); } static string ToCompatPackageName (TypeDefinition type) @@ -476,15 +498,18 @@ static string ToCompatPackageName (TypeDefinition type) // Keep in sync with ToJniNameFromAttributes(Type) and ToJniName(Type) public static string ToJniName (TypeDefinition type) => - ToJniName (type, cache: null); + ToJniName (type, resolver: null); + + public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) => + ToJniName (type, (IMetadataResolver?) cache); - public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) + public static string ToJniName (TypeDefinition type, IMetadataResolver? resolver) { - return ToJniName (type, ExportParameterKind.Unspecified, cache) ?? + return ToJniName (type, ExportParameterKind.Unspecified, resolver) ?? "java/lang/Object"; } - static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, TypeDefinitionCache? cache) + static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, IMetadataResolver? cache) { if (type == null) throw new ArgumentNullException ("type"); @@ -499,13 +524,20 @@ public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) return GetSpecialExportJniType (type.FullName, exportKind); } - return ToJniName (type, t => t.DeclaringType, t => t.Name, t => GetPackageName (t, cache), ToJniNameFromAttributes, t => IsNonStaticInnerClass (t as TypeDefinition, cache)); + return ToJniName ( + type: type, + decl: t => t.DeclaringType, + name: t => t.Name, + ns: t => GetPackageName (t, cache), + overrideName: t => ToJniNameFromAttributes (t, cache), + shouldUpdateName: t => IsNonStaticInnerClass (t as TypeDefinition, cache) + ); } - static string? ToJniNameFromAttributes (TypeDefinition type) + static string? ToJniNameFromAttributes (TypeDefinition type, IMetadataResolver? resolver) { #region CustomAttribute alternate name support - var attrs = type.CustomAttributes.Where (a => a.AttributeType.Resolve ().Interfaces.Any (it => it.InterfaceType.FullName == typeof (IJniNameProviderAttribute).FullName)); + var attrs = type.CustomAttributes.Where (a => Resolve (resolver, a.AttributeType).Interfaces.Any (it => it.InterfaceType.FullName == typeof (IJniNameProviderAttribute).FullName)); return attrs.Select (attr => { var ap = attr.Properties.FirstOrDefault (p => p.Name == "Name"); string? name = null; @@ -525,6 +557,11 @@ public static string ToJniName (TypeDefinition type, TypeDefinitionCache? cache) #endregion } + static TypeDefinition Resolve (IMetadataResolver? resolver, TypeReference typeReference) => + resolver?.Resolve (typeReference) ?? + typeReference.Resolve () ?? + throw new InvalidOperationException (); + public static int GetArrayInfo (Mono.Cecil.TypeReference type, out Mono.Cecil.TypeReference elementType) { elementType = type; @@ -561,19 +598,22 @@ public static int GetArrayInfo (Mono.Cecil.TypeReference type, out Mono.Cecil.Ty [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] public static string GetPackageName (TypeDefinition type) => - GetPackageName (type, cache: null); + GetPackageName (type, resolver: null); + + public static string GetPackageName (TypeDefinition type, TypeDefinitionCache? cache) => + GetPackageName (type, (IMetadataResolver?) cache); - public static string GetPackageName (TypeDefinition type, TypeDefinitionCache? cache) + public static string GetPackageName (TypeDefinition type, IMetadataResolver? resolver) { - if (IsPackageNamePreservedForAssembly (type.GetPartialAssemblyName (cache))) + if (IsPackageNamePreservedForAssembly (type.GetPartialAssemblyName (resolver))) return type.Namespace.ToLowerInvariant (); switch (PackageNamingPolicy) { case PackageNamingPolicy.Lowercase: return type.Namespace.ToLowerInvariant (); case PackageNamingPolicy.LowercaseWithAssemblyName: - return "assembly_" + (type.GetPartialAssemblyName (cache).Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); + return "assembly_" + (type.GetPartialAssemblyName (resolver).Replace ('.', '_') + "." + type.Namespace).ToLowerInvariant (); case PackageNamingPolicy.LowercaseCrc64: - return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + type.GetPartialAssemblyName (cache)); + return CRC_PREFIX + ToCrc64 (type.Namespace + ":" + type.GetPartialAssemblyName (resolver)); default: throw new NotSupportedException ($"PackageNamingPolicy.{PackageNamingPolicy} is no longer supported."); } @@ -619,7 +659,7 @@ static string ToJniName (T type, Func decl, Func name, Func< } #if HAVE_CECIL - internal static bool IsNonStaticInnerClass (TypeDefinition? type, TypeDefinitionCache? cache) + internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResolver? cache) { if (type == null) return false; @@ -633,7 +673,7 @@ internal static bool IsNonStaticInnerClass (TypeDefinition? type, TypeDefinition .Any (ctor => ctor.Parameters.Any (p => p.Name == "__self")); } - static IEnumerable GetBaseConstructors (TypeDefinition type, TypeDefinitionCache? cache) + static IEnumerable GetBaseConstructors (TypeDefinition type, IMetadataResolver? cache) { var baseType = type.GetBaseTypes (cache).FirstOrDefault (t => t.GetCustomAttributes (typeof (RegisterAttribute)).Any ()); if (baseType != null)