Skip to content

Commit c5708d5

Browse files
authored
Exposed type for scm method provider (#8811)
This pull request refactors how method types are defined and used throughout the client model generator codebase. The main change is the introduction of a centralized `MethodType` enum within `ScmMethodProvider`, replacing the previous scattered and internal definitions. This improves code clarity, maintainability, and consistency when handling different method types (CreateRequest, Protocol, Convenience) in both implementation and tests. **Core Refactoring:** - Centralized the definition of method types by introducing the `MethodType` enum in `ScmMethodProvider`, with clear documentation for each type. Added convenience properties for checking method type. **Codebase-wide Adoption:** - Updated all usages of method types in `RestClientProvider`, `ScmMethodProviderCollection`, and related classes to use `ScmMethodProvider.MethodType` instead of the old internal enum. **Removal of Duplicated Enum:** - Removed the old internal `MethodType` enum from `RestClientProvider`, ensuring there is a single source of truth for method types. **Test Updates:** - Updated all affected tests in `RestClientProviderTests` to use the new `ScmMethodProvider.MethodType` enum for parameterized testing and assertions These changes collectively improve code consistency, reduce duplication, and make the handling of client method types more robust and maintainable.#8037
1 parent 5e0cada commit c5708d5

File tree

7 files changed

+84
-31
lines changed

7 files changed

+84
-31
lines changed

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ protected override ScmMethodProvider[] BuildMethods()
705705
Return(
706706
Static(typeof(Volatile)).Invoke(nameof(Volatile.Read), cachedClientFieldVar)
707707
.NullCoalesce(interlockedCompareExchange.NullCoalesce(subClient._clientCachingField))),
708-
this);
708+
this,
709+
ScmMethodKind.Convenience);
709710
methods.Add(factoryMethod);
710711
}
711712

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ protected override ScmMethodProvider[] BuildMethods()
9999
private ScmMethodProvider BuildCreateRequestMethod(InputServiceMethod serviceMethod, bool isNextLinkRequest = false)
100100
{
101101
var options = ScmKnownParameters.RequestOptions;
102-
var parameters = GetMethodParameters(serviceMethod, MethodType.CreateRequest);
102+
var parameters = GetMethodParameters(serviceMethod, ScmMethodKind.CreateRequest);
103103
if (isNextLinkRequest)
104104
{
105105
parameters = [ScmKnownParameters.NextPage, .. parameters];
@@ -123,6 +123,7 @@ private ScmMethodProvider BuildCreateRequestMethod(InputServiceMethod serviceMet
123123
signature,
124124
messageStatements,
125125
this,
126+
ScmMethodKind.CreateRequest,
126127
xmlDocProvider: XmlDocProvider.Empty,
127128
serviceMethod: serviceMethod);
128129
}
@@ -757,7 +758,7 @@ public MethodProvider GetCreateNextLinkRequestMethod(InputOperation operation)
757758
return NextMethodCache[operation];
758759
}
759760

