|
| 1 | +diff --git a/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs b/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs |
| 2 | +index ec1ea955..7f8e1a1b 100644 |
| 3 | +--- a/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs |
| 4 | ++++ b/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs |
| 5 | +@@ -1,5 +1,7 @@ |
| 6 | + using System; |
| 7 | + |
| 8 | ++using Mono.Cecil; |
| 9 | ++ |
| 10 | + namespace Android.Runtime { |
| 11 | + |
| 12 | + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property)] |
| 13 | +@@ -23,7 +25,21 @@ namespace Android.Runtime { |
| 14 | + this.connector = connector; |
| 15 | + this.signature = signature; |
| 16 | + } |
| 17 | ++#if HAVE_CECIL |
| 18 | ++ public RegisterAttribute (string name, CustomAttribute originAttribute) |
| 19 | ++ : this (name) |
| 20 | ++ { |
| 21 | ++ OriginAttribute = originAttribute; |
| 22 | ++ } |
| 23 | ++ |
| 24 | ++ public RegisterAttribute (string name, string signature, string connector, CustomAttribute originAttribute) |
| 25 | ++ : this (name, signature, connector) |
| 26 | ++ { |
| 27 | ++ OriginAttribute = originAttribute; |
| 28 | ++ } |
| 29 | + |
| 30 | ++ public CustomAttribute OriginAttribute { get; } |
| 31 | ++#endif |
| 32 | + public string Connector { |
| 33 | + get { return connector; } |
| 34 | + set { connector = value; } |
| 35 | +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 |
| 36 | +index d30bce4a..afde1e48 100644 |
| 37 | +--- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs |
| 38 | ++++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs |
| 39 | +@@ -25,40 +25,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 40 | + JavaInterop1, |
| 41 | + } |
| 42 | + |
| 43 | +- public class OverriddenMethodDescriptor |
| 44 | ++ public abstract class JavaCallableMethodClassifier |
| 45 | + { |
| 46 | +- static readonly char[] methodDescSplitChars = new char[] { ':' }; |
| 47 | +- |
| 48 | +- public string JavaPackageName { get; } |
| 49 | +- public string NativeName { get; } |
| 50 | +- public string JniSignature { get; } |
| 51 | +- public string Connector { get; } |
| 52 | +- public string ManagedTypeName { get; } |
| 53 | +- public string OriginalDescString { get; } |
| 54 | +- |
| 55 | +- public OverriddenMethodDescriptor (string javaPackageName, string methodDescription, string fallbackManagedTypeName) |
| 56 | +- { |
| 57 | +- OriginalDescString = methodDescription; |
| 58 | +- JavaPackageName = javaPackageName; |
| 59 | +- string[] parts = methodDescription.Split (methodDescSplitChars, 4); |
| 60 | +- |
| 61 | +- if (parts.Length < 2) { |
| 62 | +- throw new InvalidOperationException ($"Unexpected format for method description. Expected at least 2 parts, got {parts.Length} from: '{methodDescription}'"); |
| 63 | +- } |
| 64 | +- |
| 65 | +- NativeName = parts[0]; |
| 66 | +- JniSignature = parts[1]; |
| 67 | +- if (parts.Length > 2) { |
| 68 | +- Connector = parts[2]; |
| 69 | +- if (parts.Length > 3) { |
| 70 | +- ManagedTypeName = TypeDefinitionRocks.CecilTypeNameToReflectionTypeName (parts[3]); |
| 71 | +- } |
| 72 | +- } |
| 73 | +- |
| 74 | +- if (String.IsNullOrEmpty (ManagedTypeName)) { |
| 75 | +- ManagedTypeName = fallbackManagedTypeName; |
| 76 | +- } |
| 77 | +- } |
| 78 | ++ public abstract bool ShouldBeDynamicallyRegistered (MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute registerAttribute); |
| 79 | + } |
| 80 | + |
| 81 | + public class JavaCallableWrapperGenerator { |
| 82 | +@@ -95,21 +64,22 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 83 | + List<Signature> methods = new List<Signature> (); |
| 84 | + List<Signature> ctors = new List<Signature> (); |
| 85 | + List<JavaCallableWrapperGenerator> children; |
| 86 | +- List<OverriddenMethodDescriptor> overriddenMethodDescriptors; |
| 87 | ++ |
| 88 | + readonly IMetadataResolver cache; |
| 89 | ++ readonly JavaCallableMethodClassifier methodClassifier; |
| 90 | + |
| 91 | + [Obsolete ("Use the TypeDefinitionCache overload for better performance.")] |
| 92 | + public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object []> log) |
| 93 | + : this (type, null, log, resolver: null) |
| 94 | + { } |
| 95 | + |
| 96 | +- public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache) |
| 97 | +- : this (type, log, (IMetadataResolver) cache) |
| 98 | ++ public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache, JavaCallableMethodClassifier methodClassifier = null) |
| 99 | ++ : this (type, log, (IMetadataResolver) cache, methodClassifier) |
| 100 | + { |
| 101 | + } |
| 102 | + |
| 103 | +- public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver) |
| 104 | +- : this (type, null, log, resolver) |
| 105 | ++ public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier = null) |
| 106 | ++ : this (type, null, log, resolver, methodClassifier) |
| 107 | + { |
| 108 | + if (type.HasNestedTypes) { |
| 109 | + children = new List<JavaCallableWrapperGenerator> (); |
| 110 | +@@ -117,7 +87,6 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | +- public IList<OverriddenMethodDescriptor> OverriddenMethodDescriptors => overriddenMethodDescriptors; |
| 115 | + public string ApplicationJavaClass { get; set; } |
| 116 | + public JavaPeerStyle CodeGenerationTarget { get; set; } |
| 117 | + |
| 118 | +@@ -125,6 +94,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 119 | + |
| 120 | + public bool HasExport { get; private set; } |
| 121 | + |
| 122 | ++ // If there are no methods, we need to generate "empty" registration because of backward compatibility |
| 123 | ++ public bool HasDynamicallyRegisteredMethods => methods.Count == 0 || methods.Any ((Signature sig) => sig.IsDynamicallyRegistered); |
| 124 | ++ |
| 125 | + /// <summary> |
| 126 | + /// The Java source code to be included in Instrumentation.onCreate |
| 127 | + /// |
| 128 | +@@ -152,8 +124,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 129 | + HasExport |= children.Any (t => t.HasExport); |
| 130 | + } |
| 131 | + |
| 132 | +- JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver) |
| 133 | ++ JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier = null) |
| 134 | + { |
| 135 | ++ this.methodClassifier = methodClassifier; |
| 136 | + this.type = type; |
| 137 | + this.log = log; |
| 138 | + this.cache = resolver ?? new TypeDefinitionCache (); |
| 139 | +@@ -366,12 +339,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 140 | + // attr.Resolve (); |
| 141 | + RegisterAttribute r = null; |
| 142 | + if (attr.ConstructorArguments.Count == 1) |
| 143 | +- r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value); |
| 144 | ++ r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr); |
| 145 | + else if (attr.ConstructorArguments.Count == 3) |
| 146 | + r = new RegisterAttribute ( |
| 147 | + (string) attr.ConstructorArguments [0].Value, |
| 148 | + (string) attr.ConstructorArguments [1].Value, |
| 149 | +- (string) attr.ConstructorArguments [2].Value); |
| 150 | ++ (string) attr.ConstructorArguments [2].Value, |
| 151 | ++ attr); |
| 152 | + if (r != null) { |
| 153 | + var v = attr.Properties.FirstOrDefault (p => p.Name == "DoNotGenerateAcw"); |
| 154 | + r.DoNotGenerateAcw = v.Name == null ? false : (bool) v.Argument.Value; |
| 155 | +@@ -384,7 +358,7 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 156 | + // attr.Resolve (); |
| 157 | + RegisterAttribute r = null; |
| 158 | + if (attr.ConstructorArguments.Count == 1) |
| 159 | +- r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value); |
| 160 | ++ r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr); |
| 161 | + if (r != null) { |
| 162 | + var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer"); |
| 163 | + if (v.Name == null) { |
| 164 | +@@ -403,7 +377,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 165 | + if (attr.ConstructorArguments.Count == 2) |
| 166 | + r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, |
| 167 | + (string) attr.ConstructorArguments [1].Value, |
| 168 | +- ""); |
| 169 | ++ "", |
| 170 | ++ attr); |
| 171 | + return r; |
| 172 | + } |
| 173 | + |
| 174 | +@@ -467,7 +442,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 175 | + if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-')) |
| 176 | + Diagnostic.Error (4217, LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4217, attr.Name); |
| 177 | + |
| 178 | +- var msig = new Signature (implementedMethod, attr); |
| 179 | ++ bool shouldBeDynamicallyRegistered = methodClassifier?.ShouldBeDynamicallyRegistered (registeredMethod, implementedMethod, attr.OriginAttribute) ?? true; |
| 180 | ++ var msig = new Signature (implementedMethod, attr, shouldBeDynamicallyRegistered); |
| 181 | + if (!registeredMethod.IsConstructor && !methods.Any (m => m.Name == msig.Name && m.Params == msig.Params)) |
| 182 | + methods.Add (msig); |
| 183 | + } |
| 184 | +@@ -542,21 +518,38 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 185 | + |
| 186 | + GenerateHeader (writer); |
| 187 | + |
| 188 | +- writer.WriteLine ("/** @hide */"); |
| 189 | +- writer.WriteLine ("\tpublic static final String __md_methods;"); |
| 190 | +- if (children != null) { |
| 191 | +- foreach (var i in Enumerable.Range (1, children.Count)) |
| 192 | +- writer.WriteLine ("\tstatic final String __md_{0}_methods;", i); |
| 193 | ++ bool needCtor = false; |
| 194 | ++ if (HasDynamicallyRegisteredMethods) { |
| 195 | ++ needCtor = true; |
| 196 | ++ writer.WriteLine ("/** @hide */"); |
| 197 | ++ writer.WriteLine ("\tpublic static final String __md_methods;"); |
| 198 | + } |
| 199 | +- writer.WriteLine ("\tstatic {"); |
| 200 | +- GenerateRegisterType (writer, this, "__md_methods"); |
| 201 | ++ |
| 202 | + if (children != null) { |
| 203 | +- for (int i = 0; i < children.Count; ++i) { |
| 204 | +- string methods = string.Format ("__md_{0}_methods", i + 1); |
| 205 | +- GenerateRegisterType (writer, children [i], methods); |
| 206 | ++ for (int i = 0; i < children.Count; i++) { |
| 207 | ++ if (!children[i].HasDynamicallyRegisteredMethods) { |
| 208 | ++ continue; |
| 209 | ++ } |
| 210 | ++ needCtor = true; |
| 211 | ++ writer.WriteLine ("\tstatic final String __md_{0}_methods;", i + 1); |
| 212 | ++ } |
| 213 | ++ } |
| 214 | ++ |
| 215 | ++ if (needCtor) { |
| 216 | ++ writer.WriteLine ("\tstatic {"); |
| 217 | ++ |
| 218 | ++ if (HasDynamicallyRegisteredMethods) { |
| 219 | ++ GenerateRegisterType (writer, this, "__md_methods"); |
| 220 | ++ } |
| 221 | ++ |
| 222 | ++ if (children != null) { |
| 223 | ++ for (int i = 0; i < children.Count; ++i) { |
| 224 | ++ string methods = string.Format ("__md_{0}_methods", i + 1); |
| 225 | ++ GenerateRegisterType (writer, children [i], methods); |
| 226 | ++ } |
| 227 | + } |
| 228 | ++ writer.WriteLine ("\t}"); |
| 229 | + } |
| 230 | +- writer.WriteLine ("\t}"); |
| 231 | + |
| 232 | + GenerateBody (writer); |
| 233 | + |
| 234 | +@@ -710,16 +703,19 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 235 | + |
| 236 | + void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, string field) |
| 237 | + { |
| 238 | +- if (overriddenMethodDescriptors == null) { |
| 239 | +- overriddenMethodDescriptors = new List<OverriddenMethodDescriptor> (); |
| 240 | ++ string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache); |
| 241 | ++ string javaTypeName = $"{package}.{name}"; |
| 242 | ++ |
| 243 | ++ if (!self.HasDynamicallyRegisteredMethods) { |
| 244 | ++ return; |
| 245 | + } |
| 246 | + |
| 247 | + sw.WriteLine ("\t\t{0} = ", field); |
| 248 | +- string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache); |
| 249 | +- string javaTypeName = $"{package}.{name}"; |
| 250 | ++ |
| 251 | + foreach (Signature method in self.methods) { |
| 252 | +- sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method); |
| 253 | +- overriddenMethodDescriptors.Add (new OverriddenMethodDescriptor (javaTypeName, method.Method, managedTypeName)); |
| 254 | ++ if (method.IsDynamicallyRegistered) { |
| 255 | ++ sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method); |
| 256 | ++ } |
| 257 | + } |
| 258 | + sw.WriteLine ("\t\t\t\"\";"); |
| 259 | + if (CannotRegisterInStaticConstructor (self.type)) |
| 260 | +@@ -772,12 +768,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 261 | + |
| 262 | + class Signature { |
| 263 | + |
| 264 | +- public Signature (MethodDefinition method, RegisterAttribute register) : this (method, register, null, null) {} |
| 265 | ++ public Signature (MethodDefinition method, RegisterAttribute register, bool shouldBeDynamicallyRegistered = true) : this (method, register, null, null, shouldBeDynamicallyRegistered) {} |
| 266 | + |
| 267 | +- public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType) |
| 268 | ++ public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType, bool shouldBeDynamicallyRegistered = true) |
| 269 | + : this (register.Name, register.Signature, register.Connector, managedParameters, outerType, null) |
| 270 | + { |
| 271 | + Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes); |
| 272 | ++ IsDynamicallyRegistered = shouldBeDynamicallyRegistered; |
| 273 | + } |
| 274 | + |
| 275 | + public Signature (MethodDefinition method, ExportAttribute export, IMetadataResolver cache) |
| 276 | +@@ -880,6 +877,7 @@ namespace Java.Interop.Tools.JavaCallableWrappers { |
| 277 | + public readonly string Method; |
| 278 | + public readonly bool IsExport; |
| 279 | + public readonly bool IsStatic; |
| 280 | ++ public readonly bool IsDynamicallyRegistered = true; |
| 281 | + public readonly string [] ThrownTypeNames; |
| 282 | + public readonly string Annotations; |
| 283 | + } |
0 commit comments