Skip to content

Cover type forwarding and other gaps#138

Merged
dfederm merged 3 commits intodfederm:dfederm/symbol-based-usage-detectionfrom
olstakh:dfederm/symbol-based-usage-detection
Apr 20, 2026
Merged

Cover type forwarding and other gaps#138
dfederm merged 3 commits intodfederm:dfederm/symbol-based-usage-detectionfrom
olstakh:dfederm/symbol-based-usage-detection

Conversation

@olstakh
Copy link
Copy Markdown
Contributor

@olstakh olstakh commented Apr 18, 2026

This pull request enhances the ReferenceTrimmer analyzer to more accurately detect used project references in C# code, especially in cases that previously required syntax-level analysis. The changes add support for tracking references used only in nameof() expressions, XML documentation <cref> attributes, and advanced pattern-matching constructs. Comprehensive tests are included to verify these scenarios.

Analyzer improvements:

  • Added syntax-level tracking for nameof() expressions and XML doc <cref> references, ensuring references used only in these contexts are not incorrectly reported as unused. This is implemented via a new RegisterCSharpSyntaxTracking method and corresponding registration in the analyzer. [1] [2] [3]
  • Expanded pattern-matching support to track types used in switch expression arms, pattern case clauses, local functions, anonymous functions, and sizeof operations, improving accuracy for modern C# code. [1] [2]
  • Improved handling of type-forwarded assemblies to ensure that assemblies forwarding types to used assemblies are also marked as used.
  • Changed generated code analysis configuration to analyze (not skip) generated code, increasing coverage.
  • Added handling for function pointer types in type tracking logic.

Test coverage:

  • Added end-to-end tests for scenarios where project references are used only via nameof(), XML doc <cref>, and advanced switch patterns, with corresponding test projects and source files. [1] [2] [3] [4] [5] [6] [7] [8] [9]

These improvements ensure that the analyzer correctly identifies all used references, even in subtle or modern C# usage patterns.

@dfederm dfederm merged commit 6d8d69a into dfederm:dfederm/symbol-based-usage-detection Apr 20, 2026
dfederm added a commit that referenced this pull request Apr 24, 2026
* Add experimental symbol-based usage detection (opt-in)

Replace the GetUsedAssemblyReferences approach with a Roslyn analyzer that tracks
symbol usage at finer granularity, behind the ReferenceTrimmerUseSymbolAnalysis
MSBuild property (opt-in, defaults to false).

The new approach uses RegisterSymbolAction and RegisterOperationAction to track
which assemblies contain symbols that the code actually references, rather than
relying on the compiler's broader 'used assembly' heuristic which over-reports
usage by treating transitive assembly dependencies as used.

Key design decisions:
- RT0001 (bare Reference): always uses conservative transitive closure to avoid
  breaking runtime dependencies that lack automatic transitive resolution
- RT0002 (ProjectReference): uses transitive closure only when
  DisableTransitiveProjectReferences is set; otherwise uses precise detection
- RT0003 (PackageReference): always uses precise symbol-based detection since
  NuGet handles transitive package deps automatically
- Attribute constructor/named arguments (including typeof) are tracked
- Early exit optimization when all reference assemblies are already tracked

The legacy GetUsedAssemblyReferences code path is preserved as the default.
All E2E tests run in both modes via DataRow parameterization (91 pass).
Version bumped from 3.4 to 3.5.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Cover type forwarding and other gaps (#138)

* type forwarding

* Fill out the gaps

* Add tests

* Improve symbol-based analysis coverage, perf, and testing

- Fill operation coverage gaps: switch patterns (statement + expression),
  default expressions, user-defined operators (binary/unary/compound/
  increment-decrement), function pointer types, and conversion operand types
- Performance: replace ConcurrentDictionary.Count (acquires all stripe locks
  on .NET Framework) with a monotonic int flag on the hot path; skip tracking
  for the compilation's own assembly via ReferenceEquals
- Platform-aware path comparers: case-insensitive on Windows/macOS,
  case-sensitive on Linux (addresses PR review feedback)
- Rename legacy -> default for the GetUsedAssemblyReferences analysis path
- Add analyzer unit tests (19 tests, ~6s) using CompilationWithAnalyzers
  for fast, targeted coverage of symbol tracking logic
- Replace E2E edge-case tests with unit tests to reduce test data bloat
- Add Microsoft.CodeAnalysis.CSharp.Workspaces package reference for tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improve symbol analysis: fix perf, track local vars, add 17 tests

- Replace ConcurrentDictionary.Count with Interlocked.Increment counter
  to avoid acquiring all stripe locks on .NET Framework
- Simplify allTracked flag to just trackedCount >= totalReferenceCount
- Track local variable types via IVariableDeclaratorOperation
- Add 17 new analyzer tests (19 -> 36 total):
  - nameof, XML doc cref (with doc mode on/off), type forwarding
  - local variables, lambdas, local functions, arrays, attributes
  - recursive patterns, events
  - PackageReference (RT0003): unused, used, multi-assembly aggregation
  - Bare Reference (RT0001): unused with transitive closure
- Fix test isolation: lambda and local function tests now use the
  specific handler as the sole tracking path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: olstakh <45368758+olstakh@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants