From bd4a53fc21be8ce3152edf19d8512e3ce3b1dc9b Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 06:40:31 +0000 Subject: [PATCH 01/22] Handle custom external model bases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/Providers/ModelProvider.cs | 128 ++++++++++++++++++ .../Providers/SystemObjectModelProvider.cs | 33 +++++ .../src/Providers/TypeProvider.cs | 51 ++++++- .../SystemObjectModelProviderTests.cs | 22 +++ 4 files changed, 232 insertions(+), 2 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 9f28c6bc482..2dac761b905 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -410,6 +410,134 @@ private static bool IsDiscriminator(InputProperty property) return model; } } + + if (TryCreateSystemObjectBaseModelProvider(baseType, [], requireSerializationCapability: true) is { } systemBaseModelProvider) + { + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[baseType] = systemBaseModelProvider; + return systemBaseModelProvider; + } + } + + return null; + } + + private SystemObjectModelProvider? TryCreateSystemObjectBaseModelProvider( + CSharpType systemType, + HashSet visited, + bool requireSerializationCapability) + { + if (systemType.IsFrameworkType && systemType.FrameworkType == typeof(object)) + { + return null; + } + + var key = $"{systemType.Namespace}.{systemType.Name}"; + if (!visited.Add(key)) + { + return null; + } + + if (CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(systemType, out var existingProvider) && + existingProvider is SystemObjectModelProvider existingSystemObjectModelProvider) + { + return existingSystemObjectModelProvider; + } + + var referencedType = TryGetReferencedType(systemType); + if (requireSerializationCapability && + (referencedType is null || !HasJsonModelWriteCoreInHierarchy(referencedType, new HashSet(visited)))) + { + return null; + } + + var referencedBaseType = referencedType?.BaseType ?? + systemType.BaseType ?? + (referencedType is not null ? TryGetSerializationRootBaseType(referencedType, systemType) : null); + var baseModelProvider = referencedBaseType is not null + ? TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false) + : null; + var inputModel = CreateSystemInputModel(systemType); + var systemObjectModelProvider = new SystemObjectModelProvider(systemType, inputModel, baseModelProvider, referencedType?.Properties); + + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemType] = systemObjectModelProvider; + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; + if (systemType.IsFrameworkType) + { + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[new CSharpType(systemType.FrameworkType)] = systemObjectModelProvider; + } + + return systemObjectModelProvider; + } + + private InputModelType CreateSystemInputModel(CSharpType systemType) + { + var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; + return new InputModelType( + systemType.Name, + _inputModel.Namespace, + crossLanguageDefinitionId, + _inputModel.Access, + _inputModel.Deprecation, + _inputModel.Summary, + _inputModel.Doc, + _inputModel.Usage, + [], + null, + [], + null, + null, + new Dictionary(), + null, + _inputModel.ModelAsStruct, + new(), + _inputModel.IsDynamicModel); + } + + private static TypeProvider? TryGetReferencedType(CSharpType systemType) + { + if (string.IsNullOrEmpty(systemType.Namespace)) + { + return null; + } + + return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( + systemType.Namespace, + systemType.Name, + declaringTypeName: null, + includeReferencedAssemblies: true); + } + + private static bool HasJsonModelWriteCoreInHierarchy(TypeProvider typeProvider, HashSet visited) + { + if (typeProvider.Methods.Any(method => method.Signature.Name == "JsonModelWriteCore")) + { + return true; + } + + var baseType = typeProvider.BaseType ?? typeProvider.Type.BaseType; + if (baseType is null) + { + return false; + } + + var key = $"{baseType.Namespace}.{baseType.Name}"; + return visited.Add(key) && + TryGetReferencedType(baseType) is { } baseTypeProvider && + HasJsonModelWriteCoreInHierarchy(baseTypeProvider, visited); + } + + private static CSharpType? TryGetSerializationRootBaseType(TypeProvider typeProvider, CSharpType systemType) + { + foreach (var method in typeProvider.Methods) + { + if (method.Signature.Name is not ("JsonModelCreateCore" or "PersistableModelCreateCore") || + method.Signature.ReturnType is not { } returnType || + returnType.AreNamesEqual(systemType)) + { + continue; + } + + return returnType; } return null; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs index 8708932e11e..1950908df94 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -20,6 +21,7 @@ namespace Microsoft.TypeSpec.Generator.Providers public class SystemObjectModelProvider : ModelProvider { private readonly CSharpType _systemType; + private readonly ModelProvider? _baseModelProvider; /// /// Initializes a new instance of . @@ -36,11 +38,36 @@ public SystemObjectModelProvider(CSharpType systemType, InputModelType inputMode Reset(); } + /// + /// Initializes a new instance of . + /// + /// The CSharp type from the external/system assembly. + /// The input model type that this system type replaces. + /// The external/system base model provider, if any. + /// Properties exposed by the external/system type for customization filtering. + public SystemObjectModelProvider( + CSharpType systemType, + InputModelType inputModel, + ModelProvider? baseModelProvider, + IReadOnlyList? inheritedProperties = null) + : this(systemType, inputModel) + { + _baseModelProvider = baseModelProvider; + InheritedProperties = inheritedProperties ?? []; + Reset(); + } + /// /// Gets the underlying system that this provider wraps. /// public CSharpType SystemType => _systemType; + /// + /// Gets properties exposed by the external/system type that should participate in + /// customization filtering without becoming generated constructor parameters. + /// + public IReadOnlyList InheritedProperties { get; } = []; + /// /// Gets the cross-language definition ID from the input model. /// @@ -58,6 +85,12 @@ protected override string BuildRelativeFilePath() // _systemType may be null when called from base constructor before field assignment. protected override string BuildNamespace() => _systemType?.Namespace ?? string.Empty; + /// + protected override CSharpType? BuildBaseType() => _baseModelProvider?.Type ?? base.BuildBaseType(); + + /// + protected override ModelProvider? BuildBaseModelProvider() => _baseModelProvider ?? base.BuildBaseModelProvider(); + /// protected override bool ShouldSkipDerivedModelProperties => true; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 3d71670d5a9..722cec1a3f9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -9,6 +9,7 @@ using Microsoft.TypeSpec.Generator.EmitterRpc; using Microsoft.TypeSpec.Generator.Expressions; using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Input.Extensions; using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.SourceInput; using Microsoft.TypeSpec.Generator.Statements; @@ -73,7 +74,15 @@ private IReadOnlyList BuildAllCustomProperties() { if (includeBaseProviderMembers) { - allCustomProperties.AddRange(baseTypeProvider.Properties); + if (baseTypeProvider is SystemObjectModelProvider systemObjectModelProvider && + systemObjectModelProvider.InheritedProperties.Count > 0) + { + allCustomProperties.AddRange(systemObjectModelProvider.InheritedProperties); + } + else + { + allCustomProperties.AddRange(baseTypeProvider.Properties); + } } if (baseTypeProvider.CustomCodeView is { } customCodeView) @@ -319,6 +328,7 @@ internal PropertyProvider[] FilterCustomizedProperties(IEnumerable(); var customProperties = new HashSet(); + var customWirePaths = new HashSet(); foreach (var customProperty in BuildAllCustomProperties()) { @@ -327,6 +337,10 @@ internal PropertyProvider[] FilterCustomizedProperties(IEnumerable customWirePaths) + { + if (!TryGetWirePath(property, out var wirePath) || !customWirePaths.Contains(wirePath)) + { + return false; + } + + return property.Name == wirePath.ToIdentifierName(); + } + + private static bool TryGetWirePath(PropertyProvider property, out string wirePath) + { + if (property.WireInfo is not null) + { + wirePath = property.WireInfo.SerializedName; + return true; + } + + foreach (var attribute in property.Attributes) + { + if (attribute.Type.Name is "WirePath" or "WirePathAttribute" && + attribute.Arguments is [LiteralExpression { Literal: string value }, ..]) + { + wirePath = value; + return true; + } + } + + wirePath = string.Empty; + return false; + } + internal FieldProvider[] FilterCustomizedFields(IEnumerable specFields) { var fields = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs index e5179daaa47..62e18798620 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs @@ -98,6 +98,28 @@ public void CanServeAsBaseModelProvider() Assert.IsInstanceOf(derivedProvider.BaseModelProvider); } + [Test] + public void CanRepresentExternalBaseChainAndInheritedPropertiesSeparately() + { + var baseSystemType = CreateSystemCSharpType("ResourceData", "TestFramework"); + var baseInputModel = InputFactory.Model("Resource", properties: []); + var baseProvider = new SystemObjectModelProvider(baseSystemType, baseInputModel); + + var inheritedPropertyInput = InputFactory.Model( + "TrackedResourceMetadata", + properties: [InputFactory.Property("resourceType", InputPrimitiveType.String, wireName: "type")]); + var inheritedProperties = new ModelProvider(inheritedPropertyInput).Properties; + var systemType = CreateSystemCSharpType("TrackedResourceData", "TestFramework"); + var inputModel = InputFactory.Model("TrackedResource", properties: []); + var provider = new SystemObjectModelProvider(systemType, inputModel, baseProvider, inheritedProperties); + + Assert.AreSame(baseProvider, provider.BaseModelProvider); + Assert.AreEqual(baseProvider.Type, provider.Type.BaseType); + Assert.IsEmpty(provider.Properties, "External inherited properties must not become constructor/input properties."); + Assert.AreEqual(1, provider.InheritedProperties.Count); + Assert.AreEqual("ResourceType", provider.InheritedProperties[0].Name); + } + // ------------------------------------------------------------------- // 3. Property deduplication: properties matching framework base are skipped // ------------------------------------------------------------------- From 6356dc2c2c330a777aa6d083c14114874ed537d9 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 06:54:23 +0000 Subject: [PATCH 02/22] Simplify system object model metadata 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> --- .../src/Providers/ModelProvider.cs | 2 +- .../Providers/SystemObjectModelProvider.cs | 29 ++++++++++++------- .../src/Providers/TypeProvider.cs | 12 ++------ .../SystemObjectModelProviderTests.cs | 18 +++++------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 2dac761b905..1a424ac1c10 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -457,7 +457,7 @@ private static bool IsDiscriminator(InputProperty property) ? TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false) : null; var inputModel = CreateSystemInputModel(systemType); - var systemObjectModelProvider = new SystemObjectModelProvider(systemType, inputModel, baseModelProvider, referencedType?.Properties); + var systemObjectModelProvider = new SystemObjectModelProvider(systemType, inputModel, baseModelProvider); CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemType] = systemObjectModelProvider; CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs index 1950908df94..90109df6a93 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -44,16 +45,13 @@ public SystemObjectModelProvider(CSharpType systemType, InputModelType inputMode /// The CSharp type from the external/system assembly. /// The input model type that this system type replaces. /// The external/system base model provider, if any. - /// Properties exposed by the external/system type for customization filtering. public SystemObjectModelProvider( CSharpType systemType, InputModelType inputModel, - ModelProvider? baseModelProvider, - IReadOnlyList? inheritedProperties = null) + ModelProvider? baseModelProvider) : this(systemType, inputModel) { _baseModelProvider = baseModelProvider; - InheritedProperties = inheritedProperties ?? []; Reset(); } @@ -62,17 +60,28 @@ public SystemObjectModelProvider( /// public CSharpType SystemType => _systemType; - /// - /// Gets properties exposed by the external/system type that should participate in - /// customization filtering without becoming generated constructor parameters. - /// - public IReadOnlyList InheritedProperties { get; } = []; - /// /// Gets the cross-language definition ID from the input model. /// public string CrossLanguageDefinitionId { get; } + internal override IReadOnlyList CustomizationProperties + { + get + { + if (string.IsNullOrEmpty(SystemType.Namespace)) + { + return Properties; + } + + return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( + SystemType.Namespace, + SystemType.Name, + declaringTypeName: null, + includeReferencedAssemblies: true)?.Properties.ToArray() ?? Properties; + } + } + /// // _systemType may be null when called from base constructor before field assignment. protected override string BuildName() => _systemType?.Name ?? string.Empty; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 722cec1a3f9..3dcf7eba2a4 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -74,15 +74,7 @@ private IReadOnlyList BuildAllCustomProperties() { if (includeBaseProviderMembers) { - if (baseTypeProvider is SystemObjectModelProvider systemObjectModelProvider && - systemObjectModelProvider.InheritedProperties.Count > 0) - { - allCustomProperties.AddRange(systemObjectModelProvider.InheritedProperties); - } - else - { - allCustomProperties.AddRange(baseTypeProvider.Properties); - } + allCustomProperties.AddRange(baseTypeProvider.CustomizationProperties); } if (baseTypeProvider.CustomCodeView is { } customCodeView) @@ -261,6 +253,8 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() public IReadOnlyList Properties => _properties ??= ApplyCustomizationFilter(BuildProperties()); + internal virtual IReadOnlyList CustomizationProperties => Properties; + private IReadOnlyList? _methods; public IReadOnlyList Methods => _methods ??= ApplyCustomizationFilter(BuildMethods()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs index 62e18798620..9b348b33b7c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs @@ -99,25 +99,23 @@ public void CanServeAsBaseModelProvider() } [Test] - public void CanRepresentExternalBaseChainAndInheritedPropertiesSeparately() + public void CanRepresentExternalBaseChainWithoutSeparateInheritedProperties() { var baseSystemType = CreateSystemCSharpType("ResourceData", "TestFramework"); var baseInputModel = InputFactory.Model("Resource", properties: []); var baseProvider = new SystemObjectModelProvider(baseSystemType, baseInputModel); - var inheritedPropertyInput = InputFactory.Model( - "TrackedResourceMetadata", - properties: [InputFactory.Property("resourceType", InputPrimitiveType.String, wireName: "type")]); - var inheritedProperties = new ModelProvider(inheritedPropertyInput).Properties; var systemType = CreateSystemCSharpType("TrackedResourceData", "TestFramework"); - var inputModel = InputFactory.Model("TrackedResource", properties: []); - var provider = new SystemObjectModelProvider(systemType, inputModel, baseProvider, inheritedProperties); + var inputModel = InputFactory.Model( + "TrackedResource", + properties: [InputFactory.Property("resourceType", InputPrimitiveType.String, wireName: "type")]); + + var provider = new SystemObjectModelProvider(systemType, inputModel, baseProvider); Assert.AreSame(baseProvider, provider.BaseModelProvider); Assert.AreEqual(baseProvider.Type, provider.Type.BaseType); - Assert.IsEmpty(provider.Properties, "External inherited properties must not become constructor/input properties."); - Assert.AreEqual(1, provider.InheritedProperties.Count); - Assert.AreEqual("ResourceType", provider.InheritedProperties[0].Name); + Assert.AreEqual(1, provider.Properties.Count); + Assert.AreEqual("ResourceType", provider.Properties[0].Name); } // ------------------------------------------------------------------- From a6471c1cf5a6abc63d7b9a1aae1dcf8bae525237 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 07:00:48 +0000 Subject: [PATCH 03/22] Use model inheritance for system object properties 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> --- .../src/Providers/ModelProvider.cs | 47 +++++++++++++++++-- .../Providers/SystemObjectModelProvider.cs | 24 ++-------- .../src/Providers/TypeProvider.cs | 4 +- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 1a424ac1c10..ee1e7aec197 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -214,6 +214,7 @@ protected FieldProvider? RawDataField } } protected virtual bool ShouldSkipDerivedModelProperties => false; + protected virtual bool ShouldUseFullConstructorInDerivedTypes => true; /// /// Gets whether derived models should skip overriding serialization methods from this base model. /// @@ -456,7 +457,7 @@ private static bool IsDiscriminator(InputProperty property) var baseModelProvider = referencedBaseType is not null ? TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false) : null; - var inputModel = CreateSystemInputModel(systemType); + var inputModel = CreateSystemInputModel(systemType, referencedType); var systemObjectModelProvider = new SystemObjectModelProvider(systemType, inputModel, baseModelProvider); CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemType] = systemObjectModelProvider; @@ -469,7 +470,7 @@ private static bool IsDiscriminator(InputProperty property) return systemObjectModelProvider; } - private InputModelType CreateSystemInputModel(CSharpType systemType) + private InputModelType CreateSystemInputModel(CSharpType systemType, TypeProvider? referencedType) { var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; return new InputModelType( @@ -481,7 +482,7 @@ private InputModelType CreateSystemInputModel(CSharpType systemType) _inputModel.Summary, _inputModel.Doc, _inputModel.Usage, - [], + referencedType?.Properties.Select(CreateSystemInputProperty).ToList() ?? [], null, [], null, @@ -493,6 +494,44 @@ private InputModelType CreateSystemInputModel(CSharpType systemType) _inputModel.IsDynamicModel); } + private static InputModelProperty CreateSystemInputProperty(PropertyProvider property) + { + if (property.InputProperty is InputModelProperty inputProperty) + { + return new InputModelProperty( + inputProperty.Name, + inputProperty.Summary, + inputProperty.Doc, + inputProperty.Type, + inputProperty.IsRequired, + inputProperty.IsReadOnly, + inputProperty.Access, + inputProperty.IsDiscriminator, + inputProperty.SerializedName, + inputProperty.IsHttpMetadata, + inputProperty.IsApiVersion, + inputProperty.DefaultValue, + inputProperty.SerializationOptions ?? new(), + inputProperty.Encode); + } + + var serializedName = property.WireInfo?.SerializedName ?? property.Name.ToVariableName(); + return new InputModelProperty( + property.Name, + property.Description?.ToString(), + property.Description?.ToString(), + InputPrimitiveType.String, + false, + !property.Body.HasSetter, + null, + property.IsDiscriminator, + serializedName, + false, + false, + null, + new(json: new(serializedName))); + } + private static TypeProvider? TryGetReferencedType(CSharpType systemType) { if (string.IsNullOrEmpty(systemType.Namespace)) @@ -1099,7 +1138,7 @@ private IEnumerable GetAllBaseFieldsForConstructorInitialization( baseProperties = GetAllBasePropertiesForConstructorInitialization(includeDiscriminatorParameter); baseFields = GetAllBaseFieldsForConstructorInitialization(); } - else if (BaseModelProvider is not null && !HasBaseModelProviderCycle()) + else if (BaseModelProvider is not null && BaseModelProvider.ShouldUseFullConstructorInDerivedTypes && !HasBaseModelProviderCycle()) { baseParameters.AddRange(BaseModelProvider.FullConstructor.Signature.Parameters); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs index 90109df6a93..e0fb484b08d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs @@ -2,8 +2,6 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; -using System.Linq; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -23,6 +21,7 @@ public class SystemObjectModelProvider : ModelProvider { private readonly CSharpType _systemType; private readonly ModelProvider? _baseModelProvider; + private readonly bool _skipDerivedConstructorParameters; /// /// Initializes a new instance of . @@ -52,6 +51,7 @@ public SystemObjectModelProvider( : this(systemType, inputModel) { _baseModelProvider = baseModelProvider; + _skipDerivedConstructorParameters = true; Reset(); } @@ -65,23 +65,6 @@ public SystemObjectModelProvider( /// public string CrossLanguageDefinitionId { get; } - internal override IReadOnlyList CustomizationProperties - { - get - { - if (string.IsNullOrEmpty(SystemType.Namespace)) - { - return Properties; - } - - return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( - SystemType.Namespace, - SystemType.Name, - declaringTypeName: null, - includeReferencedAssemblies: true)?.Properties.ToArray() ?? Properties; - } - } - /// // _systemType may be null when called from base constructor before field assignment. protected override string BuildName() => _systemType?.Name ?? string.Empty; @@ -100,6 +83,9 @@ protected override string BuildRelativeFilePath() /// protected override ModelProvider? BuildBaseModelProvider() => _baseModelProvider ?? base.BuildBaseModelProvider(); + /// + protected override bool ShouldUseFullConstructorInDerivedTypes => !_skipDerivedConstructorParameters; + /// protected override bool ShouldSkipDerivedModelProperties => true; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 3dcf7eba2a4..a1381e7c6b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -74,7 +74,7 @@ private IReadOnlyList BuildAllCustomProperties() { if (includeBaseProviderMembers) { - allCustomProperties.AddRange(baseTypeProvider.CustomizationProperties); + allCustomProperties.AddRange(baseTypeProvider.Properties); } if (baseTypeProvider.CustomCodeView is { } customCodeView) @@ -253,8 +253,6 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() public IReadOnlyList Properties => _properties ??= ApplyCustomizationFilter(BuildProperties()); - internal virtual IReadOnlyList CustomizationProperties => Properties; - private IReadOnlyList? _methods; public IReadOnlyList Methods => _methods ??= ApplyCustomizationFilter(BuildMethods()); From cb4ab518e289d7d4c13aacf06e168b9a28f8f716 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 07:12:32 +0000 Subject: [PATCH 04/22] Add wire path duplicate filtering test 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> --- .../ModelProviders/ModelCustomizationTests.cs | 36 +++++++++++++++++++ .../MockInputModel.cs | 15 ++++++++ 2 files changed, 51 insertions(+) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 6fb38dc3961..dd109555f3c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -1861,6 +1861,42 @@ await MockHelpers.LoadMockGeneratorAsync( Assert.That(modelContent, Does.Not.Contain("public string Name")); } + [Test] + public async Task CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase() + { + var childModel = InputFactory.Model( + "mockInputModel", + properties: + [ + InputFactory.Property("type", InputPrimitiveType.String, wireName: "type"), + InputFactory.Property("defaultName", InputPrimitiveType.String, wireName: "name"), + InputFactory.Property("childProp", InputPrimitiveType.String), + ], + usage: InputModelTypeUsage.Json); + var systemInputModel = InputFactory.Model( + "ResourceData", + properties: + [ + InputFactory.Property("resourceType", InputPrimitiveType.String, wireName: "type"), + InputFactory.Property("name", InputPrimitiveType.String, wireName: "name"), + ], + usage: InputModelTypeUsage.Json); + + await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [childModel, systemInputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var customBaseType = CreateSystemCSharpType("ResourceData", "TestFramework"); + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[customBaseType] = new SystemObjectModelProvider(customBaseType, systemInputModel); + + var modelProvider = new ModelProvider(childModel); + var propertyNames = modelProvider.Properties.Select(p => p.Name).ToArray(); + + Assert.That(propertyNames, Does.Not.Contain("Type")); + Assert.That(propertyNames, Does.Contain("DefaultName")); + Assert.That(propertyNames, Does.Contain("ChildProp")); + } + [Test] public async Task CanReadPropertyAttributes() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase/MockInputModel.cs new file mode 100644 index 00000000000..93ce98e007f --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CanFilterCanonicalDuplicateWirePathFromSystemObjectModelProviderBase/MockInputModel.cs @@ -0,0 +1,15 @@ +#nullable disable + +namespace TestFramework +{ + public class ResourceData + { + } +} + +namespace Sample.Models +{ + public partial class MockInputModel : TestFramework.ResourceData + { + } +} From 02044ac01fb761b2cc5e4caf5625a46b818a01d4 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 07:24:58 +0000 Subject: [PATCH 05/22] Use type map for system object base lookup 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> --- .../src/Providers/ModelProvider.cs | 27 ++++++++++++++++--- .../Providers/SystemObjectModelProvider.cs | 17 +++--------- .../SystemObjectModelProviderTests.cs | 9 ++++--- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index ee1e7aec197..80e6ae3cb94 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -454,13 +454,19 @@ private static bool IsDiscriminator(InputProperty property) var referencedBaseType = referencedType?.BaseType ?? systemType.BaseType ?? (referencedType is not null ? TryGetSerializationRootBaseType(referencedType, systemType) : null); - var baseModelProvider = referencedBaseType is not null - ? TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false) - : null; + if (referencedBaseType is not null) + { + _ = TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false); + } + var inputModel = CreateSystemInputModel(systemType, referencedType); - var systemObjectModelProvider = new SystemObjectModelProvider(systemType, inputModel, baseModelProvider); + var providerType = systemType.BaseType is null && referencedBaseType is not null + ? CreateSystemTypeWithBaseType(systemType, referencedBaseType) + : systemType; + var systemObjectModelProvider = new SystemObjectModelProvider(providerType, inputModel, skipDerivedConstructorParameters: true); CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemType] = systemObjectModelProvider; + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[providerType] = systemObjectModelProvider; CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; if (systemType.IsFrameworkType) { @@ -470,6 +476,19 @@ private static bool IsDiscriminator(InputProperty property) return systemObjectModelProvider; } + private static CSharpType CreateSystemTypeWithBaseType(CSharpType systemType, CSharpType baseType) + => new( + systemType.Name, + systemType.Namespace, + systemType.IsValueType, + systemType.IsNullable, + systemType.DeclaringType, + systemType.Arguments, + systemType.IsPublic, + systemType.IsStruct, + baseType, + systemType.IsEnum ? systemType.UnderlyingEnumType : null); + private InputModelType CreateSystemInputModel(CSharpType systemType, TypeProvider? referencedType) { var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs index e0fb484b08d..7a820644826 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs @@ -20,7 +20,6 @@ namespace Microsoft.TypeSpec.Generator.Providers public class SystemObjectModelProvider : ModelProvider { private readonly CSharpType _systemType; - private readonly ModelProvider? _baseModelProvider; private readonly bool _skipDerivedConstructorParameters; /// @@ -38,20 +37,13 @@ public SystemObjectModelProvider(CSharpType systemType, InputModelType inputMode Reset(); } - /// - /// Initializes a new instance of . - /// - /// The CSharp type from the external/system assembly. - /// The input model type that this system type replaces. - /// The external/system base model provider, if any. public SystemObjectModelProvider( CSharpType systemType, InputModelType inputModel, - ModelProvider? baseModelProvider) + bool skipDerivedConstructorParameters) : this(systemType, inputModel) { - _baseModelProvider = baseModelProvider; - _skipDerivedConstructorParameters = true; + _skipDerivedConstructorParameters = skipDerivedConstructorParameters; Reset(); } @@ -78,10 +70,7 @@ protected override string BuildRelativeFilePath() protected override string BuildNamespace() => _systemType?.Namespace ?? string.Empty; /// - protected override CSharpType? BuildBaseType() => _baseModelProvider?.Type ?? base.BuildBaseType(); - - /// - protected override ModelProvider? BuildBaseModelProvider() => _baseModelProvider ?? base.BuildBaseModelProvider(); + protected override CSharpType? BuildBaseType() => SystemType.BaseType ?? base.BuildBaseType(); /// protected override bool ShouldUseFullConstructorInDerivedTypes => !_skipDerivedConstructorParameters; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs index 9b348b33b7c..503c7afcd8b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/SystemObjectModelProviderTests.cs @@ -29,9 +29,9 @@ public class SystemObjectModelProviderTests /// Creates a non-framework CSharpType with the given name and namespace. /// Uses the internal constructor accessible via InternalsVisibleTo. /// - private static CSharpType CreateSystemCSharpType(string name, string ns) + private static CSharpType CreateSystemCSharpType(string name, string ns, CSharpType? baseType = null) => new(name, ns, isValueType: false, isNullable: false, declaringType: null, - args: Array.Empty(), isPublic: true, isStruct: false); + args: Array.Empty(), isPublic: true, isStruct: false, baseType: baseType); [SetUp] public void Setup() @@ -105,12 +105,13 @@ public void CanRepresentExternalBaseChainWithoutSeparateInheritedProperties() var baseInputModel = InputFactory.Model("Resource", properties: []); var baseProvider = new SystemObjectModelProvider(baseSystemType, baseInputModel); - var systemType = CreateSystemCSharpType("TrackedResourceData", "TestFramework"); var inputModel = InputFactory.Model( "TrackedResource", properties: [InputFactory.Property("resourceType", InputPrimitiveType.String, wireName: "type")]); + var systemTypeWithBase = CreateSystemCSharpType("TrackedResourceData", "TestFramework", baseSystemType); + CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[baseSystemType] = baseProvider; - var provider = new SystemObjectModelProvider(systemType, inputModel, baseProvider); + var provider = new SystemObjectModelProvider(systemTypeWithBase, inputModel, skipDerivedConstructorParameters: true); Assert.AreSame(baseProvider, provider.BaseModelProvider); Assert.AreEqual(baseProvider.Type, provider.Type.BaseType); From 65b59bfc3596ba973b5f443a79c90f452bcbf40b Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 08:44:25 +0000 Subject: [PATCH 06/22] Move system object provider creation to TypeFactory 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> --- .../src/Providers/ModelProvider.cs | 181 +---------------- .../src/TypeFactory.cs | 186 ++++++++++++++++++ 2 files changed, 187 insertions(+), 180 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 80e6ae3cb94..45a37d1f385 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -412,7 +412,7 @@ private static bool IsDiscriminator(InputProperty property) } } - if (TryCreateSystemObjectBaseModelProvider(baseType, [], requireSerializationCapability: true) is { } systemBaseModelProvider) + if (CodeModelGenerator.Instance.TypeFactory.TryCreateSystemObjectModelProvider(baseType, _inputModel, requireSerializationCapability: true) is { } systemBaseModelProvider) { CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[baseType] = systemBaseModelProvider; return systemBaseModelProvider; @@ -422,185 +422,6 @@ private static bool IsDiscriminator(InputProperty property) return null; } - private SystemObjectModelProvider? TryCreateSystemObjectBaseModelProvider( - CSharpType systemType, - HashSet visited, - bool requireSerializationCapability) - { - if (systemType.IsFrameworkType && systemType.FrameworkType == typeof(object)) - { - return null; - } - - var key = $"{systemType.Namespace}.{systemType.Name}"; - if (!visited.Add(key)) - { - return null; - } - - if (CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(systemType, out var existingProvider) && - existingProvider is SystemObjectModelProvider existingSystemObjectModelProvider) - { - return existingSystemObjectModelProvider; - } - - var referencedType = TryGetReferencedType(systemType); - if (requireSerializationCapability && - (referencedType is null || !HasJsonModelWriteCoreInHierarchy(referencedType, new HashSet(visited)))) - { - return null; - } - - var referencedBaseType = referencedType?.BaseType ?? - systemType.BaseType ?? - (referencedType is not null ? TryGetSerializationRootBaseType(referencedType, systemType) : null); - if (referencedBaseType is not null) - { - _ = TryCreateSystemObjectBaseModelProvider(referencedBaseType, new HashSet(visited), requireSerializationCapability: false); - } - - var inputModel = CreateSystemInputModel(systemType, referencedType); - var providerType = systemType.BaseType is null && referencedBaseType is not null - ? CreateSystemTypeWithBaseType(systemType, referencedBaseType) - : systemType; - var systemObjectModelProvider = new SystemObjectModelProvider(providerType, inputModel, skipDerivedConstructorParameters: true); - - CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemType] = systemObjectModelProvider; - CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[providerType] = systemObjectModelProvider; - CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; - if (systemType.IsFrameworkType) - { - CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[new CSharpType(systemType.FrameworkType)] = systemObjectModelProvider; - } - - return systemObjectModelProvider; - } - - private static CSharpType CreateSystemTypeWithBaseType(CSharpType systemType, CSharpType baseType) - => new( - systemType.Name, - systemType.Namespace, - systemType.IsValueType, - systemType.IsNullable, - systemType.DeclaringType, - systemType.Arguments, - systemType.IsPublic, - systemType.IsStruct, - baseType, - systemType.IsEnum ? systemType.UnderlyingEnumType : null); - - private InputModelType CreateSystemInputModel(CSharpType systemType, TypeProvider? referencedType) - { - var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; - return new InputModelType( - systemType.Name, - _inputModel.Namespace, - crossLanguageDefinitionId, - _inputModel.Access, - _inputModel.Deprecation, - _inputModel.Summary, - _inputModel.Doc, - _inputModel.Usage, - referencedType?.Properties.Select(CreateSystemInputProperty).ToList() ?? [], - null, - [], - null, - null, - new Dictionary(), - null, - _inputModel.ModelAsStruct, - new(), - _inputModel.IsDynamicModel); - } - - private static InputModelProperty CreateSystemInputProperty(PropertyProvider property) - { - if (property.InputProperty is InputModelProperty inputProperty) - { - return new InputModelProperty( - inputProperty.Name, - inputProperty.Summary, - inputProperty.Doc, - inputProperty.Type, - inputProperty.IsRequired, - inputProperty.IsReadOnly, - inputProperty.Access, - inputProperty.IsDiscriminator, - inputProperty.SerializedName, - inputProperty.IsHttpMetadata, - inputProperty.IsApiVersion, - inputProperty.DefaultValue, - inputProperty.SerializationOptions ?? new(), - inputProperty.Encode); - } - - var serializedName = property.WireInfo?.SerializedName ?? property.Name.ToVariableName(); - return new InputModelProperty( - property.Name, - property.Description?.ToString(), - property.Description?.ToString(), - InputPrimitiveType.String, - false, - !property.Body.HasSetter, - null, - property.IsDiscriminator, - serializedName, - false, - false, - null, - new(json: new(serializedName))); - } - - private static TypeProvider? TryGetReferencedType(CSharpType systemType) - { - if (string.IsNullOrEmpty(systemType.Namespace)) - { - return null; - } - - return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( - systemType.Namespace, - systemType.Name, - declaringTypeName: null, - includeReferencedAssemblies: true); - } - - private static bool HasJsonModelWriteCoreInHierarchy(TypeProvider typeProvider, HashSet visited) - { - if (typeProvider.Methods.Any(method => method.Signature.Name == "JsonModelWriteCore")) - { - return true; - } - - var baseType = typeProvider.BaseType ?? typeProvider.Type.BaseType; - if (baseType is null) - { - return false; - } - - var key = $"{baseType.Namespace}.{baseType.Name}"; - return visited.Add(key) && - TryGetReferencedType(baseType) is { } baseTypeProvider && - HasJsonModelWriteCoreInHierarchy(baseTypeProvider, visited); - } - - private static CSharpType? TryGetSerializationRootBaseType(TypeProvider typeProvider, CSharpType systemType) - { - foreach (var method in typeProvider.Methods) - { - if (method.Signature.Name is not ("JsonModelCreateCore" or "PersistableModelCreateCore") || - method.Signature.ReturnType is not { } returnType || - returnType.AreNamesEqual(systemType)) - { - continue; - } - - return returnType; - } - - return null; - } - private List BuildAdditionalPropertyFields() { var fields = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index cd70e60ea9a..9a3cb9ac4ee 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -214,6 +214,192 @@ protected internal TypeFactory() protected virtual ModelProvider? CreateModelCore(InputModelType model) => new ModelProvider(model); + internal SystemObjectModelProvider? TryCreateSystemObjectModelProvider( + CSharpType systemType, + InputModelType sourceModel, + bool requireSerializationCapability) + => TryCreateSystemObjectModelProvider(systemType, sourceModel, [], requireSerializationCapability); + + private SystemObjectModelProvider? TryCreateSystemObjectModelProvider( + CSharpType systemType, + InputModelType sourceModel, + HashSet visited, + bool requireSerializationCapability) + { + if (systemType.IsFrameworkType && systemType.FrameworkType == typeof(object)) + { + return null; + } + + var key = $"{systemType.Namespace}.{systemType.Name}"; + if (!visited.Add(key)) + { + return null; + } + + if (CSharpTypeMap.TryGetValue(systemType, out var existingProvider) && + existingProvider is SystemObjectModelProvider existingSystemObjectModelProvider) + { + return existingSystemObjectModelProvider; + } + + var referencedType = TryGetReferencedType(systemType); + if (requireSerializationCapability && + (referencedType is null || !HasJsonModelWriteCoreInHierarchy(referencedType, new HashSet(visited)))) + { + return null; + } + + var referencedBaseType = referencedType?.BaseType ?? + systemType.BaseType ?? + (referencedType is not null ? TryGetSerializationRootBaseType(referencedType, systemType) : null); + if (referencedBaseType is not null) + { + _ = TryCreateSystemObjectModelProvider(referencedBaseType, sourceModel, new HashSet(visited), requireSerializationCapability: false); + } + + var inputModel = CreateSystemInputModel(systemType, sourceModel, referencedType); + var providerType = systemType.BaseType is null && referencedBaseType is not null + ? CreateSystemTypeWithBaseType(systemType, referencedBaseType) + : systemType; + var systemObjectModelProvider = new SystemObjectModelProvider(providerType, inputModel, skipDerivedConstructorParameters: true); + + CSharpTypeMap[systemType] = systemObjectModelProvider; + CSharpTypeMap[providerType] = systemObjectModelProvider; + CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; + if (systemType.IsFrameworkType) + { + CSharpTypeMap[new CSharpType(systemType.FrameworkType)] = systemObjectModelProvider; + } + + return systemObjectModelProvider; + } + + private static CSharpType CreateSystemTypeWithBaseType(CSharpType systemType, CSharpType baseType) + => new( + systemType.Name, + systemType.Namespace, + systemType.IsValueType, + systemType.IsNullable, + systemType.DeclaringType, + systemType.Arguments, + systemType.IsPublic, + systemType.IsStruct, + baseType, + systemType.IsEnum ? systemType.UnderlyingEnumType : null); + + private static InputModelType CreateSystemInputModel(CSharpType systemType, InputModelType sourceModel, TypeProvider? referencedType) + { + var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; + return new InputModelType( + systemType.Name, + sourceModel.Namespace, + crossLanguageDefinitionId, + sourceModel.Access, + sourceModel.Deprecation, + sourceModel.Summary, + sourceModel.Doc, + sourceModel.Usage, + referencedType?.Properties.Select(CreateSystemInputProperty).ToList() ?? [], + null, + [], + null, + null, + new Dictionary(), + null, + sourceModel.ModelAsStruct, + new(), + sourceModel.IsDynamicModel); + } + + private static InputModelProperty CreateSystemInputProperty(PropertyProvider property) + { + if (property.InputProperty is InputModelProperty inputProperty) + { + return new InputModelProperty( + inputProperty.Name, + inputProperty.Summary, + inputProperty.Doc, + inputProperty.Type, + inputProperty.IsRequired, + inputProperty.IsReadOnly, + inputProperty.Access, + inputProperty.IsDiscriminator, + inputProperty.SerializedName, + inputProperty.IsHttpMetadata, + inputProperty.IsApiVersion, + inputProperty.DefaultValue, + inputProperty.SerializationOptions ?? new(), + inputProperty.Encode); + } + + var serializedName = property.WireInfo?.SerializedName ?? property.Name.ToVariableName(); + return new InputModelProperty( + property.Name, + property.Description?.ToString(), + property.Description?.ToString(), + InputPrimitiveType.String, + false, + !property.Body.HasSetter, + null, + property.IsDiscriminator, + serializedName, + false, + false, + null, + new(json: new(serializedName))); + } + + private static TypeProvider? TryGetReferencedType(CSharpType systemType) + { + if (string.IsNullOrEmpty(systemType.Namespace)) + { + return null; + } + + return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( + systemType.Namespace, + systemType.Name, + declaringTypeName: null, + includeReferencedAssemblies: true); + } + + private static bool HasJsonModelWriteCoreInHierarchy(TypeProvider typeProvider, HashSet visited) + { + if (typeProvider.Methods.Any(method => method.Signature.Name == "JsonModelWriteCore")) + { + return true; + } + + var baseType = typeProvider.BaseType ?? typeProvider.Type.BaseType; + if (baseType is null) + { + return false; + } + + var key = $"{baseType.Namespace}.{baseType.Name}"; + return visited.Add(key) && + TryGetReferencedType(baseType) is { } baseTypeProvider && + HasJsonModelWriteCoreInHierarchy(baseTypeProvider, visited); + } + + private static CSharpType? TryGetSerializationRootBaseType(TypeProvider typeProvider, CSharpType systemType) + { + foreach (var method in typeProvider.Methods) + { + if (method.Signature.Name is not ("JsonModelCreateCore" or "PersistableModelCreateCore") || + method.Signature.ReturnType is not { } returnType || + returnType.AreNamesEqual(systemType)) + { + continue; + } + + return returnType; + } + + return null; + } + /// /// Maps an external (one marked via @alternateType) to a /// that wraps the resolved framework/referenced type. From 929133e69da2953f6ff741665f85432b611cb417 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 09:04:24 +0000 Subject: [PATCH 07/22] Use base type providers for custom base serialization Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 6 +- .../MrwSerializationTypeDefinition.cs | 49 ++++- .../src/Providers/ModelProvider.cs | 6 - .../src/Providers/NamedTypeSymbolProvider.cs | 39 ++++ .../src/Providers/TypeProvider.cs | 65 ++++++ .../src/TypeFactory.cs | 186 ------------------ 6 files changed, 146 insertions(+), 205 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 5d76b8f44a1..f63f999e407 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -67,7 +67,7 @@ private MethodProvider BuildXmlModelWriteCoreMethod() MethodSignatureModifiers modifiers = _isStruct ? MethodSignatureModifiers.Private : MethodSignatureModifiers.Internal | MethodSignatureModifiers.Virtual; - if (_shouldOverrideXmlMethods) + if (ShouldOverrideMethods) { modifiers = MethodSignatureModifiers.Internal | MethodSignatureModifiers.Override; } @@ -81,7 +81,7 @@ private MethodProvider BuildXmlModelWriteCoreMethod() private MethodBodyStatement[] BuildXmlModelWriteCoreMethodBody() { - var categorizedProperties = _shouldOverrideXmlMethods + var categorizedProperties = ShouldOverrideMethods ? CategorizedXmlProperties : AllCategorizedXmlProperties; var statements = new List @@ -90,7 +90,7 @@ private MethodBodyStatement[] BuildXmlModelWriteCoreMethodBody() MethodBodyStatement.EmptyLine }; - if (_shouldOverrideXmlMethods) + if (ShouldOverrideMethods) { statements.Add(Base.Invoke(XmlModelWriteCoreMethodName, _xmlWriterParameter, _serializationOptionsParameter).Terminate()); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 8202a2af405..2872ea4011e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -74,10 +74,10 @@ public partial class MrwSerializationTypeDefinition : TypeProvider private ConstructorProvider? _serializationConstructor; // Flag to determine if the model should override the serialization methods private bool? _shouldOverrideMethods; - private bool ShouldOverrideMethods => _shouldOverrideMethods ??= _model.BaseModelProvider != null && !_isStruct; + private bool ShouldOverrideMethods => _shouldOverrideMethods ??= !_isStruct && + (_model.BaseModelProvider != null || HasCustomBaseMethod(JsonModelWriteCoreMethodName)); private bool? _shouldSkipSerializationMethodOverrides; - private bool ShouldSkipSerializationMethodOverrides => _shouldSkipSerializationMethodOverrides ??= ShouldSkipDerivedSerializationMethodOverrides(_model.BaseModelProvider); - private readonly bool _shouldOverrideXmlMethods; + private bool ShouldSkipSerializationMethodOverrides => _shouldSkipSerializationMethodOverrides ??= ShouldSkipDerivedSerializationMethodOverrides(_model); private readonly Lazy _additionalProperties; // Unknown discriminator models use their base model as the serialization interface type. @@ -100,7 +100,6 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m _isStruct = _model.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Struct); _supportsXml = inputModel.Usage.HasFlag(InputModelTypeUsage.Xml); _supportsJson = inputModel.Usage.HasFlag(InputModelTypeUsage.Json) || !_supportsXml; - _shouldOverrideXmlMethods = _model.BaseModelProvider != null && !_isStruct; _rawDataField = _model.Fields.FirstOrDefault(f => f.Name == AdditionalPropertiesHelper.AdditionalBinaryDataPropsFieldName); _additionalBinaryDataProperty = new(GetAdditionalBinaryDataPropertiesProp); _additionalProperties = new(() => [.. _model.Properties.Where(p => p.IsAdditionalProperties)]); @@ -152,7 +151,15 @@ private CSharpType GetRootModelType() { // We need to explicitly use the BaseModelProvider when looking up the root type // to account for any customizations that may have changed the base model. - var returnType = _model.BaseModelProvider?.Type ?? Type; + var returnType = _model.BaseModelProvider?.Type ?? + GetCustomBaseRootType() ?? + GetCustomBaseMethodReturnType(new HashSet + { + JsonModelCreateCoreMethodName, + PersistableModelCreateCoreMethodName + }) ?? + GetCustomSerializationBaseType() ?? + Type; while (returnType.BaseType != null && IsModelType(returnType.BaseType)) { @@ -180,19 +187,41 @@ private static bool IsModelType(CSharpType type) /// When it does not (for example a hand-authored base such as ResourceData), derived /// models re-introduce the methods as virtual. /// - private static bool ShouldSkipDerivedSerializationMethodOverrides(ModelProvider? baseModelProvider) + private CSharpType? GetCustomSerializationBaseType() + => _model.BaseModelProvider is null && _model.CustomCodeView?.BaseType is not null + ? _model.BaseType + : null; + + private CSharpType? GetCustomBaseRootType() + => _model.BaseModelProvider is null && _model.CustomCodeView?.BaseType is not null + ? _model.GetRootBaseTypeInHierarchy() + : null; + + private bool HasCustomBaseMethod(string methodName) + => _model.BaseModelProvider is null && + _model.CustomCodeView?.BaseType is not null && + _model.HasBaseMethodInHierarchy(methodName); + + private CSharpType? GetCustomBaseMethodReturnType(IReadOnlySet methodNames) + => _model.BaseModelProvider is null && _model.CustomCodeView?.BaseType is not null + ? _model.GetBaseMethodReturnTypeInHierarchy(methodNames) + : null; + + private static bool ShouldSkipDerivedSerializationMethodOverrides(ModelProvider model) { - if (baseModelProvider is null) + if (model.BaseModelProvider is null) { - return false; + return model.CustomCodeView?.BaseType is null || + (!model.HasBaseMethodInHierarchy(JsonModelCreateCoreMethodName) && + !model.HasBaseMethodInHierarchy(PersistableModelCreateCoreMethodName)); } - if (baseModelProvider is SystemObjectModelProvider systemBase) + if (model.BaseModelProvider is SystemObjectModelProvider systemBase) { return !SystemTypeImplementsModelReaderWriter(systemBase.SystemType); } - return baseModelProvider.ShouldSkipDerivedSerializationMethodOverrides; + return model.BaseModelProvider.ShouldSkipDerivedSerializationMethodOverrides; } private static bool SystemTypeImplementsModelReaderWriter(CSharpType systemType) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 45a37d1f385..bce57ccb41a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -411,12 +411,6 @@ private static bool IsDiscriminator(InputProperty property) return model; } } - - if (CodeModelGenerator.Instance.TypeFactory.TryCreateSystemObjectModelProvider(baseType, _inputModel, requireSerializationCapability: true) is { } systemBaseModelProvider) - { - CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap[baseType] = systemBaseModelProvider; - return systemBaseModelProvider; - } } return null; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index ed3a45d54e8..f60d77d62bd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -64,6 +64,45 @@ protected override IReadOnlyList BuildAttributes() return new NamedTypeSymbolProvider(_namedTypeSymbol.BaseType!, _compilation); } + internal override bool HasMethodInHierarchy(string methodName, HashSet? visited = null) + { + visited ??= []; + if (!visited.Add(this)) + { + return false; + } + + return _namedTypeSymbol.GetMembers(methodName).OfType().Any(method => method.AssociatedSymbol is null) || + BaseTypeProvider?.HasMethodInHierarchy(methodName, visited) == true; + } + + internal override CSharpType? GetMethodReturnTypeInHierarchy(IReadOnlySet methodNames, HashSet? visited = null) + { + visited ??= []; + if (!visited.Add(this)) + { + return null; + } + + if (BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames, visited) is { } baseReturnType) + { + return baseReturnType; + } + + foreach (var methodName in methodNames) + { + var method = _namedTypeSymbol.GetMembers(methodName) + .OfType() + .FirstOrDefault(method => method.AssociatedSymbol is null); + if (method is not null) + { + return method.ReturnType.GetCSharpType(); + } + } + + return null; + } + private bool ShouldSkipBaseType(INamedTypeSymbol? baseType) => baseType == null || baseType.SpecialType == SpecialType.System_Object diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index a1381e7c6b7..fb79e348407 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -229,6 +229,71 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() protected virtual CSharpType? BuildBaseType() => null; + internal virtual bool HasMethodInHierarchy(string methodName, HashSet? visited = null) + { + visited ??= []; + if (!visited.Add(this)) + { + return false; + } + + return Methods.Any(method => method.Signature.Name == methodName) || + BaseTypeProvider?.HasMethodInHierarchy(methodName, visited) == true; + } + + public bool HasBaseMethodInHierarchy(string methodName) + => BaseTypeProvider?.HasMethodInHierarchy(methodName) == true; + + public CSharpType? GetRootBaseTypeInHierarchy() + { + var visited = new HashSet(); + var baseTypeProvider = BaseTypeProvider; + CSharpType? rootBaseType = null; + + while (baseTypeProvider is not null && visited.Add(baseTypeProvider)) + { + if (!IsFrameworkRootType(baseTypeProvider.Type)) + { + rootBaseType = baseTypeProvider.Type; + } + baseTypeProvider = baseTypeProvider.BaseTypeProvider; + } + + return rootBaseType; + + static bool IsFrameworkRootType(CSharpType type) + => (type.IsFrameworkType && + (type.FrameworkType == typeof(object) || type.FrameworkType == typeof(ValueType))) || + (type.Namespace == "System" && (type.Name == "Object" || type.Name == "ValueType")); + } + + internal virtual CSharpType? GetMethodReturnTypeInHierarchy(IReadOnlySet methodNames, HashSet? visited = null) + { + visited ??= []; + if (!visited.Add(this)) + { + return null; + } + + if (BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames, visited) is { } baseReturnType) + { + return baseReturnType; + } + + foreach (var method in Methods) + { + if (methodNames.Contains(method.Signature.Name) && method.Signature.ReturnType is { } returnType) + { + return returnType; + } + } + + return null; + } + + public CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) + => BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames); + private IReadOnlyList? _disabledFileWarnings; public IReadOnlyList DisabledFileWarnings => _disabledFileWarnings ??= BuildDisabledFileWarnings(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index 9a3cb9ac4ee..cd70e60ea9a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -214,192 +214,6 @@ protected internal TypeFactory() protected virtual ModelProvider? CreateModelCore(InputModelType model) => new ModelProvider(model); - internal SystemObjectModelProvider? TryCreateSystemObjectModelProvider( - CSharpType systemType, - InputModelType sourceModel, - bool requireSerializationCapability) - => TryCreateSystemObjectModelProvider(systemType, sourceModel, [], requireSerializationCapability); - - private SystemObjectModelProvider? TryCreateSystemObjectModelProvider( - CSharpType systemType, - InputModelType sourceModel, - HashSet visited, - bool requireSerializationCapability) - { - if (systemType.IsFrameworkType && systemType.FrameworkType == typeof(object)) - { - return null; - } - - var key = $"{systemType.Namespace}.{systemType.Name}"; - if (!visited.Add(key)) - { - return null; - } - - if (CSharpTypeMap.TryGetValue(systemType, out var existingProvider) && - existingProvider is SystemObjectModelProvider existingSystemObjectModelProvider) - { - return existingSystemObjectModelProvider; - } - - var referencedType = TryGetReferencedType(systemType); - if (requireSerializationCapability && - (referencedType is null || !HasJsonModelWriteCoreInHierarchy(referencedType, new HashSet(visited)))) - { - return null; - } - - var referencedBaseType = referencedType?.BaseType ?? - systemType.BaseType ?? - (referencedType is not null ? TryGetSerializationRootBaseType(referencedType, systemType) : null); - if (referencedBaseType is not null) - { - _ = TryCreateSystemObjectModelProvider(referencedBaseType, sourceModel, new HashSet(visited), requireSerializationCapability: false); - } - - var inputModel = CreateSystemInputModel(systemType, sourceModel, referencedType); - var providerType = systemType.BaseType is null && referencedBaseType is not null - ? CreateSystemTypeWithBaseType(systemType, referencedBaseType) - : systemType; - var systemObjectModelProvider = new SystemObjectModelProvider(providerType, inputModel, skipDerivedConstructorParameters: true); - - CSharpTypeMap[systemType] = systemObjectModelProvider; - CSharpTypeMap[providerType] = systemObjectModelProvider; - CSharpTypeMap[systemObjectModelProvider.Type] = systemObjectModelProvider; - if (systemType.IsFrameworkType) - { - CSharpTypeMap[new CSharpType(systemType.FrameworkType)] = systemObjectModelProvider; - } - - return systemObjectModelProvider; - } - - private static CSharpType CreateSystemTypeWithBaseType(CSharpType systemType, CSharpType baseType) - => new( - systemType.Name, - systemType.Namespace, - systemType.IsValueType, - systemType.IsNullable, - systemType.DeclaringType, - systemType.Arguments, - systemType.IsPublic, - systemType.IsStruct, - baseType, - systemType.IsEnum ? systemType.UnderlyingEnumType : null); - - private static InputModelType CreateSystemInputModel(CSharpType systemType, InputModelType sourceModel, TypeProvider? referencedType) - { - var crossLanguageDefinitionId = string.IsNullOrEmpty(systemType.Namespace) ? systemType.Name : $"{systemType.Namespace}.{systemType.Name}"; - return new InputModelType( - systemType.Name, - sourceModel.Namespace, - crossLanguageDefinitionId, - sourceModel.Access, - sourceModel.Deprecation, - sourceModel.Summary, - sourceModel.Doc, - sourceModel.Usage, - referencedType?.Properties.Select(CreateSystemInputProperty).ToList() ?? [], - null, - [], - null, - null, - new Dictionary(), - null, - sourceModel.ModelAsStruct, - new(), - sourceModel.IsDynamicModel); - } - - private static InputModelProperty CreateSystemInputProperty(PropertyProvider property) - { - if (property.InputProperty is InputModelProperty inputProperty) - { - return new InputModelProperty( - inputProperty.Name, - inputProperty.Summary, - inputProperty.Doc, - inputProperty.Type, - inputProperty.IsRequired, - inputProperty.IsReadOnly, - inputProperty.Access, - inputProperty.IsDiscriminator, - inputProperty.SerializedName, - inputProperty.IsHttpMetadata, - inputProperty.IsApiVersion, - inputProperty.DefaultValue, - inputProperty.SerializationOptions ?? new(), - inputProperty.Encode); - } - - var serializedName = property.WireInfo?.SerializedName ?? property.Name.ToVariableName(); - return new InputModelProperty( - property.Name, - property.Description?.ToString(), - property.Description?.ToString(), - InputPrimitiveType.String, - false, - !property.Body.HasSetter, - null, - property.IsDiscriminator, - serializedName, - false, - false, - null, - new(json: new(serializedName))); - } - - private static TypeProvider? TryGetReferencedType(CSharpType systemType) - { - if (string.IsNullOrEmpty(systemType.Namespace)) - { - return null; - } - - return CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( - systemType.Namespace, - systemType.Name, - declaringTypeName: null, - includeReferencedAssemblies: true); - } - - private static bool HasJsonModelWriteCoreInHierarchy(TypeProvider typeProvider, HashSet visited) - { - if (typeProvider.Methods.Any(method => method.Signature.Name == "JsonModelWriteCore")) - { - return true; - } - - var baseType = typeProvider.BaseType ?? typeProvider.Type.BaseType; - if (baseType is null) - { - return false; - } - - var key = $"{baseType.Namespace}.{baseType.Name}"; - return visited.Add(key) && - TryGetReferencedType(baseType) is { } baseTypeProvider && - HasJsonModelWriteCoreInHierarchy(baseTypeProvider, visited); - } - - private static CSharpType? TryGetSerializationRootBaseType(TypeProvider typeProvider, CSharpType systemType) - { - foreach (var method in typeProvider.Methods) - { - if (method.Signature.Name is not ("JsonModelCreateCore" or "PersistableModelCreateCore") || - method.Signature.ReturnType is not { } returnType || - returnType.AreNamesEqual(systemType)) - { - continue; - } - - return returnType; - } - - return null; - } - /// /// Maps an external (one marked via @alternateType) to a /// that wraps the resolved framework/referenced type. From 6f3c7633cea9bfc0be77201423a836077342169c Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 09:44:59 +0000 Subject: [PATCH 08/22] Keep base hierarchy helpers internal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/StubLibraryGenerator.cs | 2 +- .../src/StubLibraryVisitor.cs | 8 +++---- ...soft.TypeSpec.Generator.ClientModel.csproj | 1 + .../BinaryContentHelperDefinition.cs | 2 +- .../CancellationTokenExtensionsDefinition.cs | 2 +- .../src/Providers/ClientOptionsProvider.cs | 6 ++--- .../ClientPipelineExtensionsDefinition.cs | 2 +- .../src/Providers/ClientProvider.cs | 18 ++++++++------- .../src/Providers/ClientSettingsProvider.cs | 4 ++-- .../Providers/ClientUriBuilderDefinition.cs | 8 +++---- .../Providers/CollectionResultDefinition.cs | 8 +++---- .../src/Providers/ErrorResultDefinition.cs | 10 ++++----- .../ExtensibleEnumSerializationProvider.cs | 2 +- .../FixedEnumSerializationProvider.cs | 2 +- .../ModelSerializationExtensionsDefinition.cs | 6 ++--- .../MrwSerializationTypeDefinition.cs | 8 +++---- ...ultiPartFormDataBinaryContentDefinition.cs | 8 +++---- .../MultipartFormDataHelperDefinition.cs | 2 +- ...ultipartFormDataSerializationDefinition.cs | 6 ++--- ...elineRequestHeadersExtensionsDefinition.cs | 2 +- .../src/Providers/RestClientProvider.cs | 6 ++--- .../Providers/ScmMethodProviderCollection.cs | 4 ++-- .../src/Providers/ScmModelFactoryProvider.cs | 2 +- .../src/Providers/ScmModelProvider.cs | 6 ++--- .../SerializationFormatDefinition.cs | 2 +- .../src/Providers/SystemOptionalDefinition.cs | 2 +- .../src/Providers/TypeFormattersDefinition.cs | 4 ++-- .../Utf8JsonBinaryContentDefinition.cs | 8 +++---- .../src/ScmCodeModelGenerator.cs | 2 +- .../src/ScmLibraryVisitor.cs | 2 +- .../ClientProviderSubClientTests.cs | 8 +++---- .../ClientProviders/ClientProviderTests.cs | 22 +++++++++---------- .../DeserializationTests.cs | 4 ++-- .../JsonModelCoreTests.cs | 4 ++-- .../PersistableModelCoreTests.cs | 4 ++-- .../XmlDeserializationTests.cs | 2 +- .../XmlSerializationTests.cs | 4 ++-- .../RestClientProviderTests.cs | 6 ++--- .../src/Properties/AssemblyInfo.cs | 1 + .../src/Providers/TypeProvider.cs | 6 ++--- 40 files changed, 105 insertions(+), 101 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs index c9e46a18b0a..c40f23bbd0d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs @@ -12,7 +12,7 @@ public class StubLibraryGenerator : ScmCodeModelGenerator [ImportingConstructor] public StubLibraryGenerator(GeneratorContext context) : base(context) { } - protected override void Configure() + protected internal override void Configure() { base.Configure(); AddVisitor(new StubLibraryVisitor()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs index fb41de57dcc..ac79f81b916 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs @@ -43,7 +43,7 @@ internal class StubLibraryVisitor : ScmLibraryVisitor return type; } - protected override ConstructorProvider? VisitConstructor(ConstructorProvider constructor) + protected internal override ConstructorProvider? VisitConstructor(ConstructorProvider constructor) { if (!IsCallingBaseCtor(constructor) && !IsEffectivelyPublic(constructor.Signature.Modifiers) && @@ -94,7 +94,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) constructor.Signature.Initializer.Arguments.Count > 0; } - protected override FieldProvider? VisitField(FieldProvider field) + protected internal override FieldProvider? VisitField(FieldProvider field) { // For ClientOptions, keep the non-public field as this currently represents the latest service version for a client. // For ClientProvider, keep const and static fields as they are referenced by stub constructor initializers @@ -108,7 +108,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) : null; } - protected override MethodProvider? VisitMethod(MethodProvider method) + protected internal override MethodProvider? VisitMethod(MethodProvider method) { if (method.Signature.ExplicitInterface is null && !IsEffectivelyPublic(method.Signature.Modifiers)) { @@ -125,7 +125,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) return method; } - protected override PropertyProvider? VisitProperty(PropertyProvider property) + protected internal override PropertyProvider? VisitProperty(PropertyProvider property) { if (!property.IsDiscriminator && !IsEffectivelyPublic(property.Modifiers)) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj index 3179721bdfb..693afef0555 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj @@ -5,6 +5,7 @@ 1.0.0-beta.1 true + $(NoWarn);CS0436 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs index a2ee813e298..71e7343684e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs @@ -35,7 +35,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var methods = new List { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs index 6168a29ba2f..e81e80770bc 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs @@ -30,7 +30,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "CancellationTokenExtensions"; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index 24c20fd2c0e..ef84564e9cd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -277,7 +277,7 @@ protected override CSharpType BuildBaseType() return ScmCodeModelGenerator.Instance.TypeFactory.ClientPipelineApi.ClientPipelineOptionsType; } - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { if (LatestVersionsFields is null) { @@ -297,7 +297,7 @@ protected override TypeProvider[] BuildNestedTypes() return [.. _serviceVersionsEnums.Values.OrderBy(e => e.Name)]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var configSectionCtor = BuildConfigurationSectionConstructor(); @@ -459,7 +459,7 @@ private ConstructorProvider BuildConfigurationSectionConstructor() this); } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { var properties = VersionProperties is not null ? [.. VersionProperties.Values.OrderBy(p => p.Name)] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs index 02864633aca..22622776fd2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs @@ -41,7 +41,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ClientPipelineExtensions"; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs index f8ee8744e32..6de1b356af9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs @@ -149,7 +149,8 @@ public ClientProvider(InputClient inputClient) { string tokenCredentialFieldName = TokenCredentialFieldName; FormattableString tokenCredentialDescription = $"A credential used to authenticate to the service."; - if (tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType)) + if (ClientPipelineProvider.Instance.TokenCredentialType is not null && + tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType)) { tokenCredentialFieldName = TokenProviderFieldName; tokenCredentialDescription = $"A credential provider used to authenticate to the service."; @@ -254,7 +255,7 @@ private string BuildNamespaceCore() // figure out if this namespace has been changed for this client if (!IsLastNamespaceSegmentTheSame(ns, _inputClient.Namespace)) { - ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic(DiagnosticCodes.ClientNamespaceConflict, $"namespace {_inputClient.Namespace} conflicts with client {_inputClient.Name}, please use `@clientName` to specify a different name for the client.", _inputClient.CrossLanguageDefinitionId); + ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic(Utilities.DiagnosticCodes.ClientNamespaceConflict, $"namespace {_inputClient.Namespace} conflicts with client {_inputClient.Name}, please use `@clientName` to specify a different name for the client.", _inputClient.CrossLanguageDefinitionId); } return ns; } @@ -426,7 +427,7 @@ private IReadOnlyList GetClientParameters() protected override string BuildName() => _inputClient.IsExactName ? _inputClient.Name : _inputClient.Name.ToIdentifierName(); - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { List fields = [EndpointField]; @@ -560,12 +561,12 @@ private List BuildApiVersionFields( } } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [PipelineProperty]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var mockingConstructor = ConstructorProviderHelper.BuildMockingConstructor(this); // handle sub-client constructors @@ -1141,7 +1142,7 @@ public ScmMethodProviderCollection GetMethodCollectionByOperation(InputOperation return MethodCache[operation]; } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { var subClients = _subClients.Value; var subClientCount = subClients.Count; @@ -1261,7 +1262,7 @@ protected override ScmMethodProvider[] BuildMethods() return [.. methods]; } - protected sealed override IReadOnlyList BuildMethodsForBackCompatibility(IEnumerable originalMethods) + protected internal sealed override IReadOnlyList BuildMethodsForBackCompatibility(IEnumerable originalMethods) { List materializedMethods = [.. originalMethods]; @@ -1611,7 +1612,8 @@ private static bool IsSupersededByClientParameter(InputParameter param, HashSet< private FieldProvider BuildTokenCredentialScopesField(InputOAuth2Auth oauth2Auth, CSharpType tokenCredentialType) { - return tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType) + return ClientPipelineProvider.Instance.TokenCredentialType is not null && + tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType) ? BuildTokenCredentialFlowsField(oauth2Auth) : BuildTokenCredentialScopesField(oauth2Auth); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs index 5f7e3d38390..53970aaec3a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs @@ -85,7 +85,7 @@ protected override IReadOnlyList BuildAttributes() return [new AttributeStatement(typeof(ExperimentalAttribute), Literal(ClientSettingsDiagnosticId))]; } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { var properties = new List(); @@ -156,7 +156,7 @@ protected override PropertyProvider[] BuildProperties() return [.. properties]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var sectionParam = new ParameterProvider("section", $"The configuration section.", IConfigurationSectionType); var body = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs index 92e0cf23a67..97d53f7cc1f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs @@ -72,17 +72,17 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ClientUriBuilder"; - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [_uriBuilderField, _pathAndQueryField, _pathLengthField]; } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [UriBuilderProperty, PathAndQueryProperty]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -92,7 +92,7 @@ protected override ConstructorProvider[] BuildConstructors() return [new ConstructorProvider(signature, MethodBodyStatement.Empty, this, XmlDocProvider.Empty)]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var methods = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs index 62f28d86c8d..f9c45f3f47b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs @@ -217,9 +217,9 @@ private bool HasPagingOperationNameCollision(string operationName) protected override TypeSignatureModifiers BuildDeclarationModifiers() => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; - protected override FieldProvider[] BuildFields() => [ClientField, .. RequestFields]; + protected internal override FieldProvider[] BuildFields() => [ClientField, .. RequestFields]; - protected override CSharpType[] BuildImplements() => + protected internal override CSharpType[] BuildImplements() => (_modelType: ItemModelType, IsAsync) switch { (null, true) => [new CSharpType(typeof(AsyncCollectionResult))], @@ -228,7 +228,7 @@ protected override CSharpType[] BuildImplements() => (_, false) => [new CSharpType(typeof(CollectionResult<>), ItemModelType)], }; - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var clientParameter = new ParameterProvider( "client", @@ -280,7 +280,7 @@ private MethodBodyStatement[] BuildConstructorBody(ParameterProvider clientParam /// public string GetNextResponseMethodName => IsAsync ? "GetNextResponseAsync" : "GetNextResponse"; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { MethodBodyStatement[] getRawPagesMethodBody = (Paging.NextLink, Paging.ContinuationToken) switch { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs index 05615bddea0..f72e893e86b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs @@ -46,17 +46,17 @@ protected override CSharpType[] GetTypeArguments() return [_t]; } - protected override CSharpType[] BuildImplements() + protected internal override CSharpType[] BuildImplements() { return [new CSharpType(ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseOfTType.FrameworkType, _t)]; } - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [_responseField, _exceptionField]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { return [BuildCtor()]; } @@ -76,7 +76,7 @@ private ConstructorProvider BuildCtor() }, this, XmlDocProvider.Empty); } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [BuildValue()]; } @@ -88,7 +88,7 @@ private PropertyProvider BuildValue() this); } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return IsClientResult ? [] : [BuildGetRawResponse()]; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs index f3c5a792c95..e79a86e11e9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs @@ -34,7 +34,7 @@ protected override string BuildRelativeFilePath() protected override TypeSignatureModifiers BuildDeclarationModifiers() => _enumProvider.DeclarationModifiers; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { // for string-based extensible enums, we are using `ToString` as its serialization // for non-string-based extensible enums, we need a method to serialize them diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs index f5224038ede..b2b16e21148 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs @@ -57,7 +57,7 @@ private bool NeedsSerializationMethod() return true; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var methods = new List(); // serialization method (in some cases we do not need serialization) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs index 34cfb90210c..2c638825df0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs @@ -108,12 +108,12 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ModelSerializationExtensions"; - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [WireOptionsField, _jsonDocumentOptionsField, .. BuildXmlFields()]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var writer = ScmKnownParameters.Utf8JsonWriter.As(); var dateTimeOffsetValueParameter = @@ -205,7 +205,7 @@ .. BuildXmlExtensionMethods(), return [.. methods]; } - protected override SuppressionStatement[] BuildDisabledFileWarnings() + protected internal override SuppressionStatement[] BuildDisabledFileWarnings() => HasFileBinaryContentJsonModel || HasFileBinaryContentXmlModel ? [new SuppressionStatement(null, Literal(ScmModelProvider.FileBinaryContentDiagnosticId), ScmModelProvider.ScmEvaluationTypeSuppressionJustification)] : []; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 2872ea4011e..df37eda39db 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -125,7 +125,7 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m protected override CSharpType? BuildBaseType() => _model.BaseType; - protected override SuppressionStatement[] BuildDisabledFileWarnings() + protected internal override SuppressionStatement[] BuildDisabledFileWarnings() { if (_model.CanonicalView.Properties.Any(p => ScmModelProvider.IsFileBinaryContentType(p.Type))) { @@ -246,7 +246,7 @@ private static bool SystemTypeImplementsModelReaderWriter(CSharpType systemType) return false; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { List constructors = new(); bool ctorWithNoParamsExist = false; @@ -275,7 +275,7 @@ protected override ConstructorProvider[] BuildConstructors() /// Builds the serialization methods for the model. /// /// A list of serialization and deserialization methods for the model. - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var methods = new List(); @@ -460,7 +460,7 @@ private MethodProvider BuildToBinaryContentMethod() /// Builds the types that the model type serialization implements. /// /// An array of types that the model implements. - protected override CSharpType[] BuildImplements() + protected internal override CSharpType[] BuildImplements() { var interfaces = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs index 3ba1fad08c9..fc4804a5fba 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs @@ -83,17 +83,17 @@ public MultiPartFormDataBinaryContentDefinition() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [_multipartContentField, _randomField, _boundaryValuesFields]; } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [_contentTypeProperty, _httpContentProperty]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -111,7 +111,7 @@ protected override ConstructorProvider[] BuildConstructors() ]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs index 14f332d2cbc..04cc6a590ac 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs @@ -29,7 +29,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() => [BuildFromEnumerableMethod(), BuildFromDictionaryMethod()]; private MethodProvider BuildFromEnumerableMethod() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs index 88cb97b16e7..b56a8469018 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs @@ -51,10 +51,10 @@ protected override string BuildRelativeFilePath() return Path.Combine("src", "Generated", "Models", $"{Name}.Serialization.Multipart.cs"); } - protected override SuppressionStatement[] BuildDisabledFileWarnings() + protected internal override SuppressionStatement[] BuildDisabledFileWarnings() => [new SuppressionStatement(null, Literal(ScmModelProvider.FileBinaryContentDiagnosticId), ScmModelProvider.ScmEvaluationTypeSuppressionJustification)]; - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { if (_hasJsonOrXmlUsage) { @@ -69,7 +69,7 @@ protected override ConstructorProvider[] BuildConstructors() return [BuildEmptyConstructor()]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var signature = new MethodSignature( ToMultipartFormContentMethodName, diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs index 288b7f1af24..cd0492ebabe 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs @@ -34,7 +34,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "PipelineRequestHeadersExtensions"; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs index f00d78571d0..be0c3a1688e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs @@ -57,12 +57,12 @@ public RestClientProvider(InputClient inputClient, ClientProvider clientProvider protected override string BuildNamespace() => ClientProvider.Type.Namespace; - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [.. _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name)]; } - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { List pipelineMessage20xClassifiersFields = new(_pipelineMessage20xClassifiers.Count); var orderedClassifierProperties = _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name); @@ -78,7 +78,7 @@ protected override FieldProvider[] BuildFields() return [.. pipelineMessage20xClassifiersFields]; } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { List methods = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs index a88310c03b9..f020f6b6fe5 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs @@ -712,7 +712,7 @@ private MethodBodyStatement GetFrameworkTypeConversionFromReader(CSharpType elem } ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic( - DiagnosticCodes.UnsupportedFrameworkType, + Utilities.DiagnosticCodes.UnsupportedFrameworkType, $"Unsupported framework type: {frameworkType}. Element will be skipped.", ServiceMethod.Operation.CrossLanguageDefinitionId, EmitterDiagnosticSeverity.Error); @@ -1365,7 +1365,7 @@ private CSharpType GetConvenienceReturnType(IReadOnlyList models) : base(mode _models = models; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var methods = base.BuildMethods(); if (methods.Length == 0) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs index 07cc8e9c1d2..8b3b9a1af4c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs @@ -73,7 +73,7 @@ public ScmModelProvider(InputModelType inputModel) : base(inputModel) BaseJsonPatchProperty = new(GetBaseJsonPatchProperty()); } - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { if (JsonPatchField is null) { @@ -96,7 +96,7 @@ protected override FieldProvider[] BuildFields() return [JsonPatchField, .. updatedFields]; } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { PropertyProvider[] properties; if (JsonPatchProperty is null) @@ -126,7 +126,7 @@ protected override PropertyProvider[] BuildProperties() return properties; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { List constructors = [.. base.BuildConstructors()]; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs index af294640060..5e76cbb58e1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs @@ -91,7 +91,7 @@ protected override IReadOnlyList BuildEnumValues() return members; } - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() => EnumValues.Select(v => v.Field).ToArray(); protected override CSharpType BuildEnumUnderlyingType() => new CSharpType(typeof(int)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs index dce19d8223d..3cfe1e66291 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs @@ -15,7 +15,7 @@ namespace Microsoft.TypeSpec.Generator.ClientModel.Providers internal sealed class SystemOptionalDefinition : OptionalDefinition { private const string IsDefinedMethodName = "IsDefined"; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods(), IsJsonElementDefined()]; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs index 4e0509bc78e..cb572e32a05 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs @@ -45,14 +45,14 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() private readonly FieldProvider _roundtripZFormatField; private readonly FieldProvider _defaultNumberFormatField; - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [_roundtripZFormatField, _defaultNumberFormatField]; } private readonly MethodSignatureModifiers _methodModifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static; - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { var boolValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(bool)); var boolSignature = new MethodSignature( diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs index d470b06b8d6..65d9b14bf02 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs @@ -56,17 +56,17 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override CSharpType BuildBaseType() => ScmCodeModelGenerator.Instance.TypeFactory.RequestContentApi.RequestContentType; - protected override FieldProvider[] BuildFields() + protected internal override FieldProvider[] BuildFields() { return [_streamField, _contentField]; } - protected override PropertyProvider[] BuildProperties() + protected internal override PropertyProvider[] BuildProperties() { return [_writerProperty]; } - protected override ConstructorProvider[] BuildConstructors() + protected internal override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -83,7 +83,7 @@ protected override ConstructorProvider[] BuildConstructors() return [new ConstructorProvider(signature, body, this)]; } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs index ba4c5ffe6a1..edcf460f1df 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs @@ -43,7 +43,7 @@ public ScmCodeModelGenerator(GeneratorContext context) _instance = this; } - protected override void Configure() + protected internal override void Configure() { base.Configure(); AddMetadataReference(MetadataReference.CreateFromFile(typeof(ClientResult).Assembly.Location)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs index 08614d74341..0d75c6b8e6f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs @@ -30,7 +30,7 @@ public abstract class ScmLibraryVisitor : LibraryVisitor return clientProvider; } - protected override MethodProvider? VisitMethod(MethodProvider method) + protected internal override MethodProvider? VisitMethod(MethodProvider method) { if (method is ScmMethodProvider scmMethod) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs index 46566e74c68..ab3603bc67d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs @@ -127,14 +127,14 @@ public MockClientProvider(InputClient inputClient, string[] expectedSubClientFac _expectedSubClientFactoryMethodNames = expectedSubClientFactoryMethodNames; } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => _expectedSubClientFactoryMethodNames.Contains(m.Signature?.Name))]; } - protected override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; - protected override PropertyProvider[] BuildProperties() => []; + protected internal override FieldProvider[] BuildFields() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; + protected internal override PropertyProvider[] BuildProperties() => []; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 5e47ec0a1ad..32dfb2fd907 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -1969,7 +1969,7 @@ public ValidateQueryParamDiffClientProvider(InputClient client, bool isAsync = f _isAsync = isAsync; } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => p is { Name: "queryParam", Type.Name: "InputEnum" } && @@ -1978,9 +1978,9 @@ protected override ScmMethodProvider[] BuildMethods() return [method]; } - protected override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; - protected override PropertyProvider[] BuildProperties() => []; + protected internal override FieldProvider[] BuildFields() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; + protected internal override PropertyProvider[] BuildProperties() => []; } // This custom client provider is used to validate operations where non-body request parameters are declared within a request body model. @@ -1988,7 +1988,7 @@ private class TestNonBodyRequestParametersInBodyDiffClientProvider : ClientProvi { public TestNonBodyRequestParametersInBodyDiffClientProvider(InputClient client) : base(client) { } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => p is { Name: "body" } && m.Signature.Name.EndsWith("Async"))); @@ -1996,9 +1996,9 @@ protected override ScmMethodProvider[] BuildMethods() return [method]; } - protected override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; - protected override PropertyProvider[] BuildProperties() => []; + protected internal override FieldProvider[] BuildFields() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; + protected internal override PropertyProvider[] BuildProperties() => []; } private class UnsupportedAuthClientProvider : ClientProvider @@ -2006,10 +2006,10 @@ private class UnsupportedAuthClientProvider : ClientProvider public UnsupportedAuthClientProvider(InputClient client) : base(client) { } - protected override ScmMethodProvider[] BuildMethods() => []; + protected internal override ScmMethodProvider[] BuildMethods() => []; - protected override FieldProvider[] BuildFields() => []; - protected override PropertyProvider[] BuildProperties() => []; + protected internal override FieldProvider[] BuildFields() => []; + protected internal override PropertyProvider[] BuildProperties() => []; } public static IEnumerable BuildAuthFieldsTestCases diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs index a36667983e0..55a75eec8b2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs @@ -28,13 +28,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.StartsWith("Deserialize"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs index 4f1e0c3aade..8c72e7b56d9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs @@ -26,13 +26,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.Equals("JsonModelWriteCore"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs index 6a29e80ede9..a1ec01d7758 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs @@ -27,13 +27,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.Equals("PersistableModelWriteCore"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; + protected internal override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs index c34ae949f14..4987d1e1b7b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs @@ -641,7 +641,7 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods() .Where(m => m.Signature.Name.StartsWith("Deserialize") || m.Signature.Name.StartsWith("PersistableModelCreateCore"))]; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs index 91417351981..3a87861e1ee 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs @@ -821,7 +821,7 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { return [.. base.BuildMethods() .Where(m => m.Signature.Name.StartsWith("XmlModelWriteCore") || @@ -839,7 +839,7 @@ public MockIPersistableModelMrwProvider(InputModelType inputModel, ModelProvider { } - protected override MethodProvider[] BuildMethods() + protected internal override MethodProvider[] BuildMethods() { // Filter to only include IPersistableModel explicit interface methods return [.. base.BuildMethods() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs index e8bcb2fa0fb..466dbf769fa 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs @@ -1729,14 +1729,14 @@ private class MockClientProvider : RestClientProvider { public MockClientProvider(InputClient inputClient, ClientProvider clientProvider) : base(inputClient, clientProvider) { } - protected override ScmMethodProvider[] BuildMethods() + protected internal override ScmMethodProvider[] BuildMethods() { return [.. base.BuildMethods()]; } - protected override FieldProvider[] BuildFields() => []; + protected internal override FieldProvider[] BuildFields() => []; protected internal override ConstructorProvider[] BuildConstructors() => []; - protected override PropertyProvider[] BuildProperties() => []; + protected internal override PropertyProvider[] BuildProperties() => []; protected override TypeProvider[] BuildNestedTypes() => []; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs index a3fef5ece98..dc228062d94 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] +[assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.ClientModel, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.ClientModel.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests.Perf, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests.Common, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index fb79e348407..f431093117e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -241,10 +241,10 @@ internal virtual bool HasMethodInHierarchy(string methodName, HashSet BaseTypeProvider?.HasMethodInHierarchy(methodName) == true; - public CSharpType? GetRootBaseTypeInHierarchy() + internal CSharpType? GetRootBaseTypeInHierarchy() { var visited = new HashSet(); var baseTypeProvider = BaseTypeProvider; @@ -291,7 +291,7 @@ static bool IsFrameworkRootType(CSharpType type) return null; } - public CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) + internal CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) => BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames); private IReadOnlyList? _disabledFileWarnings; From 41b0d050e8057170d6b7e1e998a39ce8e7d7cee5 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 09:48:05 +0000 Subject: [PATCH 09/22] Revert "Keep base hierarchy helpers internal" This reverts commit 6f3c7633cea9bfc0be77201423a836077342169c. --- .../src/StubLibraryGenerator.cs | 2 +- .../src/StubLibraryVisitor.cs | 8 +++---- ...soft.TypeSpec.Generator.ClientModel.csproj | 1 - .../BinaryContentHelperDefinition.cs | 2 +- .../CancellationTokenExtensionsDefinition.cs | 2 +- .../src/Providers/ClientOptionsProvider.cs | 6 ++--- .../ClientPipelineExtensionsDefinition.cs | 2 +- .../src/Providers/ClientProvider.cs | 18 +++++++-------- .../src/Providers/ClientSettingsProvider.cs | 4 ++-- .../Providers/ClientUriBuilderDefinition.cs | 8 +++---- .../Providers/CollectionResultDefinition.cs | 8 +++---- .../src/Providers/ErrorResultDefinition.cs | 10 ++++----- .../ExtensibleEnumSerializationProvider.cs | 2 +- .../FixedEnumSerializationProvider.cs | 2 +- .../ModelSerializationExtensionsDefinition.cs | 6 ++--- .../MrwSerializationTypeDefinition.cs | 8 +++---- ...ultiPartFormDataBinaryContentDefinition.cs | 8 +++---- .../MultipartFormDataHelperDefinition.cs | 2 +- ...ultipartFormDataSerializationDefinition.cs | 6 ++--- ...elineRequestHeadersExtensionsDefinition.cs | 2 +- .../src/Providers/RestClientProvider.cs | 6 ++--- .../Providers/ScmMethodProviderCollection.cs | 4 ++-- .../src/Providers/ScmModelFactoryProvider.cs | 2 +- .../src/Providers/ScmModelProvider.cs | 6 ++--- .../SerializationFormatDefinition.cs | 2 +- .../src/Providers/SystemOptionalDefinition.cs | 2 +- .../src/Providers/TypeFormattersDefinition.cs | 4 ++-- .../Utf8JsonBinaryContentDefinition.cs | 8 +++---- .../src/ScmCodeModelGenerator.cs | 2 +- .../src/ScmLibraryVisitor.cs | 2 +- .../ClientProviderSubClientTests.cs | 8 +++---- .../ClientProviders/ClientProviderTests.cs | 22 +++++++++---------- .../DeserializationTests.cs | 4 ++-- .../JsonModelCoreTests.cs | 4 ++-- .../PersistableModelCoreTests.cs | 4 ++-- .../XmlDeserializationTests.cs | 2 +- .../XmlSerializationTests.cs | 4 ++-- .../RestClientProviderTests.cs | 6 ++--- .../src/Properties/AssemblyInfo.cs | 1 - .../src/Providers/TypeProvider.cs | 6 ++--- 40 files changed, 101 insertions(+), 105 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs index c40f23bbd0d..c9e46a18b0a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryGenerator.cs @@ -12,7 +12,7 @@ public class StubLibraryGenerator : ScmCodeModelGenerator [ImportingConstructor] public StubLibraryGenerator(GeneratorContext context) : base(context) { } - protected internal override void Configure() + protected override void Configure() { base.Configure(); AddVisitor(new StubLibraryVisitor()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs index ac79f81b916..fb41de57dcc 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel.StubLibrary/src/StubLibraryVisitor.cs @@ -43,7 +43,7 @@ internal class StubLibraryVisitor : ScmLibraryVisitor return type; } - protected internal override ConstructorProvider? VisitConstructor(ConstructorProvider constructor) + protected override ConstructorProvider? VisitConstructor(ConstructorProvider constructor) { if (!IsCallingBaseCtor(constructor) && !IsEffectivelyPublic(constructor.Signature.Modifiers) && @@ -94,7 +94,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) constructor.Signature.Initializer.Arguments.Count > 0; } - protected internal override FieldProvider? VisitField(FieldProvider field) + protected override FieldProvider? VisitField(FieldProvider field) { // For ClientOptions, keep the non-public field as this currently represents the latest service version for a client. // For ClientProvider, keep const and static fields as they are referenced by stub constructor initializers @@ -108,7 +108,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) : null; } - protected internal override MethodProvider? VisitMethod(MethodProvider method) + protected override MethodProvider? VisitMethod(MethodProvider method) { if (method.Signature.ExplicitInterface is null && !IsEffectivelyPublic(method.Signature.Modifiers)) { @@ -125,7 +125,7 @@ private static bool IsCallingBaseCtor(ConstructorProvider constructor) return method; } - protected internal override PropertyProvider? VisitProperty(PropertyProvider property) + protected override PropertyProvider? VisitProperty(PropertyProvider property) { if (!property.IsDiscriminator && !IsEffectivelyPublic(property.Modifiers)) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj index 693afef0555..3179721bdfb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Microsoft.TypeSpec.Generator.ClientModel.csproj @@ -5,7 +5,6 @@ 1.0.0-beta.1 true - $(NoWarn);CS0436 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs index 71e7343684e..a2ee813e298 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/BinaryContentHelperDefinition.cs @@ -35,7 +35,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var methods = new List { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs index e81e80770bc..6168a29ba2f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CancellationTokenExtensionsDefinition.cs @@ -30,7 +30,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "CancellationTokenExtensions"; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index ef84564e9cd..24c20fd2c0e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -277,7 +277,7 @@ protected override CSharpType BuildBaseType() return ScmCodeModelGenerator.Instance.TypeFactory.ClientPipelineApi.ClientPipelineOptionsType; } - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { if (LatestVersionsFields is null) { @@ -297,7 +297,7 @@ protected override TypeProvider[] BuildNestedTypes() return [.. _serviceVersionsEnums.Values.OrderBy(e => e.Name)]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var configSectionCtor = BuildConfigurationSectionConstructor(); @@ -459,7 +459,7 @@ private ConstructorProvider BuildConfigurationSectionConstructor() this); } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { var properties = VersionProperties is not null ? [.. VersionProperties.Values.OrderBy(p => p.Name)] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs index 22622776fd2..02864633aca 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientPipelineExtensionsDefinition.cs @@ -41,7 +41,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ClientPipelineExtensions"; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs index 6de1b356af9..f8ee8744e32 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs @@ -149,8 +149,7 @@ public ClientProvider(InputClient inputClient) { string tokenCredentialFieldName = TokenCredentialFieldName; FormattableString tokenCredentialDescription = $"A credential used to authenticate to the service."; - if (ClientPipelineProvider.Instance.TokenCredentialType is not null && - tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType)) + if (tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType)) { tokenCredentialFieldName = TokenProviderFieldName; tokenCredentialDescription = $"A credential provider used to authenticate to the service."; @@ -255,7 +254,7 @@ private string BuildNamespaceCore() // figure out if this namespace has been changed for this client if (!IsLastNamespaceSegmentTheSame(ns, _inputClient.Namespace)) { - ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic(Utilities.DiagnosticCodes.ClientNamespaceConflict, $"namespace {_inputClient.Namespace} conflicts with client {_inputClient.Name}, please use `@clientName` to specify a different name for the client.", _inputClient.CrossLanguageDefinitionId); + ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic(DiagnosticCodes.ClientNamespaceConflict, $"namespace {_inputClient.Namespace} conflicts with client {_inputClient.Name}, please use `@clientName` to specify a different name for the client.", _inputClient.CrossLanguageDefinitionId); } return ns; } @@ -427,7 +426,7 @@ private IReadOnlyList GetClientParameters() protected override string BuildName() => _inputClient.IsExactName ? _inputClient.Name : _inputClient.Name.ToIdentifierName(); - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { List fields = [EndpointField]; @@ -561,12 +560,12 @@ private List BuildApiVersionFields( } } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [PipelineProperty]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var mockingConstructor = ConstructorProviderHelper.BuildMockingConstructor(this); // handle sub-client constructors @@ -1142,7 +1141,7 @@ public ScmMethodProviderCollection GetMethodCollectionByOperation(InputOperation return MethodCache[operation]; } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { var subClients = _subClients.Value; var subClientCount = subClients.Count; @@ -1262,7 +1261,7 @@ protected internal override ScmMethodProvider[] BuildMethods() return [.. methods]; } - protected internal sealed override IReadOnlyList BuildMethodsForBackCompatibility(IEnumerable originalMethods) + protected sealed override IReadOnlyList BuildMethodsForBackCompatibility(IEnumerable originalMethods) { List materializedMethods = [.. originalMethods]; @@ -1612,8 +1611,7 @@ private static bool IsSupersededByClientParameter(InputParameter param, HashSet< private FieldProvider BuildTokenCredentialScopesField(InputOAuth2Auth oauth2Auth, CSharpType tokenCredentialType) { - return ClientPipelineProvider.Instance.TokenCredentialType is not null && - tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType) + return tokenCredentialType.Equals(ClientPipelineProvider.Instance.TokenCredentialType) ? BuildTokenCredentialFlowsField(oauth2Auth) : BuildTokenCredentialScopesField(oauth2Auth); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs index 53970aaec3a..5f7e3d38390 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientSettingsProvider.cs @@ -85,7 +85,7 @@ protected override IReadOnlyList BuildAttributes() return [new AttributeStatement(typeof(ExperimentalAttribute), Literal(ClientSettingsDiagnosticId))]; } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { var properties = new List(); @@ -156,7 +156,7 @@ protected internal override PropertyProvider[] BuildProperties() return [.. properties]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var sectionParam = new ParameterProvider("section", $"The configuration section.", IConfigurationSectionType); var body = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs index 97d53f7cc1f..92e0cf23a67 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientUriBuilderDefinition.cs @@ -72,17 +72,17 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ClientUriBuilder"; - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [_uriBuilderField, _pathAndQueryField, _pathLengthField]; } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [UriBuilderProperty, PathAndQueryProperty]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -92,7 +92,7 @@ protected internal override ConstructorProvider[] BuildConstructors() return [new ConstructorProvider(signature, MethodBodyStatement.Empty, this, XmlDocProvider.Empty)]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var methods = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs index f9c45f3f47b..62f28d86c8d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/CollectionResultDefinition.cs @@ -217,9 +217,9 @@ private bool HasPagingOperationNameCollision(string operationName) protected override TypeSignatureModifiers BuildDeclarationModifiers() => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; - protected internal override FieldProvider[] BuildFields() => [ClientField, .. RequestFields]; + protected override FieldProvider[] BuildFields() => [ClientField, .. RequestFields]; - protected internal override CSharpType[] BuildImplements() => + protected override CSharpType[] BuildImplements() => (_modelType: ItemModelType, IsAsync) switch { (null, true) => [new CSharpType(typeof(AsyncCollectionResult))], @@ -228,7 +228,7 @@ protected internal override CSharpType[] BuildImplements() => (_, false) => [new CSharpType(typeof(CollectionResult<>), ItemModelType)], }; - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var clientParameter = new ParameterProvider( "client", @@ -280,7 +280,7 @@ private MethodBodyStatement[] BuildConstructorBody(ParameterProvider clientParam /// public string GetNextResponseMethodName => IsAsync ? "GetNextResponseAsync" : "GetNextResponse"; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { MethodBodyStatement[] getRawPagesMethodBody = (Paging.NextLink, Paging.ContinuationToken) switch { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs index f72e893e86b..05615bddea0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ErrorResultDefinition.cs @@ -46,17 +46,17 @@ protected override CSharpType[] GetTypeArguments() return [_t]; } - protected internal override CSharpType[] BuildImplements() + protected override CSharpType[] BuildImplements() { return [new CSharpType(ScmCodeModelGenerator.Instance.TypeFactory.ClientResponseApi.ClientResponseOfTType.FrameworkType, _t)]; } - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [_responseField, _exceptionField]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { return [BuildCtor()]; } @@ -76,7 +76,7 @@ private ConstructorProvider BuildCtor() }, this, XmlDocProvider.Empty); } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [BuildValue()]; } @@ -88,7 +88,7 @@ private PropertyProvider BuildValue() this); } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return IsClientResult ? [] : [BuildGetRawResponse()]; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs index e79a86e11e9..f3c5a792c95 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ExtensibleEnumSerializationProvider.cs @@ -34,7 +34,7 @@ protected override string BuildRelativeFilePath() protected override TypeSignatureModifiers BuildDeclarationModifiers() => _enumProvider.DeclarationModifiers; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { // for string-based extensible enums, we are using `ToString` as its serialization // for non-string-based extensible enums, we need a method to serialize them diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs index b2b16e21148..f5224038ede 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/FixedEnumSerializationProvider.cs @@ -57,7 +57,7 @@ private bool NeedsSerializationMethod() return true; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var methods = new List(); // serialization method (in some cases we do not need serialization) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs index 2c638825df0..34cfb90210c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ModelSerializationExtensionsDefinition.cs @@ -108,12 +108,12 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "ModelSerializationExtensions"; - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [WireOptionsField, _jsonDocumentOptionsField, .. BuildXmlFields()]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var writer = ScmKnownParameters.Utf8JsonWriter.As(); var dateTimeOffsetValueParameter = @@ -205,7 +205,7 @@ .. BuildXmlExtensionMethods(), return [.. methods]; } - protected internal override SuppressionStatement[] BuildDisabledFileWarnings() + protected override SuppressionStatement[] BuildDisabledFileWarnings() => HasFileBinaryContentJsonModel || HasFileBinaryContentXmlModel ? [new SuppressionStatement(null, Literal(ScmModelProvider.FileBinaryContentDiagnosticId), ScmModelProvider.ScmEvaluationTypeSuppressionJustification)] : []; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index df37eda39db..2872ea4011e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -125,7 +125,7 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m protected override CSharpType? BuildBaseType() => _model.BaseType; - protected internal override SuppressionStatement[] BuildDisabledFileWarnings() + protected override SuppressionStatement[] BuildDisabledFileWarnings() { if (_model.CanonicalView.Properties.Any(p => ScmModelProvider.IsFileBinaryContentType(p.Type))) { @@ -246,7 +246,7 @@ private static bool SystemTypeImplementsModelReaderWriter(CSharpType systemType) return false; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { List constructors = new(); bool ctorWithNoParamsExist = false; @@ -275,7 +275,7 @@ protected internal override ConstructorProvider[] BuildConstructors() /// Builds the serialization methods for the model. /// /// A list of serialization and deserialization methods for the model. - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var methods = new List(); @@ -460,7 +460,7 @@ private MethodProvider BuildToBinaryContentMethod() /// Builds the types that the model type serialization implements. /// /// An array of types that the model implements. - protected internal override CSharpType[] BuildImplements() + protected override CSharpType[] BuildImplements() { var interfaces = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs index fc4804a5fba..3ba1fad08c9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultiPartFormDataBinaryContentDefinition.cs @@ -83,17 +83,17 @@ public MultiPartFormDataBinaryContentDefinition() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [_multipartContentField, _randomField, _boundaryValuesFields]; } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [_contentTypeProperty, _httpContentProperty]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -111,7 +111,7 @@ protected internal override ConstructorProvider[] BuildConstructors() ]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs index 04cc6a590ac..14f332d2cbc 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataHelperDefinition.cs @@ -29,7 +29,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Internal", $"{Name}.cs"); - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() => [BuildFromEnumerableMethod(), BuildFromDictionaryMethod()]; private MethodProvider BuildFromEnumerableMethod() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs index b56a8469018..88cb97b16e7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MultipartFormDataSerializationDefinition.cs @@ -51,10 +51,10 @@ protected override string BuildRelativeFilePath() return Path.Combine("src", "Generated", "Models", $"{Name}.Serialization.Multipart.cs"); } - protected internal override SuppressionStatement[] BuildDisabledFileWarnings() + protected override SuppressionStatement[] BuildDisabledFileWarnings() => [new SuppressionStatement(null, Literal(ScmModelProvider.FileBinaryContentDiagnosticId), ScmModelProvider.ScmEvaluationTypeSuppressionJustification)]; - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { if (_hasJsonOrXmlUsage) { @@ -69,7 +69,7 @@ protected internal override ConstructorProvider[] BuildConstructors() return [BuildEmptyConstructor()]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var signature = new MethodSignature( ToMultipartFormContentMethodName, diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs index cd0492ebabe..288b7f1af24 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/PipelineRequestHeadersExtensionsDefinition.cs @@ -34,7 +34,7 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override string BuildName() => "PipelineRequestHeadersExtensions"; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs index be0c3a1688e..f00d78571d0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs @@ -57,12 +57,12 @@ public RestClientProvider(InputClient inputClient, ClientProvider clientProvider protected override string BuildNamespace() => ClientProvider.Type.Namespace; - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [.. _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name)]; } - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { List pipelineMessage20xClassifiersFields = new(_pipelineMessage20xClassifiers.Count); var orderedClassifierProperties = _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name); @@ -78,7 +78,7 @@ protected internal override FieldProvider[] BuildFields() return [.. pipelineMessage20xClassifiersFields]; } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { List methods = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs index f020f6b6fe5..a88310c03b9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs @@ -712,7 +712,7 @@ private MethodBodyStatement GetFrameworkTypeConversionFromReader(CSharpType elem } ScmCodeModelGenerator.Instance.Emitter.ReportDiagnostic( - Utilities.DiagnosticCodes.UnsupportedFrameworkType, + DiagnosticCodes.UnsupportedFrameworkType, $"Unsupported framework type: {frameworkType}. Element will be skipped.", ServiceMethod.Operation.CrossLanguageDefinitionId, EmitterDiagnosticSeverity.Error); @@ -1365,7 +1365,7 @@ private CSharpType GetConvenienceReturnType(IReadOnlyList models) : base(mode _models = models; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var methods = base.BuildMethods(); if (methods.Length == 0) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs index 8b3b9a1af4c..07cc8e9c1d2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmModelProvider.cs @@ -73,7 +73,7 @@ public ScmModelProvider(InputModelType inputModel) : base(inputModel) BaseJsonPatchProperty = new(GetBaseJsonPatchProperty()); } - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { if (JsonPatchField is null) { @@ -96,7 +96,7 @@ protected internal override FieldProvider[] BuildFields() return [JsonPatchField, .. updatedFields]; } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { PropertyProvider[] properties; if (JsonPatchProperty is null) @@ -126,7 +126,7 @@ protected internal override PropertyProvider[] BuildProperties() return properties; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { List constructors = [.. base.BuildConstructors()]; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs index 5e76cbb58e1..af294640060 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SerializationFormatDefinition.cs @@ -91,7 +91,7 @@ protected override IReadOnlyList BuildEnumValues() return members; } - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() => EnumValues.Select(v => v.Field).ToArray(); protected override CSharpType BuildEnumUnderlyingType() => new CSharpType(typeof(int)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs index 3cfe1e66291..dce19d8223d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/SystemOptionalDefinition.cs @@ -15,7 +15,7 @@ namespace Microsoft.TypeSpec.Generator.ClientModel.Providers internal sealed class SystemOptionalDefinition : OptionalDefinition { private const string IsDefinedMethodName = "IsDefined"; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods(), IsJsonElementDefined()]; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs index cb572e32a05..4e0509bc78e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/TypeFormattersDefinition.cs @@ -45,14 +45,14 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() private readonly FieldProvider _roundtripZFormatField; private readonly FieldProvider _defaultNumberFormatField; - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [_roundtripZFormatField, _defaultNumberFormatField]; } private readonly MethodSignatureModifiers _methodModifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static; - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { var boolValueParameter = new ParameterProvider("value", FormattableStringHelpers.Empty, typeof(bool)); var boolSignature = new MethodSignature( diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs index 65d9b14bf02..d470b06b8d6 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/Utf8JsonBinaryContentDefinition.cs @@ -56,17 +56,17 @@ protected override TypeSignatureModifiers BuildDeclarationModifiers() protected override CSharpType BuildBaseType() => ScmCodeModelGenerator.Instance.TypeFactory.RequestContentApi.RequestContentType; - protected internal override FieldProvider[] BuildFields() + protected override FieldProvider[] BuildFields() { return [_streamField, _contentField]; } - protected internal override PropertyProvider[] BuildProperties() + protected override PropertyProvider[] BuildProperties() { return [_writerProperty]; } - protected internal override ConstructorProvider[] BuildConstructors() + protected override ConstructorProvider[] BuildConstructors() { var signature = new ConstructorSignature( type: Type, @@ -83,7 +83,7 @@ protected internal override ConstructorProvider[] BuildConstructors() return [new ConstructorProvider(signature, body, this)]; } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs index edcf460f1df..ba4c5ffe6a1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs @@ -43,7 +43,7 @@ public ScmCodeModelGenerator(GeneratorContext context) _instance = this; } - protected internal override void Configure() + protected override void Configure() { base.Configure(); AddMetadataReference(MetadataReference.CreateFromFile(typeof(ClientResult).Assembly.Location)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs index 0d75c6b8e6f..08614d74341 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmLibraryVisitor.cs @@ -30,7 +30,7 @@ public abstract class ScmLibraryVisitor : LibraryVisitor return clientProvider; } - protected internal override MethodProvider? VisitMethod(MethodProvider method) + protected override MethodProvider? VisitMethod(MethodProvider method) { if (method is ScmMethodProvider scmMethod) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs index ab3603bc67d..46566e74c68 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderSubClientTests.cs @@ -127,14 +127,14 @@ public MockClientProvider(InputClient inputClient, string[] expectedSubClientFac _expectedSubClientFactoryMethodNames = expectedSubClientFactoryMethodNames; } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => _expectedSubClientFactoryMethodNames.Contains(m.Signature?.Name))]; } - protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; - protected internal override PropertyProvider[] BuildProperties() => []; + protected override FieldProvider[] BuildFields() => []; + protected override ConstructorProvider[] BuildConstructors() => []; + protected override PropertyProvider[] BuildProperties() => []; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 32dfb2fd907..5e47ec0a1ad 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -1969,7 +1969,7 @@ public ValidateQueryParamDiffClientProvider(InputClient client, bool isAsync = f _isAsync = isAsync; } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => p is { Name: "queryParam", Type.Name: "InputEnum" } && @@ -1978,9 +1978,9 @@ protected internal override ScmMethodProvider[] BuildMethods() return [method]; } - protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; - protected internal override PropertyProvider[] BuildProperties() => []; + protected override FieldProvider[] BuildFields() => []; + protected override ConstructorProvider[] BuildConstructors() => []; + protected override PropertyProvider[] BuildProperties() => []; } // This custom client provider is used to validate operations where non-body request parameters are declared within a request body model. @@ -1988,7 +1988,7 @@ private class TestNonBodyRequestParametersInBodyDiffClientProvider : ClientProvi { public TestNonBodyRequestParametersInBodyDiffClientProvider(InputClient client) : base(client) { } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => p is { Name: "body" } && m.Signature.Name.EndsWith("Async"))); @@ -1996,9 +1996,9 @@ protected internal override ScmMethodProvider[] BuildMethods() return [method]; } - protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; - protected internal override PropertyProvider[] BuildProperties() => []; + protected override FieldProvider[] BuildFields() => []; + protected override ConstructorProvider[] BuildConstructors() => []; + protected override PropertyProvider[] BuildProperties() => []; } private class UnsupportedAuthClientProvider : ClientProvider @@ -2006,10 +2006,10 @@ private class UnsupportedAuthClientProvider : ClientProvider public UnsupportedAuthClientProvider(InputClient client) : base(client) { } - protected internal override ScmMethodProvider[] BuildMethods() => []; + protected override ScmMethodProvider[] BuildMethods() => []; - protected internal override FieldProvider[] BuildFields() => []; - protected internal override PropertyProvider[] BuildProperties() => []; + protected override FieldProvider[] BuildFields() => []; + protected override PropertyProvider[] BuildProperties() => []; } public static IEnumerable BuildAuthFieldsTestCases diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs index 55a75eec8b2..a36667983e0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/DeserializationTests.cs @@ -28,13 +28,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.StartsWith("Deserialize"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; + protected override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs index 8c72e7b56d9..4f1e0c3aade 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/JsonModelCoreTests.cs @@ -26,13 +26,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.Equals("JsonModelWriteCore"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; + protected override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs index a1ec01d7758..6a29e80ede9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/PersistableModelCoreTests.cs @@ -27,13 +27,13 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods().Where(m => m.Signature.Name.Equals("PersistableModelWriteCore"))]; } protected internal override FieldProvider[] BuildFields() => []; - protected internal override ConstructorProvider[] BuildConstructors() => []; + protected override ConstructorProvider[] BuildConstructors() => []; } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs index 4987d1e1b7b..c34ae949f14 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs @@ -641,7 +641,7 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods() .Where(m => m.Signature.Name.StartsWith("Deserialize") || m.Signature.Name.StartsWith("PersistableModelCreateCore"))]; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs index 3a87861e1ee..91417351981 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs @@ -821,7 +821,7 @@ public MockMrwProvider(InputModelType inputModel, ModelProvider modelProvider) { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { return [.. base.BuildMethods() .Where(m => m.Signature.Name.StartsWith("XmlModelWriteCore") || @@ -839,7 +839,7 @@ public MockIPersistableModelMrwProvider(InputModelType inputModel, ModelProvider { } - protected internal override MethodProvider[] BuildMethods() + protected override MethodProvider[] BuildMethods() { // Filter to only include IPersistableModel explicit interface methods return [.. base.BuildMethods() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs index 466dbf769fa..e8bcb2fa0fb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs @@ -1729,14 +1729,14 @@ private class MockClientProvider : RestClientProvider { public MockClientProvider(InputClient inputClient, ClientProvider clientProvider) : base(inputClient, clientProvider) { } - protected internal override ScmMethodProvider[] BuildMethods() + protected override ScmMethodProvider[] BuildMethods() { return [.. base.BuildMethods()]; } - protected internal override FieldProvider[] BuildFields() => []; + protected override FieldProvider[] BuildFields() => []; protected internal override ConstructorProvider[] BuildConstructors() => []; - protected internal override PropertyProvider[] BuildProperties() => []; + protected override PropertyProvider[] BuildProperties() => []; protected override TypeProvider[] BuildNestedTypes() => []; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs index dc228062d94..a3fef5ece98 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Properties/AssemblyInfo.cs @@ -4,7 +4,6 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] -[assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.ClientModel, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.ClientModel.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests.Perf, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] [assembly: InternalsVisibleTo("Microsoft.TypeSpec.Generator.Tests.Common, PublicKey=002400000480000094000000060200000024000052534131000400000100010041df4fe80c5af6ff9a410db5a173b0ce24ad68764c623e308b1584a88b1d1d82277f746c1cccba48997e13db3366d5ed676576ffd293293baf42c643f008ba2e8a556e25e529c0407a38506555340749559f5100e6fd78cc935bb6c82d2af303beb0d3c6563400659610759b4ed5cb2e0faf36b17e6842f04cdc544c74e051ba")] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index f431093117e..fb79e348407 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -241,10 +241,10 @@ internal virtual bool HasMethodInHierarchy(string methodName, HashSet BaseTypeProvider?.HasMethodInHierarchy(methodName) == true; - internal CSharpType? GetRootBaseTypeInHierarchy() + public CSharpType? GetRootBaseTypeInHierarchy() { var visited = new HashSet(); var baseTypeProvider = BaseTypeProvider; @@ -291,7 +291,7 @@ static bool IsFrameworkRootType(CSharpType type) return null; } - internal CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) + public CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) => BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames); private IReadOnlyList? _disabledFileWarnings; From b7815f67a53826cf11eff1afb58295741b092ec8 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Tue, 7 Jul 2026 09:50:22 +0000 Subject: [PATCH 10/22] Avoid public TypeProvider helper APIs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.cs | 101 ++++++++++++++++-- .../src/Providers/NamedTypeSymbolProvider.cs | 39 ------- .../src/Providers/TypeProvider.cs | 65 ----------- 3 files changed, 91 insertions(+), 114 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index 2872ea4011e..c66ffacffc1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Text; using System.Text.Json; using System.Xml; @@ -193,18 +194,15 @@ private static bool IsModelType(CSharpType type) : null; private CSharpType? GetCustomBaseRootType() - => _model.BaseModelProvider is null && _model.CustomCodeView?.BaseType is not null - ? _model.GetRootBaseTypeInHierarchy() - : null; + => GetCustomSerializationBaseType() is { } baseType ? GetRootBaseType(baseType) : null; private bool HasCustomBaseMethod(string methodName) - => _model.BaseModelProvider is null && - _model.CustomCodeView?.BaseType is not null && - _model.HasBaseMethodInHierarchy(methodName); + => GetCustomSerializationBaseType() is { } baseType && + HasMethodInTypeHierarchy(baseType, methodName); private CSharpType? GetCustomBaseMethodReturnType(IReadOnlySet methodNames) - => _model.BaseModelProvider is null && _model.CustomCodeView?.BaseType is not null - ? _model.GetBaseMethodReturnTypeInHierarchy(methodNames) + => GetCustomSerializationBaseType() is { } baseType + ? GetMethodReturnTypeInHierarchy(baseType, methodNames) : null; private static bool ShouldSkipDerivedSerializationMethodOverrides(ModelProvider model) @@ -212,8 +210,8 @@ private static bool ShouldSkipDerivedSerializationMethodOverrides(ModelProvider if (model.BaseModelProvider is null) { return model.CustomCodeView?.BaseType is null || - (!model.HasBaseMethodInHierarchy(JsonModelCreateCoreMethodName) && - !model.HasBaseMethodInHierarchy(PersistableModelCreateCoreMethodName)); + !HasMethodInTypeHierarchy(model.BaseType!, JsonModelCreateCoreMethodName) && + !HasMethodInTypeHierarchy(model.BaseType!, PersistableModelCreateCoreMethodName); } if (model.BaseModelProvider is SystemObjectModelProvider systemBase) @@ -224,6 +222,89 @@ private static bool ShouldSkipDerivedSerializationMethodOverrides(ModelProvider return model.BaseModelProvider.ShouldSkipDerivedSerializationMethodOverrides; } + private static CSharpType? GetRootBaseType(CSharpType baseType) + { + var visited = new HashSet(); + CSharpType? rootBaseType = null; + var current = baseType; + + while (current is not null && visited.Add(current.FullyQualifiedName)) + { + if (!IsFrameworkRootType(current)) + { + rootBaseType = current; + } + + current = current.BaseType; + } + + return rootBaseType; + } + + private static bool HasMethodInTypeHierarchy(CSharpType type, string methodName) + => GetMethodReturnTypeInHierarchy(type, new HashSet { methodName }) is not null; + + private static CSharpType? GetMethodReturnTypeInHierarchy(CSharpType type, IReadOnlySet methodNames) + { + var visited = new HashSet(); + return GetMethodReturnTypeInHierarchy(type, methodNames, visited); + } + + private static CSharpType? GetMethodReturnTypeInHierarchy(CSharpType type, IReadOnlySet methodNames, HashSet visited) + { + if (!visited.Add(type.FullyQualifiedName)) + { + return null; + } + + if (type.BaseType is not null && + GetMethodReturnTypeInHierarchy(type.BaseType, methodNames, visited) is { } baseReturnType) + { + return baseReturnType; + } + + foreach (var methodName in methodNames) + { + if (TryGetMethodReturnType(type, methodName) is { } returnType) + { + return returnType; + } + } + + return null; + } + + private static CSharpType? TryGetMethodReturnType(CSharpType type, string methodName) + { + if (type.IsFrameworkType) + { + var method = type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .FirstOrDefault(method => method.Name == methodName); + return method is null ? null : new CSharpType(method.ReturnType); + } + + if (TryGetReferencedType(type) is { } referencedType) + { + return referencedType.Methods.FirstOrDefault(method => method.Signature.Name == methodName)?.Signature.ReturnType; + } + + return null; + } + + private static TypeProvider? TryGetReferencedType(CSharpType type) + => string.IsNullOrEmpty(type.Namespace) + ? null + : CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( + type.Namespace, + type.Name, + declaringTypeName: null, + includeReferencedAssemblies: true); + + private static bool IsFrameworkRootType(CSharpType type) + => (type.IsFrameworkType && + (type.FrameworkType == typeof(object) || type.FrameworkType == typeof(ValueType))) || + (type.Namespace == "System" && (type.Name == "Object" || type.Name == "ValueType")); + private static bool SystemTypeImplementsModelReaderWriter(CSharpType systemType) { if (!systemType.IsFrameworkType) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index f60d77d62bd..ed3a45d54e8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -64,45 +64,6 @@ protected override IReadOnlyList BuildAttributes() return new NamedTypeSymbolProvider(_namedTypeSymbol.BaseType!, _compilation); } - internal override bool HasMethodInHierarchy(string methodName, HashSet? visited = null) - { - visited ??= []; - if (!visited.Add(this)) - { - return false; - } - - return _namedTypeSymbol.GetMembers(methodName).OfType().Any(method => method.AssociatedSymbol is null) || - BaseTypeProvider?.HasMethodInHierarchy(methodName, visited) == true; - } - - internal override CSharpType? GetMethodReturnTypeInHierarchy(IReadOnlySet methodNames, HashSet? visited = null) - { - visited ??= []; - if (!visited.Add(this)) - { - return null; - } - - if (BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames, visited) is { } baseReturnType) - { - return baseReturnType; - } - - foreach (var methodName in methodNames) - { - var method = _namedTypeSymbol.GetMembers(methodName) - .OfType() - .FirstOrDefault(method => method.AssociatedSymbol is null); - if (method is not null) - { - return method.ReturnType.GetCSharpType(); - } - } - - return null; - } - private bool ShouldSkipBaseType(INamedTypeSymbol? baseType) => baseType == null || baseType.SpecialType == SpecialType.System_Object diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index fb79e348407..a1381e7c6b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -229,71 +229,6 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() protected virtual CSharpType? BuildBaseType() => null; - internal virtual bool HasMethodInHierarchy(string methodName, HashSet? visited = null) - { - visited ??= []; - if (!visited.Add(this)) - { - return false; - } - - return Methods.Any(method => method.Signature.Name == methodName) || - BaseTypeProvider?.HasMethodInHierarchy(methodName, visited) == true; - } - - public bool HasBaseMethodInHierarchy(string methodName) - => BaseTypeProvider?.HasMethodInHierarchy(methodName) == true; - - public CSharpType? GetRootBaseTypeInHierarchy() - { - var visited = new HashSet(); - var baseTypeProvider = BaseTypeProvider; - CSharpType? rootBaseType = null; - - while (baseTypeProvider is not null && visited.Add(baseTypeProvider)) - { - if (!IsFrameworkRootType(baseTypeProvider.Type)) - { - rootBaseType = baseTypeProvider.Type; - } - baseTypeProvider = baseTypeProvider.BaseTypeProvider; - } - - return rootBaseType; - - static bool IsFrameworkRootType(CSharpType type) - => (type.IsFrameworkType && - (type.FrameworkType == typeof(object) || type.FrameworkType == typeof(ValueType))) || - (type.Namespace == "System" && (type.Name == "Object" || type.Name == "ValueType")); - } - - internal virtual CSharpType? GetMethodReturnTypeInHierarchy(IReadOnlySet methodNames, HashSet? visited = null) - { - visited ??= []; - if (!visited.Add(this)) - { - return null; - } - - if (BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames, visited) is { } baseReturnType) - { - return baseReturnType; - } - - foreach (var method in Methods) - { - if (methodNames.Contains(method.Signature.Name) && method.Signature.ReturnType is { } returnType) - { - return returnType; - } - } - - return null; - } - - public CSharpType? GetBaseMethodReturnTypeInHierarchy(IReadOnlySet methodNames) - => BaseTypeProvider?.GetMethodReturnTypeInHierarchy(methodNames); - private IReadOnlyList? _disabledFileWarnings; public IReadOnlyList DisabledFileWarnings => _disabledFileWarnings ??= BuildDisabledFileWarnings(); From 801b71055093d2d2f1587236643a2da0729ceb74 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 03:15:24 +0000 Subject: [PATCH 11/22] fix(http-client-csharp): use xml-specific serialization override check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 16 +++++++++--- .../MockInputModel.cs | 17 ++++++++++++ .../XmlSerializationCustomizationTests.cs | 26 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index f63f999e407..67b748ac92e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -61,13 +61,23 @@ private record XmlPropertyCategories( private XmlPropertyCategories? _categorizedXmlProperties; private XmlPropertyCategories CategorizedXmlProperties => _categorizedXmlProperties ??= CategorizeXmlProperties(ownPropertiesOnly: true); + private bool? _shouldOverrideXmlMethods; + private bool ShouldOverrideXmlMethods => _shouldOverrideXmlMethods ??= !_isStruct && + (HasGeneratedBaseSerializationMethod(XmlModelWriteCoreMethodName) || HasCustomBaseMethod(XmlModelWriteCoreMethodName)); + + private bool HasGeneratedBaseSerializationMethod(string methodName) + => _model.BaseModelProvider is not null && + _model.BaseModelProvider is not SystemObjectModelProvider && + _model.BaseModelProvider.SerializationProviders + .OfType() + .Any(serialization => serialization.Methods.Any(method => method.Signature.Name == methodName)); private MethodProvider BuildXmlModelWriteCoreMethod() { MethodSignatureModifiers modifiers = _isStruct ? MethodSignatureModifiers.Private : MethodSignatureModifiers.Internal | MethodSignatureModifiers.Virtual; - if (ShouldOverrideMethods) + if (ShouldOverrideXmlMethods) { modifiers = MethodSignatureModifiers.Internal | MethodSignatureModifiers.Override; } @@ -81,7 +91,7 @@ private MethodProvider BuildXmlModelWriteCoreMethod() private MethodBodyStatement[] BuildXmlModelWriteCoreMethodBody() { - var categorizedProperties = ShouldOverrideMethods + var categorizedProperties = ShouldOverrideXmlMethods ? CategorizedXmlProperties : AllCategorizedXmlProperties; var statements = new List @@ -90,7 +100,7 @@ private MethodBodyStatement[] BuildXmlModelWriteCoreMethodBody() MethodBodyStatement.EmptyLine }; - if (ShouldOverrideMethods) + if (ShouldOverrideXmlMethods) { statements.Add(Base.Invoke(XmlModelWriteCoreMethodName, _xmlWriterParameter, _serializationOptionsParameter).Terminate()); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase/MockInputModel.cs new file mode 100644 index 00000000000..28a7c8aee8a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase/MockInputModel.cs @@ -0,0 +1,17 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace Sample.Models; + +public partial class MockInputModel : JsonOnlyBase +{ +} + +public class JsonOnlyBase +{ + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index e85c5a4c46d..7c40be9f3d9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -89,6 +89,32 @@ public async Task CanChangePropertyName() Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase() + { + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider); + Assert.AreEqual("JsonOnlyBase", modelProvider.BaseType?.Name); + + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + // Validates that a custom deserialization hook can be used to customize property deserialization. [Test] public async Task CanCustomizeDeserializationMethod() From 7344f89640fbc3a90a3e078725e1fed7515aa96b Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 03:30:00 +0000 Subject: [PATCH 12/22] fix(http-client-csharp): detect customized xml base serialization Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 13 +++++++- .../BaseModel.cs | 13 ++++++++ .../XmlSerializationCustomizationTests.cs | 32 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement/BaseModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 67b748ac92e..e94cb3a005d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -63,7 +63,9 @@ private record XmlPropertyCategories( private XmlPropertyCategories CategorizedXmlProperties => _categorizedXmlProperties ??= CategorizeXmlProperties(ownPropertiesOnly: true); private bool? _shouldOverrideXmlMethods; private bool ShouldOverrideXmlMethods => _shouldOverrideXmlMethods ??= !_isStruct && - (HasGeneratedBaseSerializationMethod(XmlModelWriteCoreMethodName) || HasCustomBaseMethod(XmlModelWriteCoreMethodName)); + (HasGeneratedBaseSerializationMethod(XmlModelWriteCoreMethodName) || + HasGeneratedBaseCustomXmlModelWriteCoreMethod() || + HasCustomBaseMethod(XmlModelWriteCoreMethodName)); private bool HasGeneratedBaseSerializationMethod(string methodName) => _model.BaseModelProvider is not null && @@ -72,6 +74,15 @@ _model.BaseModelProvider is not SystemObjectModelProvider && .OfType() .Any(serialization => serialization.Methods.Any(method => method.Signature.Name == methodName)); + private bool HasGeneratedBaseCustomXmlModelWriteCoreMethod() + => _model.BaseModelProvider is not null && + _model.BaseModelProvider is not SystemObjectModelProvider && + _model.BaseModelProvider.CustomCodeView?.Methods.Any(IsXmlModelWriteCoreMethod) == true; + + private bool IsXmlModelWriteCoreMethod(MethodProvider method) + => method.Signature.Name == XmlModelWriteCoreMethodName && + method.Signature.Parameters.Count == 2; + private MethodProvider BuildXmlModelWriteCoreMethod() { MethodSignatureModifiers modifiers = _isStruct diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement/BaseModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement/BaseModel.cs new file mode 100644 index 00000000000..0852b6b93af --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement/BaseModel.cs @@ -0,0 +1,13 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class BaseModel +{ + internal virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 7c40be9f3d9..c154372aead 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -115,6 +115,38 @@ public async Task XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase() StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() + { + var baseModel = InputFactory.Model( + "baseModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("BaseProp", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("baseProp"))) + ]); + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + baseModel: baseModel, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [baseModel, inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + StringAssert.Contains("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + // Validates that a custom deserialization hook can be used to customize property deserialization. [Test] public async Task CanCustomizeDeserializationMethod() From b64a3326b944cf1393c1bfbe6de8f64b605e466a Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 03:45:28 +0000 Subject: [PATCH 13/22] fix(http-client-csharp): validate custom xml core override signature Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 12 ++++++- .../BaseModel.cs | 13 ++++++++ .../XmlSerializationCustomizationTests.cs | 32 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod/BaseModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index e94cb3a005d..e2fc54c0179 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -81,7 +81,17 @@ _model.BaseModelProvider is not SystemObjectModelProvider && private bool IsXmlModelWriteCoreMethod(MethodProvider method) => method.Signature.Name == XmlModelWriteCoreMethodName && - method.Signature.Parameters.Count == 2; + IsOverridable(method.Signature.Modifiers) && + !method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Static) && + (method.Signature.ReturnType is null || method.Signature.ReturnType.Equals(typeof(void))) && + method.Signature.Parameters.Count == 2 && + method.Signature.Parameters[0].Type.Equals(typeof(XmlWriter)) && + method.Signature.Parameters[1].Type.Equals(typeof(ModelReaderWriterOptions)); + + private static bool IsOverridable(MethodSignatureModifiers modifiers) + => modifiers.HasFlag(MethodSignatureModifiers.Virtual) || + modifiers.HasFlag(MethodSignatureModifiers.Override) || + modifiers.HasFlag(MethodSignatureModifiers.Abstract); private MethodProvider BuildXmlModelWriteCoreMethod() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod/BaseModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod/BaseModel.cs new file mode 100644 index 00000000000..edbbf75ae94 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod/BaseModel.cs @@ -0,0 +1,13 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class BaseModel +{ + internal void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index c154372aead..1a8542cb1c1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -147,6 +147,38 @@ public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() StringAssert.Contains("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCustomMethod() + { + var baseModel = InputFactory.Model( + "baseModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("BaseProp", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("baseProp"))) + ]); + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + baseModel: baseModel, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [baseModel, inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + // Validates that a custom deserialization hook can be used to customize property deserialization. [Test] public async Task CanCustomizeDeserializationMethod() From d48bfd95abe9a7422e4e7e2abb3de6817ed7f32b Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 03:54:40 +0000 Subject: [PATCH 14/22] fix(http-client-csharp): require internal custom xml core overrides Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 1 + .../BaseModel.cs | 13 ++++++++ .../XmlSerializationCustomizationTests.cs | 32 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod/BaseModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index e2fc54c0179..bdd36455a03 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -81,6 +81,7 @@ _model.BaseModelProvider is not SystemObjectModelProvider && private bool IsXmlModelWriteCoreMethod(MethodProvider method) => method.Signature.Name == XmlModelWriteCoreMethodName && + method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal) && IsOverridable(method.Signature.Modifiers) && !method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Static) && (method.Signature.ReturnType is null || method.Signature.ReturnType.Equals(typeof(void))) && diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod/BaseModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod/BaseModel.cs new file mode 100644 index 00000000000..180b8548502 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod/BaseModel.cs @@ -0,0 +1,13 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class BaseModel +{ + protected virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 1a8542cb1c1..4365370be06 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -179,6 +179,38 @@ public async Task XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithNonVirtualCus StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCustomMethod() + { + var baseModel = InputFactory.Model( + "baseModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("BaseProp", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("baseProp"))) + ]); + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + baseModel: baseModel, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [baseModel, inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + // Validates that a custom deserialization hook can be used to customize property deserialization. [Test] public async Task CanCustomizeDeserializationMethod() From 92343e0ad816150e97f5fc48ce16d89974030900 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 05:34:49 +0000 Subject: [PATCH 15/22] fix(http-client-csharp): validate external xml core overrides Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 37 ++++++++++++++++++- .../MockInputModel.cs | 17 +++++++++ .../XmlSerializationCustomizationTests.cs | 26 +++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index bdd36455a03..4fe0b5137c1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Text.Json; using System.Xml; using System.Xml.Linq; @@ -65,7 +66,7 @@ private record XmlPropertyCategories( private bool ShouldOverrideXmlMethods => _shouldOverrideXmlMethods ??= !_isStruct && (HasGeneratedBaseSerializationMethod(XmlModelWriteCoreMethodName) || HasGeneratedBaseCustomXmlModelWriteCoreMethod() || - HasCustomBaseMethod(XmlModelWriteCoreMethodName)); + HasCustomBaseXmlModelWriteCoreMethod()); private bool HasGeneratedBaseSerializationMethod(string methodName) => _model.BaseModelProvider is not null && @@ -94,6 +95,40 @@ private static bool IsOverridable(MethodSignatureModifiers modifiers) modifiers.HasFlag(MethodSignatureModifiers.Override) || modifiers.HasFlag(MethodSignatureModifiers.Abstract); + private bool HasCustomBaseXmlModelWriteCoreMethod() + => GetCustomSerializationBaseType() is { } baseType && + HasCompatibleXmlModelWriteCoreInHierarchy(baseType, []); + + private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet visited) + { + if (!visited.Add(type.FullyQualifiedName)) + { + return false; + } + + return HasCompatibleXmlModelWriteCore(type) || + type.BaseType is not null && HasCompatibleXmlModelWriteCoreInHierarchy(type.BaseType, visited); + } + + private bool HasCompatibleXmlModelWriteCore(CSharpType type) + { + if (type.IsFrameworkType) + { + return type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) + .Any(method => + method.Name == XmlModelWriteCoreMethodName && + method.IsAssembly && + (method.IsVirtual || method.IsAbstract) && + !method.IsFinal && + method.ReturnType == typeof(void) && + method.GetParameters() is [{ ParameterType: var writerType }, { ParameterType: var optionsType }] && + writerType == typeof(XmlWriter) && + optionsType == typeof(ModelReaderWriterOptions)); + } + + return TryGetReferencedType(type)?.Methods.Any(IsXmlModelWriteCoreMethod) == true; + } + private MethodProvider BuildXmlModelWriteCoreMethod() { MethodSignatureModifiers modifiers = _isStruct diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase/MockInputModel.cs new file mode 100644 index 00000000000..44718db7161 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase/MockInputModel.cs @@ -0,0 +1,17 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class MockInputModel : ProtectedXmlBase +{ +} + +public class ProtectedXmlBase +{ + protected virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 4365370be06..00617b07617 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -115,6 +115,32 @@ public async Task XmlModelWriteCoreDoesNotOverrideJsonOnlyCustomBase() StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase() + { + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider); + Assert.AreEqual("ProtectedXmlBase", modelProvider.BaseType?.Name); + + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + [Test] public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() { From 760682789eedfcb12571f848e72f0a9dde98dde5 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 05:44:58 +0000 Subject: [PATCH 16/22] fix(http-client-csharp): ignore reflected external xml core hooks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 12 +--------- .../XmlSerializationCustomizationTests.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 4fe0b5137c1..782ae8ccaea 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Net; -using System.Reflection; using System.Text.Json; using System.Xml; using System.Xml.Linq; @@ -114,16 +113,7 @@ private bool HasCompatibleXmlModelWriteCore(CSharpType type) { if (type.IsFrameworkType) { - return type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) - .Any(method => - method.Name == XmlModelWriteCoreMethodName && - method.IsAssembly && - (method.IsVirtual || method.IsAbstract) && - !method.IsFinal && - method.ReturnType == typeof(void) && - method.GetParameters() is [{ ParameterType: var writerType }, { ParameterType: var optionsType }] && - writerType == typeof(XmlWriter) && - optionsType == typeof(ModelReaderWriterOptions)); + return false; } return TryGetReferencedType(type)?.Methods.Any(IsXmlModelWriteCoreMethod) == true; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 00617b07617..bf6a0be3b3b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.ClientModel.Primitives; using System.Linq; +using System.Reflection; using System.Threading.Tasks; +using System.Xml; using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -141,6 +144,18 @@ public async Task XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase() StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public void ReflectedInternalXmlModelWriteCoreIsNotOverrideCompatible() + { + MockHelpers.LoadMockGenerator(); + var inputModel = InputFactory.Model("mockInputModel", usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml); + var serializationProvider = new MrwSerializationTypeDefinition(inputModel, new ModelProvider(inputModel)); + var method = typeof(MrwSerializationTypeDefinition).GetMethod("HasCompatibleXmlModelWriteCore", BindingFlags.Instance | BindingFlags.NonPublic); + + Assert.IsNotNull(method); + Assert.AreEqual(false, method!.Invoke(serializationProvider, [new CSharpType(typeof(ReflectedInternalXmlBase))])); + } + [Test] public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() { @@ -405,5 +420,12 @@ public async Task CanSerializeCustomizedNullableDateTimeOffset() var file = writer.Write(); Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); } + + private class ReflectedInternalXmlBase + { + internal virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } + } } } From 9434c3afd3b87403f156a9c3bdc9f70ff351f7d0 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 06:02:50 +0000 Subject: [PATCH 17/22] fix(http-client-csharp): reject sealed xml core overrides Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 7 ++-- .../BaseModel.cs | 20 +++++++++++ .../XmlSerializationCustomizationTests.cs | 36 +++++++++++++++++++ .../Primitives/MethodSignatureModifiers.cs | 3 +- .../src/Providers/NamedTypeSymbolProvider.cs | 4 +++ .../src/Writers/CodeWriter.cs | 2 ++ 6 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod/BaseModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 782ae8ccaea..b4d8e84dc8c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -90,9 +90,10 @@ private bool IsXmlModelWriteCoreMethod(MethodProvider method) method.Signature.Parameters[1].Type.Equals(typeof(ModelReaderWriterOptions)); private static bool IsOverridable(MethodSignatureModifiers modifiers) - => modifiers.HasFlag(MethodSignatureModifiers.Virtual) || - modifiers.HasFlag(MethodSignatureModifiers.Override) || - modifiers.HasFlag(MethodSignatureModifiers.Abstract); + => !modifiers.HasFlag(MethodSignatureModifiers.Sealed) && + (modifiers.HasFlag(MethodSignatureModifiers.Virtual) || + modifiers.HasFlag(MethodSignatureModifiers.Override) || + modifiers.HasFlag(MethodSignatureModifiers.Abstract)); private bool HasCustomBaseXmlModelWriteCoreMethod() => GetCustomSerializationBaseType() is { } baseType && diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod/BaseModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod/BaseModel.cs new file mode 100644 index 00000000000..3657b063eda --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod/BaseModel.cs @@ -0,0 +1,20 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class BaseModel : BaseModelXmlHook +{ + internal sealed override void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} + +public class BaseModelXmlHook +{ + internal virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index bf6a0be3b3b..4a7da2b58c5 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -252,6 +252,42 @@ public async Task XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithProtectedCust StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideGeneratedBaseWithSealedCustomMethod() + { + var baseModel = InputFactory.Model( + "baseModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("BaseProp", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("baseProp"))) + ]); + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + baseModel: baseModel, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [baseModel, inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var baseModelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "BaseModel"); + var customBaseMethod = baseModelProvider.CustomCodeView!.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + Assert.IsTrue(customBaseMethod.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Sealed)); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + // Validates that a custom deserialization hook can be used to customize property deserialization. [Test] public async Task CanCustomizeDeserializationMethod() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureModifiers.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureModifiers.cs index 77c755b3299..dca28b18e71 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureModifiers.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Primitives/MethodSignatureModifiers.cs @@ -23,6 +23,7 @@ public enum MethodSignatureModifiers Explicit = 2048, Implicit = 4096, Partial = 8192, - Abstract = 16384 + Abstract = 16384, + Sealed = 32768 } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index ed3a45d54e8..a6b260b834c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -365,6 +365,10 @@ private void AddAdditionalModifiers(IMethodSymbol methodSymbol, ref MethodSignat { modifiers |= MethodSignatureModifiers.Override; } + if (methodSymbol.IsSealed) + { + modifiers |= MethodSignatureModifiers.Sealed; + } if (methodSymbol.IsAsync) { modifiers |= MethodSignatureModifiers.Async; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Writers/CodeWriter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Writers/CodeWriter.cs index 1e25bccefce..eeb1c57a30d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Writers/CodeWriter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Writers/CodeWriter.cs @@ -340,6 +340,7 @@ public void WriteProperty(PropertyProvider property) .AppendRawIf("internal ", modifiers.HasFlag(MethodSignatureModifiers.Internal)) .AppendRawIf("private ", modifiers.HasFlag(MethodSignatureModifiers.Private)) .AppendRawIf("new ", modifiers.HasFlag(MethodSignatureModifiers.New)) + .AppendRawIf("sealed ", modifiers.HasFlag(MethodSignatureModifiers.Sealed)) .AppendRawIf("override ", modifiers.HasFlag(MethodSignatureModifiers.Override)) .AppendRawIf("static ", modifiers.HasFlag(MethodSignatureModifiers.Static)) .AppendRawIf("virtual ", modifiers.HasFlag(MethodSignatureModifiers.Virtual)); @@ -837,6 +838,7 @@ public IDisposable WriteMethodDeclarationNoScope(MethodSignatureBase methodBase, { AppendRawIf("virtual ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)) .AppendRawIf("abstract ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.Abstract)) + .AppendRawIf("sealed ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.Sealed)) .AppendRawIf("override ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.Override)) .AppendRawIf("new ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.New)) .AppendRawIf("async ", methodBase.Modifiers.HasFlag(MethodSignatureModifiers.Async)); From 15757c73861d45a9c4f209dd6218298e0e88209a Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Wed, 8 Jul 2026 06:39:00 +0000 Subject: [PATCH 18/22] fix(http-client-csharp): stop xml core lookup at incompatible overrides Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 31 ++++++++++++++----- .../XmlSerializationCustomizationTests.cs | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index b4d8e84dc8c..691fa23c0ae 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Reflection; using System.Text.Json; using System.Xml; using System.Xml.Linq; @@ -80,9 +81,12 @@ _model.BaseModelProvider is not SystemObjectModelProvider && _model.BaseModelProvider.CustomCodeView?.Methods.Any(IsXmlModelWriteCoreMethod) == true; private bool IsXmlModelWriteCoreMethod(MethodProvider method) - => method.Signature.Name == XmlModelWriteCoreMethodName && + => IsXmlModelWriteCoreSignature(method) && method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal) && - IsOverridable(method.Signature.Modifiers) && + IsOverridable(method.Signature.Modifiers); + + private bool IsXmlModelWriteCoreSignature(MethodProvider method) + => method.Signature.Name == XmlModelWriteCoreMethodName && !method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Static) && (method.Signature.ReturnType is null || method.Signature.ReturnType.Equals(typeof(void))) && method.Signature.Parameters.Count == 2 && @@ -106,18 +110,31 @@ private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet< return false; } - return HasCompatibleXmlModelWriteCore(type) || - type.BaseType is not null && HasCompatibleXmlModelWriteCoreInHierarchy(type.BaseType, visited); + if (GetXmlModelWriteCoreCompatibility(type) is { } isCompatible) + { + return isCompatible; + } + + return type.BaseType is not null && HasCompatibleXmlModelWriteCoreInHierarchy(type.BaseType, visited); } - private bool HasCompatibleXmlModelWriteCore(CSharpType type) + private bool? GetXmlModelWriteCoreCompatibility(CSharpType type) { if (type.IsFrameworkType) { - return false; + var method = type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly) + .FirstOrDefault(method => + method.Name == XmlModelWriteCoreMethodName && + method.ReturnType == typeof(void) && + method.GetParameters() is [{ ParameterType: var writerType }, { ParameterType: var optionsType }] && + writerType == typeof(XmlWriter) && + optionsType == typeof(ModelReaderWriterOptions)); + + return method is null ? null : false; } - return TryGetReferencedType(type)?.Methods.Any(IsXmlModelWriteCoreMethod) == true; + var sourceMethod = TryGetReferencedType(type)?.Methods.FirstOrDefault(IsXmlModelWriteCoreSignature); + return sourceMethod is null ? null : IsXmlModelWriteCoreMethod(sourceMethod); } private MethodProvider BuildXmlModelWriteCoreMethod() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 4a7da2b58c5..4776a3b2fb7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -150,7 +150,7 @@ public void ReflectedInternalXmlModelWriteCoreIsNotOverrideCompatible() MockHelpers.LoadMockGenerator(); var inputModel = InputFactory.Model("mockInputModel", usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml); var serializationProvider = new MrwSerializationTypeDefinition(inputModel, new ModelProvider(inputModel)); - var method = typeof(MrwSerializationTypeDefinition).GetMethod("HasCompatibleXmlModelWriteCore", BindingFlags.Instance | BindingFlags.NonPublic); + var method = typeof(MrwSerializationTypeDefinition).GetMethod("GetXmlModelWriteCoreCompatibility", BindingFlags.Instance | BindingFlags.NonPublic); Assert.IsNotNull(method); Assert.AreEqual(false, method!.Invoke(serializationProvider, [new CSharpType(typeof(ReflectedInternalXmlBase))])); From d927d77c3a5b5bdca61417cb492331f4d2bb986d Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Thu, 9 Jul 2026 07:40:19 +0000 Subject: [PATCH 19/22] fix(http-client-csharp): use type providers for xml core lookup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 33 +++++++++---------- .../XmlSerializationCustomizationTests.cs | 22 ------------- 2 files changed, 16 insertions(+), 39 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 691fa23c0ae..b8f6a2f7247 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Net; -using System.Reflection; using System.Text.Json; using System.Xml; using System.Xml.Linq; @@ -100,7 +99,8 @@ private static bool IsOverridable(MethodSignatureModifiers modifiers) modifiers.HasFlag(MethodSignatureModifiers.Abstract)); private bool HasCustomBaseXmlModelWriteCoreMethod() - => GetCustomSerializationBaseType() is { } baseType && + => GetCustomSerializationBaseType() is not null && + _model.BaseType is { } baseType && HasCompatibleXmlModelWriteCoreInHierarchy(baseType, []); private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet visited) @@ -110,31 +110,30 @@ private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet< return false; } - if (GetXmlModelWriteCoreCompatibility(type) is { } isCompatible) + var provider = TryGetTypeProvider(type); + if (provider is not null && GetXmlModelWriteCoreCompatibility(provider) is { } isCompatible) { return isCompatible; } - return type.BaseType is not null && HasCompatibleXmlModelWriteCoreInHierarchy(type.BaseType, visited); + var baseType = provider?.BaseType ?? type.BaseType; + return baseType is not null && HasCompatibleXmlModelWriteCoreInHierarchy(baseType, visited); } - private bool? GetXmlModelWriteCoreCompatibility(CSharpType type) + private bool? GetXmlModelWriteCoreCompatibility(TypeProvider type) { - if (type.IsFrameworkType) - { - var method = type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly) - .FirstOrDefault(method => - method.Name == XmlModelWriteCoreMethodName && - method.ReturnType == typeof(void) && - method.GetParameters() is [{ ParameterType: var writerType }, { ParameterType: var optionsType }] && - writerType == typeof(XmlWriter) && - optionsType == typeof(ModelReaderWriterOptions)); + var sourceMethod = type.Methods.FirstOrDefault(IsXmlModelWriteCoreSignature); + return sourceMethod is null ? null : IsXmlModelWriteCoreMethod(sourceMethod); + } - return method is null ? null : false; + private static TypeProvider? TryGetTypeProvider(CSharpType type) + { + if (ScmCodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(type, out var provider)) + { + return provider; } - var sourceMethod = TryGetReferencedType(type)?.Methods.FirstOrDefault(IsXmlModelWriteCoreSignature); - return sourceMethod is null ? null : IsXmlModelWriteCoreMethod(sourceMethod); + return TryGetReferencedType(type); } private MethodProvider BuildXmlModelWriteCoreMethod() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 4776a3b2fb7..65680f2a6a8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -1,11 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.ClientModel.Primitives; using System.Linq; -using System.Reflection; using System.Threading.Tasks; -using System.Xml; using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -144,18 +141,6 @@ public async Task XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase() StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } - [Test] - public void ReflectedInternalXmlModelWriteCoreIsNotOverrideCompatible() - { - MockHelpers.LoadMockGenerator(); - var inputModel = InputFactory.Model("mockInputModel", usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml); - var serializationProvider = new MrwSerializationTypeDefinition(inputModel, new ModelProvider(inputModel)); - var method = typeof(MrwSerializationTypeDefinition).GetMethod("GetXmlModelWriteCoreCompatibility", BindingFlags.Instance | BindingFlags.NonPublic); - - Assert.IsNotNull(method); - Assert.AreEqual(false, method!.Invoke(serializationProvider, [new CSharpType(typeof(ReflectedInternalXmlBase))])); - } - [Test] public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() { @@ -456,12 +441,5 @@ public async Task CanSerializeCustomizedNullableDateTimeOffset() var file = writer.Write(); Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); } - - private class ReflectedInternalXmlBase - { - internal virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) - { - } - } } } From c4a19ce7b4dd752dcce28e7b81459281dcb8129a Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Thu, 9 Jul 2026 07:53:09 +0000 Subject: [PATCH 20/22] fix(http-client-csharp): remove reflection from mrw override lookup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 10 ---- .../MrwSerializationTypeDefinition.cs | 53 +++++++++++-------- .../SystemObjectModelSerializationTests.cs | 15 +++++- .../src/Providers/NamedTypeSymbolProvider.cs | 3 ++ 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index b8f6a2f7247..1eb6d793816 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -126,16 +126,6 @@ private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet< return sourceMethod is null ? null : IsXmlModelWriteCoreMethod(sourceMethod); } - private static TypeProvider? TryGetTypeProvider(CSharpType type) - { - if (ScmCodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(type, out var provider)) - { - return provider; - } - - return TryGetReferencedType(type); - } - private MethodProvider BuildXmlModelWriteCoreMethod() { MethodSignatureModifiers modifiers = _isStruct diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index c66ffacffc1..6e9318310ca 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -9,7 +9,6 @@ using System.IO; using System.Linq; using System.Net; -using System.Reflection; using System.Text; using System.Text.Json; using System.Xml; @@ -276,16 +275,34 @@ private static bool HasMethodInTypeHierarchy(CSharpType type, string methodName) private static CSharpType? TryGetMethodReturnType(CSharpType type, string methodName) { - if (type.IsFrameworkType) + if (TryGetTypeProvider(type) is { } referencedType) { - var method = type.FrameworkType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .FirstOrDefault(method => method.Name == methodName); - return method is null ? null : new CSharpType(method.ReturnType); + return referencedType.Methods.FirstOrDefault(method => method.Signature.Name == methodName)?.Signature.ReturnType; } - if (TryGetReferencedType(type) is { } referencedType) + return null; + } + + private static TypeProvider? TryGetTypeProvider(CSharpType type) + { + if (TryGetMappedTypeProvider(type) is { } provider) { - return referencedType.Methods.FirstOrDefault(method => method.Signature.Name == methodName)?.Signature.ReturnType; + return provider; + } + + return TryGetReferencedType(type); + } + + private static TypeProvider? TryGetMappedTypeProvider(CSharpType type) + { + foreach (var (mappedType, provider) in ScmCodeModelGenerator.Instance.TypeFactory.CSharpTypeMap) + { + if (mappedType.FullyQualifiedName == type.FullyQualifiedName || + provider is SystemObjectModelProvider systemProvider && + systemProvider.SystemType.FullyQualifiedName == type.FullyQualifiedName) + { + return provider; + } } return null; @@ -297,7 +314,7 @@ private static bool HasMethodInTypeHierarchy(CSharpType type, string methodName) : CodeModelGenerator.Instance.SourceInputModel.FindForTypeInCustomization( type.Namespace, type.Name, - declaringTypeName: null, + declaringTypeName: type.DeclaringType?.Name, includeReferencedAssemblies: true); private static bool IsFrameworkRootType(CSharpType type) @@ -307,26 +324,18 @@ private static bool IsFrameworkRootType(CSharpType type) private static bool SystemTypeImplementsModelReaderWriter(CSharpType systemType) { - if (!systemType.IsFrameworkType) + if (TryGetMappedTypeProvider(systemType) is not { } systemTypeProvider) { return false; } - foreach (var @interface in systemType.FrameworkType.GetInterfaces()) - { - if (@interface.IsGenericType) - { - var definition = @interface.GetGenericTypeDefinition(); - if (definition == typeof(IJsonModel<>) || definition == typeof(IPersistableModel<>)) - { - return true; - } - } - } - - return false; + return systemTypeProvider.Implements.Any(IsModelReaderWriterInterface); } + private static bool IsModelReaderWriterInterface(CSharpType type) + => type.Namespace == typeof(IJsonModel<>).Namespace && + (type.Name == nameof(IJsonModel) || type.Name == nameof(IPersistableModel)); + protected override ConstructorProvider[] BuildConstructors() { List constructors = new(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/SystemObjectModelSerializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/SystemObjectModelSerializationTests.cs index fcc90582416..0514e1dd24b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/SystemObjectModelSerializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/SystemObjectModelSerializationTests.cs @@ -246,7 +246,7 @@ private static (ModelProvider Model, MrwSerializationTypeDefinition Serializatio // The base wraps a framework type that declares the generated MRW *Core methods, so a // derived model must override them (mirrors deriving from an external MRW-generated type). var systemType = new CSharpType(typeof(FakeMrwBase)); - var systemBase = new SystemObjectModelProvider(systemType, baseInputModel); + var systemBase = new FakeMrwSystemObjectModelProvider(systemType, baseInputModel); var generator = MockHelpers.LoadMockGenerator( inputModels: () => [baseInputModel, derivedInputModel], @@ -354,6 +354,19 @@ string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOpti => "J"; } + private class FakeMrwSystemObjectModelProvider : SystemObjectModelProvider + { + private readonly CSharpType _type; + + public FakeMrwSystemObjectModelProvider(CSharpType type, InputModelType inputModel) : base(type, inputModel) + { + _type = type; + } + + protected internal override CSharpType[] BuildImplements() + => [new CSharpType(typeof(IJsonModel<>), _type)]; + } + private class DelayedBaseModelProvider(InputModelType inputModel) : ModelProvider(inputModel) { public ModelProvider? BaseModel { get; set; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index a6b260b834c..dcd43dbb8fd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -42,6 +42,9 @@ public NamedTypeSymbolProvider(INamedTypeSymbol namedTypeSymbol, Compilation com protected override IReadOnlyList BuildAttributes() => [.._namedTypeSymbol.GetAttributes().Select(a => new AttributeStatement(a))]; + protected internal override CSharpType[] BuildImplements() + => [.. _namedTypeSymbol.Interfaces.Select(i => i.GetCSharpType())]; + internal override TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); protected override CSharpType? BuildBaseType() From 6e556ff1ec14ddaf397253f00025ffc500e7aecb Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Fri, 10 Jul 2026 01:25:16 +0000 Subject: [PATCH 21/22] Fix custom base review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 33 +++++++++++++++- .../MockInputModel.cs | 17 +++++++++ .../XmlSerializationCustomizationTests.cs | 26 +++++++++++++ .../src/Providers/ModelProvider.cs | 5 +-- .../src/Providers/NamedTypeSymbolProvider.cs | 15 ++++---- .../Providers/SystemObjectModelProvider.cs | 16 ++++---- .../src/Providers/TypeProvider.cs | 6 ++- .../InterfaceTests.cs | 38 +++++++++++++++++++ 8 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedInternalCustomExternalBase/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index 1eb6d793816..ea8b8bb6c15 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -81,9 +81,15 @@ _model.BaseModelProvider is not SystemObjectModelProvider && private bool IsXmlModelWriteCoreMethod(MethodProvider method) => IsXmlModelWriteCoreSignature(method) && - method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal) && + HasInternalOnlyAccessibility(method.Signature.Modifiers) && IsOverridable(method.Signature.Modifiers); + private static bool HasInternalOnlyAccessibility(MethodSignatureModifiers modifiers) + => modifiers.HasFlag(MethodSignatureModifiers.Internal) && + !modifiers.HasFlag(MethodSignatureModifiers.Public) && + !modifiers.HasFlag(MethodSignatureModifiers.Protected) && + !modifiers.HasFlag(MethodSignatureModifiers.Private); + private bool IsXmlModelWriteCoreSignature(MethodProvider method) => method.Signature.Name == XmlModelWriteCoreMethodName && !method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Static) && @@ -100,8 +106,31 @@ private static bool IsOverridable(MethodSignatureModifiers modifiers) private bool HasCustomBaseXmlModelWriteCoreMethod() => GetCustomSerializationBaseType() is not null && - _model.BaseType is { } baseType && + BaseDeclaresCompatibleXmlModelWriteCore(); + + private bool BaseDeclaresCompatibleXmlModelWriteCore() + { + foreach (var provider in EnumerateBaseTypeProviders()) + { + var source = provider.CustomCodeView ?? provider; + if (GetXmlModelWriteCoreCompatibility(source) is { } isCompatible) + { + return isCompatible; + } + } + + return _model.BaseType is { } baseType && HasCompatibleXmlModelWriteCoreInHierarchy(baseType, []); + } + + private IEnumerable EnumerateBaseTypeProviders() + { + var visited = new HashSet(); + for (var provider = _model.BaseTypeProvider; provider is not null && visited.Add(provider); provider = provider.BaseTypeProvider) + { + yield return provider; + } + } private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet visited) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedInternalCustomExternalBase/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedInternalCustomExternalBase/MockInputModel.cs new file mode 100644 index 00000000000..07ae8c5f006 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationCustomizationTests/XmlModelWriteCoreDoesNotOverrideProtectedInternalCustomExternalBase/MockInputModel.cs @@ -0,0 +1,17 @@ +#nullable disable + +using System.ClientModel.Primitives; +using System.Xml; + +namespace Sample.Models; + +public partial class MockInputModel : ProtectedInternalXmlBase +{ +} + +public class ProtectedInternalXmlBase +{ + protected internal virtual void XmlModelWriteCore(XmlWriter writer, ModelReaderWriterOptions options) + { + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs index 65680f2a6a8..6965519f773 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationCustomizationTests.cs @@ -141,6 +141,32 @@ public async Task XmlModelWriteCoreDoesNotOverrideProtectedCustomExternalBase() StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); } + [Test] + public async Task XmlModelWriteCoreDoesNotOverrideProtectedInternalCustomExternalBase() + { + var inputModel = InputFactory.Model( + "mockInputModel", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.Xml, + properties: + [ + InputFactory.Property("Prop1", InputPrimitiveType.String, serializationOptions: InputFactory.Serialization.Options(xml: InputFactory.Serialization.Xml("prop1"))) + ]); + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModels: () => [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider); + Assert.AreEqual("ProtectedInternalXmlBase", modelProvider.BaseType?.Name); + + var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition); + var xmlWriteCore = serializationProvider.Methods.Single(m => m.Signature.Name == "XmlModelWriteCore"); + + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)); + Assert.IsTrue(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Virtual)); + Assert.IsFalse(xmlWriteCore.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Override)); + StringAssert.DoesNotContain("base.XmlModelWriteCore", xmlWriteCore.BodyStatements!.ToDisplayString()); + } + [Test] public async Task XmlModelWriteCoreOverridesGeneratedBaseWithCustomReplacement() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index bce57ccb41a..afc2cd651b0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -124,10 +124,7 @@ private IReadOnlyList BuildDerivedModels() return [.. derivedModels]; } - internal override TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); - private TypeProvider? _baseTypeProvider; - - private TypeProvider? BuildBaseTypeProvider() + private protected override TypeProvider? BuildBaseTypeProvider() { // First check if there's a generated base model if (BaseModelProvider != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index dcd43dbb8fd..fca09bb9ba5 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -22,7 +22,6 @@ internal sealed class NamedTypeSymbolProvider : TypeProvider { private INamedTypeSymbol _namedTypeSymbol; private readonly Compilation _compilation; - private TypeProvider? _baseTypeProvider; public NamedTypeSymbolProvider(INamedTypeSymbol namedTypeSymbol, Compilation compilation) { @@ -43,28 +42,26 @@ protected override IReadOnlyList BuildAttributes() => [.._namedTypeSymbol.GetAttributes().Select(a => new AttributeStatement(a))]; protected internal override CSharpType[] BuildImplements() - => [.. _namedTypeSymbol.Interfaces.Select(i => i.GetCSharpType())]; + => [.. _namedTypeSymbol.AllInterfaces.Select(i => i.GetCSharpType())]; - internal override TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); - - protected override CSharpType? BuildBaseType() + private protected override TypeProvider? BuildBaseTypeProvider() { if (ShouldSkipBaseType(_namedTypeSymbol.BaseType)) { return null; } - return _namedTypeSymbol.BaseType!.GetCSharpType(); + return new NamedTypeSymbolProvider(_namedTypeSymbol.BaseType!, _compilation); } - private TypeProvider? BuildBaseTypeProvider() + protected override CSharpType? BuildBaseType() { if (ShouldSkipBaseType(_namedTypeSymbol.BaseType)) { return null; } - return new NamedTypeSymbolProvider(_namedTypeSymbol.BaseType!, _compilation); + return _namedTypeSymbol.BaseType!.GetCSharpType(); } private bool ShouldSkipBaseType(INamedTypeSymbol? baseType) @@ -517,6 +514,8 @@ private static XDocument ParseXml(ISymbol docsSymbol, string xmlDocumentation) Accessibility.Protected => MethodSignatureModifiers.Protected, Accessibility.Internal => MethodSignatureModifiers.Internal, Accessibility.Public => MethodSignatureModifiers.Public, + Accessibility.ProtectedOrInternal => MethodSignatureModifiers.Protected | MethodSignatureModifiers.Internal, + Accessibility.ProtectedAndInternal => MethodSignatureModifiers.Protected | MethodSignatureModifiers.Private, _ => MethodSignatureModifiers.None }; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs index 7a820644826..1c8c5f6e640 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/SystemObjectModelProvider.cs @@ -27,23 +27,23 @@ public class SystemObjectModelProvider : ModelProvider /// /// The CSharp type from the external/system assembly. /// The input model type that this system type replaces. - public SystemObjectModelProvider(CSharpType systemType, InputModelType inputModel) : base(inputModel) + public SystemObjectModelProvider(CSharpType systemType, InputModelType inputModel) + : this(systemType, inputModel, skipDerivedConstructorParameters: false) { - _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) + : base(inputModel) { + _systemType = systemType ?? throw new ArgumentNullException(nameof(systemType)); _skipDerivedConstructorParameters = skipDerivedConstructorParameters; + 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(); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index a1381e7c6b7..070f4fe28e7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -225,7 +225,10 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() return modifiers; } - internal virtual TypeProvider? BaseTypeProvider => null; + public TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); + private TypeProvider? _baseTypeProvider; + + private protected virtual TypeProvider? BuildBaseTypeProvider() => null; protected virtual CSharpType? BuildBaseType() => null; @@ -589,6 +592,7 @@ public virtual void Reset() _description = null; _type = null; _arguments = null; + _baseTypeProvider = null; } /// diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/NamedTypeSymbolProviders/InterfaceTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/NamedTypeSymbolProviders/InterfaceTests.cs index 5cd0511f436..6ab8acf4c15 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/NamedTypeSymbolProviders/InterfaceTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/NamedTypeSymbolProviders/InterfaceTests.cs @@ -62,6 +62,19 @@ public void VerifyBaseTypeIsNull() Assert.IsNull(namedTypeSymbolProvider.Type.BaseType); } + [Test] + public void IncludesInterfacesInheritedFromBaseType() + { + var baseModel = new DisposableBaseModel(); + var derivedModel = new DerivedModel(baseModel); + var compilation = CompilationHelper.LoadCompilation([baseModel, derivedModel], [typeof(IDisposable)]); + var iNamedSymbol = CompilationHelper.GetSymbol(compilation.Assembly.Modules.First().GlobalNamespace, "DerivedModel"); + + var namedTypeSymbolProvider = new NamedTypeSymbolProvider(iNamedSymbol!, compilation); + + Assert.IsTrue(namedTypeSymbolProvider.Implements.Any(i => i.Equals(typeof(IDisposable)))); + } + private class Model : TypeProvider { protected override string BuildRelativeFilePath() => "."; @@ -90,5 +103,30 @@ protected internal override PropertyProvider[] BuildProperties() ]; } } + + private class DisposableBaseModel : TypeProvider + { + protected override string BuildRelativeFilePath() => "."; + + protected override string BuildName() => "DisposableBaseModel"; + + protected internal override CSharpType[] BuildImplements() + => [typeof(IDisposable)]; + + protected internal override MethodProvider[] BuildMethods() + => [new MethodProvider( + new MethodSignature("Dispose", $"", MethodSignatureModifiers.Public, null, $"", []), + Snippet.ThrowExpression(Snippet.Null), + this)]; + } + + private class DerivedModel(DisposableBaseModel baseModel) : TypeProvider + { + protected override string BuildRelativeFilePath() => "."; + + protected override string BuildName() => "DerivedModel"; + + protected override CSharpType? BuildBaseType() => baseModel.Type; + } } } From 8169c699a9e6c5c24ffe90c69bd00837595f5d23 Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Fri, 10 Jul 2026 01:36:32 +0000 Subject: [PATCH 22/22] Avoid exposing base type provider Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MrwSerializationTypeDefinition.Xml.cs | 25 +------------------ .../src/Providers/ModelProvider.cs | 5 +++- .../src/Providers/NamedTypeSymbolProvider.cs | 5 +++- .../src/Providers/TypeProvider.cs | 6 +---- 4 files changed, 10 insertions(+), 31 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs index ea8b8bb6c15..11da0d059db 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.Xml.cs @@ -106,31 +106,8 @@ private static bool IsOverridable(MethodSignatureModifiers modifiers) private bool HasCustomBaseXmlModelWriteCoreMethod() => GetCustomSerializationBaseType() is not null && - BaseDeclaresCompatibleXmlModelWriteCore(); - - private bool BaseDeclaresCompatibleXmlModelWriteCore() - { - foreach (var provider in EnumerateBaseTypeProviders()) - { - var source = provider.CustomCodeView ?? provider; - if (GetXmlModelWriteCoreCompatibility(source) is { } isCompatible) - { - return isCompatible; - } - } - - return _model.BaseType is { } baseType && + _model.BaseType is { } baseType && HasCompatibleXmlModelWriteCoreInHierarchy(baseType, []); - } - - private IEnumerable EnumerateBaseTypeProviders() - { - var visited = new HashSet(); - for (var provider = _model.BaseTypeProvider; provider is not null && visited.Add(provider); provider = provider.BaseTypeProvider) - { - yield return provider; - } - } private bool HasCompatibleXmlModelWriteCoreInHierarchy(CSharpType type, HashSet visited) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index afc2cd651b0..bce57ccb41a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -124,7 +124,10 @@ private IReadOnlyList BuildDerivedModels() return [.. derivedModels]; } - private protected override TypeProvider? BuildBaseTypeProvider() + internal override TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); + private TypeProvider? _baseTypeProvider; + + private TypeProvider? BuildBaseTypeProvider() { // First check if there's a generated base model if (BaseModelProvider != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs index fca09bb9ba5..4591a4b39a0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/NamedTypeSymbolProvider.cs @@ -22,6 +22,7 @@ internal sealed class NamedTypeSymbolProvider : TypeProvider { private INamedTypeSymbol _namedTypeSymbol; private readonly Compilation _compilation; + private TypeProvider? _baseTypeProvider; public NamedTypeSymbolProvider(INamedTypeSymbol namedTypeSymbol, Compilation compilation) { @@ -44,7 +45,9 @@ protected override IReadOnlyList BuildAttributes() protected internal override CSharpType[] BuildImplements() => [.. _namedTypeSymbol.AllInterfaces.Select(i => i.GetCSharpType())]; - private protected override TypeProvider? BuildBaseTypeProvider() + internal override TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); + + private TypeProvider? BuildBaseTypeProvider() { if (ShouldSkipBaseType(_namedTypeSymbol.BaseType)) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 070f4fe28e7..a1381e7c6b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -225,10 +225,7 @@ private TypeSignatureModifiers BuildDeclarationModifiersInternal() return modifiers; } - public TypeProvider? BaseTypeProvider => _baseTypeProvider ??= BuildBaseTypeProvider(); - private TypeProvider? _baseTypeProvider; - - private protected virtual TypeProvider? BuildBaseTypeProvider() => null; + internal virtual TypeProvider? BaseTypeProvider => null; protected virtual CSharpType? BuildBaseType() => null; @@ -592,7 +589,6 @@ public virtual void Reset() _description = null; _type = null; _arguments = null; - _baseTypeProvider = null; } ///