Skip to content

fix(generator): ship a single Roslyn analyzer slot - #2305

Merged
ChrisPulman merged 3 commits into
mainfrom
fix/single-roslyn-analyzer-slot
Aug 14, 2026
Merged

fix(generator): ship a single Roslyn analyzer slot#2305
ChrisPulman merged 3 commits into
mainfrom
fix/single-roslyn-analyzer-slot

Conversation

@glennawatson

@glennawatson glennawatson commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Bug fix, plus a dependency update and a build configuration change.

What is the new behavior?

The package ships a single analyzers/dotnet/roslyn4.8/cs slot, so exactly one source generator runs on every project style.

  • The Roslyn 5.0 generator, analyzer and code fix projects are gone. Both builds emitted byte-identical source; the only version-specific code was collection expressions standing in for array builders, forced by the System.Collections.Immutable version the 4.8 leg resolves rather than by any compiler capability.
  • A compiler older than the shipped slot now fails the build with REFIT001, naming the Roslyn version it found and pointing at either upgrading the build tools or DisableRefitSourceGenerator plus Refit.Reflection.
  • The README documents the build-time requirements - Roslyn 4.8, Visual Studio 2022 17.8, .NET SDK 8.0.100, PackageReference. The SDK Requirements heading had been empty since v8.0.0, and the minimum moved to Roslyn 4.8 in v12 without a note anywhere.
  • A test pins the packaged slot and the REFIT001 floor to each other, so moving one without the other fails rather than shipping a package whose guard disagrees with its contents.

All 21 stale non-Roslyn dependencies move to their newest release within their own major band. The Roslyn toolchain stays pinned, since its version is what sets the minimum compiler consumers need.

