[http-client-csharp]: Don't include custom required literal properties in public ctor (#4783)
This PR addresses an issue where required spec properties that were literals and then customized to another literal type were being incorrectly included in the public constructor. fixes: https://github.com/microsoft/typespec/issues/4747
This commit is contained in:
Родитель
a689659f64
Коммит
f1bfe9cdf9
|
@ -103,20 +103,10 @@ namespace Microsoft.Generator.CSharp.Providers
|
|||
}
|
||||
|
||||
// handle customized enums - we need to pull the type information from the spec property
|
||||
if (IsCustomizedEnumProperty(specProperty, customProperty.Type, out var specType))
|
||||
{
|
||||
customProperty.Type = new CSharpType(
|
||||
customProperty.Type.Name,
|
||||
customProperty.Type.Namespace,
|
||||
customProperty.Type.IsValueType,
|
||||
customProperty.Type.IsNullable,
|
||||
customProperty.Type.DeclaringType,
|
||||
customProperty.Type.Arguments,
|
||||
customProperty.Type.IsPublic,
|
||||
customProperty.Type.IsStruct,
|
||||
customProperty.Type.BaseType,
|
||||
TypeFactory.CreatePrimitiveCSharpTypeCore(specType));
|
||||
}
|
||||
customProperty.Type = EnsureEnum(specProperty, customProperty.Type);
|
||||
|
||||
// ensure literal types are correctly represented in the custom property using the info from the spec property
|
||||
customProperty.Type = EnsureLiteral(specProperty, customProperty.Type);
|
||||
}
|
||||
|
||||
return [..generatedProperties, ..customProperties];
|
||||
|
@ -181,20 +171,10 @@ namespace Microsoft.Generator.CSharp.Providers
|
|||
}
|
||||
|
||||
// handle customized enums - we need to pull the type information from the spec property
|
||||
if (IsCustomizedEnumProperty(specProperty, customField.Type, out var specType))
|
||||
{
|
||||
customField.Type = new CSharpType(
|
||||
customField.Type.Name,
|
||||
customField.Type.Namespace,
|
||||
customField.Type.IsValueType,
|
||||
customField.Type.IsNullable,
|
||||
customField.Type.DeclaringType,
|
||||
customField.Type.Arguments,
|
||||
customField.Type.IsPublic,
|
||||
customField.Type.IsStruct,
|
||||
customField.Type.BaseType,
|
||||
TypeFactory.CreatePrimitiveCSharpTypeCore(specType));
|
||||
}
|
||||
customField.Type = EnsureEnum(specProperty, customField.Type);
|
||||
|
||||
// ensure literal types are correctly represented in the custom field using the info from the spec property
|
||||
customField.Type = EnsureLiteral(specProperty, customField.Type);
|
||||
}
|
||||
|
||||
return [..generatedFields, ..customFields];
|
||||
|
@ -220,6 +200,35 @@ namespace Microsoft.Generator.CSharp.Providers
|
|||
return false;
|
||||
}
|
||||
|
||||
private static CSharpType EnsureLiteral(InputModelProperty? specProperty, CSharpType customType)
|
||||
{
|
||||
if (specProperty?.Type is InputLiteralType inputLiteral && (customType.IsFrameworkType || customType.IsEnum))
|
||||
{
|
||||
return CSharpType.FromLiteral(customType, inputLiteral.Value);
|
||||
}
|
||||
|
||||
return customType;
|
||||
}
|
||||
|
||||
private static CSharpType EnsureEnum(InputModelProperty? specProperty, CSharpType customType)
|
||||
{
|
||||
if (IsCustomizedEnumProperty(specProperty, customType, out var specType))
|
||||
{
|
||||
return new CSharpType(
|
||||
customType.Name,
|
||||
customType.Namespace,
|
||||
customType.IsValueType,
|
||||
customType.IsNullable,
|
||||
customType.DeclaringType,
|
||||
customType.Arguments,
|
||||
customType.IsPublic,
|
||||
customType.IsStruct,
|
||||
customType.BaseType,
|
||||
TypeFactory.CreatePrimitiveCSharpTypeCore(specType));
|
||||
}
|
||||
return customType;
|
||||
}
|
||||
|
||||
private static InputPrimitiveType? GetEnumValueType(InputType? type)
|
||||
{
|
||||
return type switch
|
||||
|
|
|
@ -500,5 +500,75 @@ namespace Microsoft.Generator.CSharp.Tests.Providers.ModelProviders
|
|||
Assert.IsTrue(ctors.Any(c => c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public)));
|
||||
Assert.IsTrue(ctors.Any(c => c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Internal)));
|
||||
}
|
||||
|
||||
// Validates that if a required literal property is customized, then the default ctor
|
||||
// does not include the custom property as a parameter.
|
||||
[Test]
|
||||
public async Task DoesNotIncludeReqCustomLiteralInDefaultCtor()
|
||||
{
|
||||
var enumType = InputFactory.Enum(
|
||||
"originalEnum",
|
||||
InputPrimitiveType.String,
|
||||
values: [InputFactory.EnumMember.String("bar", "bar")]);
|
||||
var plugin = await MockHelpers.LoadMockPluginAsync(
|
||||
inputModelTypes: [
|
||||
InputFactory.Model(
|
||||
"mockInputModel",
|
||||
usage: InputModelTypeUsage.Input,
|
||||
properties:
|
||||
[
|
||||
InputFactory.Property("Prop1", InputFactory.Literal.Enum(enumType, "bar"), isRequired: true),
|
||||
InputFactory.Property("Prop2", InputPrimitiveType.String, isRequired: true),
|
||||
])
|
||||
],
|
||||
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());
|
||||
var csharpGen = new CSharpGen();
|
||||
|
||||
await csharpGen.ExecuteAsync();
|
||||
|
||||
var ctors = plugin.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel").Constructors;
|
||||
Assert.AreEqual(2, ctors.Count);
|
||||
|
||||
var publicCtor = ctors.FirstOrDefault(c => c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public));
|
||||
Assert.IsNotNull(publicCtor);
|
||||
|
||||
var ctorParams = publicCtor!.Signature.Parameters;
|
||||
|
||||
// should not have the custom required literal property
|
||||
Assert.AreEqual(1, ctorParams.Count);
|
||||
Assert.AreEqual("prop2", ctorParams[0].Name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DoesNotIncludeReqCustomFieldLiteralInDefaultCtor()
|
||||
{
|
||||
var plugin = await MockHelpers.LoadMockPluginAsync(
|
||||
inputModelTypes: [
|
||||
InputFactory.Model(
|
||||
"mockInputModel",
|
||||
usage: InputModelTypeUsage.Input,
|
||||
properties:
|
||||
[
|
||||
InputFactory.Property("Prop1", InputFactory.Literal.String("bar"), isRequired: true),
|
||||
InputFactory.Property("Prop2", InputPrimitiveType.String, isRequired: true),
|
||||
])
|
||||
],
|
||||
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());
|
||||
var csharpGen = new CSharpGen();
|
||||
|
||||
await csharpGen.ExecuteAsync();
|
||||
|
||||
var ctors = plugin.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel").Constructors;
|
||||
Assert.AreEqual(2, ctors.Count);
|
||||
|
||||
var publicCtor = ctors.FirstOrDefault(c => c.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public));
|
||||
Assert.IsNotNull(publicCtor);
|
||||
|
||||
var ctorParams = publicCtor!.Signature.Parameters;
|
||||
|
||||
// should not have the custom required literal property
|
||||
Assert.AreEqual(1, ctorParams.Count);
|
||||
Assert.AreEqual("prop2", ctorParams[0].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Generator.CSharp.Customization;
|
||||
|
||||
namespace Sample.Models;
|
||||
|
||||
public partial class MockInputModel
|
||||
{
|
||||
[CodeGenMember("Prop1")]
|
||||
private string _prop1 = "bar";
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.Generator.CSharp.Customization;
|
||||
|
||||
namespace Sample.Models;
|
||||
|
||||
public partial class MockInputModel
|
||||
{
|
||||
[CodeGenMember("Prop1")]
|
||||
public CustomEnum Prop1 { get; } = CustomEnum.Bar;
|
||||
}
|
||||
|
||||
public enum CustomEnum
|
||||
{
|
||||
Bar
|
||||
}
|
Загрузка…
Ссылка в новой задаче