Handle custom external model bases#11183
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
commit: |
|
No changes needing a change description found. |
Use the system object model provider's base model chain for inheritance and expose customization-only properties through a TypeProvider hook instead of storing inherited properties separately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Populate synthetic system object input models with referenced type properties so existing ModelProvider inheritance handles inherited property filtering. Skip constructor forwarding for synthetic custom-base providers so external constructor surfaces are not generated into derived models. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover canonical generated duplicate removal when a custom system object base exposes the same wire path through a differently named property. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stop storing a base model provider on SystemObjectModelProvider. Seed the CSharpTypeMap for external base types and let the existing BaseType/BuildBaseModelProvider path resolve inheritance normally. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the ModelProvider-local custom base helper and centralize synthetic SystemObjectModelProvider creation in TypeFactory. ModelProvider now only asks TypeFactory to create/register a model provider for a custom external base, then uses the existing BaseType/CSharpTypeMap lookup path for inheritance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The root cause is fixed in microsoft/typespec#11183, so this SDK PR should not carry generator changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This reverts commit 6f3c763.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
No diff in regen: Azure/azure-sdk-for-net#60807 |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refines how the C# generator models and serializes types that derive from custom/external base classes, removing reliance on a synthetic base-provider path and instead using existing type metadata and hierarchy-aware detection (especially for MRW XML serialization). It also adds test coverage around external base chains and canonical wire-path deduplication.
Changes:
- Extend model/provider plumbing to better represent external/custom base type chains (base type + constructor-parameter propagation behavior).
- Improve MRW serialization override decisions (JSON root return type discovery; XML override detection with signature/accessibility/overridability checks).
- Add tests + test data for external base behaviors and canonical duplicate wire-path filtering.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs | Adds coverage for representing an external base chain via type metadata without duplicating inherited properties. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase/MockInputModel.cs | Adds test customization source defining a framework-like base (ResourceData) and a derived partial model. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs | Adds test ensuring canonical duplicate wire-path properties are filtered when a system/custom base already maps that wire path. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Writers/CodeWriter.cs | Adds sealed emission support for method/property signatures. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs | Enhances customized-member filtering to consider canonical duplicate wire paths (not just names). |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs | Adds base-type propagation and derived-constructor parameter behavior control for wrapped system types. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs | Adds interface list materialization and propagates sealed into method signature modifiers. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs | Gates base-constructor parameter propagation based on the base provider’s preference. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureModifiers.cs | Adds Sealed to the modifier bitflags. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs | Adds extensive XML override-detection tests across multiple base scenarios. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement/BaseModel.cs | Adds test data for a generated base with a compatible virtual XML core method. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase/MockInputModel.cs | Adds test data for a protected XML base method that must not be overridden by an internal method. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase/MockInputModel.cs | Adds test data for a JSON-only base to ensure XML methods are not overridden incorrectly. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod/BaseModel.cs | Adds test data ensuring a sealed override in a customized base prevents derived overrides. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod/BaseModel.cs | Adds test data ensuring protected custom methods don’t trigger internal overrides. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod/BaseModel.cs | Adds test data ensuring non-virtual methods don’t trigger overrides. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/SystemObjectModelSerializationTests.cs | Adjusts system-base MRW tests to explicitly model interface implementation via a specialized provider. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs | Reworks XML override detection to be XML-specific and hierarchy-aware. |
| packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs | Improves MRW override decisions and root-type discovery for models with custom/external bases. |
| protected internal override CSharpType[] BuildImplements() | ||
| => [.. _namedTypeSymbol.Interfaces.Select(i => i.GetCSharpType())]; |
| public SystemObjectModelProvider(CSharpType systemType, InputModelType inputModel) : base(inputModel) | ||
| { | ||
| _systemType = systemType ?? throw new ArgumentNullException(nameof(systemType)); | ||
| CrossLanguageDefinitionId = inputModel.CrossLanguageDefinitionId; | ||
|
|
||
| // The base ModelProvider constructor can evaluate Type before _systemType is assigned. | ||
| // Clear those cached values so Name/Namespace/BaseType are rebuilt from the wrapped type. | ||
| Reset(); | ||
| } | ||
|
|
||
| public SystemObjectModelProvider( | ||
| CSharpType systemType, | ||
| InputModelType inputModel, | ||
| bool skipDerivedConstructorParameters) | ||
| : this(systemType, inputModel) | ||
| { | ||
| _skipDerivedConstructorParameters = skipDerivedConstructorParameters; | ||
| Reset(); | ||
| } |
| private bool IsXmlModelWriteCoreMethod(MethodProvider method) | ||
| => IsXmlModelWriteCoreSignature(method) && | ||
| method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal) && | ||
| IsOverridable(method.Signature.Modifiers); | ||
|
|
| @@ -74,10 +74,10 @@ public partial class MrwSerializationTypeDefinition : TypeProvider | |||
| private ConstructorProvider? _serializationConstructor; | |||
There was a problem hiding this comment.
I'm wondering if we can avoid all of these changes by just changing the accessibility of BaseTypeProvider:
public TypeProvider? BaseTypeProvider => BaseTypeProviderTypeProvider;
private protected virtual TypeProvider? BaseTypeProviderTypeProvider => null;Then in this file we can add a helper:
private bool BaseDeclaresOverridable(string methodName)
{
for (var provider = _model.BaseTypeProvider; provider is not null; provider = provider.BaseTypeProvider)
{
// Prefer the custom view so hand-authored replacements/hooks win over generated members.
var source = provider.CustomCodeView ?? provider;
var method = source.Methods.FirstOrDefault(m => m.Signature.Name == methodName);
if (method is null)
{
continue; // not declared at this level; keep walking up
}
var mods = method.Signature.Modifiers;
return !mods.HasFlag(MethodSignatureModifiers.Sealed)
&& (mods.HasFlag(MethodSignatureModifiers.Virtual)
|| mods.HasFlag(MethodSignatureModifiers.Override)
|| mods.HasFlag(MethodSignatureModifiers.Abstract));
}
return false;
}Will this help simplify the proposed changes or am I missing something ?
| Partial = 8192, | ||
| Abstract = 16384 | ||
| Abstract = 16384, | ||
| Sealed = 32768 |
| return property.Name == wirePath.ToIdentifierName(); | ||
| } | ||
|
|
||
| private static bool TryGetWirePath(PropertyProvider property, out string wirePath) |
There was a problem hiding this comment.
why is this needed?
Summary
SystemObjectModelProviderpath and keep custom C# bases represented through existing type metadata.JsonModelWriteCoreas an override when the custom base already defines it;ResourceData;XmlModelWriteCoreonly overrides when the base exposes a compatible, accessible, non-sealed XML core method:BaseModelProviderbehavior for real input-model inheritance and external@alternateTypemodel mappings.Validation
dotnet test ./generator/Microsoft.TypeSpec.Generator.ClientModel/test/Microsoft.TypeSpec.Generator.ClientModel.Tests.csproj --no-restorefrompackages/http-client-csharpdotnet test ./generator/Microsoft.TypeSpec.Generator/test/Microsoft.TypeSpec.Generator.Tests.csproj --no-restorefrompackages/http-client-csharpazure-sdk-for-netwith temporary local project references: full Azure SDK mgmt generator tests passed.