SIGN IN SIGN UP

Transaction analyzer: a lambda/local-function boundary is not "might queue more than once" (#3166)

TryGetBranch lumped IAnonymousFunctionOperation and ILocalFunctionOperation in with ILoopOperation and
returned false, which the caller reads as "this call can queue N times" and uses to disqualify the whole
transaction. Roslyn hands out no separate operation block for a lambda or local function - the body arrives
as part of the containing method - so every transaction written inside one was silently invisible. That
includes top-level statements, where the entire program body is one synthesised method, so the analyzer said
nothing at all about the commonest way a small repro gets written.

The repeat risk belongs to the *captured* transaction, not to the boundary itself. A transaction that is a
local of the function being walked out of is created afresh on each invocation, so one invocation holds one
whole transaction and the counts within it are exact; whatever encloses the function governs how many
transactions there are, not what goes into each. The two boundary cases now stop the walk and accept when the
transaction local belongs to that function, and keep returning false when it was captured from outside. A
loop inside such a function is still hit first, as it must be.

Tests: the two existing negatives were already the captured shape, so they are unchanged and still pass. Four
added - transaction declared in a local function (the reported shape), in a lambda, in a local function called
in a loop (N transactions, not one with N commands), and a loop inside such a function (still suppressed).

docs/rules/index.md stated the old blanket behaviour as an intentional limitation; corrected.

No AnalyzerReleases change: detection coverage only, no new or altered diagnostic IDs.
M
Marc Gravell committed
5517cbf219095ac5d97b863915164d82bfc7b3c9
Parent: 0ee2082
Committed by GitHub <noreply@github.com> on 8/6/2026, 10:42:23 AM