Skip to content

fix(ownir): drop pooled-view provenance on reassignment (POOL002 FP)#98

Merged
PhysShell merged 4 commits into
mainfrom
claude/pool-view-reassign-fp
Jun 24, 2026
Merged

fix(ownir): drop pooled-view provenance on reassignment (POOL002 FP)#98
PhysShell merged 4 commits into
mainfrom
claude/pool-view-reassign-fp

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 24, 2026

Copy link
Copy Markdown
Owner

ViewOwnerOf read a Span/Memory view local's owner from its declaration initializer only, ignoring later reassignments. So after v = otherBuf.AsSpan(), every later reference to v was still attributed to the original buffer — a false OWN002 (use-after-return) once that original was Returned, including the reassignment's own LHS.

Fix, entirely extractor-side (the core sees no provenance):

  • A simple-assignment target / ref/out arg is a DEF, not a use, so it is excluded from the use scan (IsWriteTarget). An element/member write (v[0] = …) still reads the variable.
  • A reference to a view local past a reassignment of that same symbol drops the declared owner and goes silent (ReassignedBetween, source-order, symbol-matched, intraprocedural).

Both edits only ever REMOVE a use, so the change is monotonic in findings — it cannot manufacture a false positive; its only risk is over-suppression (an FN), guarded by the fixture. Full flow-sensitive per-path provenance (branch-merge, loop back-edges) is left for later.

Pinned by FlowLocalsSample.ReassignedView: the pre-reassignment read of a returned buffer stays a real OWN002 (exactly one, on bufA); the post-reassignment read of the live bufB is silent. Resolves P-007 OQ#1.

Claude-Session: https://claude.ai/code/session_01XdphCUFvstTdkYmYTkAH46

Summary by CodeRabbit

  • New Features

    • Expanded pooled-buffer Span view scenarios in samples for reassignment, reslicing, and stale ref/out usage.
  • Bug Fixes

    • Improved pooled-buffer ownership tracking so findings stay tied to the correct buffer after view reassignment.
    • Reduced false positives by refining what counts as a use, and correctly handling pure writes plus ref/out rebinding timing.
  • Tests

    • Strengthened CI regression checks with targeted OWN002 assertions and negative controls.
  • Documentation

    • Updated proposal text and scenario notes to reflect resolved view provenance behavior and remaining precision limits.

`ViewOwnerOf` read a Span/Memory view local's owner from its declaration
initializer only, ignoring later reassignments. So after
`v = otherBuf.AsSpan()`, every later reference to `v` was still attributed
to the original buffer — a false OWN002 (use-after-return) once that original
was Returned, including the reassignment's own LHS.

Fix, entirely extractor-side (the core sees no provenance):
- A simple-assignment target / `ref`/`out` arg is a DEF, not a use, so it is
  excluded from the use scan (`IsWriteTarget`). An element/member write
  (`v[0] = …`) still reads the variable.
- A reference to a view local past a reassignment of that same symbol drops
  the declared owner and goes silent (`ReassignedBetween`, source-order,
  symbol-matched, intraprocedural).

Both edits only ever REMOVE a `use`, so the change is monotonic in findings —
it cannot manufacture a false positive; its only risk is over-suppression
(an FN), guarded by the fixture. Full flow-sensitive per-path provenance
(branch-merge, loop back-edges) is left for later.