760-
internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod serviceMethod, MethodType methodType)
761+
internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod serviceMethod, ScmMethodKind methodType)
761762
{
762763
SortedList<int, ParameterProvider> sortedParams = [];
763764
int path = 0;
@@ -768,10 +769,10 @@ internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod s
768769

769770
var operation = serviceMethod.Operation;
770771
// For convenience methods, use the service method parameters
771-
var inputParameters = methodType is MethodType.Convenience ? serviceMethod.Parameters : operation.Parameters;
772+
var inputParameters = methodType is ScmMethodKind.Convenience ? serviceMethod.Parameters : operation.Parameters;
772773

773774
ModelProvider? spreadSource = null;
774-
if (methodType == MethodType.Convenience)
775+
if (methodType == ScmMethodKind.Convenience)
775776
{
776777
InputParameter? inputOperationSpreadParameter = operation.Parameters.FirstOrDefault(p => p.Scope.HasFlag(InputParameterScope.Spread));
777778
spreadSource = inputOperationSpreadParameter != null
@@ -816,11 +817,11 @@ internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod s
816817
continue;
817818
}
818819

819-
if (methodType is MethodType.Protocol or MethodType.CreateRequest)
820+
if (methodType is ScmMethodKind.Protocol or ScmMethodKind.CreateRequest)
820821
{
821822
if (inputParam is InputBodyParameter)
822823
{
823-
if (methodType == MethodType.CreateRequest)
824+
if (methodType == ScmMethodKind.CreateRequest)
824825
{
825826
parameter = ScmKnownParameters.RequestContent;
826827
}
@@ -836,7 +837,7 @@ internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod s
836837
parameter.Type = parameter.Type.IsEnum ? parameter.Type.UnderlyingEnumType : parameter.Type;
837838
}
838839
}
839-
else if (methodType is MethodType.Convenience &&
840+
else if (methodType is ScmMethodKind.Convenience &&
840841
spreadSource != null
841842
&& inputParam is InputMethodParameter inputMethodParameter
842843
&& inputMethodParameter.Location == InputRequestLocation.Body)
@@ -875,7 +876,7 @@ internal static List<ParameterProvider> GetMethodParameters(InputServiceMethod s
875876
sortedParams.Add(bodyRequired++, ScmKnownParameters.ContentType);
876877
}
877878

878-
if (methodType == MethodType.CreateRequest)
879+
if (methodType == ScmMethodKind.CreateRequest)
879880
{
880881
// All the parameters should be required for the CreateRequest method
881882
foreach (var parameter in sortedParams.Values)
@@ -897,13 +898,6 @@ internal static InputModelType GetSpreadParameterModel(InputParameter inputParam
897898
throw new InvalidOperationException($"inputParam `{inputParam.Name}` is `Spread` but not a model type");
898899
}
899900

900-
internal enum MethodType
901-
{
902-
CreateRequest,
903-
Protocol,
904-
Convenience
905-
}
906-
907901
private class StatusCodesComparer : IEqualityComparer<List<int>>
908902
{
909903
bool IEqualityComparer<List<int>>.Equals(List<int>? x, List<int>? y)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
5+
{
6+
/// <summary>
7+
/// Defines the different Kinds of methods that can be generated by the SCM (System Client Model) generator.
8+
/// </summary>
9+
public enum ScmMethodKind
10+
{
11+
/// <summary>
12+
/// Internal method that creates HTTP request messages for protocol methods.
13+
/// These methods are typically used internally by protocol methods to construct HTTP requests.
14+
/// </summary>
15+
CreateRequest,
16+
17+
/// <summary>
18+
/// Protocol method that handles raw HTTP requests and responses.
19+
/// These methods provide low-level access to HTTP operations with minimal abstraction.
20+
/// </summary>
21+
Protocol,
22+
23+
/// <summary>
24+
/// Convenience method with strongly-typed parameters and return values.
25+
/// These methods provide a high-level, developer-friendly API with strong typing.
26+
/// </summary>
27+
Convenience
28+
}
29+
}

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProvider.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,33 @@
55
using Microsoft.TypeSpec.Generator.Primitives;
66
using Microsoft.TypeSpec.Generator.Providers;
77
using Microsoft.TypeSpec.Generator.Statements;
8+
using Microsoft.TypeSpec.Generator.ClientModel.Primitives;
89

910
namespace Microsoft.TypeSpec.Generator.ClientModel.Providers
1011
{
1112
public class ScmMethodProvider : MethodProvider
1213
{
1314
public InputServiceMethod? ServiceMethod { get; }
1415
public TypeProvider? CollectionDefinition { get; }
15-
public bool IsProtocolMethod { get; }
16+
17+
/// <summary>
18+
/// Gets the kind of method (CreateRequest, Protocol, or Convenience).
19+
/// </summary>
20+
public ScmMethodKind Kind { get; }
1621

1722
public ScmMethodProvider(
1823
MethodSignature signature,
1924
MethodBodyStatement bodyStatements,
2025
TypeProvider enclosingType,
26+
ScmMethodKind methodKind,
2127
XmlDocProvider? xmlDocProvider = default,
2228
TypeProvider? collectionDefinition = default,
23-
InputServiceMethod? serviceMethod = default,
24-
bool isProtocolMethod = false)
29+
InputServiceMethod? serviceMethod = default)
2530
: base(signature, bodyStatements, enclosingType, xmlDocProvider)
2631
{
2732
CollectionDefinition = collectionDefinition;
28-
IsProtocolMethod = isProtocolMethod;
2933
ServiceMethod = serviceMethod;
34+
Kind = methodKind;
3035
}
3136
}
3237
}

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ public class ScmMethodProviderCollection : IReadOnlyList<ScmMethodProvider>
2828
private readonly MethodProvider _createRequestMethod;
2929
private static readonly ClientPipelineExtensionsDefinition _clientPipelineExtensionsDefinition = new();
3030
private static readonly CancellationTokenExtensionsDefinition _cancellationTokenExtensionsDefinition = new();
31-
private IList<ParameterProvider> ProtocolMethodParameters => _protocolMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, RestClientProvider.MethodType.Protocol);
31+
private IList<ParameterProvider> ProtocolMethodParameters => _protocolMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Protocol);
3232
private IList<ParameterProvider>? _protocolMethodParameters;
3333

34-
private IReadOnlyList<ParameterProvider> ConvenienceMethodParameters => _convenienceMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, RestClientProvider.MethodType.Convenience);
34+
private IReadOnlyList<ParameterProvider> ConvenienceMethodParameters => _convenienceMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Convenience);
3535
private IReadOnlyList<ParameterProvider>? _convenienceMethodParameters;
3636
private readonly InputPagingServiceMethod? _pagingServiceMethod;
3737
private IReadOnlyList<ScmMethodProvider>? _methods;
@@ -160,7 +160,7 @@ .. GetStackVariablesForReturnValueConversion(result, responseBodyType, isAsync,
160160
];
161161
}
162162

