Skip to content

Commit

Permalink
[RGen] Add the code generation for the data attributes. (#22053)
Browse files Browse the repository at this point in the history
This change adds two more properties to the data models when they are
compile. One to check if the data attr is present, and a second one with
the attribute details.

The boolean property is decorated acordingly to help with the
nullability analisys.

An example of the generated code can be found here:
https://gist.github.com/mandel-macaque/04185ea481ca30ef9ff2ecf6dbf51ea0

---------

Co-authored-by: GitHub Actions Autoformatter <[email protected]>
  • Loading branch information
mandel-macaque and GitHub Actions Autoformatter authored Jan 27, 2025
1 parent e15f298 commit b56304e
Showing 1 changed file with 50 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ static string [] GetFlagsForTarget (Dictionary<string, (string AttributeFullName
.Select (kv => kv.Key)
.ToArray ();

static (string AttributeFullName, string AttributeName, BindingAttributeData Data) [] GetAttributesForTarget (
Dictionary<string, (string AttributeFullName, string AttributeName, BindingAttributeData Data)> dataAttribute,
AttributeTargets targets)
=> dataAttribute.Where (kv => kv.Value.Data.Target.HasFlag (targets))
.Select (kv => kv.Value)
.ToArray ();


static void WriteFlagProperty (TabbedStringBuilder sb, string flagName)
{
// write the backing field
Expand All @@ -83,13 +91,34 @@ static void WriteFlagProperty (TabbedStringBuilder sb, string flagName)
}
}

static void WriteDataModelExtension (TabbedStringBuilder sb, string dataModel, string [] flags)
static void WriteAttributeProperty (TabbedStringBuilder sb,
(string AttributeFullName, string AttributeName, BindingAttributeData Data) attrData)
{
// add a property that will state if we have the attr, this will help with nullability
sb.AppendLine ($"readonly bool _has{attrData.AttributeName} = false;");
sb.AppendLine ($"[MemberNotNullWhen (true, nameof ({attrData.AttributeName}))]");
using (var flagPropertyBlock = sb.CreateBlock ($"public bool Has{attrData.AttributeName}", block: true)) {
flagPropertyBlock.AppendLine ($"get => _has{attrData.AttributeName};");
flagPropertyBlock.AppendLine ($"private init => _has{attrData.AttributeName} = value;");
}
sb.AppendLine ();
sb.AppendLine ($"readonly {attrData.Data.DataModelType}? _{attrData.AttributeName} = null;");
// decorate to help with nullability
using (var attributePropertyBlock = sb.CreateBlock ($"public {attrData.Data.DataModelType}? {attrData.AttributeName}", block: true)) {
attributePropertyBlock.AppendLine ($"get => _{attrData.AttributeName};");
attributePropertyBlock.AppendLine ($"private init => _{attrData.AttributeName} = value;");
}
}

static void WriteDataModelExtension (TabbedStringBuilder sb, string dataModel, string [] flags,
(string AttributeFullName, string AttributeName, BindingAttributeData Data) [] attributes)
{
sb.Clear ();
sb.AppendLine ("// <auto-generated/>");
sb.AppendLine ("#nullable enable");
sb.AppendLine ("");
sb.AppendLine ("using System;");
sb.AppendLine ("using System.Diagnostics.CodeAnalysis;");
sb.AppendLine ("using Microsoft.CodeAnalysis;");
sb.AppendLine ("using Microsoft.Macios.Transformer.Extensions;");
sb.AppendLine ();
Expand All @@ -103,6 +132,11 @@ static void WriteDataModelExtension (TabbedStringBuilder sb, string dataModel, s
WriteFlagProperty (modelBlock, flag);
}

foreach (var attrData in attributes) {
modelBlock.AppendLine ();
WriteAttributeProperty (modelBlock, attrData);
}

// property to store the dictionary
modelBlock.AppendLine ();
modelBlock.AppendLine ("readonly Dictionary<string, List<AttributeData>>? _attributesDictionary = null;");
Expand All @@ -114,7 +148,15 @@ static void WriteDataModelExtension (TabbedStringBuilder sb, string dataModel, s
initBlock.AppendLine ("_attributesDictionary = value;");
using (var ifBlock = initBlock.CreateBlock ("if (_attributesDictionary is not null)", block: true)) {
foreach (var flag in flags) {
ifBlock.AppendLine ($"_{flag} = _attributesDictionary.{flag} ();");
ifBlock.AppendLine ($"{flag} = _attributesDictionary.{flag} ();");
}

foreach (var attributeData in attributes) {
// check if the attribute is present, if it is, set the value
ifBlock.AppendLine ($"Has{attributeData.AttributeName} = _attributesDictionary.Has{attributeData.AttributeName} ();");
using (var attrIfBlock = ifBlock.CreateBlock ($"if (Has{attributeData.AttributeName})", block: true)) {
attrIfBlock.AppendLine ($"{attributeData.AttributeName} = _attributesDictionary.Get{attributeData.AttributeName} ();");
}
}
}
}
Expand All @@ -123,11 +165,14 @@ static void WriteDataModelExtension (TabbedStringBuilder sb, string dataModel, s
}

static void GenerateModelExtension (TabbedStringBuilder sb, string dataModel,
Dictionary<string, (string AttributeFullName, AttributeTargets Targets)> flags, AttributeTargets targets,
Dictionary<string, (string AttributeFullName, AttributeTargets Targets)> flags,
Dictionary<string, (string AttributeFullName, string AttributeName, BindingAttributeData Data)> attributes,
AttributeTargets targets,
SourceProductionContext context)
{
var methodFlags = GetFlagsForTarget (flags, targets);
WriteDataModelExtension (sb, dataModel, methodFlags);
var methodAttributes = GetAttributesForTarget (attributes, targets);
WriteDataModelExtension (sb, dataModel, methodFlags, methodAttributes);
context.AddSource ($"{dataModel}.Transformer.g.cs",
SourceText.From (sb.ToString (), Encoding.UTF8));
}
Expand Down Expand Up @@ -204,7 +249,7 @@ void GenerateCode (SourceProductionContext context, Compilation compilation,
#pragma warning restore format

foreach (var (model, target) in models) {
GenerateModelExtension (sb, model, flags, target, context);
GenerateModelExtension (sb, model, flags, dataAttributes, target, context);
}
}

Expand Down

0 comments on commit b56304e

Please sign in to comment.