Files
osu-framework/osu.Framework.SourceGeneration/Generators/IncrementalSourceEmitter.cs
2023-04-28 23:13:30 +09:00

87 lines
2.9 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace osu.Framework.SourceGeneration.Generators
{
public abstract class IncrementalSourceEmitter
{
protected abstract string FileSuffix { get; }
private const string headers = @"// <auto-generated/>
#nullable enable
#pragma warning disable CS4014
";
public readonly IncrementalSemanticTarget Target;
protected IncrementalSourceEmitter(IncrementalSemanticTarget target)
{
Target = target;
}
public void Emit(AddSourceDelegate addSource)
{
if (!Target.IsValid)
return;
StringBuilder result = new StringBuilder();
result.Append(headers);
if (Target.ContainingNamespace == null)
{
result.Append(
emitTypeTree().NormalizeWhitespace());
}
else
{
result.Append(
SyntaxFactory.NamespaceDeclaration(
SyntaxFactory.IdentifierName(Target.ContainingNamespace))
.WithMembers(
SyntaxFactory.SingletonList(
emitTypeTree()))
.NormalizeWhitespace());
}
// Fully qualified name, with generics replaced with friendly characters.
string typeName = Target.FullyQualifiedTypeName.Replace('<', '{').Replace('>', '}');
string filename = $"g_{typeName}_{FileSuffix}.cs";
addSource(filename, result.ToString());
}
protected abstract ClassDeclarationSyntax ConstructClass(ClassDeclarationSyntax initialClass);
private MemberDeclarationSyntax emitTypeTree()
{
List<ClassDeclarationSyntax> classes = new List<ClassDeclarationSyntax>();
foreach (string type in Target.TypeHierarchy)
classes.Add(createClassSyntax(type));
classes[0] = ConstructClass(classes[0]);
for (int i = 0; i < classes.Count - 1; i++)
classes[i + 1] = classes[i + 1].WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(new[] { classes[i] }));
return classes.Last();
static ClassDeclarationSyntax createClassSyntax(string type) =>
SyntaxFactory.ClassDeclaration(type)
.WithModifiers(
SyntaxTokenList.Create(
SyntaxFactory.Token(SyntaxKind.PartialKeyword)));
}
}
public delegate void AddSourceDelegate(string filename, string sourceText);
}