Found by: the issue #201 oracle sweep, docs/notes/oracle-sweep-2026-07-10.md; catalogued as docs/notes/field-notes-patterns.md entry 14.
The pattern
private CancellationTokenSource cts;
public void Cancel() {
using (cts = new CancellationTokenSource()) { // field IS the using acquisition target
...
}
// cts.Dispose() ran at the end of the using block
}
A using (expr) { } disposes whatever expr evaluates to at block exit, regardless of whether expr is a bare new T(), a pre-existing local (already handled — see field-dispose-via-* corpus fixtures / oracle-known-fps.md root-cause 1, the using (preExistingLocal) shape), or, as here, an assignment to a field.
The flow-locals detector's using-release recognition appears scoped to a local target; a field on the left-hand side of the acquisition expression inside using (...) isn't threaded back to the field-disposal scan, so the field reads as permanently un-disposed.
Evidence — ShareX/ShareX, 3 confirmed instances
ShareX.HelpersLib/Cryptographic/HashChecker.cs:59 — using (cts = new CancellationTokenSource())
ShareX.HelpersLib/TaskEx.cs:55 — using (cts = new CancellationTokenSource())
ShareX.IndexerLib/IndexerJson.cs:49 — using (jsonWriter = new JsonTextWriter(sw))
Suggested direction (not prescriptive)
When the using acquisition expression is an assignment (field = new T(...) or field = <owning-factory-call>), thread the field itself as released at the using block's exit — the same lowering already applied to using (preExistingLocal), generalized to a field-typed assignment target.
Scope
No analyzer code changed as part of the sweep — this issue tracks the fix as its own unit of work.
Found by: the issue #201 oracle sweep,
docs/notes/oracle-sweep-2026-07-10.md; catalogued asdocs/notes/field-notes-patterns.mdentry 14.The pattern
A
using (expr) { }disposes whateverexprevaluates to at block exit, regardless of whetherexpris a barenew T(), a pre-existing local (already handled — seefield-dispose-via-*corpus fixtures / oracle-known-fps.md root-cause 1, theusing (preExistingLocal)shape), or, as here, an assignment to a field.The flow-locals detector's
using-release recognition appears scoped to a local target; a field on the left-hand side of the acquisition expression insideusing (...)isn't threaded back to the field-disposal scan, so the field reads as permanently un-disposed.Evidence — ShareX/ShareX, 3 confirmed instances
ShareX.HelpersLib/Cryptographic/HashChecker.cs:59—using (cts = new CancellationTokenSource())ShareX.HelpersLib/TaskEx.cs:55—using (cts = new CancellationTokenSource())ShareX.IndexerLib/IndexerJson.cs:49—using (jsonWriter = new JsonTextWriter(sw))Suggested direction (not prescriptive)
When the
usingacquisition expression is an assignment (field = new T(...)orfield = <owning-factory-call>), thread the field itself as released at theusingblock's exit — the same lowering already applied tousing (preExistingLocal), generalized to a field-typed assignment target.Scope
No analyzer code changed as part of the sweep — this issue tracks the fix as its own unit of work.