Skip to content

extractor: normalize new-delegate handlers in event release-matching#163

Merged
PhysShell merged 4 commits into
mainfrom
extractor-delegate-handler-normalization
Jul 2, 2026
Merged

extractor: normalize new-delegate handlers in event release-matching#163
PhysShell merged 4 commits into
mainfrom
extractor-delegate-handler-normalization

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Экстрактор сопоставлял -= с += по сырому тексту хендлера, поэтому
+= new PropertyChangedEventHandler(H) не находил парный голый -= H
(доминирующий teardown-идиом SectorTS), а IsHandler вовсе отвергал
delegate-creation — из-за чего обычный -= не собирался, а P-004
static-handler exemption пропускался для обычного статического метода.
Корректно отписанные подписки уходили в OWN001 как ложные срабатывания.
Фикс добавля
применяет его на всех точках сравнения release-ключа + в IsStaticHandler.
На полном прогоне STS: subscription-находки 323 → 156 (−52%), при неизменных
OWN050/OWN014/idisposable.

Тип изменения

  • fix — исправление бага

Как проверено

  • python tests/run_tests.py — вся ownlang-сюита зелёная, вкл. новый кейс
  • ruff / mypy — не запускал: изменение в C#-экстракторе, не в python
  • python scripts/benchmark.py --selftest — OK
  • extractor red→green на кейсе; WPF-корпус — все after.cs чисты
  • реальн

Связанные issue

Нет связанного issue.

