Skip to content

Conversation

@baronfel
Copy link
Member

@baronfel baronfel commented Dec 7, 2025

Add BC0303 BuildCheck: Detect undisposed private item lists in targets

Summary

Adds a new BuildCheck analyzer (BC0303) that detects memory waste from undisposed private item lists in MSBuild targets.

Problem

MSBuild targets often create temporary "private" item lists (conventionally prefixed with _) for internal calculations. These items persist in memory for the duration of the build unless explicitly removed, which can waste memory in large builds.

Example of problematic code:

<Target Name="BadExample">
  <ItemGroup>
    <_DotnetExecArgs Include="dotnet;tool;exec;$(CoolToolName)" />
  </ItemGroup>
  <Exec Command="@(_DotnetExecArgs, ' ')" />
  <!-- Missing: <_DotnetExecArgs Remove="@(_DotnetExecArgs)" /> -->
</Target>

Solution

This PR introduces BC0303 - ItemDisposalCheck, a new built-in BuildCheck analyzer that:

  • Detects private item lists (starting with _) created within targets via Include
  • Verifies they are cleaned up with a corresponding Remove operation
  • Exempts items exposed via Outputs or Returns attributes (part of the target's public contract)

Technical Details

Implementation

  • File: src/Build/BuildCheck/Checks/ItemDisposalCheck.cs
  • Severity: Warning (default)
  • Scope: Project file only
  • Key Features:
    • Order-sensitive analysis (Remove must come after Include)
    • Case-insensitive item type matching
    • Uses ExpressionShredder.GetReferencedItemNamesAndMetadata() for robust parsing of Outputs/Returns expressions
    • Handles complex MSBuild expressions including transforms, separators, item functions, and nested properties

Why ExpressionShredder instead of Regex?

Initially considered regex-based parsing, but switched to MSBuild's built-in ExpressionShredder to properly handle:

  • Complex transforms with semicolons: @(_Items->'%(Identity);%(FullPath)')
  • Multiple item references: @(_Sources);@(_Resources);@(_Content)
  • Custom separators: @(_Files, ';')
  • Item functions: @(_Duplicates->Distinct())
  • All other MSBuild expression features

Documentation

  • Error Code: BC0303
  • Documentation: documentation/specs/BuildCheck/Codes.md
  • Specification: documentation/specs/BuildCheck/ItemDisposalCheck.md

Testing

Added 31 comprehensive test cases in src/BuildCheck.UnitTests/ItemDisposalCheck_Tests.cs:

Positive tests (should fire):

  • Private items not removed
  • Multiple undisposed items
  • Conditional includes without cleanup

Negative tests (should NOT fire):

  • Properly removed items
  • Public items (no _ prefix)
  • Items in Outputs or Returns
  • Update-only operations

Edge cases:

  • Case-insensitive matching
  • Remove before Include (doesn't clean up the Include)
  • Complex Outputs/Returns expressions with transforms and semicolons
  • Multiple item references in single expression
  • Item functions in Returns

All 31 tests pass ✅

Related Work

This analyzer was created using the msbuild-buildcheck-creator agent, following established patterns in the BuildCheck infrastructure.

Copilot AI review requested due to automatic review settings December 7, 2025 16:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces BC0303 - ItemDisposalCheck, a new BuildCheck analyzer that detects memory waste from undisposed private item lists in MSBuild targets. Private items (prefixed with _) are conventionally used for internal calculations within targets but persist in memory for the entire build unless explicitly removed, which can waste memory in large builds. This analyzer encourages build authors to clean up these temporary items using Remove operations.

Key changes:

  • Implements static analysis of target XML to detect private items without matching Remove operations
  • Uses MSBuild's ExpressionShredder API for robust parsing of Outputs/Returns attributes
  • Includes comprehensive test suite with 31 test cases covering positive, negative, and edge cases

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Build/BuildCheck/Checks/ItemDisposalCheck.cs Core implementation of BC0303 analyzer with target analysis logic and ExpressionShredder-based parsing
src/BuildCheck.UnitTests/ItemDisposalCheck_Tests.cs Comprehensive test suite with 31 tests covering all scenarios
src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs Registration of new ItemDisposalCheck in built-in checks array
src/Build/Resources/Strings.resx Added BC0303 title and message format resource strings
src/Build/Resources/xlf/*.xlf Localization entries for 12 languages (marked as state="new")
documentation/specs/BuildCheck/ItemDisposalCheck.md Detailed specification including motivation, detection logic, and examples
documentation/specs/BuildCheck/Codes.md Documentation entry for BC0303 with code examples and resolution guidance
.claude/agents/msbuild-buildcheck-creator.md Agent documentation for creating BuildCheck analyzers (meta-documentation)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants