This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/src/MfGames.Nitride.Generators/WithPropertiesSourceGenerator.cs

116 lines
3.6 KiB
C#
Raw Permalink Normal View History

2021-09-07 05:15:45 +00:00
using System.Collections.Generic;
using System.Linq;
using System.Text;
2021-09-07 05:15:45 +00:00
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
2022-09-06 05:53:22 +00:00
namespace MfGames.Nitride.Generators;
/// <summary>
/// Implements a source generator that creates Set* methods for the various
/// properties that also returns the same object for purposes of chaining
/// together calls.
/// </summary>
[Generator]
public class WithPropertiesSourceGenerator
: ClassAttributeSourceGeneratorBase<WithPropertiesSyntaxReceiver>
2021-09-07 05:15:45 +00:00
{
/// <inheritdoc />
protected override WithPropertiesSyntaxReceiver CreateSyntaxReceiver(
GeneratorInitializationContext context)
2021-09-07 05:15:45 +00:00
{
return new WithPropertiesSyntaxReceiver(context);
}
2021-09-07 05:15:45 +00:00
protected override void GenerateClassFile(
2022-07-09 04:52:10 +00:00
GeneratorExecutionContext context,
ClassAttributeReference unit)
{
// Pull out some fields.
ClassDeclarationSyntax cds = unit.ClassDeclaration;
2021-09-07 05:15:45 +00:00
// Create the partial class.
StringBuilder buffer = new();
buffer.AppendLine("#nullable enable");
2021-09-07 05:15:45 +00:00
// Copy the using statements from the file.
foreach (UsingDirectiveSyntax? uds in unit.UsingDirectiveList)
{
buffer.AppendLine(uds.ToString());
}
2021-09-07 05:15:45 +00:00
buffer.AppendLine();
2021-09-07 05:15:45 +00:00
// Create the namespace.
buffer.AppendLine($"namespace {unit.Namespace}");
buffer.AppendLine("{");
buffer.AppendLine($" public partial class {cds.Identifier}");
buffer.AppendLine(" {");
2021-09-07 05:15:45 +00:00
// Go through the properties of the namespace.
IEnumerable<PropertyDeclarationSyntax> properties = cds.Members
.Where(m => m.Kind() == SyntaxKind.PropertyDeclaration)
.Cast<PropertyDeclarationSyntax>();
2022-07-09 04:52:10 +00:00
bool first = true;
2021-09-07 05:15:45 +00:00
foreach (PropertyDeclarationSyntax pds in properties)
2021-09-07 05:15:45 +00:00
{
// See if we have a setter.
bool found = pds.AccessorList?.Accessors
.Any(x => x.Keyword.ToString() == "set")
?? false;
2021-09-07 05:15:45 +00:00
if (!found)
2021-09-07 05:15:45 +00:00
{
continue;
2021-09-07 05:15:45 +00:00
}
// If we aren't first, then add a newline before it.
if (first)
{
first = false;
}
else
2021-09-07 05:15:45 +00:00
{
buffer.AppendLine();
2021-09-07 05:15:45 +00:00
}
// Write some documentation.
buffer.AppendLine(" /// <summary>");
2022-07-09 04:52:10 +00:00
buffer.AppendLine(
string.Format(
" /// Sets the {0} value and returns the operation for chaining.",
pds.Identifier.ToString()));
2022-07-09 04:52:10 +00:00
buffer.AppendLine(" /// </summary>");
// We have the components for writing out a setter.
buffer.AppendLine(
string.Format(
" public virtual {0} With{1}({2} value)",
cds.Identifier,
pds.Identifier,
pds.Type));
2022-07-09 04:52:10 +00:00
buffer.AppendLine(" {");
buffer.AppendLine(
string.Format(" this.{0} = value;", pds.Identifier));
buffer.AppendLine(" return this;");
buffer.AppendLine(" }");
2021-09-07 05:15:45 +00:00
}
// Finish up the class.
buffer.AppendLine(" }");
buffer.AppendLine("}");
// Create the source text and write out the file.
var sourceText = SourceText.From(buffer.ToString(), Encoding.UTF8);
context.AddSource(cds.Identifier + ".Generated.cs", sourceText);
2021-09-07 05:15:45 +00:00
}
}