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
Local functions declared inside a member that carries [ExcludeFromCodeCoverage] remain in the
coverage denominator after the issue #457 closure filter. This is residual (b) of #457: a deliberate
scope choice, recorded so it can be addressed on its own terms rather than by widening #457.
A local function is emitted as <method name="<Member>g__Local|N_M"> inside the declaring
type's own<class> element rather than inside a compiler-generated closure type, and it does not
inherit the enclosing member's attribute. The #457 filter scopes strictly to closure classes - those
whose name carries the .<>c marker - so a local function on a non-closure class is never a candidate
for removal.
Environment
OS/version: Windows 11 Pro 10.0.26200
.NET/framework: .NET Framework 4.8.1 (net481); post-processing runs under PowerShell 7
Data source or fixture: any first-party C# file with a member carrying [ExcludeFromCodeCoverage] that declares a local function in its body
Steps to Reproduce
Take a member that carries [ExcludeFromCodeCoverage] and declares a local function in its body.
Run the coverage pipeline.
Inspect the post-processed Cobertura report for that file.
Observe a <method name="<Member>g__Local|N_M"> element still present on the declaring type's own <class>, with its lines counted in lines-valid.
Expected Behavior
A local function declared inside a member carrying [ExcludeFromCodeCoverage] is excluded from the
coverage denominator, exactly as the attributed member's own lines are.
Actual Behavior
The local function's lines are retained, because it lives on the declaring type's own class, which the #457 filter never mutates.
Logs / Screenshots
Attached minimal logs or screenshot
The shape is pinned by regression case 5 part B in tests/scripts/vscode/Invoke-MSTestWithCoverage.ClosureFilter.Tests.ps1, whose fixture carries a
declaring class Ns.B whose only method is <Exempt>g__Local|7_0:
That test asserts Ns.B is retained byte-for-byte unmutated, which is the current, deliberate
behaviour.
Impact / Severity
Blocker
High
Medium
Low
The failure mode is under-exclusion: a file measures no better than it truly is. No coverage is
wrongly deleted. The cost is a residual ceiling on files that use local functions inside exempt
members.
Summary
Local functions declared inside a member that carries
[ExcludeFromCodeCoverage]remain in thecoverage denominator after the issue #457 closure filter. This is residual (b) of #457: a deliberate
scope choice, recorded so it can be addressed on its own terms rather than by widening #457.
A local function is emitted as
<method name="<Member>g__Local|N_M">inside the declaringtype's own
<class>element rather than inside a compiler-generated closure type, and it does notinherit the enclosing member's attribute. The #457 filter scopes strictly to closure classes - those
whose name carries the
.<>cmarker - so a local function on a non-closure class is never a candidatefor removal.
Environment
net481); post-processing runs under PowerShell 7pwsh -NoProfile -File scripts/vscode/Invoke-MSTestWithCoverage.ps1 -SearchRoot . -Configuration Debug -CoverageOutput "coverage\coverage.cobertura.xml"[ExcludeFromCodeCoverage]that declares a local function in its bodySteps to Reproduce
[ExcludeFromCodeCoverage]and declares a local function in its body.<method name="<Member>g__Local|N_M">element still present on the declaring type's own<class>, with its lines counted inlines-valid.Expected Behavior
A local function declared inside a member carrying
[ExcludeFromCodeCoverage]is excluded from thecoverage denominator, exactly as the attributed member's own lines are.
Actual Behavior
The local function's lines are retained, because it lives on the declaring type's own class, which the
#457 filter never mutates.
Logs / Screenshots
Attached minimal logs or screenshot
The shape is pinned by regression case 5 part B in
tests/scripts/vscode/Invoke-MSTestWithCoverage.ClosureFilter.Tests.ps1, whose fixture carries adeclaring class
Ns.Bwhose only method is<Exempt>g__Local|7_0:That test asserts
Ns.Bis retained byte-for-byte unmutated, which is the current, deliberatebehaviour.
Impact / Severity
The failure mode is under-exclusion: a file measures no better than it truly is. No coverage is
wrongly deleted. The cost is a residual ceiling on files that use local functions inside exempt
members.
Source
From: docs/features/potential/2026-08-11-local-functions-in-exempt-members-remain-counted.md