This commit is contained in:
Kurt 2025-02-02 04:27:11 -06:00
parent 72d99b41b8
commit 24f4efd312

View File

@ -12,6 +12,9 @@ namespace pkNX.Structures.FlatBuffers.SourceGen;
[Generator]
public class ExpandableAttributeGenerator : IIncrementalGenerator
{
private static bool IsFlatBufferTableAttribute(AttributeSyntax a)
=> a.Name.ToString() is "FlatBufferTable" or "FlatBufferStruct";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var declarations = context.SyntaxProvider
@ -19,6 +22,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
predicate: static (node, _) => node switch
{
ClassDeclarationSyntax => true,
RecordDeclarationSyntax => true,
StructDeclarationSyntax => true,
_ => false,
},
@ -27,18 +31,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
MemberDeclarationSyntax c => c.AttributeLists,
_ => throw new InvalidOperationException("Unexpected node type."),
}).SelectMany(x => x.Attributes).Any(IsFlatBufferAttribute))
}).SelectMany(x => x.Attributes).Any(IsFlatBufferTableAttribute))
.Collect();
context.RegisterSourceOutput(declarations, static (spc, source) =>
{
var sb = new StringBuilder();
var newAttribute = GetExpandableObjectAttribute();
// Convert to string with normalized whitespace.
var attrText = newAttribute.NormalizeWhitespace().ToFullString();
sb.AppendLine("// <auto-generated/>");
sb.AppendLine("using System;");
sb.AppendLine("using System.ComponentModel;");
sb.AppendLine();
@ -53,30 +54,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
sb.AppendLine("{");
}
foreach (var xNode in group)
foreach (var node in group)
{
var typeDecl = (TypeDeclarationSyntax)xNode;
// Use the original declaration's modifiers, keyword, name, type parameters, and constraints.
var modifiers = typeDecl.Modifiers.ToFullString().Trim();
// If the original declaration wasn't marked partial, force it to be partial.
// Note: This will trigger a compile error if the original declaration isn't declared partial.
// Revise the generator if you would rather skip the class entirely.
var partialModifier = modifiers.Contains("partial") ? "" : "partial ";
var keyword = typeDecl.Keyword.Text; // "class" or "struct"
var identifier = typeDecl.Identifier.Text;
var typeParameterList = typeDecl.TypeParameterList?.ToFullString() ?? "";
var constraintClauses = typeDecl.ConstraintClauses.Count > 0
? " " + string.Join(" ", typeDecl.ConstraintClauses.Select(c => c.ToFullString()))
: "";
var type = (TypeDeclarationSyntax)node;
var keyword = type.Keyword.Text; // "class" or "struct"
var identifier = type.Identifier.Text;
// [Attribute] class;
sb.Append(attrText).Append(' ');
sb.Append($"{modifiers} {partialModifier}{keyword} {identifier}{typeParameterList}{constraintClauses}");
// insert any interfaces?
sb.Append(';');
sb.AppendLine();
sb.AppendLine($" {newAttribute} partial {keyword} {identifier};");
}
if (!string.IsNullOrEmpty(ns))
@ -115,14 +100,4 @@ private static string GetNamespace(SyntaxNode node)
var namespaceDeclaration = node.Ancestors().OfType<BaseNamespaceDeclarationSyntax>().FirstOrDefault();
return namespaceDeclaration != null ? namespaceDeclaration.Name.ToString() : "";
}
private static bool IsFlatBufferAttribute(AttributeSyntax a)
{
var name = a.Name.ToString();
if (name.Contains("FlatBufferTable"))
return true;
if (name.Contains("FlatBufferStruct"))
return true;
return false;
}
}