My generator needs to find all types in referenced projects which meet a specific criteria and generate a class for each of them using their method return types.
Example input (in a referenced project, not the one that references generator):
class SuitableClass
{
public CustomType1 GetCustomType1() { ... }
public CustomType2 GetCustomType2() { ... }
}
class SuitableClass2
{
public CustomType3 GetCustomType4() { ... }
public CustomType4 GetCustomType4() { ... }
}
Example output:
public class SuitableClassGenerated
{
public void Handle(CustomType1) { ... }
public void Handle(CustomType2) { ... }
}
public class SuitableClass2Generated
{
public void Handle(CustomType3) { ... }
public void Handle(CustomType4) { ... }
}
Generator code:
public void Initialize(IncrementalGeneratorInitializationContext context)
{
IncrementalValuesProvider<string> typeNames = context
.CompilationProvider
.SelectMany((c, _) => GetAllSupportedTypes(c.SourceModule.ReferencedAssemblySymbols)
.Select(x => x.ContainingNamespace.ToDisplayString() + "." + x.MetadataName));
IncrementalValuesProvider<Info> generationInput = typeNames
.Combine(context.CompilationProvider)
.Select((c, _) =>
{
var clientType = c.Right.GetTypeByMetadataName(c.Left);
if (clientType == null)
return default;
return new Info(clientType.Name,
clientType.GetMembers().OfType<IMethodSymbol>()
.Where(m => m is { DeclaredAccessibility: Accessibility.Public, IsStatic: false, ReturnsVoid: false })
.Select(m => m.ReturnType.ToDisplayString())
.ToImmutableArray());
})
.Where(x => x.Methods != null);
context.RegisterSourceOutput(generationInput,
(ctx, input) =>
{
var code = GenerateCode(input);
if (code != null)
ctx.AddSource($"{input.Name}.g.cs", code);
});
}
record struct Info(string Name, ImmutableArray<string> Methods);
As you see, the two stages require an access to Compilation which breaks the whole caching idea. Is there a way to make caching work so that some stages can be omitted? For an example, if I add a method with a new return type, I only need the second stage to be rerun.
Is there a way to rewrite such multi-stage Compilation-related pipeline to make it more cache-friendly?
CompilationProviderand not theSyntaxProvider? Any specific reason? Furthermore how do you determine the suitable class, via an attribute?