Pinned by `FlowLocalsSample.ReassignedView`: the pre-reassignment read of a
returned buffer stays a real OWN002 (exactly one, on `bufA`); the
post-reassignment read of the live `bufB` is silent. Resolves P-007 OQ#1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdphCUFvstTdkYmYTkAH46
// use-after-return -> exactly ONE OWN002 on `bufA`; `bufB` is returned after its last read -> silent.
public void ReassignedView(int n, int m)
{
byte[] bufA = ArrayPool<byte>.Shared.Rent(n);
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 67c692a5-538f-4169-94b8-135d62b97fcc

📥 Commits

Reviewing files that changed from the base of the PR and between 2d33f55 and 97014cd.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • corpus/real-world/arraypool-span-view-after-return/notes.md
  • docs/proposals/P-007-arraypool-span.md
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/samples/FlowLocalsSample.cs

📝 Walkthrough

Walkthrough

Updates Span view ownership tracking for reassigned locals, adds sample cases for post-return and ref/out use, and extends CI and documentation to cover the new behavior.

Changes

Span View Reassignment Fix

Layer / File(s) Summary
ReassignedView sample method
frontend/roslyn/samples/FlowLocalsSample.cs
Adds sample methods covering post-return reads, reassignment to a second buffer, reslicing after return, ref/out argument timing, and a for-loop incrementor case.
Use collection and owner suppression
frontend/roslyn/OwnSharp.Extractor/Program.cs
Skips pure write identifiers in use collection, adds write/rebind classification helpers, and suppresses view-owner attribution when a view local is reassigned before later use.
Regression assertions and docs
.github/workflows/ci.yml, corpus/real-world/arraypool-span-view-after-return/notes.md, docs/proposals/P-007-arraypool-span.md
Adds CI checks for reassignment, stale-view, sibling-argument, for-incrementor, and out-arg cases tied to OWN002, and updates the notes and proposal text to describe the implemented view-provenance behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PhysShell/Own.NET#69: Modifies the same extractor ownership attribution path for pooled Span views.
  • PhysShell/Own.NET#73: Changes the same ViewOwner/ViewOwnerOf attribution pipeline for pooled buffer views.

Poem

🐇 I hopped from bufA to bufB with a grin,
Then OWN002 stayed where the stale reads begin.
Ref, out, and loops did their timing just right,
And the rabbit taped labels in moon-silver light.
A span got reassigned, the trail stayed neat and clean,
With carrots of truth in the review-machine.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: suppressing stale pooled-view provenance after reassignment to fix a false positive.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/pool-view-reassign-fp

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62e7e7df60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1540 to +1542
if (id.SpanStart > lo && id.SpanStart < hi && IsWriteTarget(id)
&& SymbolEqualityComparer.Default.Equals(model.GetSymbolInfo(id).Symbol, sym))
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't count the current assignment as an earlier rebind

For a RHS reference in an assignment to the same view local, the LHS identifier has an earlier SpanStart, so this loop treats the assignment itself as a prior reassignment. After ArrayPool<byte>.Shared.Return(buf); v = v.Slice(1);, the RHS v is the stale view that should still emit OWN002, but ViewOwnerOf returns null; subsequent uses are also silenced even though Slice preserves the same owner. The rebind check needs to ignore writes from the assignment containing the current use, or compare at statement boundaries.

Useful? React with 👍 / 👎.

Comment on lines +1203 to +1204
&& (arg.RefKindKeyword.IsKind(SyntaxKind.OutKeyword)
|| arg.RefKindKeyword.IsKind(SyntaxKind.RefKeyword))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't treat ref arguments as pure writes

ref arguments are not pure definitions: the current value is passed to the callee and can be read before any assignment, unlike out. With this condition, EmitFlowExpr skips the identifier entirely and ReassignedBetween treats it as a rebind, so cases such as Return(buf); Touch(ref v); no longer emit a use-after-return for the view, and later uses are dropped even if the callee only read it. Keep the pure-write exemption to out, or model ref as both a use and a possible write.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/roslyn/OwnSharp.Extractor/Program.cs`:
- Around line 1534-1541: Adjust ReassignedBetween in OwnSharp.Extractor.Program
so the reassignment scan does not descend into nested deferred bodies like
lambdas or local functions. The current use of scope.DescendantNodes() over
BaseMethodDeclarationSyntax, AccessorDeclarationSyntax, and
LocalFunctionStatementSyntax can see writes inside deferred bodies and
incorrectly block outer uses. Limit the traversal to the immediate body of the
current scope or explicitly skip nested deferred bodies while checking
IdentifierNameSyntax writes against sym.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 021edd92-2846-469d-8856-d63841d4b5f1

📥 Commits

Reviewing files that changed from the base of the PR and between 2d33f55 and 62e7e7d.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • corpus/real-world/arraypool-span-view-after-return/notes.md
  • docs/proposals/P-007-arraypool-span.md
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/samples/FlowLocalsSample.cs

Comment thread frontend/roslyn/OwnSharp.Extractor/Program.cs Outdated
Addresses three over-suppression cases the Codex/CodeRabbit review of #98
found in the b' reassignment-FP fix:

- ref vs out: a `ref` argument passes the current value (a read), unlike
  `out`. Split `IsPureWrite` (`=` LHS + `out`, excluded from the use scan)
  from `IsRebind` (`+ ref`, suppresses later refs), so `Return(buf);
  Touch(ref v);` again emits the use-after-return it had started dropping.
- same-assignment LHS: in `v = v.Slice(1)` the RHS reads the still-stale
  view, so the assignment's own LHS must not count as a prior rebind of its
  own RHS — the reslice keeps tripping OWN002.
- deferred bodies: `ReassignedBetween` no longer treats a write inside a
  nested lambda / local function as a straight-line rebind (it runs on
  invoke, not at its textual position).

Each fix only RESTORES a true-positive use that the first cut over-suppressed;
none can add a false positive. New fixtures `SliceReassignAfterReturn` and
`RefArgUseAfterReturn` pin the two Codex cases (OWN002 on 'sb' / 'rb'); the
deferred-body guard is defensive (exotic to fixture) and covered by the
exact-count flow-locals asserts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdphCUFvstTdkYmYTkAH46
// deferred re-slice gap, so this method has exactly the one RHS finding.)
public void SliceReassignAfterReturn(int n)
{
byte[] sb = ArrayPool<byte>.Shared.Rent(n);
// use-after-return -> OWN002 on 'rb'. Only `out` is the pure def that is exempt from the use scan.
public void RefArgUseAfterReturn(int n)
{
byte[] rb = ArrayPool<byte>.Shared.Rent(n);
@PhysShell

Copy link
Copy Markdown
Owner Author

@CodeRabbit @codex review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the main changed files
echo "=== Program.cs ==="
cat -n frontend/roslyn/OwnSharp.Extractor/Program.cs

echo ""
echo "=== FlowLocalsSample.cs ==="
cat -n frontend/roslyn/samples/FlowLocalsSample.cs

echo ""
echo "=== CI workflow ==="
cat -n .github/workflows/ci.yml

echo ""
echo "=== Proposal doc ==="
cat -n docs/proposals/P-007-arraypool-span.md

echo ""
echo "=== Corpus notes ==="
cat -n corpus/real-world/arraypool-span-view-after-return/notes.md

Length of output: 175645


🏁 Script executed:

#!/bin/bash
# Find the new helpers added to Program.cs in this PR
echo "=== IsPureWrite / IsRebind / ReassignedBetween / InDeferredBody ==="
grep -n "IsPureWrite\|IsRebind\|ReassignedBetween\|InDeferredBody\|ViewOwnerOf" \
    frontend/roslyn/OwnSharp.Extractor/Program.cs | head -80

echo ""
echo "=== Surrounding implementation (search for IsPureWrite definition) ==="
# find the line of IsPureWrite definition
line=$(grep -n "bool IsPureWrite" frontend/roslyn/OwnSharp.Extractor/Program.cs | head -1 | cut -d: -f1)
echo "IsPureWrite defined at line $line"
[ -n "$line" ] && sed -n "$((line-2)),$((line+80))p" frontend/roslyn/OwnSharp.Extractor/Program.cs

echo ""
echo "=== ReassignedBetween definition ==="
line2=$(grep -n "bool ReassignedBetween\|ReassignedBetween(" frontend/roslyn/OwnSharp.Extractor/Program.cs | head -1 | cut -d: -f1)
echo "ReassignedBetween at line $line2"
[ -n "$line2" ] && sed -n "$((line2-2)),$((line2+60))p" frontend/roslyn/OwnSharp.Extractor/Program.cs

echo ""
echo "=== ViewOwnerOf definition and reassignment check ==="
line3=$(grep -n "string? ViewOwnerOf\|ViewOwnerOf(" frontend/roslyn/OwnSharp.Extractor/Program.cs | head -1 | cut -d: -f1)
echo "ViewOwnerOf at line $line3"
[ -n "$line3" ] && sed -n "$((line3-2)),$((line3+60))p" frontend/roslyn/OwnSharp.Extractor/Program.cs

echo ""
echo "=== EmitFlowExpr use-scan call-site (where IsPureWrite gates the use) ==="
grep -n "IsPureWrite\|IsRebind" frontend/roslyn/OwnSharp.Extractor/Program.cs

Length of output: 16145



@PhysShell — comprehensive review below.


Review of PR #98 — Span-view reassignment false-positive fix

Overall verdict

The fix is correct and sound. The invariant "only ever removes uses, never adds new ones" ensures it cannot introduce false positives. Every edge case I could construct is handled by a dedicated guard with a clear comment. The fixtures and CI assertions are precise enough to catch regressions. ✅ Ready to merge, with one optional observation.


Core logic — Program.cs

IsPureWrite (Line 1198)

static bool IsPureWrite(IdentifierNameSyntax idn) =>
    (idn.Parent is AssignmentExpressionSyntax asg
        && asg.IsKind(SyntaxKind.SimpleAssignmentExpression)
        && asg.Left == idn)
    || (idn.Parent is ArgumentSyntax arg
        && arg.RefKindKeyword.IsKind(SyntaxKind.OutKeyword)
        && arg.Expression == idn);

Correct. The SimpleAssignmentExpression kind guard correctly excludes compound assignments (+=, etc.) which do read the current value. The asg.Left == idn reference-equality check (not text equality) correctly excludes element/member writes — for v[0] = 1, the parent of v is ElementAccessExpressionSyntax, not AssignmentExpressionSyntax, so IsPureWrite is false and it's counted as a read.

IsRebind (Line 1210)

static bool IsRebind(IdentifierNameSyntax idn) =>
    IsPureWrite(idn)
    || (idn.Parent is ArgumentSyntax arg
        && arg.RefKindKeyword.IsKind(SyntaxKind.RefKeyword)
        && arg.Expression == idn);

Correct. The semantic distinction is clean: ref is a read at the call site (so IsPureWrite is false and the use scan fires), but the callee may rebind it, so later owner attribution is dropped. This is the exact reasoning that makes RefArgUseAfterReturn produce one OWN002 (at the Touch(ref rv) call itself) and suppress any hypothetical later references.

ReassignedBetween (Line 1543)

Five distinct guards are implemented and each is correct:

Guard Rationale Verdict
id.SpanStart <= lo || id.SpanStart >= hi Stay within the decl→use window
!IsRebind(id) Only pure writes and ref args reset provenance
id.FirstAncestorOrSelf<AssignmentExpressionSyntax>() == useAssign sliced = sliced.Slice(1) — the LHS rebind is in the same assignment as the RHS read
InDeferredBody(id, scope) A write inside a lambda/local function runs on invoke, not at its textual position
SymbolEqualityComparer.Default.Equals(...) Symbol-based matching prevents same-named locals in other scopes from being conflated

The source-order-approximation trade-off (a rebind on a non-taken branch suppresses conservatively, causing a possible miss rather than a false positive) is explicitly acknowledged in comments and in the proposal doc. It's the right engineering call for the b′ slice.

InDeferredBody (Line 1569)

static bool InDeferredBody(SyntaxNode node, SyntaxNode scope)
{
    for (var p = node.Parent; p is not null && p != scope; p = p.Parent)
        if (p is AnonymousFunctionExpressionSyntax or LocalFunctionStatementSyntax)
            return true;
    return false;
}

Correct. Walks from the candidate node up to (but not including) scope. The pattern union AnonymousFunctionExpressionSyntax or LocalFunctionStatementSyntax covers lambdas, anonymous methods, and local functions — the complete deferred-body set in Roslyn.

ViewOwnerOf reassignment check (Line 1528)

if (ReassignedBetween(sym, decl, idn, model))
    return null;
return ViewOwner(init, model);

Correct placement. The check sits after the symbol is resolved but before the owner string is returned, so every call-site that asks for the view's owner for the purpose of emitting a use op gets null for post-reassignment references — causing the use to be silently dropped rather than attributed to the stale owner.


Fixtures — FlowLocalsSample.cs

All three new methods have clear, detailed comments explaining exactly which line should (and shouldn't) fire and why.

ReassignedView (Line 608) — pins the main scenario: exactly one OWN002 on bufA (the v[0] = 1 pre-reassignment read), silent thereafter. The comments label each line (i) / (ii) which directly matches the CI assertion language.

SliceReassignAfterReturn (Line 624) — the same-assignment RHS guard test. sliced = sliced.Slice(1) reads the stale view on the RHS, and the LHS must not suppress that read. One OWN002 on sb. Exactly the fixture needed to prevent the useAssign guard from over-suppressing.

RefArgUseAfterReturn (Line 635) + Touch(ref Span<byte> s) (Line 643) — confirms ref is a use, not a pure write. The static Touch helper is appropriately scoped and its single-expression body (s = s.Slice(0)) makes the rebinding intent unambiguous.


CI assertions — .github/workflows/ci.yml

The three new assertion blocks (Lines 658–678) use exact-count guards where appropriate:

nrv=$(echo "$out" | grep -cE "OWN002.*'bufA'")
[ "$nrv" = "1" ] || { echo "FAIL: expected exactly 1 OWN002 on 'bufA' ..."; exit 1; }

This is the right pattern — a plain grep -q would pass even if a regression re-introduced extra false OWN002s. The bufB negative assertion is also explicit. The sb and rb assertions correctly use grep -qE (single findings, no duplicate risk).


Documentation

P-007-arraypool-span.md — Open question #1 is now well-resolved: the precise description of the gap (reassignment → false attribution), the fix (drop declared owner after rebind), and the monotonicity guarantee are all stated clearly.

corpus/real-world/arraypool-span-view-after-return/notes.md — Updated to mention Memory<T> and view reassignment. Clean and accurate.


One optional observation

There is currently no fixture for the out-argument shape — e.g.:

Span<byte> v = bufA.AsSpan(0, n);
ArrayPool<byte>.Shared.Return(bufA);
F(out v);      // IsPureWrite → excluded from use scan; IsRebind → suppresses later refs
v[0] = 1;     // should be silent (owner dropped after the out-rebind)

The ref case is covered by RefArgUseAfterReturn, but out follows a different code path (IsPureWrite rather than IsRebind-only). Since out args exclude the view from the use scan entirely and then suppress later attribution, the combined behaviour is correct by construction — but a fixture would add confidence and document the contract. This is not blocking (the analysis is correct without it), but worth noting for a follow-up.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4ecfe4be9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// reference, as dropping the declared owner. A `ref` is also a USE (it is not an IsPureWrite), so it
// still emits a use of the current owner at its own position and only suppresses LATER references.
static bool IsRebind(IdentifierNameSyntax idn) =>
IsPureWrite(idn)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't suppress reads in the same call as an out arg

Treating out as a prior rebind purely by source order drops real stale-view reads in later arguments of the same invocation. For example, after Return(buf), a call like Reinit(out v, v[0]) still evaluates v[0] before the callee assigns the out parameter, but ReassignedBetween sees the earlier out v, returns null from ViewOwnerOf, and emits no OWN002 for the returned buffer. Please ignore out/ref rebinds that are in the same invocation as the use, or otherwise model that the rebind only takes effect after argument evaluation.

Useful? React with 👍 / 👎.

… use — arguments evaluate before the callee writes the param, so Reinit(out v, v[0]) keeps tripping OWN002
// sibling argument of the same call (it is not yet in effect during argument evaluation).
public void OutArgSiblingUseAfterReturn(int n)
{
byte[] ob = ArrayPool<byte>.Shared.Rent(n);
@PhysShell

Copy link
Copy Markdown
Owner Author

@codex @CodeRabbit re-review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 94d6a7f734

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

int lo = decl.SpanStart, hi = use.SpanStart;
foreach (var id in scope.DescendantNodes().OfType<IdentifierNameSyntax>())
{
if (id.SpanStart <= lo || id.SpanStart >= hi || !IsRebind(id))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude for-increment rebinds before body uses

When the rebind is in a for incrementor, this source-order test treats it as occurring before a use in the loop body because the incrementor appears in the header, but C# executes it after the body. For example, after Return(buf), for (; ; v = default) { v[0] = 1; } still reads the stale view on the first iteration; this check makes ReassignedBetween return true and ViewOwnerOf drops the owner, hiding the OWN002 that was previously reported. Please ignore incrementor rebinds for uses inside the same loop body, or otherwise account for runtime order.

Useful? React with 👍 / 👎.

// suppress a use in the loop body.
public void ForIncrementorBodyUseAfterReturn(int n)
{
byte[] fb = ArrayPool<byte>.Shared.Rent(n);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

679-688: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use exact OWN002 counts for ob and fb assertions.

These are currently presence checks; switching to = 1 (like bufA) will catch duplicate-regression noise too.

Suggested diff
-          echo "$out" | grep -qE "OWN002.*'ob'" \
-            || { echo "FAIL: expected OWN002 on 'ob' (sibling-arg read before the out-write)"; exit 1; }
+          nob=$(echo "$out" | grep -cE "OWN002.*'ob'")
+          [ "$nob" = "1" ] \
+            || { echo "FAIL: expected exactly 1 OWN002 on 'ob' (sibling-arg read before the out-write), got $nob"; exit 1; }

-          echo "$out" | grep -qE "OWN002.*'fb'" \
-            || { echo "FAIL: expected OWN002 on 'fb' (for-incrementor must not suppress the body use)"; exit 1; }
+          nfb=$(echo "$out" | grep -cE "OWN002.*'fb'")
+          [ "$nfb" = "1" ] \
+            || { echo "FAIL: expected exactly 1 OWN002 on 'fb' (for-incrementor must not suppress the body use), got $nfb"; exit 1; }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 679 - 688, Update the OWN002
assertions in the CI workflow to check exact match counts for the `ob` and `fb`
cases instead of only verifying presence. In the test block that exercises the
`Reinit(out ov, ov[0])` sibling-argument case and the for-incrementor `fv[0]`
case, change the existing grep-based checks so they assert a single OWN002
occurrence for each symbol, matching the stricter pattern already used for
`bufA`. This keeps the validation anchored to the existing test names and
symbols while catching duplicate-regression noise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 679-688: Update the OWN002 assertions in the CI workflow to check
exact match counts for the `ob` and `fb` cases instead of only verifying
presence. In the test block that exercises the `Reinit(out ov, ov[0])`
sibling-argument case and the for-incrementor `fv[0]` case, change the existing
grep-based checks so they assert a single OWN002 occurrence for each symbol,
matching the stricter pattern already used for `bufA`. This keeps the validation
anchored to the existing test names and symbols while catching
duplicate-regression noise.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: eec5283c-cf42-4394-abe1-5e368e8c942f

📥 Commits

Reviewing files that changed from the base of the PR and between d4ecfe4 and 97014cd.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/samples/FlowLocalsSample.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/roslyn/OwnSharp.Extractor/Program.cs

@PhysShell

Copy link
Copy Markdown
Owner Author

@CodeRabbit @codex re-re-review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

@PhysShell — triggering another full review pass now. I'll go through all the changes again and report any new findings.

✅ Action performed

Full review finished.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 97014cd022

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@PhysShell PhysShell merged commit a21bcaa into main Jun 24, 2026
22 checks passed
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