Чеклист

  • покрыто тестом (corpus/wpf/... + C#-гейт scripts/benchmark.py)
  • docs: корневая причина в notes.md кейса
  • коммиты в стиле репо (extractor: …)

Summary by CodeRabbit

  • Bug Fixes
    • Improved WPF event subscription release detection so handlers added via wrapped/explicit delegate syntax are correctly matched with their corresponding unsubscriptions.
    • Reduced false leak warnings and improved detection consistency for wrapped and target-typed handler patterns.
    • Enhanced detection for handler use-after-dispose scenarios with wrapped delegate subscriptions.
  • Tests
    • Added/updated corpus coverage and expectations for subscription-release (OWN001) and handler-after-dispose (OWN002) scenarios.
  • Documentation
    • Added a note describing the prior false-positive pattern and the expected matching behavior for wrapped delegate handlers.

Event release-matching keyed on raw handler text, so `+= new
PropertyChangedEventHandler(H)` never matched a bare `-= H` (the dominant
SectorTS teardown idiom), and IsHandler rejected delegate-creation outright —
so a wrapped `-=` was not collected and the P-004 static-handler exemption was
skipped for a wrapped static method. Correctly torn-down subscriptions were
reported as OWN001 false positives (~253/330 STS subscription findings use
explicit delegate-creation).

Add NormalizeHandler (unwrap `new SomeHandler(X)` -> `X`) and apply it at the
release-key sites (+= released check, -= collect + IsHandler gate) and inside
IsStaticHandler; the emitted handler fact text is unchanged.

Regression: corpus/wpf/subscription-explicit-delegate-release (before caught /
after clean). Verified real STS eDeclarant.xaml.cs 4->0, BranchDescription.cs ->0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 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: 21e03096-2a46-4082-9883-6082e0e60ea9

📥 Commits

Reviewing files that changed from the base of the PR and between 7a0f2f1 and 02075b7.

📒 Files selected for processing (11)
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/after.cs
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/before.cs
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/case.own
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/expected-diagnostics.txt
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/notes.md
  • corpus/wpf/subscription-target-typed-delegate-release/after.cs
  • corpus/wpf/subscription-target-typed-delegate-release/before.cs
  • corpus/wpf/subscription-target-typed-delegate-release/case.own
  • corpus/wpf/subscription-target-typed-delegate-release/expected-diagnostics.txt
  • corpus/wpf/subscription-target-typed-delegate-release/notes.md
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
✅ Files skipped from review due to trivial changes (5)
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/expected-diagnostics.txt
  • corpus/wpf/subscription-target-typed-delegate-release/expected-diagnostics.txt
  • corpus/wpf/handler-use-after-dispose-wrapped-delegate/notes.md
  • corpus/wpf/subscription-target-typed-delegate-release/notes.md
  • corpus/wpf/subscription-target-typed-delegate-release/case.own

📝 Walkthrough

Walkthrough

This PR normalizes wrapped delegate-creation handlers in the Roslyn extractor and adds WPF corpus cases for subscription release and handler-use-after-dispose detection, including updated OWN001 and OWN002 expectations.

Changes

Extractor normalization and WPF corpus cases

Layer / File(s) Summary
Normalize wrapped handlers
frontend/roslyn/OwnSharp.Extractor/Program.cs
Adds handler normalization and applies it to unsubscribe keying, release checks, static-handler exemption, and live subscription tracking.
Explicit delegate subscription release
corpus/wpf/subscription-explicit-delegate-release/before.cs, corpus/wpf/subscription-explicit-delegate-release/after.cs, corpus/wpf/subscription-explicit-delegate-release/case.own, corpus/wpf/subscription-explicit-delegate-release/expected-diagnostics.txt, corpus/wpf/subscription-explicit-delegate-release/notes.md
Adds the unreleased and released SourceView samples, the subscription ownership model, the expected diagnostic, and notes for the explicit delegate release case.
Target-typed delegate subscription release
corpus/wpf/subscription-target-typed-delegate-release/before.cs, corpus/wpf/subscription-target-typed-delegate-release/after.cs, corpus/wpf/subscription-target-typed-delegate-release/case.own, corpus/wpf/subscription-target-typed-delegate-release/expected-diagnostics.txt, corpus/wpf/subscription-target-typed-delegate-release/notes.md
Adds the target-typed delegate subscription samples, ownership model, expected diagnostic, and notes for the corresponding release case.
Wrapped delegate use-after-dispose case
corpus/wpf/handler-use-after-dispose-wrapped-delegate/before.cs, corpus/wpf/handler-use-after-dispose-wrapped-delegate/after.cs, corpus/wpf/handler-use-after-dispose-wrapped-delegate/case.own, corpus/wpf/handler-use-after-dispose-wrapped-delegate/expected-diagnostics.txt, corpus/wpf/handler-use-after-dispose-wrapped-delegate/notes.md
Adds the before/after example, ownership model, expected diagnostic, and notes for the handler-use-after-dispose case.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • PhysShell/Own.NET#8: Related extractor work around event subscription release checks in the OwnIR leak pipeline.
  • PhysShell/Own.NET#75: Updates the same extractor handler-matching path to normalize wrapped new ...Handler(h) forms for subscription release detection.
  • PhysShell/Own.NET#86: Covers the same WPF subscription-release corpus pattern and the corresponding extractor normalization behavior.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: normalizing delegate-created handlers for event release matching.
Description check ✅ Passed The description follows the template and covers purpose, change type, verification, related issues, and checklist, with only minor incomplete items.
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.
✨ 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 extractor-delegate-handler-normalization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: a4458be705

ℹ️ 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".

if (!isTimer && source == "static" && clsIsApp)
continue;
var released = unsub.Contains($"{a.Left}|{a.Right}")
var released = unsub.Contains($"{a.Left}|{NormalizeHandler(a.Right)}")

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 Do not match releases across receiver rebinding

When the receiver is reassigned between the detach and attach (as in the new after.cs setter: _source.PropertyChanged -= ...; _source = value; _source.PropertyChanged += new ...), this class-wide string key treats both sides as _source.PropertyChanged|OnSourcePropertyChanged. The -= only removes the handler from the old source; the newly assigned injected source remains subscribed and can still retain SourceView if it is assigned once or not reset during teardown, but this change marks that subscription released and suppresses the leak.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch — you're right about the soundness gap. Two clarifications on scope:

  1. Pre-existing, not introduced here. own-check's release model is non-flow-sensitive ("any matching -= in the class = released"); a bare -=/+= rebinding setter already behaved identically before this PR. NormalizeHandler only makes the wrapped new …Handler(H) form consistent with the bare form — it doesn't change flow-sensitivity.

  2. The test no longer leans on it. I reworked after.cs to a single readonly source subscribed in the ctor and released in Dispose (no receiver rebinding), so "after = clean" is unconditionally true and the regression asserts the delegate-normalization only. The rebind last-subscription gap is now documented in notes.md as a separate, tracked follow-up — properly fixing it needs flow-sensitive release analysis (a receiver reassigned between the -= and the += should not count as released), which is out of scope for this text-normalization change.

…x P2)

Codex flagged that after.cs's setter-rebind teardown leaned on own-check's
non-flow-sensitive "any -= in the class = released" model: the -= detaches only
the old source, and the rebound source stays subscribed. Rework the case to a
readonly single source subscribed in the ctor and released in Dispose (no
rebinding), so "after = clean" is unconditionally true and the regression asserts
the delegate-normalization only. Document the rebind soundness gap (pre-existing,
orthogonal to this fix) in notes.md.

before.cs -> OWN001 (caught) / after.cs -> clean, unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PhysShell

Copy link
Copy Markdown
Owner Author

@codex @CodeRabbit review new changes

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr view 163 --repo PhysShell/Own.NET --json title,body,commits,files -q '.'
echo "-----DIFF-----"
gh pr diff 163 --repo PhysShell/Own.NET

Length of output: 17615


🏁 Script executed:

#!/bin/bash
cd /tmp && rm -rf ownnet && git clone --depth 50 https://github.com/PhysShell/Own.NET.git ownnet 2>&1 | tail -5
cd ownnet && git fetch origin pull/163/head:pr163 2>&1 | tail -5 && git checkout pr163 2>&1 | tail -5
echo "---- search for handler text usage ----"
rg -n 'IsHandler|a\.Right|a\.Left|NormalizeHandler|\.ToString\(\)' frontend/roslyn/OwnSharp.Extractor/Program.cs | sed -n '1,200p'

Length of output: 5106


🏁 Script executed:

#!/bin/bash
cd /tmp/ownnet
sed -n '3420,3530p' frontend/roslyn/OwnSharp.Extractor/Program.cs
echo "-----3740-3800-----"
sed -n '3740,3800p' frontend/roslyn/OwnSharp.Extractor/Program.cs

Length of output: 11854


🏁 Script executed:

#!/bin/bash
cd /tmp/ownnet
rg -n 'static string\? FieldName' frontend/roslyn/OwnSharp.Extractor/Program.cs
sed -n '470,485p' frontend/roslyn/OwnSharp.Extractor/Program.cs

Length of output: 1161


@PhysShell Reviewed the new changes.

Core fix (frontend/roslyn/OwnSharp.Extractor/Program.cs)

  • NormalizeHandler correctly unwraps new SomeHandler(H)H, looping to handle nested wraps, and safely no-ops when ArgumentList is null (pattern match short-circuits).
  • It's applied consistently at all three places needed for this bug: the unsub collection keying (Line 3340-3341), the released lookup (Line 3488), and IsStaticHandler (Line 597) — matching exactly what the PR description promises, and the emitted handler fact text (a.Right.ToString()) is left untouched as intended.
  • The "RHS of an event +=/-= that's new T(arg) is always a delegate creation" assumption is sound given C# event-assignment semantics.

Corpus regression

  • before.cs/after.cs/case.own/expected-diagnostics.txt/notes.md are solid. The second commit's rework to a readonly single-source ctor+Dispose (rather than a rebinding setter) is the right call — it isolates the regression to the delegate-normalization fix and avoids conflating it with the pre-existing non-flow-sensitive release-model gap you documented (nice, honest write-up in notes.md).

One related item worth a look (optional follow-up, not blocking)
There's a second raw-text handler comparison in the same file that wasn't touched by this fix — around the liveEventKeys construction feeding the handler-use-after-dispose check:

foreach (var a in assigns)
    if (IsHandler(a.Right) && FieldName(a.Right) is { } hn)
    {
        var key = $"{a.Left}|{hn}";
        if (a.IsKind(SyntaxKind.AddAssignmentExpression)) liveEventKeys.Add(key);
        else if (a.IsKind(SyntaxKind.SubtractAssignmentExpression)) liveEventKeys.Remove(key);
    }

Since this also calls IsHandler(a.Right) on the raw (non-normalized) RHS, a += new PropertyChangedEventHandler(H) subscription won't populate liveEventKeys/subscribed for H, which feeds the "handler still live" tracking for the use-after-dispose check. It's a different check than OWN001 (so out of scope for this PR's stated fix), but it's the same underlying asymmetry class this PR just fixed elsewhere. Might be worth a follow-up PR applying NormalizeHandler here too if the same SectorTS explicit-delegate idiom is common around disposal/use-after-dispose sites.

Otherwise, the fix, tests, and docs all look sound to me.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 7a0f2f1f70

ℹ️ 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".

// to reject. Loops to peel a (rare) doubly-wrapped delegate.
static ExpressionSyntax NormalizeHandler(ExpressionSyntax e)
{
while (e is ObjectCreationExpressionSyntax { ArgumentList.Arguments: { Count: 1 } args })

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Handle target-typed delegate creations too

In C# 9+ projects, an event subscription can validly use target-typed delegate creation such as _source.PropertyChanged += new(OnSourcePropertyChanged); with a bare -= OnSourcePropertyChanged; Roslyn represents that RHS as ImplicitObjectCreationExpressionSyntax, so this loop leaves it unnormalized. The later IsHandler(...) and release-key comparison still compare new(...) with OnSourcePropertyChanged, preserving the same false OWN001/static-handler false positive this fix is intended to remove for valid modern syntax.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed. NormalizeHandler now matches BaseObjectCreationExpressionSyntax — the shared base of ObjectCreationExpressionSyntax (explicit new T(H)) and ImplicitObjectCreationExpressionSyntax (target-typed new(H)) — so both normalize to the inner handler before keying. Added a regression twin corpus/wpf/subscription-target-typed-delegate-release (before → OWN001 / after → clean). 👍

NormalizeHandler unwrapped only ObjectCreationExpressionSyntax (explicit
`new T(H)`); a C# 9 target-typed `new(H)` is ImplicitObjectCreationExpressionSyntax,
so it stayed unnormalized and `new(H)` != bare `H` on the release key — the same
release-match / static-handler false positive, for modern syntax. Match
BaseObjectCreationExpressionSyntax, the shared base of both forms.

Regression: corpus/wpf/subscription-target-typed-delegate-release (before caught /
after clean). Explicit-delegate case unchanged; ownlang wpf 8/8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PhysShell

Copy link
Copy Markdown
Owner Author

@codex @CodeRabbit review new changes

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr view 163 --repo PhysShell/Own.NET --json commits,updatedAt -q '.commits[-5:] | .[] | {oid: .oid, messageHeadline: .messageHeadline, committedDate: .committedDate}'
echo "---- comments on PR ----"
gh api repos/PhysShell/Own.NET/issues/163/comments --jq '.[] | {user: .user.login, created_at: .created_at, body: (.body[0:80])}'
echo "---- latest commit sha vs reviewed ----"
gh pr view 163 --repo PhysShell/Own.NET --json headRefOid -q '.headRefOid'

Length of output: 1798


🏁 Script executed:

#!/bin/bash
cd /tmp && rm -rf ownnet && git clone --depth 100 https://github.com/PhysShell/Own.NET.git ownnet 2>&1 | tail -3
cd ownnet && git fetch origin pull/163/head:pr163 2>&1 | tail -3
git show 24c79f35f7935869fa781bd6f78dff7467d76d67 --stat
echo "-----DIFF-----"
git show 24c79f35f7935869fa781bd6f78dff7467d76d67

Length of output: 10030


@PhysShell Reviewed the new commit (24c79f35, "extractor: normalize target-typed delegate creations too (Codex P3)").

Fix (frontend/roslyn/OwnSharp.Extractor/Program.cs)

  • Widening NormalizeHandler's pattern from ObjectCreationExpressionSyntax to BaseObjectCreationExpressionSyntax is the correct fix — that's the actual shared base of ObjectCreationExpressionSyntax (explicit new T(H)) and ImplicitObjectCreationExpressionSyntax (C# 9 target-typed new(H)) in Roslyn.
  • The rest of the loop (peeling single-argument wraps) is untouched, so behavior for the previously-fixed explicit-delegate form is unchanged, and nested/doubly-wrapped cases still work identically for both forms.
  • The updated comment correctly documents the rationale.

Corpus regression

  • corpus/wpf/subscription-target-typed-delegate-release/{before,after,case.own,expected-diagnostics.txt,notes.md} mirrors the earlier explicit-delegate case: readonly single-source ctor-subscribe / Dispose-release, avoiding rebinding to keep the regression isolated to the normalization fix. notes.md is clear and consistent with the earlier one.

This is a clean, well-scoped extension of the same normalization fix to modern C# 9 syntax — no issues found. The earlier optional follow-up item I mentioned (the raw-text IsHandler check feeding liveEventKeys for the use-after-dispose tracking) is still open but unrelated to this commit and remains non-blocking.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 24c79f35f7

ℹ️ 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 +467 to +471
static ExpressionSyntax NormalizeHandler(ExpressionSyntax e)
{
while (e is BaseObjectCreationExpressionSyntax { ArgumentList.Arguments: { Count: 1 } args })
e = args[0].Expression;
return e;

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 Reuse normalized handlers in all event analyses

Because this helper is opt-in, the handler-use-after-dispose pass later in this file still checks IsHandler(a.Right)/FieldName(a.Right) on the raw RHS. For a live subscription written as source.Changed += new EventHandler(OnChanged), that pass never adds OnChanged to the subscribed-handler set, so a disposed field read from OnChanged is no longer reported as OWN002 even though the new normalization proves this spelling is the same handler. Please apply the normalized RHS to the remaining handler-name checks as well, not only release matching and the static-handler exemption.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Done — closed the whole class. NormalizeHandler is now applied to the handler-use-after-dispose live-subscription keying too (not just release matching + the static-handler exemption), so += new EventHandler(OnX) and target-typed += new(OnX) register OnX as a live subscription target and its disposed-field read is flagged OWN002.

Added a regression case corpus/wpf/handler-use-after-dispose-wrapped-delegate — self-owned source, so OWN002 is isolated from OWN001. Verified pre-fix the OWN002 was missed; post-fix before.cs → OWN002 / after.cs → clean. 👍

…x P2)

The handler-use-after-dispose pass keyed live subscription targets by IsHandler/
FieldName on the raw RHS, so a wrapped `+= new EventHandler(OnX)` never registered
OnX as subscribed and a disposed-field read in OnX escaped OWN002 — the same
NormalizeHandler gap as the release matching, in a second pass. Apply NormalizeHandler
to the live-subscription keying so wrapped and target-typed spellings register
consistently.

Regression: corpus/wpf/handler-use-after-dispose-wrapped-delegate (before caught /
after clean; self-owned source, so OWN002 is isolated from OWN001). Verified pre-fix
that OWN002 was missed. ownlang wpf 9/9.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PhysShell

Copy link
Copy Markdown
Owner Author

@codex @CodeRabbit review new changes

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr view 163 --repo PhysShell/Own.NET --json commits,headRefOid -q '{head: .headRefOid, last3: .commits[-3:] | map({oid, messageHeadline, committedDate})}'

Length of output: 910


🏁 Script executed:

#!/bin/bash
cd /tmp && rm -rf ownnet && git clone --depth 100 https://github.com/PhysShell/Own.NET.git ownnet 2>&1 | tail -3
cd ownnet && git fetch origin pull/163/head:pr163 2>&1 | tail -3
git show 02075b7810e96e9e0bd378ad255057799d7ed11f --stat
echo "-----DIFF-----"
git show 02075b7810e96e9e0bd378ad255057799d7ed11f

Length of output: 11199


@PhysShell Reviewed the new commit (02075b78, "extractor: normalize handlers in the use-after-dispose pass too (Codex P2)").

Fix (frontend/roslyn/OwnSharp.Extractor/Program.cs, Line ~3770)

  • This closes exactly the follow-up item I flagged in my first review round: the liveEventKeys construction was keying off IsHandler(a.Right)/FieldName(a.Right) on the raw RHS, so a wrapped += new EventHandler(OnX) never registered OnX as a live subscription target for the use-after-dispose (OWN002) pass.
  • The fix applies NormalizeHandler(a.Right) before IsHandler/FieldName, consistent with how the OWN001 release-matching fix was applied earlier in the PR. The receiver (a.Left) used in the key is untouched, which is correct since normalization only concerns the handler expression, not the receiver.
  • Good use of is var rhs && ... to reuse the normalized value across both IsHandler and FieldName calls without duplicating the normalization call.

Corpus regression (corpus/wpf/handler-use-after-dispose-wrapped-delegate/)

  • Nicely isolated: the source (Publisher) is self-owned by SourceView, so there's no OWN001 leak to entangle with — the regression cleanly targets OWN002 only.
  • before.cs/after.cs differ only by the if (_disposed) return; guard, which is the right minimal delta to flip the diagnostic.
  • notes.md clearly documents the root cause and ties it back to the same NormalizeHandler gap as the earlier P3 fix, with proper regression guard description matching scripts/benchmark.py conventions used elsewhere in this PR.

This fully addresses the optional follow-up I raised earlier — no remaining concerns from me. Nice work tracking this down across both passes.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 02075b7810

ℹ️ 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".

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.

1 participant