Skip to content

feat: Phase 4c discriminate captured-reference property accesses#12

Merged
vbreuss merged 2 commits into
mainfrom
feat/phase-4c-captured-reference
May 15, 2026
Merged

feat: Phase 4c discriminate captured-reference property accesses#12
vbreuss merged 2 commits into
mainfrom
feat/phase-4c-captured-reference

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented May 15, 2026

Today every MockFileData property access reports the generic propertyRead or propertyWrite pattern; the code-fix's TryMatchOneShotGetFileRead/Write then bails internally for captured references (locals, parameters, fields) because the receiver is not an <expr>.GetFile(path) invocation. That works but the diagnostic is indistinguishable from a fixable one-shot access — users have no signal that flow analysis is what's missing.

Move the shape check into the analyzer: a property reference whose Instance is <expr>.GetFile(<single-arg>) stays on the existing propertyRead/Write pattern; everything else gets the new capturedReferenceRead/Write pattern. The code-fix dispatcher has no case for the captured-ref patterns, so it falls through silently — observable behavior is unchanged.

The code-fix's internal shape check is kept for defense in depth: if the analyzer's gate is ever loosened, the code-fix still won't try to rewrite a non-one-shot site.

Tests cover local, parameter and field receivers; the existing CapturedReference HasNoFix tests still pass via the new pattern fall- through and get an updated comment.

Today every MockFileData property access reports the generic propertyRead
or propertyWrite pattern; the code-fix's TryMatchOneShotGetFileRead/Write
then bails internally for captured references (locals, parameters, fields)
because the receiver is not an `<expr>.GetFile(path)` invocation. That
works but the diagnostic is indistinguishable from a fixable one-shot
access — users have no signal that flow analysis is what's missing.

Move the shape check into the analyzer: a property reference whose
Instance is `<expr>.GetFile(<single-arg>)` stays on the existing
propertyRead/Write pattern; everything else gets the new
capturedReferenceRead/Write pattern. The code-fix dispatcher has no case
for the captured-ref patterns, so it falls through silently — observable
behavior is unchanged.

The code-fix's internal shape check is kept for defense in depth: if the
analyzer's gate is ever loosened, the code-fix still won't try to rewrite
a non-one-shot site.

Tests cover local, parameter and field receivers; the existing
CapturedReference HasNoFix tests still pass via the new pattern fall-
through and get an updated comment.
@vbreuss vbreuss self-assigned this May 15, 2026
Copilot AI review requested due to automatic review settings May 15, 2026 06:38
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

This PR refines the System.IO.Abstractions migration analyzer to distinguish one-shot fs.GetFile(path).Prop property accesses (potentially auto-fixable) from captured-reference MockFileData property accesses (manual review), improving diagnostic signal without changing observable code-fix behavior.

Changes:

  • Update the analyzer to emit new pattern IDs for MockFileData property reads/writes when the receiver is not a one-shot GetFile(...) invocation.
  • Add analyzer tests covering captured-reference receivers via local, parameter, and field.
  • Update/extend test fixtures and comments to reflect the new Phase 4c classification.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Tests/Testably.Abstractions.Migration.Tests/SystemIOAbstractionsCodeFixProviderTests.MockFileDataTests.cs Updates the captured-reference “no fix” test commentary to reflect the new analyzer pattern classification.
Tests/Testably.Abstractions.Migration.Tests/SystemIOAbstractionsAnalyzerTests.cs Adds new analyzer tests for captured-reference reads/writes (local/parameter/field).
Tests/Testably.Abstractions.Migration.SystemIOAbstractionsPlayground/MockFileDataTests.cs Adds a playground/manual-review fixture demonstrating captured-reference access via a local.
Source/Testably.Abstractions.Migration.Analyzers/SystemIOAbstractionsAnalyzer.cs Implements Phase 4c discriminator logic to choose between one-shot vs captured-reference pattern IDs.
Source/Testably.Abstractions.Migration.Analyzers/Patterns.cs Introduces new pattern constants for captured-reference reads and writes.

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

Comment thread Source/Testably.Abstractions.Migration.Analyzers/SystemIOAbstractionsAnalyzer.cs Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

Test Results

  6 files  ± 0    6 suites  ±0   1m 17s ⏱️ -2s
110 tests + 5  110 ✅ + 5  0 💤 ±0  0 ❌ ±0 
330 runs  +15  328 ✅ +15  2 💤 ±0  0 ❌ ±0 

Results for commit 2db005d. ± Comparison against base commit 9fbd17f.

♻️ This comment has been updated with latest results.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 15, 2026 06:43
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 15, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
2 New issues

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@vbreuss vbreuss merged commit c837ba9 into main May 15, 2026
10 of 11 checks passed
@vbreuss vbreuss deleted the feat/phase-4c-captured-reference branch May 15, 2026 06:47
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment on lines +322 to +362
[Fact]
public async Task MockFileDataCapturedReferenceRead_FromLocal_ShouldBeFlagged()
{
const string source = """
using System.IO.Abstractions.TestingHelpers;

public class C
{
public string Read(MockFileSystem fs)
{
MockFileData data = fs.GetFile("/a");
return {|#0:data.TextContents|};
}
}
""";

await Verifier.VerifyAnalyzerAsync(
source,
Verifier.Diagnostic(Rules.SystemIOAbstractionsRule).WithLocation(0));
}

[Fact]
public async Task MockFileDataCapturedReferenceWrite_FromLocal_ShouldBeFlagged()
{
const string source = """
using System.IO;
using System.IO.Abstractions.TestingHelpers;

public class C
{
public void Write(MockFileSystem fs)
{
MockFileData data = fs.GetFile("/a");
{|#0:data.Attributes|} = FileAttributes.ReadOnly;
}
}
""";

await Verifier.VerifyAnalyzerAsync(
source,
Verifier.Diagnostic(Rules.SystemIOAbstractionsRule).WithLocation(0));
Comment on lines +94 to +104
/// A read access to a <c>MockFileData</c> property whose receiver is a captured
/// reference (local, parameter, field, etc.) rather than a one-shot
/// <c>fs.GetFile(path)</c> invocation — no safe textual rewrite without flow
/// analysis.
/// </summary>
public const string MockFileDataCapturedReferenceRead = "MockFileData.capturedReferenceRead";

/// <summary>
/// A write/assignment to a <c>MockFileData</c> property whose receiver is a
/// captured reference rather than a one-shot <c>fs.GetFile(path)</c> invocation
/// — no safe textual rewrite without flow analysis.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants