Skip to content

Precision gap: no-op Dispose() exemption limited to named BCL types, doesn't cover user-defined empty Dispose bodies #225

Description

@PhysShell

Found by: the issue #201 oracle sweep, docs/notes/oracle-sweep-2026-07-10.md; catalogued as docs/notes/field-notes-patterns.md entry 19 (extends entry 9 / IsNoOpDisposeWrapper, oracle-known-fps.md root-cause 2).

The pattern

internal class Enumerator : IEnumerator<Point> {
    ...
    public void Dispose() { }   // literally empty — no base call, no field release
}
// caller:
var enumerator = new Enumerator(this, area);
while (enumerator.MoveNext()) { ... }   // never disposed — flagged OWN001

Enumerator implements IDisposable only because IEnumerator<T> requires it, not because it holds a real resource — its Dispose() does nothing at all. Never calling it cannot leak anything.

The existing IsNoOpDisposeWrapper exemption already covers this idea for a handful of named BCL types (StringWriter/StringReader — see docs/notes/no-op-dispose-wrapper.md), but doesn't reach a user-defined type, however trivially empty its Dispose() is.

Evidence — ClosedXML/ClosedXML, 5 confirmed instances, single root cause

  • ClosedXML/Excel/Cells/Slice.cs:91,109,149,188,219 — all Slice.Enumerator locals (Slice.cs:324-416; Dispose() body verified empty, no other override in the type, no unmanaged handle anywhere in the class)

Suggested direction (not prescriptive)

Rather than (only) growing a list of known-safe type names, recognise any Dispose() method whose body is provably empty (no statements, no base call needed since the type has no base Dispose) as safe to skip — first-party or third-party, named allowlist or not. Keep the existing named-BCL-type path for cases where the body isn't literally empty but is still knowably a no-op (e.g. StringWriter's Dispose calls into TextWriter.Dispose which does real but harmless work).

Scope

No analyzer code changed as part of the sweep — this issue tracks the fix as its own unit of work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions