HavenDV / H.Generators.Extensions

A set of extensions to simplify the code of generators
MIT License
11 stars 3 forks source link

Add a way to report Diagnostic #5

Closed trejjam closed 1 year ago

trejjam commented 1 year ago

Hi,

I found myself in need to report Diagnostics of my own creation inside a source generator.

How do you like this code to be part of this project?

public static class IncrementalValuesProviderExtensions
{
    /// <summary>
    ///
    /// </summary>
    /// <param name="source"></param>
    /// <param name="initializationContext"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static IncrementalValuesProvider<T> SelectAndReportDiagnostics<T>(
        this IncrementalValuesProvider<ResultWithDiagnostics<T>> source,
        IncrementalGeneratorInitializationContext initializationContext
    ) where T : notnull
    {
        initializationContext.RegisterSourceOutput(source
                .Where(static x => x.Diagnostics is { Length: > 0 }),
            (context, result) =>
            {
                foreach (var diagnostic in result.Diagnostics)
                {
                    context.ReportDiagnostic(diagnostic);
                }
            });

        return source
            .Where(static x => x.Result is not null)
            .Select(static (x, _) => x.Result!);
    }
}

public record struct ResultWithDiagnostics<T>(
    T? Result,
    ImmutableArray<Diagnostic> Diagnostics
) where T : notnull
{
    public ResultWithDiagnostics(T? result) : this(result, ImmutableArray<Diagnostic>.Empty)
    {
    }

    public static ResultWithDiagnostics<T> Empty => new();
}

public static class ResultWithDiagnosticsExtensions
{
    public static ResultWithDiagnostics<T> ToResultWithDiagnostics<T>(this T? result) where T : notnull => new(result);

    public static ResultWithDiagnostics<T> ToResultWithDiagnostics<T>(this T? result, ImmutableArray<Diagnostic> diagnostics) where T : notnull => new(result, diagnostics);
}
HavenDV commented 1 year ago

Yes, of course, I will gladly accept PR regarding this. We need to consider whether your class is suitable for caching. There is a special EquatableArray (from CommunityToolkit.Mvvm.SourceGenerators) here that can be compared.

Are you familiar with how caching works in Source Generators?

HavenDV commented 1 year ago

I added it and indicated you as co-author: https://github.com/HavenDV/H.Generators.Extensions/commit/187d7e46c8c4b2494aac6197566a52bf44e2723d

I didn't understand the need for where T : notnull in your code. This may be my misunderstanding of the nullable system in C#, but it seems redundant to me. Please check if needed I will fix it

trejjam commented 1 year ago

Thank you for the release. It works without T : notnull also, the only difference is that you need to specify ResultWithDiagnostics<T?> instead of ResultWithDiagnostics<T> but it's not an issue. Thank you again.

trejjam commented 1 year ago

I know that caching is heavily used in source generators, but I was not aware that ImmutableArray is not enough