Skip to content

feat: migrate whole document in a single pass via custom FixAllProvider#22

Merged
vbreuss merged 2 commits into
mainfrom
feat/fix-all-provider-single-pass
May 16, 2026
Merged

feat: migrate whole document in a single pass via custom FixAllProvider#22
vbreuss merged 2 commits into
mainfrom
feat/fix-all-provider-single-pass

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented May 16, 2026

The previous BatchFixer-based pipeline dropped per-diagnostic rewrites whose text changes overlapped on the using-directive line, and once the first using swap landed the analyzer no longer fired on remaining TestableIO bindings — leaving files partially migrated and uncompilable.

Each per-pattern Apply method is split into a pure helper that operates on (CompilationUnitSyntax, SyntaxNode) without touching usings. A new SystemIOAbstractionsFixAllProvider annotates every diagnostic target, dispatches the pure helpers sequentially with annotation-relocation and re-acquired semantic models, then applies a single using-directive change at the end. The per-diagnostic CodeAction re-runs the analyzer to find sibling diagnostics in the same document and routes through the same provider, so one click in the IDE migrates the whole file (Mockolate-style).

The previous BatchFixer-based pipeline dropped per-diagnostic rewrites
whose text changes overlapped on the using-directive line, and once the
first using swap landed the analyzer no longer fired on remaining
TestableIO bindings — leaving files partially migrated and uncompilable.

Each per-pattern Apply method is split into a pure helper that operates
on (CompilationUnitSyntax, SyntaxNode) without touching usings. A new
SystemIOAbstractionsFixAllProvider annotates every diagnostic target,
dispatches the pure helpers sequentially with annotation-relocation and
re-acquired semantic models, then applies a single using-directive change
at the end. The per-diagnostic CodeAction re-runs the analyzer to find
sibling diagnostics in the same document and routes through the same
provider, so one click in the IDE migrates the whole file (Mockolate-style).
@vbreuss vbreuss self-assigned this May 16, 2026
Copilot AI review requested due to automatic review settings May 16, 2026 08:14
@vbreuss vbreuss added the enhancement New feature or request label May 16, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 16, 2026

Test Results

  6 files  ±0    6 suites  ±0   1m 33s ⏱️ -3s
164 tests +3  164 ✅ +3  0 💤 ±0  0 ❌ ±0 
492 runs  +9  490 ✅ +9  2 💤 ±0  0 ❌ ±0 

Results for commit ecd68ce. ± Comparison against base commit 14b2560.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Replaces the default BatchFixer-based fix-all pipeline (which dropped overlapping using-line edits and lost subsequent diagnostics after the first using swap) with a custom SystemIOAbstractionsFixAllProvider. Each per-pattern rewriter is refactored into a pure helper operating on (CompilationUnitSyntax, SyntaxNode); the new provider annotates targets, dispatches the pure helpers sequentially with re-acquired semantic models, and applies a single using-directive change at the end. Per-diagnostic CodeActions also reroute through this provider so one click migrates the whole file.

Changes:

  • Introduce SystemIOAbstractionsFixAllProvider.MigrateDocumentAsync to annotate, sequentially rewrite, and apply a single using-directive change.
  • Refactor every per-pattern ApplyXxxRewriteAsync into pure ApplyXxxPure helpers; centralize using-directive policy (UsingChange, GetUsingChange, ApplyUsingChange) and add ApplySinglePatternAsync that re-runs the analyzer to expand single fixes to whole-file fixes.
  • Add FixAllTests covering multi-diagnostic, mixed-pattern, and same-receiver scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
Source/Testably.Abstractions.Migration.Analyzers.CodeFixers/SystemIOAbstractionsFixAllProvider.cs New DocumentBasedFixAllProvider orchestrating the annotation-and-rewrite pass.
Source/Testably.Abstractions.Migration.Analyzers.CodeFixers/SystemIOAbstractionsCodeFixProvider.cs Refactors per-pattern rewrites into pure helpers; adds dispatch, using-change policy, and single-diagnostic→whole-file routing.
Tests/Testably.Abstractions.Migration.Tests/SystemIOAbstractionsCodeFixProviderTests.FixAllTests.cs End-to-end tests for multi-diagnostic fix-all scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Extract CollectAndAnnotate + ApplyRewritesAsync helpers so each method
stays under Sonar's cognitive-complexity ceiling of 15 (the original
MigrateDocumentAsync hit 23).

Hoist maxUsingChange computation from the work-item intent before the
rewrite loop, so a block-level rewrite that absorbs a sibling annotated
node still applies the absorbed item's using-directive change. Guard the
final swap with anyRewriteSucceeded so a no-op pass doesn't add a
Testably using to a still-TestingHelpers-bound file.

Skip the Document round-trip for purely syntactic patterns (most of them)
and only sync through a fresh SemanticModel for AccessorAddFile,
FilesCtor*, and AddFilesFromEmbeddedNamespace. When a sync is necessary,
re-locate the annotated target in the round-tripped tree — Roslyn's
WithSyntaxRoot may produce a tree whose nodes are not reference-equal to
the input, which would make SemanticModel.GetSymbolInfo reject them.
@vbreuss vbreuss enabled auto-merge (squash) May 16, 2026 16:36
@sonarqubecloud
Copy link
Copy Markdown

@vbreuss vbreuss merged commit 78ea842 into main May 16, 2026
9 checks passed
@vbreuss vbreuss deleted the feat/fix-all-provider-single-pass branch May 16, 2026 16:39
@github-actions
Copy link
Copy Markdown

This is addressed in release v0.2.0.

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

Labels

enhancement New feature or request state: released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants