RegisterHostOutputs
- Dominant language
- C#
- Stars
- 20.7k
- Forks
- 4.3k
- PR merge metrics
- PR metrics pending
Description
## Background and Motivation
This is a re-working of a previous proposal: https://github.com/dotnet/roslyn/issues/63291
The basic idea is to allow generators to specify a 'host specific' output. That is, something that doesn't contribute to the compilation, or even do anything other than appear in the run result for the generator.
Razor would like to use this to store the intermediate state that was used to generate documents, which is needed for the tooling.
It would also be useful in testing scenarios. We have lots of places today where we want to check something was called, or some operation produced some output, and we 'smuggle' the result out by adding some source with a content like `// {result.ToString()}`. Host outputs would allow us an easy mechanism to do this sort of result-based testing.
## Proposed API
Implementation PR: https://github.com/dotnet/roslyn/pull/74750/
```diff
namespace Microsoft.CodeAnalysis
{
public readonly partial struct IncrementalGeneratorInitializationContext
{
+ public void RegisterHostOutput(IncrementalValueProvider source, Action action);
+
+ public void RegisterHostOutput(IncrementalValuesProvider source, Action action);
}
+ public readonly struct HostOutputProductionContext
+ {
+ ///
+ /// Adds a host specific output
+ ///
+ /// The name of the output to be added.
+ /// The output to be added.
+ ///
+ /// A host output has no defined use. It does not contribute to the final compilation in any way. Any outputs registered
+ /// here are made available via the collection, and it is up the host to
+ /// decide how to use them. A host may also disable these outputs altogether if they are not needed. The generator driver
+ /// otherwise makes no guarantees about how the outputs are used, other than that they will be present if the host has
+ /// requested they be produced.
+ ///
+ public void AddOutput(string name, object value) => Outputs.Add((name, value));
+
+ ///
+ /// A that can be checked to see if producing the output should be cancelled.
+ ///
+ public CancellationToken CancellationToken { get; }
+ }
public readonly struct GeneratorRunResult
{
+ ///
+ /// A collection of items added via .
+ ///
+ public ImmutableArray<(string, object)> HostOutputs { get; }
}
}
```
## Usage Examples
``` C#
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var provider = context.CompilationProvider.Select(/* .. */);
// make outputs available to other consumers
context.RegisterHostOutput(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) => /* .. */);
}
```
## Alternative Designs
In the previous design discussion we talked about if it should be `object` or `string`. We decided on `string` because there were worries about things like serialization and how we would handle that. This proposal switches back to `object` as the seralization overhead for Razor is going to be far too much and we've explicitly designed co-hosting to live in the same process.
For third party usage, I think we should just make it clear that it's entirely up to the host what happens with these outputs, and there is no defined expectation.
## Risks
Contributor guide
Assessment
This issue has not been assessed yet.