Skip to content

Commit

Permalink
[generator] Refactor enum writing to use SourceWriters (#1063)
Browse files Browse the repository at this point in the history
Context: #1037

Refactor `EnumGenerator` to use `SourceWriters` instead of
`TextWriter`.  This will make it possible to use our existing code to
apply `[PlatformOSSupported]` attributes to enums in a future PR.

This is a separate PR to help verify there was no output changed from
the refactor.
  • Loading branch information
jpobst authored Dec 8, 2022
1 parent c2daa9f commit 149d70f
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ public static ConstantEntry FromElement (XElement elem)
return entry;
}

public override string ToString () => $"[{EnumMember}, {Value}]";

public string ToVersion2String ()
{
var fields = new [] {
Expand Down
44 changes: 44 additions & 0 deletions src/Xamarin.SourceWriter/Models/EnumMemberWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;

namespace Xamarin.SourceWriter
{
public class EnumMemberWriter : ISourceWriter
{
public string Name { get; set; }
public List<string> Comments { get; } = new List<string> ();
public List<AttributeWriter> Attributes { get; } = new List<AttributeWriter> ();
public string Value { get; set; }
public int Priority { get; set; }

public virtual void Write (CodeWriter writer)
{
WriteComments (writer);
WriteAttributes (writer);
WriteSignature (writer);
}

public virtual void WriteComments (CodeWriter writer)
{
foreach (var c in Comments)
writer.WriteLine (c);
}

public virtual void WriteAttributes (CodeWriter writer)
{
foreach (var att in Attributes)
att.WriteAttribute (writer);
}

public virtual void WriteSignature (CodeWriter writer)
{
if (Value.HasValue ()) {
writer.Write (Name + " = ");
writer.Write (Value);
writer.WriteLine (",");
} else {
writer.WriteLine ($"{Name},");
}
}
}
}
74 changes: 74 additions & 0 deletions src/Xamarin.SourceWriter/Models/EnumWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;

namespace Xamarin.SourceWriter
{
public class EnumWriter : ISourceWriter
{
Visibility visibility;

public string Name { get; set; }
public bool IsPublic { get => visibility.HasFlag (Visibility.Public); set => visibility = value ? Visibility.Public : Visibility.Default; }
public bool IsInternal { get => visibility.HasFlag (Visibility.Internal); set => visibility = value ? Visibility.Internal : Visibility.Default; }
public bool IsPrivate { get => visibility.HasFlag (Visibility.Private); set => visibility = value ? Visibility.Private : Visibility.Default; }
public bool IsProtected { get => visibility.HasFlag (Visibility.Protected); set => visibility = value ? Visibility.Protected : Visibility.Default; }
public List<string> Comments { get; } = new List<string> ();
public List<AttributeWriter> Attributes { get; } = new List<AttributeWriter> ();
public List<EnumMemberWriter> Members { get; } = new List<EnumMemberWriter> ();

public int Priority { get; set; }

public void Write (CodeWriter writer)
{
WriteComments (writer);
WriteAttributes (writer);
WriteSignature (writer);
WriteMembers (writer);
WriteTypeClose (writer);
}

public virtual void WriteComments (CodeWriter writer)
{
foreach (var c in Comments)
writer.WriteLine (c);
}

public virtual void WriteAttributes (CodeWriter writer)
{
foreach (var att in Attributes)
att.WriteAttribute (writer);
}

public virtual void WriteSignature (CodeWriter writer)
{
if (IsPublic)
writer.Write ("public ");
if (IsProtected)
writer.Write ("protected ");
if (IsInternal)
writer.Write ("internal ");
if (IsPrivate)
writer.Write ("private ");

writer.Write ("enum ");
writer.WriteLine (Name + " ");

writer.WriteLine ("{");
writer.Indent ();
}

public virtual void WriteMembers (CodeWriter writer)
{
foreach (var member in Members) {
member.Write (writer);
writer.WriteLine ();
}
}

public virtual void WriteTypeClose (CodeWriter writer)
{
writer.Unindent ();
writer.WriteLine ("}");
}
}
}
11 changes: 4 additions & 7 deletions tests/generator-Tests/Unit-Tests/EnumGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Reflection;
using System.Text;
using Java.Interop.Tools.Generator.Enumification;
using MonoDroid.Generation;
using NUnit.Framework;
using NUnit.Framework.Internal;
Expand Down Expand Up @@ -69,13 +70,9 @@ protected string GetExpected (string testName)
KeyValuePair<string, EnumMappings.EnumDescription> CreateEnum ()
{
var enu = new EnumMappings.EnumDescription {
Members = new Dictionary<string, string> {
{ "WithExcluded", "1" },
{ "IgnoreUnavailable", "2" }
},
JniNames = new Dictionary<string, string> {
{ "WithExcluded", "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE" },
{ "IgnoreUnavailable", "android/app/ActivityManager.RECENT_WITH_EXCLUDED" }
Members = new List<ConstantEntry> {
new ConstantEntry { EnumMember = "WithExcluded", Value = "1", JavaSignature = "android/app/ActivityManager.RECENT_IGNORE_UNAVAILABLE" },
new ConstantEntry { EnumMember = "IgnoreUnavailable", Value = "2", JavaSignature = "android/app/ActivityManager.RECENT_WITH_EXCLUDED" }
},
BitField = false,
FieldsRemoved = false
Expand Down
14 changes: 7 additions & 7 deletions tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void BasicEnumificationTest ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down Expand Up @@ -65,7 +65,7 @@ public void AddConstantOnlyTest ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, ]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("", enums.First().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down Expand Up @@ -128,7 +128,7 @@ public void TransientEnumificationTest ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down Expand Up @@ -164,7 +164,7 @@ public void TransientAddConstantOnlyTest ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, ]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}
[Test]
Expand All @@ -183,7 +183,7 @@ public void BasicEnumificationV2Test ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down Expand Up @@ -219,7 +219,7 @@ public void AddConstantOnlyV2Test ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (true, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, ]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("", enums.First ().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down Expand Up @@ -282,7 +282,7 @@ public void TransientEnumificationV2Test ()
Assert.AreEqual ("Org.XmlPull.V1.XmlPullParserNode", enums.Single ().Key);
Assert.AreEqual (false, enums.Single ().Value.BitField);
Assert.AreEqual (false, enums.Single ().Value.FieldsRemoved);
Assert.AreEqual ("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]", enums.First ().Value.JniNames.Single ().ToString ());
Assert.AreEqual ("I:org/xmlpull/v1/XmlPullParser.CDSECT", enums.First ().Value.Members.Single ().JavaSignature);
Assert.AreEqual ("[Cdsect, 5]", enums.First ().Value.Members.Single ().ToString ());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using generator.SourceWriters;
using Java.Interop.Tools.Generator.Enumification;
using Xamarin.SourceWriter;
using static MonoDroid.Generation.EnumMappings;

using CodeGenerationTarget = Xamarin.Android.Binder.CodeGenerationTarget;
Expand All @@ -19,30 +22,51 @@ public EnumGenerator (TextWriter writer)

public void WriteEnumeration (CodeGenerationOptions opt, KeyValuePair<string, EnumDescription> enu, GenBase [] gens)
{
string ns = enu.Key.Substring (0, enu.Key.LastIndexOf ('.')).Trim ();
string enoom = enu.Key.Substring (enu.Key.LastIndexOf ('.') + 1).Trim ();
var ns = enu.Key.Substring (0, enu.Key.LastIndexOf ('.')).Trim ();
var cw = new CodeWriter (sw);

cw.WriteLine ($"namespace {ns}");
cw.WriteLine ("{");

var enoom = CreateWriter (opt, enu, gens);
enoom.Write (cw);

cw.WriteLine ("}");
}

EnumWriter CreateWriter (CodeGenerationOptions opt, KeyValuePair<string, EnumDescription> enu, GenBase [] gens)
{
var enoom = new EnumWriter {
Name = enu.Key.Substring (enu.Key.LastIndexOf ('.') + 1).Trim (),
IsPublic = true
};

sw.WriteLine ("namespace {0} {{", ns);
if (enu.Value.BitField)
sw.WriteLine ("\t[System.Flags]");
sw.WriteLine ("\tpublic enum {0} {{", enoom);
enoom.Attributes.Add (new FlagsAttr ());

foreach (var member in enu.Value.Members) {
var managedMember = FindManagedMember (enu.Value, member.Key, gens);
var m = new EnumMemberWriter {
Name = member.EnumMember.Trim (),
Value = member.Value.Trim (),
};

var managedMember = FindManagedMember (enu.Value, member, gens);

if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1)
sw.WriteLine ("\t\t[global::Android.Runtime.IntDefinition (" + (managedMember != null ? "\"" + managedMember + "\"" : "null") + ", JniField = \"" + StripExtraInterfaceSpec (enu.Value.JniNames [member.Key]) + "\")]");
sw.WriteLine ("\t\t{0} = {1},", member.Key.Trim (), member.Value.Trim ());
m.Attributes.Add (new IntDefinitionAttr (managedMember, StripExtraInterfaceSpec (member.JavaSignature)));

enoom.Members.Add (m);
}
sw.WriteLine ("\t}");
sw.WriteLine ("}");

return enoom;
}

string FindManagedMember (EnumDescription desc, string enumFieldName, IEnumerable<GenBase> gens)
string FindManagedMember (EnumDescription desc, ConstantEntry member, IEnumerable<GenBase> gens)
{
if (desc.FieldsRemoved)
return null;

var jniMember = desc.JniNames [enumFieldName];
var jniMember = member.JavaSignature;
if (string.IsNullOrWhiteSpace (jniMember)) {
// enum values like "None" falls here.
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ namespace MonoDroid.Generation {
partial class EnumMappings {

public class EnumDescription {
public Dictionary<string, string> Members = new Dictionary<string, string> ();
public Dictionary<string, string> JniNames = new Dictionary<string, string> ();
public List<ConstantEntry> Members = new List<ConstantEntry> ();
public bool BitField;
public bool FieldsRemoved;
}
Expand Down Expand Up @@ -69,10 +68,7 @@ internal Dictionary<string, EnumDescription> ParseFieldMappings (TextReader sour
BitField = group.Any (c => c.IsFlags) || enumFlags?.Contains (group.Key) == true
};

foreach (var c in group) {
desc.Members.Add (c.EnumMember, c.Value);
desc.JniNames.Add (c.EnumMember, c.JavaSignature);
}
desc.Members.AddRange (group);

enums.Add (group.Key, desc);
}
Expand Down
13 changes: 13 additions & 0 deletions tools/generator/SourceWriters/Attributes/FlagsAttr.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using Xamarin.SourceWriter;

namespace generator.SourceWriters
{
public class FlagsAttr : AttributeWriter
{
public override void WriteAttribute (CodeWriter writer)
{
writer.WriteLine ("[System.Flags]");
}
}
}
23 changes: 23 additions & 0 deletions tools/generator/SourceWriters/Attributes/IntDefinitionAttr.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using Xamarin.SourceWriter;

namespace generator.SourceWriters
{
public class IntDefinitionAttr : AttributeWriter
{
public string ManagedMember { get; set; }
public string JniField { get; set; }

public IntDefinitionAttr (string managedMember, string jniField)
{
ManagedMember = managedMember;
JniField = jniField;
}

public override void WriteAttribute (CodeWriter writer)
{
var member = ManagedMember is null ? "null" : "\"" + ManagedMember + "\"";
writer.WriteLine ($"[global::Android.Runtime.IntDefinition ({member}, JniField = \"{JniField}\")]");
}
}
}

0 comments on commit 149d70f

Please sign in to comment.