Skip to content

Commit c084a83

Browse files
jonathanpeppersjonpryor
authored andcommitted
[generator] refactoring for methods (#298)
In the same fashion that 7a96efe refactored fields, this commit aims at refactoring methods. I also added various unit tests to add coverage around the new `TestMethod` support type. Refactoring in generator: - Dropped the method "support" classes in favor of extension methods from `ManagedExtensions` and `XmlExtensions`. These existed due to C# single-inheritance getting in the way of the relationship between methods, properties, constructors, etc. - Moved methods from `Method` and `MethodBase` to `CodeGenerator` and renamed them from `Generate*` to `WriteMethod*`. I tried to not modify the code in these methods other than to add a parameter for the incoming method. - Output of generator *should* remain the same. - `*Method` classes are now much closer to POCOs Other changes: - Dropped usage of `ContextTypes` stack in `XamarinAndroidCodeGenerator` - Added a base test class for `JavaInteropCodeGeneratorTests` and `XamarinAndroidCodeGeneratorTests` because there were several tests that were completely identical (due to `CodeGenerator` base class) - Changed `StreamWriter` to `TextWriter` as needed - Now up to 88 tests! Most new ones are ~1ms Future plans (trying to keep this commit of reasonable size): - The `CodeGenerator` base class is starting to get large. As refactoring continues, I would like to make a class for `FieldGenerator`, `MethodGenerator`, etc. and `CodeGenerator` would get properties named `Fields` and `Methods` that would return these child generator classes - This is exactly what @grendello did with his [prototype][0], so we should adopt this improvement. [0]: https://github.com/grendello/JavaBindingGenerator/blob/fb8864d1842bdf0b8d45eb04b89ef2bd57de0014/src/Java.Interop.Bindings/Compiler/MethodCodeGenerator.cs
1 parent c9d5316 commit c084a83

16 files changed

+1283
-669
lines changed

tools/generator/ClassGen.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@
1515
using System.Xml.Linq;
1616

1717
namespace MonoDroid.Generation {
18-
#if HAVE_CECIL
19-
static class ManagedExtensions
20-
{
21-
public static string FullNameCorrected (this TypeReference t)
22-
{
23-
return t.FullName.Replace ('/', '.');
24-
}
25-
}
26-
18+
#if HAVE_CECIL
2719
public class ManagedClassGen : ClassGen {
2820
TypeDefinition t;
2921
TypeReference nominal_base_type;
@@ -352,9 +344,9 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt)
352344
bool virt = m.IsVirtual;
353345
m.IsVirtual = !IsFinal && virt;
354346
if (m.IsAbstract && !m.IsInterfaceDefaultMethodOverride && !m.IsInterfaceDefaultMethod)
355-
m.GenerateAbstractDeclaration (sw, indent, opt, null, this);
347+
opt.CodeGenerator.WriteMethodAbstractDeclaration (m, sw, indent, opt, null, this);
356348
else
357-
m.Generate (sw, indent, opt, this, true);
349+
opt.CodeGenerator.WriteMethod (m, sw, indent, opt, this, true);
358350
opt.ContextGeneratedMethods.Add (m);
359351
m.IsVirtual = virt;
360352
}
@@ -497,7 +489,7 @@ public override void Generate (StreamWriter sw, string indent, CodeGenerationOpt
497489
if (m.IsInterfaceDefaultMethod || m.IsStatic)
498490
continue;
499491
if (m.IsGeneric)
500-
m.GenerateExplicitIface (sw, indent + "\t", opt, gs);
492+
opt.CodeGenerator.WriteMethodExplicitIface (m, sw, indent + "\t", opt, gs);
501493
}
502494

503495
var adapter = gs.Gen.AssemblyQualifiedName + "Invoker";
@@ -631,11 +623,11 @@ void GenerateInvoker (StreamWriter sw, IEnumerable<Method> methods, string inden
631623
continue;
632624
if (IsExplicitlyImplementedMethod (sig)) {
633625
// sw.WriteLine ("// This invoker explicitly implements this method");
634-
m.GenerateExplicitInterfaceInvoker (sw, indent, opt, gen);
626+
opt.CodeGenerator.WriteMethodExplicitInterfaceInvoker (m, sw, indent, opt, gen);
635627
} else {
636628
// sw.WriteLine ("// This invoker overrides {0} method", gen.FullName);
637629
m.IsOverride = true;
638-
m.Generate (sw, indent, opt, this, false);
630+
opt.CodeGenerator.WriteMethod (m, sw, indent, opt, this, false);
639631
m.IsOverride = false;
640632
}
641633
}

tools/generator/CodeGenerator.cs

Lines changed: 343 additions & 0 deletions
Large diffs are not rendered by default.

tools/generator/Ctor.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,10 @@ public class ManagedCtor : Ctor {
1515
bool is_acw;
1616

1717
public ManagedCtor (GenBase declaringType, MethodDefinition m)
18-
: this (declaringType, m, new ManagedMethodBaseSupport (m))
19-
{
20-
}
21-
22-
ManagedCtor (GenBase declaringType, MethodDefinition m, ManagedMethodBaseSupport support)
23-
: base (declaringType, support)
18+
: base (declaringType)
2419
{
2520
this.m = m;
21+
GenericArguments = m.GenericArguments ();
2622
name = m.Name;
2723
// If 'elem' is a constructor for a non-static nested type, then
2824
// the type of the containing class must be inserted as the first
@@ -31,7 +27,7 @@ public ManagedCtor (GenBase declaringType, MethodDefinition m)
3127
Parameters.AddFirst (Parameter.FromManagedType (m.DeclaringType.DeclaringType, DeclaringType.JavaName));
3228
var regatt = m.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "Android.Runtime.RegisterAttribute");
3329
is_acw = regatt != null;
34-
foreach (var p in support.GetParameters (regatt))
30+
foreach (var p in m.GetParameters (regatt))
3531
Parameters.Add (p);
3632
}
3733

@@ -52,17 +48,26 @@ public override string Name {
5248
public override string CustomAttributes {
5349
get { return null; }
5450
}
51+
52+
public override string AssemblyName => m.DeclaringType.Module.Assembly.FullName;
53+
54+
public override string Visibility => m.Visibility ();
55+
56+
public override string Deprecated => m.Deprecated ();
5557
}
5658
#endif // HAVE_CECIL
5759

5860
public class XmlCtor : Ctor {
61+
XElement elem;
5962
string name;
6063
bool nonStaticNestedType;
6164
bool missing_enclosing_class;
6265
string custom_attributes;
6366

64-
public XmlCtor (GenBase declaringType, XElement elem) : base (declaringType, new XmlMethodBaseSupport (elem))
67+
public XmlCtor (GenBase declaringType, XElement elem) : base (declaringType)
6568
{
69+
this.elem = elem;
70+
GenericArguments = elem.GenericArguments ();
6671
name = elem.XGetAttribute ("name");
6772
int idx = name.LastIndexOf ('.');
6873
if (idx > 0)
@@ -125,12 +130,16 @@ protected override bool OnValidate (CodeGenerationOptions opt, GenericParameterD
125130
public override string CustomAttributes {
126131
get { return custom_attributes; }
127132
}
133+
134+
public override string Deprecated => elem.Deprecated ();
135+
136+
public override string Visibility => elem.Visibility ();
128137
}
129138

130139
public abstract class Ctor : MethodBase {
131140

132-
protected Ctor (GenBase declaringType, IMethodBaseSupport support)
133-
: base (declaringType, support)
141+
protected Ctor (GenBase declaringType)
142+
: base (declaringType)
134143
{
135144
}
136145

tools/generator/InterfaceGen.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,15 @@ void GenMethods (StreamWriter sw, string indent, CodeGenerationOptions opt)
200200
foreach (Method m in Methods.Where (m => !m.IsStatic)) {
201201
if (m.Name == Name || ContainsProperty (m.Name, true))
202202
m.Name = "Invoke" + m.Name;
203-
m.GenerateDeclaration (sw, indent, opt, this, AssemblyQualifiedName + "Invoker");
203+
opt.CodeGenerator.WriteMethodDeclaration (m, sw, indent, opt, this, AssemblyQualifiedName + "Invoker");
204204
}
205205
}
206206

207207
void GenExtensionMethods (StreamWriter sw, string indent, CodeGenerationOptions opt)
208208
{
209209
foreach (Method m in Methods.Where (m => !m.IsStatic)) {
210-
m.GenerateExtensionOverload (sw, indent, opt, FullName);
211-
m.GenerateExtensionAsyncWrapper (sw, indent, opt, FullName);
210+
opt.CodeGenerator.WriteMethodExtensionOverload (m, sw, indent, opt, FullName);
211+
opt.CodeGenerator.WriteMethodExtensionAsyncWrapper (m, sw, indent, opt, FullName);
212212
}
213213
}
214214

@@ -288,7 +288,7 @@ void GenerateInvoker (StreamWriter sw, IEnumerable<Method> methods, string inden
288288
if (members.Contains (sig))
289289
continue;
290290
members.Add (sig);
291-
m.GenerateInvoker (sw, indent, opt, this);
291+
opt.CodeGenerator.WriteMethodInvoker (m, sw, indent, opt, this);
292292
}
293293
}
294294

@@ -632,9 +632,9 @@ public void GenerateAbstractMembers (ClassGen gen, StreamWriter sw, string inden
632632
if (mapped)
633633
continue;
634634
if (gen.ExplicitlyImplementedInterfaceMethods.Contains (sig))
635-
m.GenerateExplicitInterfaceImplementation (sw, indent, opt, this);
635+
opt.CodeGenerator.WriteMethodExplicitInterfaceImplementation (m, sw, indent, opt, this);
636636
else
637-
m.GenerateAbstractDeclaration (sw, indent, opt, this, gen);
637+
opt.CodeGenerator.WriteMethodAbstractDeclaration (m, sw, indent, opt, this, gen);
638638
opt.ContextGeneratedMethods.Add (m);
639639
}
640640
foreach (Property prop in Properties.Where (p => !p.Getter.IsStatic)) {
@@ -714,7 +714,7 @@ public override void Generate (StreamWriter sw, string indent, CodeGenerationOpt
714714
}
715715

716716
foreach (var m in Methods.Where (m => m.IsStatic))
717-
m.Generate (sw, indent + "\t", opt, this, true);
717+
opt.CodeGenerator.WriteMethod (m, sw, indent + "\t", opt, this, true);
718718

719719
if (needsClassRef) {
720720
sw.WriteLine ();
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using Java.Interop.Tools.TypeNameMappings;
2+
using Mono.Cecil;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace MonoDroid.Generation
7+
{
8+
#if HAVE_CECIL
9+
internal static class ManagedExtensions
10+
{
11+
public static string FullNameCorrected (this TypeReference t) => t.FullName.Replace ('/', '.');
12+
13+
public static GenericParameterDefinitionList GenericArguments (this MethodDefinition m) =>
14+
m.HasGenericParameters ? GenericParameterDefinitionList.FromMetadata (m.GenericParameters) : null;
15+
16+
public static string Deprecated (this MethodDefinition m)
17+
{
18+
var v = m.CustomAttributes.FirstOrDefault (a => a.AttributeType.FullName == "System.ObsoleteAttribute");
19+
return v != null ? (string)v.ConstructorArguments [0].Value ?? "deprecated" : null;
20+
}
21+
22+
public static string Visibility (this MethodDefinition m) =>
23+
m.IsPublic ? "public" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : m.IsAssembly ? "internal" : "private";
24+
25+
public static IEnumerable<Parameter> GetParameters (this MethodDefinition m, CustomAttribute regatt)
26+
{
27+
var jnisig = (string)(regatt.ConstructorArguments.Count > 1 ? regatt.ConstructorArguments [1].Value : regatt.Properties.First (p => p.Name == "JniSignature").Argument.Value);
28+
var types = jnisig == null ? null : JavaNativeTypeManager.FromSignature (jnisig);
29+
var e = types?.GetEnumerator ();
30+
31+
foreach (var p in m.Parameters) {
32+
if (e != null && !e.MoveNext ())
33+
e = null;
34+
// Here we do some tricky thing:
35+
// Both java.io.InputStream and java.io.OutputStream could be mapped to
36+
// System.IO.Stream. And when there is Stream in parameters, we have to
37+
// determine which direction of the Stream it was - in or out.
38+
// To do that, we inspect JNI Signature to handle that.
39+
//
40+
// We could *always* use this JNI information, *IF* there were no
41+
// int->enum conversion. Sadly this is not true, we still have to expect
42+
// custom enum types and cannot simply use JNI signature here.
43+
var rawtype = e?.Current.Type;
44+
var type = p.ParameterType.FullName == "System.IO.Stream" && e != null ? e.Current.Type : null;
45+
yield return Parameter.FromManagedParameter (p, type, rawtype);
46+
}
47+
}
48+
}
49+
#endif
50+
}

0 commit comments

Comments
 (0)