C# Trigger source generator from generated source

Viewed 21

I've created an incremental source generator that generates a class that meet the requirements of a JSON source generator class.

My problem is: how can I trigger source generation from a source generated file? Currently I've solved it by building the project twice. The first time it'll execute my generator and fail ('WeatherJsonContext' does not implement inherited abstract member ...). The second time it'll execute the JSON source generator and the build succeeds.

Some code (for testing I use a const):

namespace ClassJsonGen;

using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

[Generator]
public class CustomGenerator : IIncrementalGenerator
{
    private const string TestSource = @"
            namespace WebJsonGen {
                using System.Text.Json.Serialization;
                [JsonSerializable(typeof(IEnumerable<WeatherForecast>))]
                [JsonSerializable(typeof(IEnumerable<StormForecast>))]
                public partial class WeatherJsonContext : JsonSerializerContext
                { } 
            }";

    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
#if DEBUG
        if (!Debugger.IsAttached)
        {
            Debugger.Launch();
        }
#endif

        var todoInput = context.SyntaxProvider
            .CreateSyntaxProvider(
                predicate: static (s, _) => s is ClassDeclarationSyntax,
                transform: static (ctx, _) => ctx.Node)
            .Where(static m => m is not null);

        context.RegisterSourceOutput(todoInput, (ctx, inp) =>
        {
            // TODO use input to determine which [JsonSerializable] we need :-)
            ctx.AddSource("JSON.g.cs", SourceText.From(TestSource, Encoding.UTF8));
        });
    }
}

Which generates:

namespace WebJsonGen {
    using System.Text.Json.Serialization;
    [JsonSerializable(typeof(IEnumerable<WeatherForecast>))]
    [JsonSerializable(typeof(IEnumerable<StormForecast>))]
    public partial class WeatherJsonContext : JsonSerializerContext
    { } 
}

In the consuming project I've added in the .csproj:

    <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>

    <ItemGroup>
        <!-- Exclude the output of source generators from the compilation -->
        <Compile Remove="$(CompilerGeneratedFilesOutputPath)/System.Text.Json.SourceGeneration/**/*.cs" />
        <Compile Include="$(CompilerGeneratedFilesOutputPath)/System.Text.Json.SourceGeneration/**/JSON*.cs" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassJsonGen\ClassJsonGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    </ItemGroup>
0 Answers
Related