The repository adopts the shared ReactiveUI .editorconfig.

  • Refit's file_header_template is kept, so source files keep the ReactiveUI and Contributors licence header rather than the .NET Foundation one.
  • RS0016 and RS0017 stay at error. They enforce the PublicAPI baselines under src/*/PublicAPI, which the shared config does not carry because ReactiveUI does not track public API that way.
  • Fourteen rules relax to none and eighteen arrive at error. Satisfying the new ones reordered documentation tags into their canonical order and reordered four negative-valued enum fixtures into ascending order.

What is the current behavior?

Closes #2304.

  • The package ships two analyzer slots, roslyn4.8 and roslyn5.0. Only the .NET SDK narrows that to one folder - ResolvePackageAssets picks the highest slot at or below $(CompilerApiVersion).
  • A legacy non-SDK .csproj never runs that task, so it receives both slots, runs both generators, and fails to build on duplicate attributes and duplicate members. Upgrading Visual Studio cannot fix it, because no version of MSBuild runs that task for a non-SDK project.
  • This regressed in v12. A prune target in refit.targets used to handle it; the target was dropped during a reformat in refactor: align Refit with rxui coding standards and modernize #2149 and the file removed in feat: generate request construction to avoid reflection pipeline #2150.
  • A consumer below Roslyn 4.8 gets no analyzer at all - NuGet drops a slot newer than the host compiler with no diagnostic - so generation silently produces nothing.

What might this PR break?

  • ReactiveUI.Primitives moves from 7.0.0 to 7.1.1, raising the runtime dependency version the shipped package resolves. In-major, so no API change.
  • Roslyn 4.8 is now enforced rather than merely assumed. A project below it previously built with no generated clients and confusing downstream errors; it now fails with REFIT001. The effective minimum is unchanged - v12 already shipped no slot below 4.8.
  • The InterfaceStubGeneratorV3 assembly no longer exists in the package. Nothing referenced it by name; the generated GeneratedCodeAttribute now always reads InterfaceStubGeneratorV2.
  • Contributors get a different analyzer set. This changes what the build rejects, not what the library does.

Checklist

  • I have read the Contribute guide
  • Tests have been added or updated (for bug fixes / features)
  • Docs have been added or updated (for bug fixes / features)
  • Changes target the main branch
  • PR title follows Conventional Commits

Additional information

Most of the diff is deletions, mechanical repointing, and tool-driven reordering. The hand-written parts worth review are:

  • src/Refit/targets/refit.props - the REFIT001 target. It has to be a target rather than a plain condition, because $(CompilerApiVersion) is set by the Roslyn targets long after this .props file is evaluated. Every guard is fail-open: an unset, non-C#, non-Roslyn or malformed value skips the check rather than breaking a build we do not understand.
  • src/tests/Refit.GeneratorTests/AnalyzerPackagingTests.cs - the three packaging invariants.
  • src/Refit/Refit.csproj - the comment on the packaging block explaining why a second slot must not be added back.
  • .editorconfig - the preserved file_header_template, and the RS0016/RS0017 entries kept alongside the PAS block.

Everything else in the third commit is a documentation-tag reorder produced by a syntax rewriter. No documentation text changed, only tag order.

The second commit carries three code changes that are fallout from the dependency bump, not from the fix: an interpolated string, a loop variable moved into its for header, and a suppression on the DynamicallyAccessedMemberTypes polyfill, which mirrors a BCL enum whose bit 1 has no standalone member - naming one would diverge from the type it stands in for.

- Drop the Roslyn 5.0 generator, analyzer and code fix projects so the package
  ships one analyzers/dotnet/roslyn4.8/cs slot.
- Only the .NET SDK narrows a multi-slot package to one folder. A legacy non-SDK
  .csproj never runs ResolvePackageAssets, so it received both slots, ran both
  generators and failed to build on duplicate types.
- Both builds emitted byte-identical source; the only version-specific code was
  collection expressions standing in for array builders.
- Fail the build with REFIT001 when the compiler predates the shipped slot, which
  NuGet otherwise drops silently, leaving no generated clients and no explanation.
- Document the build-time requirements in the README, whose SDK Requirements
  heading had been empty since v8.0.0.

Closes #2304.
- Move all 21 stale pins to their newest release within their own major band.
  The Roslyn toolchain stays pinned, since its version sets the minimum compiler
  consumers need.
- ReactiveUI.Primitives 7.0.0 -> 7.1.1 raises the runtime dependency the shipped
  package resolves.
- Rewrite a string.Concat as interpolation and hoist a loop variable into its for
  header, both newly reported by the analyzer bump.
- Suppress SST2461 on the DynamicallyAccessedMemberTypes polyfill, which mirrors a
  BCL enum whose bit 1 has no standalone member.
- Disable SST1534, which reverses SST1525 and RCS1111. Braces on switch sections
  are the house style, and RCS1031 is already off for the same reason.
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.91%. Comparing base (b455f65) to head (572fba1).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2305      +/-   ##
==========================================
- Coverage   99.91%   99.91%   -0.01%     
==========================================
  Files         192      192              
  Lines       10029    10027       -2     
  Branches     1924     1924              
==========================================
- Hits        10020    10018       -2     
  Partials        9        9              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Replace .editorconfig with the ReactiveUI copy, keeping Refit's
  file_header_template so source files keep their own licence header.
- Keep RS0016 and RS0017 at error. They enforce the PublicAPI baselines under
  src/*/PublicAPI, which ReactiveUI does not track and the copy would have dropped.
- Order documentation tags canonically, which SST1666 now requires.
- Order the negative-valued enum fixtures ascending for SST1222. Member order
  carries no semantics, so the fixtures behave as before.
@sonarqubecloud

Copy link
Copy Markdown

@ChrisPulman
ChrisPulman merged commit 74cbb64 into main Aug 14, 2026
18 checks passed
@ChrisPulman
ChrisPulman deleted the fix/single-roslyn-analyzer-slot branch August 14, 2026 13:57
@github-actions

Copy link
Copy Markdown

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Multiple StubGenerator on .net framework project

2 participants