roslyn
roslyn copied to clipboard
Intermediate Generator outputs
Background and Motivation
Today, generators act like a 'black box. Inputs go in at one end, generated source files come out at the other end. As we continue to enable and support DSL-like experiences there becomes a desire to be able to 'see' into the workings of the generator. This is especially true for tooling scenarios (such as razor) that are using the generator infrastructure to handle compilation: the tooling needs a way of getting extra information out of the generator beyond simply the generated files.
This proposal adds a new output type, known as an Intermediate Output, that consists of a simple key value pair, that allows generators to emit arbitrary data. This can then be accessed from the generator run result by any interested party. Much like source file hint names, the key must be unique within a generator, but will not collide across generators.
It is expected that this API would only take effect in IDE scenarios, and be a no-op on command line builds.
Proposed API
namespace Microsoft.CodeAnalysis
{
public readonly partial struct IncrementalGeneratorInitializationContext
{
+ public void RegisterIntermediateOutput<TSource>(IncrementalValueProvider<TSource> source, Action<IntermediateOutputContext, TSource> action);
+
+ public void RegisterIntermediateOutput<TSource>(IncrementalValuesProvider<TSource> source, Action<IntermediateOutputContext, TSource> action);
}
+ public readonly struct IntermediateOutputContext
+ {
+ public CancellationToken CancellationToken { get; }
+
+ public void AddOutput(string name, object value);
+ }
public readonly struct GeneratorRunResult
{
+ public ImmutableDictionary<string, object> Intermediates { get; }
}
}
Usage Examples
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.CompilationProvider.Select(/* .. */);
// make outputs available to other consumers
context.RegisterIntermediateOutput(provider, (context, value) =>
{
context.AddOutput("key", value);
});
// NOTE: can still do more with the provider
var provider2 = provider.Select(/* .. */);
// regular source output
context.RegisterSourceOutput(provider2, (context, value) => /* .. */);
}