Skip to content

Identical metadata in a new AdditionalText instance re-runs the whole generator, because MetadataFile has no value equality #27

Description

@matt-edmondson

What's wrong

GeneratorBase projects each AdditionalText into new MetadataFile(...) and then Collects the results (GeneratorBase.cs:60-66). MetadataFile (MetadataFile.cs:18) is a class with no Equals or GetHashCode. Roslyn compares incremental step outputs with default equality, so the check is effectively reference identity. A new AdditionalText with byte-identical contents therefore always produces a "modified" step, and the whole Generate runs again: every file is deserialized and every source re-emitted.

In an IDE a new AdditionalText instance is created in several ordinary cases, such as an edit followed by an undo, or a save with no content change. The incremental pipeline does not save any work in those cases.

GeneratorHarness.ReusesCachedOutputOnRerun does not catch this. It reuses the same AdditionalText instances and changes only the compilation.

Repro

  1. Create a driver with trackIncrementalGeneratorSteps: true and the test project's ThingsGenerator, and run it once.
  2. Call driver.ReplaceAdditionalText(t1, new MemText(samePath, sameText)).
  3. Run it again against the same compilation.
  • Observed: the tracked output step's reason is Modified.
  • Expected: Cached or Unchanged.

Suggested fix

  • Implement IEquatable<MetadataFile> using ordinal comparison of FileName, the path and Text (or SourceText.ContentEquals), with a matching GetHashCode.
  • Extend GeneratorHarness with a check that swaps in equal-content AdditionalTexts and asserts the outputs are cached, so a regression is caught.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    readyFully specified; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions