SyntaxValueProvider.CreateSyntaxProvider takes two Func arguments: a predicate that filters the syntax elements, and a transform that returns the interesting details from the syntax context. The result sets from each Func are cached and compared with previous invocations to avoid unnecessary regeneration.
CreateSyntaxProvider returns an IncrementalValuesProvider, which has several extension methods that look like LINQ but aren't. Are the result sets from these extensions also cached and compared, potentially preventing regeneration if their output is unchanged?
In many tutorials, the transform returns either the interesting details from the syntax context, or null. The nulls are then removed with a pseudo-LINQ Where:
var provider = context.SyntaxProvider.CreateSyntaxProvider(
(syntax, _) => Predicate(syntax),
(syntaxContext, _) => DetailsOrNull(syntaxContext))
.Where(details => details != null);
initContext.RegisterSourceOutput(provider, (spc, details) => Generate(spc, details));
What I'm getting at with this question is whether the following would be equivalent in terms of preventing Generate from being called:
var provider = context.SyntaxProvider.CreateSyntaxProvider(
(syntax, _) => Predicate(syntax),
(syntaxContext, _) => syntaxContext
.Where(syntaxContext => IsInteresting(syntaxContext))
.Select((syntaxContext, _) => Details(syntaxContext));
initContext.RegisterSourceOutput(provider, (spc, details) => Generate(spc, details));
This would be less efficient if IsInteresting and Details extract the same information from syntaxContext. But if they don't duplicate work, is there any reason to do it the first way?
As far as I understand the whole thing is a pipeline with several steps. Each step of the pipeline represents a stage which has input/output cached. I don't think that the clarify that, however Andrew Lock's blog post describes that well. The LINQ-like extension method
.Whereis step 4.Also image from the blog post: