You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ReusesCachedOutputOnRerun always passes, even for a non-incremental generator, because both runs use the same Compilation #19
GeneratorHarness.ReusesCachedOutputOnRerun (SourceGeneratorToolkit.Testing/GeneratorHarness.cs:~102-127) runs the driver twice against the sameCSharpCompilation instance, with the same AdditionalText instances. Roslyn compares incremental inputs by reference, so on the second run every node, CompilationProvider included, is reported as Cached/Unchanged whatever the generator does.
The doc comment says the check exists to catch "a generator that recomputes everything on every keystroke". A keystroke produces a newCompilation, and this check never creates one, so it cannot detect that. TheGeneratorReusesItsOutputWhenNothingChanged (GeneratorBaseTests.cs:203) therefore asserts nothing meaningful.
Reproduction (ran)
The generator below is non-incremental by construction:
For comparison, running it on c1 and then on c1.AddSyntaxTrees(CSharpSyntaxTree.ParseText("")) reports the output step as Modified.
Why it matters
This is a test helper that consumers rely on to prove their generators are incremental. A check that always passes gives false confidence and lets IDE-performance regressions ship.
Suggested fix / acceptance criteria
Run the second pass on a new but semantically equivalent compilation, for example compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(string.Empty)) or compilation.WithAssemblyName(compilation.AssemblyName). Ideally also rebuild the AdditionalText instances with identical content, as an IDE does.
Treat "no tracked output steps" as not proven (false, or throw) rather than true.
Add a negative test: the CompilationProvider.Select(_ => new object()) generator above must fail the check.
Priority: High. ReusesCachedOutputOnRerun is the helper consumers use to prove a generator is incremental, and it always returns true. A check that can't fail gives false confidence and lets IDE-performance regressions ship in downstream generators. The toolkit's own test TheGeneratorReusesItsOutputWhenNothingChanged currently proves nothing.
Area / suggested assignee:GeneratorHarness in SourceGeneratorToolkit.Testing. Maintainer: @matt-edmondson.
Next steps: Run the second pass on a new, semantically equivalent Compilation (for example AddSyntaxTrees(ParseText(""))), and rebuild the AdditionalText instances. Return false when no output steps are tracked. Add the negative test from the issue (CompilationProvider.Select(_ => new object()) must fail). Some existing consumer tests may start failing once this lands; that exposes real non-incremental generators, so call it out in the release notes.
Activity
matt-edmondson commentedon Sep 26, 2026
Triage
ReusesCachedOutputOnRerunis the helper consumers use to prove a generator is incremental, and it always returnstrue. A check that can't fail gives false confidence and lets IDE-performance regressions ship in downstream generators. The toolkit's own testTheGeneratorReusesItsOutputWhenNothingChangedcurrently proves nothing.GeneratorHarnessinSourceGeneratorToolkit.Testing. Maintainer: @matt-edmondson.Compilation(for exampleAddSyntaxTrees(ParseText(""))), and rebuild theAdditionalTextinstances. Returnfalsewhen no output steps are tracked. Add the negative test from the issue (CompilationProvider.Select(_ => new object())must fail). Some existing consumer tests may start failing once this lands; that exposes real non-incremental generators, so call it out in the release notes.Generated by Claude Code