163-
var convenienceMethod = new ScmMethodProvider(methodSignature, methodBody, EnclosingType, collectionDefinition: collection, serviceMethod: ServiceMethod);
163+
var convenienceMethod = new ScmMethodProvider(methodSignature, methodBody, EnclosingType, ScmMethodKind.Convenience, collectionDefinition: collection, serviceMethod: ServiceMethod);
164164

165165
if (convenienceMethod.XmlDocs != null)
166166
{
@@ -653,7 +653,7 @@ private ScmMethodProvider BuildProtocolMethod(MethodProvider createRequestMethod
653653
}
654654

655655
var protocolMethod =
656-
new ScmMethodProvider(methodSignature, methodBody, EnclosingType, collectionDefinition: collection, serviceMethod: ServiceMethod, isProtocolMethod: true);
656+
new ScmMethodProvider(methodSignature, methodBody, EnclosingType, ScmMethodKind.Protocol, collectionDefinition: collection, serviceMethod: ServiceMethod);
657657

658658
if (protocolMethod.XmlDocs != null)
659659
{

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public void ValidateProperties()
104104
[TestCaseSource(nameof(GetMethodParametersTestCases))]
105105
public void TestGetMethodParameters(InputServiceMethod inputServiceMethod)
106106
{
107-
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, RestClientProvider.MethodType.Convenience);
107+
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, ScmMethodKind.Convenience);
108108

109109
Assert.IsTrue(methodParameters.Count > 0);
110110

@@ -139,7 +139,7 @@ public void TestGetMethodParameters(InputServiceMethod inputServiceMethod)
139139
[TestCase]
140140
public void TestGetMethodParameters_ProperOrdering()
141141
{
142-
var methodParameters = RestClientProvider.GetMethodParameters(ServiceMethodWithMixedParamOrdering, RestClientProvider.MethodType.Convenience);
142+
var methodParameters = RestClientProvider.GetMethodParameters(ServiceMethodWithMixedParamOrdering, ScmMethodKind.Convenience);
143143

144144
Assert.AreEqual(ServiceMethodWithMixedParamOrdering.Parameters.Count, methodParameters.Count);
145145

@@ -152,7 +152,7 @@ public void TestGetMethodParameters_ProperOrdering()
152152
Assert.AreEqual("optionalHeader", methodParameters[5].Name);
153153
Assert.AreEqual("optionalContentType", methodParameters[6].Name);
154154

155-
var orderedPathParams = RestClientProvider.GetMethodParameters(ServiceMethodWithOnlyPathParams, RestClientProvider.MethodType.Convenience);
155+
var orderedPathParams = RestClientProvider.GetMethodParameters(ServiceMethodWithOnlyPathParams, ScmMethodKind.Convenience);
156156
Assert.AreEqual(ServiceMethodWithOnlyPathParams.Parameters.Count, orderedPathParams.Count);
157157
Assert.AreEqual("c", orderedPathParams[0].Name);
158158
Assert.AreEqual("a", orderedPathParams[1].Name);
@@ -185,7 +185,7 @@ public void HeaderParameterOptionality(bool isRequired, bool isValueType)
185185
"TestClient",
186186
methods: [testServiceMethod]);
187187
var clientProvider = new ClientProvider(client);
188-
var parameters = RestClientProvider.GetMethodParameters(testServiceMethod, RestClientProvider.MethodType.Convenience);
188+
var parameters = RestClientProvider.GetMethodParameters(testServiceMethod, ScmMethodKind.Convenience);
189189
Assert.IsNotNull(parameters);
190190

191191
if (isRequired)
@@ -705,7 +705,7 @@ public void TestReadOnlyParameters_FilteredFromProtocolMethod()
705705
InputFactory.MethodParameter("normalBody", InputPrimitiveType.Boolean, isRequired: false, location: InputRequestLocation.Body)
706706
]);
707707

