Skip to content

[Draft] Use hybrid C# reference map for post-processing#10976

Draft
live1206 wants to merge 25 commits into
microsoft:mainfrom
live1206:mtg-hybrid-reference-map
Draft

[Draft] Use hybrid C# reference map for post-processing#10976
live1206 wants to merge 25 commits into
microsoft:mainfrom
live1206:mtg-hybrid-reference-map

Conversation

@live1206

@live1206 live1206 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a hybrid reference-map replacement for C# generated-code post-processing.

The hybrid path replaces broad Roslyn reference-map construction with:

  • provider metadata for generated-code references
  • explicit provider dependencies for known generated body-only references
  • a small Roslyn scan only for custom/shared code roots

No benchmark measurement/profiling code is included in the production generator path in this PR.

Why

The earlier experimental PR measured full generation and identified Roslyn reference-map construction inside GeneratedCodeWorkspace.PostProcessAsync() as the largest hotspot.

This PR keeps generated output parity with the Roslyn cleanup path while moving generated-code reachability to provider metadata.

Latest Benchmark Data

Focused profile data from the benchmark PR, measuring reference-map construction/replacement rather than total full-generation wall time:

Path Avg Time Avg Allocated
Roslyn reference maps 405.8 ms 22.64 MB
Provider reference map replacement 226.4 ms 12.85 MB

Approximate focused improvement:

Time:       ~44.2% faster
Allocation: ~43.2% less

Profile breakdown:

Step Avg Time Avg Allocated
Roslyn public reference map 172.6 ms 11.43 MB
Roslyn all reference map 233.3 ms 11.21 MB
Provider map analysis 225.9 ms 12.81 MB
Provider candidate consumption ~0.55 ms ~38 KB

Profile notes:

  • Data comes from POSTPROCESSING_BENCHMARK_PROFILE_STEPS=true on the full-generation benchmark so both Roslyn and provider-map paths run against real TypeProvider output.
  • Roslyn rows are PostProcessor.Internalize.BuildPublicReferenceMapAsync and PostProcessor.Remove.BuildAllReferenceMapAsync.
  • Provider rows are Generation.ProviderReferenceMapShadowAnalysis, PostProcessor.Internalize.UseShadowCandidates, PostProcessor.Remove.UseShadowCandidates, and PostProcessor.Remove.BuildShadowReferencedSet.
  • Runtime: .NET 10.0.9, Ubuntu 26.04, AMD EPYC 7763.

Correctness Notes

The hybrid implementation preserves Roslyn cleanup behavior for generated output parity:

  • model factory signatures and bodies do not keep otherwise-unused models alive
  • MRW context/buildable attributes do not keep buildable-only models alive
  • serialization providers are removable together with their owning model
  • retained serialization providers report explicit helper dependencies such as ChangeTrackingDictionary and Optional
  • collection-result providers report explicit body dependencies instead of relying on Roslyn body scanning
  • client providers report explicit body dependencies for collection results, service method types, operation parameters, and operation response body/header types
  • rest-client providers report explicit helper dependencies for generated collection parameter null checks, including ChangeTrackingList and ChangeTrackingDictionary
  • generated body-only references are still handled for static helpers
  • public discriminator subtypes stay public by matching Roslyn public-reference-map derived-class behavior
  • internal/non-public discriminator constructor/property references do not make discriminator enum types public

Validation

Local validation performed while stabilizing the PR included:

  • dotnet build packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Microsoft.TypeSpec.Generator.csproj -c Release
  • focused generator tests covering post-processing/workspace/customization scenarios
  • full generator test assembly: 1530/1530 passed
  • regenerated and built previously failing generated projects/scenarios, including:
    • Sample-TypeSpec
    • Spector/http/authentication/api-key
    • Spector/http/parameters/collection-format
    • Spector/http/documentation
    • Spector/http/special-headers/repeatability
    • discriminator inheritance scenarios used by Spector tests

Implemented Generated Dependency Handling

This PR now avoids Roslyn body scanning for several generated cases:

  • collection-result body dependencies are reported by CollectionResultDefinition
  • client body dependencies are reported by ClientProvider
  • rest-client helper dependencies are reported by RestClientProvider
  • serialization provider helper dependencies are reported by serialization providers
  • model factory is treated specially so unreachable model factory methods do not root models
  • non-root MRW context/buildable attributes are excluded from model reachability

Custom/shared code references still use Roslyn because arbitrary user C# can reference generated types in ways providers cannot reliably describe.

Follow-Up Performance Opportunities

Potential next improvements, ordered by reward/risk:

Rank Improvement Reward Risk Notes
1 Precompute name lookup maps for AddMatchingName Medium Low Avoid repeated full-node scans for helper/root matching.
2 Cache flattened provider lists and provider names Medium Low Avoid repeated lazy provider/name materialization during analysis.
3 Conservative custom-code syntax prefilter Medium Medium/High Can reduce custom Roslyn semantic work but must not miss arbitrary custom references.

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

@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Jun 12, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@10976

commit: dc6f0f2

@github-actions

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

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

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant