You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(extractor): recognise Behavior.AssociatedObject as a self-owned source (#227)
A `Behavior`-derived class subscribing to (an element reached from) its own
base-class `AssociatedObject` accessor was tiered "injected" and warned OWN001
(the MahApps TiltBehavior FP from the issue #201 sweep). A behavior is attached
to and detached from exactly one element and cannot outlive being attached, so
that element is co-lifetimed with the subscriber — the same collectable
source<->this cycle the shipped self-owned-source exemption already encodes for a
constructed field, just reached through a base-class accessor.
The exemption is deliberately narrow, within the issue's fixed guardrails:
- subscriber gate: the class must derive from `Behavior` (`IsBehaviorSubscriber`,
direct-base simple-name match, mirroring `IsProcessLivedApplication`) — the
attach/detach pairing is what guarantees co-lifetime;
- source gate: the `+=` receiver must resolve, same-class and assignment-chain-
local, to `this.AssociatedObject` (`ResolvesToAssociatedObject`) — directly, via
a `var x = ...`/`is`-pattern local (only when never reassigned), or via a field
every assignment to which resolves to `AssociatedObject` (a single injected write
denies the proof). No interprocedural guessing.
Unlike #228 a lambda handler is fine here: the source is co-lifetimed with the
behavior, so a capture just closes the collectable cycle rather than pinning a
process-lived source to a shorter-lived local.
Pinned by AssociatedObjectSourceSample.cs: three silent positives (is-pattern
field, direct `this.AssociatedObject.Event`, bare-identifier local) and the four
controls the guardrails require — the unrelated injected source in the same
OnAttached, a non-Behavior subscriber, a field also assigned an injected value,
and a resolver-bound local reassigned before the `+=` — wired into the
wpf-extractor CI job with assertions both ways.
Verified locally with the real extractor (.NET 8): the sample yields exactly the
four control warnings, all three positives silent; a full-sample-set diff of old
vs new extractor output is byte-identical (zero regression). Gates: run_tests
276/276, ruff, mypy, yaml all green.
Closes#227
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U2AWb9N2VUsby2XpdftBcu
0 commit comments