83 lines
3.2 KiB
C#
83 lines
3.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
|
|
namespace Nebula.SourceGenerators;
|
|
|
|
[Generator]
|
|
public class DependencyAutoGenerator : IIncrementalGenerator
|
|
{
|
|
private static readonly string ConstructGeneratorAttributeName = "Nebula.Shared.Attributes.ConstructGeneratorAttribute";
|
|
private static readonly string GeneratePropertyAttributeName = "Nebula.Shared.Attributes.GeneratePropertyAttribute";
|
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
{
|
|
var provider = context.SyntaxProvider
|
|
.CreateSyntaxProvider(
|
|
(s, _) => s is ClassDeclarationSyntax,
|
|
(ctx, _) => SourceHelper.GetClassDeclarationForSourceGen(ctx,ConstructGeneratorAttributeName))
|
|
.Where(t => t.reportAttributeFound)
|
|
.Select((t, _) => t.Item1);
|
|
|
|
context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()),
|
|
(ctx, t) => GenerateCode(ctx, t.Left, t.Right));
|
|
}
|
|
|
|
private void GenerateCode(SourceProductionContext context, Compilation compilation,
|
|
ImmutableArray<ClassDeclarationSyntax> classDeclarations)
|
|
{
|
|
foreach (var classDeclarationSyntax in classDeclarations)
|
|
{
|
|
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
|
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
|
continue;
|
|
|
|
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
|
var className = classDeclarationSyntax.Identifier.Text;
|
|
|
|
var propertiesGenerated = GetProperties(classSymbol).ToList();
|
|
|
|
var constr = propertiesGenerated.Select(a => $"{a.Type.ToDisplayString()} g{a.Name}");
|
|
var body = propertiesGenerated.Select(a => $"this.{a.Name} = g{a.Name};");
|
|
|
|
var propertiesGeneratedC = GetProperties(classSymbol)
|
|
.Where(a=>
|
|
SourceHelper.HasAttribute(a,"Nebula.Shared.Attributes.DesignConstructAttribute"))
|
|
.ToList();
|
|
|
|
var bodyC = propertiesGeneratedC.Select(a => $"this.{a.Name} = new {a.Type.ToDisplayString()}();");
|
|
|
|
var code = $@"// <auto-generated/>
|
|
namespace {namespaceName};
|
|
|
|
partial class {className}
|
|
{{
|
|
|
|
public {className}(){{
|
|
{string.Join("\n\t\t", bodyC)}
|
|
InitialiseInDesignMode();
|
|
}}
|
|
public {className}(
|
|
{string.Join(",\n\t\t", constr)}
|
|
) : base(){{
|
|
{string.Join("\n\t\t", body)}
|
|
Initialise();
|
|
}}
|
|
}}
|
|
";
|
|
|
|
// Add the source code to the compilation.
|
|
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
|
}
|
|
}
|
|
|
|
private static IEnumerable<IPropertySymbol> GetProperties(INamedTypeSymbol classSymbol)
|
|
{
|
|
return classSymbol.GetMembers().OfType<IPropertySymbol>().Where(a =>
|
|
SourceHelper.HasAttribute(a, GeneratePropertyAttributeName));
|
|
}
|
|
} |