708-
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, RestClientProvider.MethodType.Protocol);
708+
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, ScmMethodKind.Protocol);
709709

710710
// Verify read-only parameters are filtered out
711711
Assert.IsFalse(methodParameters.Any(p => p.Name == "readOnlyPath"));
@@ -737,7 +737,7 @@ public void TestReadOnlyParameters_FilteredFromConvenienceMethod()
737737
InputFactory.MethodParameter("normalHeader", InputPrimitiveType.Boolean, isRequired: false, location: InputRequestLocation.Header)
738738
]);
739739

740-
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, RestClientProvider.MethodType.Convenience);
740+
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, ScmMethodKind.Convenience);
741741

742742
// Verify read-only parameters are filtered out
743743
Assert.IsFalse(methodParameters.Any(p => p.Name == "readOnlyQuery"));
@@ -773,7 +773,7 @@ public void TestReadOnlyParameters_WithMixedParameterTypes()
773773
InputFactory.MethodParameter("normalBody", InputPrimitiveType.Boolean, isRequired: false, location: InputRequestLocation.Body)
774774
]);
775775

776-
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, RestClientProvider.MethodType.Convenience);
776+
var methodParameters = RestClientProvider.GetMethodParameters(inputServiceMethod, ScmMethodKind.Convenience);
777777

778778
Assert.AreEqual(4, methodParameters.Count); // Only non-readonly parameters
779779
Assert.IsTrue(methodParameters.Any(p => p.Name == "normalPath"));

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,5 +1073,29 @@ public static IEnumerable<TestCaseData> DefaultCSharpMethodCollectionTestCases
10731073
]));
10741074
}
10751075
}
1076+
1077+
[Test]
1078+
public void TestMethodTypeIdentification()
1079+
{
1080+
MockHelpers.LoadMockGenerator();
1081+
1082+
var inputOperation = InputFactory.Operation("TestOperation");
1083+
var inputServiceMethod = InputFactory.BasicServiceMethod("Test", inputOperation);
1084+
var inputClient = InputFactory.Client("TestClient", methods: [inputServiceMethod]);
1085+
var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient);
1086+
var methodCollection = new ScmMethodProviderCollection(inputServiceMethod, client!);
1087+
1088+
// Verify protocol methods
1089+
var protocolMethods = methodCollection.Where(m => ((ScmMethodProvider)m).Kind == ScmMethodKind.Protocol).ToList();
1090+
Assert.AreEqual(2, protocolMethods.Count); // sync + async
1091+
1092+
// Verify convenience methods
1093+
var convenienceMethods = methodCollection.Where(m => ((ScmMethodProvider)m).Kind == ScmMethodKind.Convenience).ToList();
1094+
Assert.AreEqual(2, convenienceMethods.Count); // sync + async
1095+
1096+
// Verify CreateRequest method
1097+
var createRequestMethod = (ScmMethodProvider)client!.RestClient.GetCreateRequestMethod(inputOperation);
1098+
Assert.AreEqual(ScmMethodKind.CreateRequest, createRequestMethod.Kind);
1099+
}
10761100
}
10771101
}

0 commit comments

Comments
 (0)