A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

94 lines
3.9 KiB

using System.IO;
using System.Linq;
using System.Text;
using Generator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace DevGenerators;
[Generator(LanguageNames.CSharp)]
public class EnumMemberDictionaryGenerator : IIncrementalGenerator
{
const string DictionaryAttributeFullName = "global::Avalonia.SourceGenerator.GenerateEnumValueDictionaryAttribute";
const string ListAttributeFullName = "global::Avalonia.SourceGenerator.GenerateEnumValueListAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var allMethodsWithAttributes = context.SyntaxProvider
.CreateSyntaxProvider(
static (s, _) => s is MethodDeclarationSyntax
{
AttributeLists.Count: > 0,
} md && md.Modifiers.Any(m=>m.IsKind(SyntaxKind.PartialKeyword)),
static (context, _) =>
(IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
var all = allMethodsWithAttributes
.Where(s =>
s.HasAttributeWithFullyQualifiedName(DictionaryAttributeFullName)
|| s.HasAttributeWithFullyQualifiedName(ListAttributeFullName)
).Collect();
context.RegisterSourceOutput(all, static (context, methods) =>
{
foreach (var typeGroup in methods.GroupBy(f => f.ContainingType, SymbolEqualityComparer.Default))
{
var classBuilder = new StringBuilder();
if (typeGroup.Key.ContainingNamespace != null)
classBuilder
.AppendLine("using System;")
.Append("namespace ")
.Append(typeGroup.Key.ContainingNamespace)
.AppendLine(";");
classBuilder
.Append("partial class ")
.AppendLine(typeGroup.Key.Name)
.AppendLine("{");
foreach (var method in typeGroup)
{
var namedReturn = method.ReturnType as INamedTypeSymbol;
var arrayReturn = method.ReturnType as IArrayTypeSymbol;
if ((namedReturn != null && namedReturn.Arity > 0) || arrayReturn != null)
{
ITypeSymbol enumType = namedReturn != null
? namedReturn.TypeArguments.Last()
: arrayReturn!.ElementType;
var isDic = method.HasAttributeWithFullyQualifiedName(DictionaryAttributeFullName);
classBuilder
.Pad(1)
.Append("private static partial " + method.ReturnType + " " + method.Name + "()")
.AppendLine().Pad(4).Append(" => new ").Append(method.ReturnType).AppendLine("{");
foreach (var member in enumType.GetMembers())
{
if (member.Name == ".ctor")
continue;
if (isDic)
classBuilder.Pad(2)
.Append("{\"")
.Append(member.Name)
.Append("\", ")
.Append(member.ToString())
.AppendLine("},");
else
classBuilder.Pad(2).Append(member.ToString()).AppendLine(",");
}
classBuilder.Pad(1).AppendLine("};");
}
}
classBuilder.AppendLine("}");
context.AddSource(typeGroup.Key.GetFullyQualifiedName().Replace(":", ""), classBuilder.ToString());
}
});
}
}