Skip to content

Add SystemObjectModelProvider for non-generated base type customization#9862

Draft
live1206 wants to merge 6 commits intomicrosoft:mainfrom
live1206:feature/system-object-model-provider
Draft

Add SystemObjectModelProvider for non-generated base type customization#9862
live1206 wants to merge 6 commits intomicrosoft:mainfrom
live1206:feature/system-object-model-provider

Conversation

@live1206
Copy link
Contributor

@live1206 live1206 commented Mar 2, 2026

Summary

Fixes #9234

Adds SystemObjectModelProvider, a new ModelProvider subclass that represents model types from external/system assemblies (e.g., TrackedResourceData, ResourceData) that are mapped from input model types. This enables downstream generators (like the Azure Management generator) to customize base types of generated models to non-generated framework types.

Changes

New: SystemObjectModelProvider

  • Extends ModelProvider (not TypeProvider like the existing SystemObjectTypeProvider)
  • Takes a CSharpType (the system/framework type) and an InputModelType (the input model it replaces)
  • Exposes SystemType property for accessing the underlying framework type
  • Exposes CrossLanguageDefinitionId property for downstream generators that need to identify the model
  • Null-safe BuildName() and BuildNamespace() since _systemType may be null when called from base constructor before field assignment
  • Throws InvalidOperationException from BuildRelativeFilePath() since this type should never be written during generation

Fix: ModelProvider.BuildBaseModelProvider() name-based fallback

  • When looking up a base model in CSharpTypeMap, framework CSharpTypes (from typeof()) and non-framework CSharpTypes (from ModelProvider) have different equality semantics — they hash to the same bucket but fail Equals() because _type differs
  • Added a name+namespace fallback that searches CSharpTypeMap values when the direct lookup fails, ensuring SystemObjectModelProvider entries are found correctly

Motivation

In the Azure Management generator, ARM resource models inherit from system types like TrackedResourceData or ResourceData. Previously, this required a local InheritableSystemObjectModelProvider class. By adding SystemObjectModelProvider to the base generator, downstream generators can use it directly and the base generator can eventually handle property deduplication, serialization modifiers, and constructor updates natively for system model bases.

Testing

  • All 2558 existing tests pass (1255 base + 1169 ClientModel + 82 input + 37 local + 15 spector)
  • Validated in the Azure Management generator: all 115 mgmt tests pass when using SystemObjectModelProvider instead of the local InheritableSystemObjectModelProvider

live1206 and others added 2 commits March 2, 2026 16:56
…ed fallback

Add SystemObjectModelProvider extending ModelProvider for downstream generators
that map input models to existing framework types (e.g., ARM Resource to
ResourceData). Unlike SystemObjectTypeProvider which extends TypeProvider,
this class can serve as BaseModelProvider for derived models.

Fix BuildBaseModelProvider() to use name+namespace based CSharpTypeMap fallback
when strict CSharpType equality fails. This resolves the case where custom code
overrides a base type to an external type (e.g., TrackedResourceData) but the
CSharpTypeMap lookup fails due to framework vs non-framework CSharpType mismatch.

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

- Added CrossLanguageDefinitionId property (from input model) to support downstream
  generators that need to check the cross-language definition ID
- Fixed BuildName() null safety: _systemType may be null when called from base
  constructor before field assignment (same pattern as BuildNamespace)

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 Mar 2, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 2, 2026

Open in StackBlitz

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

commit: 23ad09c

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

No changes needing a change description found.

live1206 added a commit to live1206/azure-sdk-for-net that referenced this pull request Mar 2, 2026
…ovider from upstream

Use SystemObjectModelProvider from Microsoft.TypeSpec.Generator instead of the local
InheritableSystemObjectModelProvider. This aligns with the upstream PR
microsoft/typespec#9862 which adds SystemObjectModelProvider to the base generator.

- ManagementTypeFactory: create SystemObjectModelProvider(replacedType, model)
- InheritableSystemObjectModelVisitor: swap all type checks and property access
- NameVisitor: use SystemObjectModelProvider pattern match
- ManagementOutputLibrary: filter SystemObjectModelProvider

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
live1206 and others added 4 commits March 2, 2026 18:20
…zation, and constructors

- SystemObjectModelProvider now returns empty for BuildProperties, BuildFields,
  BuildSerializationProviders, BuildConstructors, and null for BuildRawDataField
- ModelProvider.BuildProperties skips base properties when base chain includes
  SystemObjectModelProvider
- ModelProvider.BuildRawDataField changed to protected virtual
- MrwSerializationTypeDefinition uses virtual (not override) for create/persist
  methods when base is SystemObjectModelProvider

This enables downstream generators (mgmt) to handle framework type bases
natively without post-processing visitors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests demonstrate capabilities that SystemObjectModelProvider provides that are
missing from SystemObjectTypeProvider:

1. Type hierarchy: SystemObjectModelProvider extends ModelProvider (not TypeProvider),
   so it can serve as BaseModelProvider for derived models
2. Property deduplication: derived models skip properties defined in framework base
3. Raw data field: SystemObjectModelProvider returns null, derived models create own
4. Empty members: no generated properties/fields/constructors/serialization
5. Serialization modifiers: correct virtual vs override for 4 serialization methods
6. Name/namespace from system CSharpType

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…se property dedup from SystemObjectModelProvider chain

- SetBaseModelProvider: public method allowing visitors to replace a model's base
- Reset override: clears rawDataField, additionalPropertyFields/Properties, fullConstructor
- InputModel property: exposes the private _inputModel field for external use
- BuildProperties: when base is SystemObjectModelProvider, also includes base properties
  from its InputModel chain for proper dedup when custom code overrides base type

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

unable to customize base type of generated model to a non-generated type

1 participant