From 249d5db6c41c1d0ea87a64eaf67e5420c0fa08cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:52:45 +0000 Subject: [PATCH 01/11] Initial plan From 970737fdba350665d2a261b4145866663813b677 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:58:01 +0000 Subject: [PATCH 02/11] Add OriginalName property to InputOperation and use it in CollectionResultDefinition.BuildName Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../Providers/CollectionResultDefinition.cs | 2 +- .../CollectionResultDefinitionTests.cs | 36 +++++++++++++++++++ .../src/InputTypes/InputOperation.cs | 2 ++ .../Serialization/InputOperationConverter.cs | 1 + 4 files changed, 40 insertions(+), 1 deletion(-) 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 b85fc44c6a9..1dc98f558fb 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 @@ -182,7 +182,7 @@ private PropertyProvider FindPropertyInModelHierarchy(TypeProvider model, string protected override string BuildNamespace() => Client.Type.Namespace; protected override string BuildName() - => $"{Client.Type.Name}{Operation.Name.ToIdentifierName()}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; + => $"{Client.Type.Name}{Operation.OriginalName.ToIdentifierName()}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; protected override TypeSignatureModifiers BuildDeclarationModifiers() => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs index 6947ee8104e..a8e5aea1a4b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs @@ -205,6 +205,42 @@ public void TestEmptyStringHandlingForUriNextLink() "Generated code should check for null URI"); } + [Test] + public void TestCollectionResultNameUsesOriginalNameAfterMutation() + { + var inputModel = InputFactory.Model("cat", properties: + [ + InputFactory.Property("color", InputPrimitiveType.String, isRequired: true), + ]); + var parameter = InputFactory.QueryParameter("myToken", InputPrimitiveType.String, isRequired: true); + var pagingMetadata = InputFactory.ContinuationTokenPagingMetadata(parameter, ["cats"], ["nextPage"], InputResponseLocation.Body); + var catsProperty = InputFactory.Property("cats", InputFactory.Array(inputModel)); + var nextCatProperty = InputFactory.Property("nextPage", InputPrimitiveType.String); + var response = InputFactory.OperationResponse( + [200], + InputFactory.Model( + "page", + properties: [catsProperty, nextCatProperty])); + var operation = InputFactory.Operation("getCats", parameters: [parameter], responses: [response]); + + // Mutate the operation name after creation + operation.Update(name: "listCats"); + + // OriginalName should still be the original name + Assert.AreEqual("getCats", operation.OriginalName); + Assert.AreEqual("listCats", operation.Name); + + var inputServiceMethod = InputFactory.PagingServiceMethod("getCats", operation, pagingMetadata: pagingMetadata); + var client = InputFactory.Client("catClient", methods: [inputServiceMethod]); + + MockHelpers.LoadMockGenerator(inputModels: () => [inputModel], clients: () => [client]); + + // The CollectionResult name should use the original name "getCats", not the mutated name "listCats" + var collectionResultDefinition = ScmCodeModelGenerator.Instance.OutputLibrary.TypeProviders.FirstOrDefault( + t => t is CollectionResultDefinition && t.Name == "CatClientGetCatsCollectionResult") as CollectionResultDefinition; + Assert.IsNotNull(collectionResultDefinition); + } + internal static void CreatePagingOperation(InputResponseLocation responseLocation, bool isNested = false) { var inputModel = InputFactory.Model("cat", properties: diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs index 54f37df38db..7f5f7e0a573 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs @@ -32,6 +32,7 @@ public InputOperation( string? ns) { Name = name; + OriginalName = name; ResourceName = resourceName; Summary = summary; Doc = doc; @@ -73,6 +74,7 @@ public InputOperation() : this( { } public string Name { get; internal set; } + public string OriginalName { get; internal set; } public string? ResourceName { get; internal set; } public string? Summary { get; internal set; } public string? Doc { get; internal set; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputOperationConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputOperationConverter.cs index 28b6a06c988..32e27880757 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputOperationConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputOperationConverter.cs @@ -87,6 +87,7 @@ public override void Write(Utf8JsonWriter writer, InputOperation value, JsonSeri } operation.Name = name ?? throw new JsonException("InputOperation must have name"); + operation.OriginalName = name; operation.ResourceName = resourceName; operation.Summary = summary; operation.Doc = doc; From 8269787907b30aabef08dec052be70c149c84b82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:02:39 +0000 Subject: [PATCH 03/11] Add clarifying comment in test for service method name vs operation name Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../CollectionResultDefinitionTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs index a8e5aea1a4b..d8373395259 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs @@ -230,12 +230,13 @@ public void TestCollectionResultNameUsesOriginalNameAfterMutation() Assert.AreEqual("getCats", operation.OriginalName); Assert.AreEqual("listCats", operation.Name); + // The service method name "getCats" is independent from the operation name which was mutated to "listCats" var inputServiceMethod = InputFactory.PagingServiceMethod("getCats", operation, pagingMetadata: pagingMetadata); var client = InputFactory.Client("catClient", methods: [inputServiceMethod]); MockHelpers.LoadMockGenerator(inputModels: () => [inputModel], clients: () => [client]); - // The CollectionResult name should use the original name "getCats", not the mutated name "listCats" + // The CollectionResult name should use the original operation name "getCats", not the mutated name "listCats" var collectionResultDefinition = ScmCodeModelGenerator.Instance.OutputLibrary.TypeProviders.FirstOrDefault( t => t is CollectionResultDefinition && t.Name == "CatClientGetCatsCollectionResult") as CollectionResultDefinition; Assert.IsNotNull(collectionResultDefinition); From 5a578f9d119674aa13b11e36163ff71bcea1d634 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:10:11 +0000 Subject: [PATCH 04/11] Only use OriginalName when paging operation names collide; add collision and no-collision tests Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/ClientProvider.cs | 1 + .../Providers/CollectionResultDefinition.cs | 29 ++++++- .../CollectionResultDefinitionTests.cs | 86 +++++++++++++------ 3 files changed, 90 insertions(+), 26 deletions(-) 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 a296420f62f..c829e290267 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 @@ -42,6 +42,7 @@ private record ApiVersionFields(FieldProvider Field, PropertyProvider? Correspon private const string ClientSuffix = "Client"; private readonly FormattableString _publicCtorDescription; private readonly InputClient _inputClient; + internal InputClient InputClient => _inputClient; private readonly InputAuth? _inputAuth; private readonly ParameterProvider _endpointParameter; /// 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 1dc98f558fb..89065fe50c1 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 @@ -182,7 +182,34 @@ private PropertyProvider FindPropertyInModelHierarchy(TypeProvider model, string protected override string BuildNamespace() => Client.Type.Namespace; protected override string BuildName() - => $"{Client.Type.Name}{Operation.OriginalName.ToIdentifierName()}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; + { + var operationName = Operation.Name.ToIdentifierName(); + // Check if there is another paging operation in the same client whose name would produce a collision. + // If so, use the OriginalName to differentiate. + if (HasPagingOperationNameCollision(operationName)) + { + operationName = Operation.OriginalName.ToIdentifierName(); + } + return $"{Client.Type.Name}{operationName}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; + } + + private bool HasPagingOperationNameCollision(string operationName) + { + var pagingMethods = Client.InputClient.Methods.OfType(); + int count = 0; + foreach (var method in pagingMethods) + { + if (method.Operation.Name.ToIdentifierName() == operationName) + { + count++; + if (count > 1) + { + return true; + } + } + } + return false; + } protected override TypeSignatureModifiers BuildDeclarationModifiers() => TypeSignatureModifiers.Internal | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs index d8373395259..24f567d6327 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs @@ -206,40 +206,76 @@ public void TestEmptyStringHandlingForUriNextLink() } [Test] - public void TestCollectionResultNameUsesOriginalNameAfterMutation() + public void TestCollectionResultNamesDoNotCollideWhenOperationsAreRenamed() { - var inputModel = InputFactory.Model("cat", properties: + // Two paging operations "list" and "listAll" both get renamed to "GetAll" by CleanOperationNames. + // The CollectionResult names should use OriginalName to avoid collision. + var thingModel = InputFactory.Model("thing", properties: [ - InputFactory.Property("color", InputPrimitiveType.String, isRequired: true), + InputFactory.Property("name", InputPrimitiveType.String, isRequired: true), ]); - var parameter = InputFactory.QueryParameter("myToken", InputPrimitiveType.String, isRequired: true); - var pagingMetadata = InputFactory.ContinuationTokenPagingMetadata(parameter, ["cats"], ["nextPage"], InputResponseLocation.Body); - var catsProperty = InputFactory.Property("cats", InputFactory.Array(inputModel)); - var nextCatProperty = InputFactory.Property("nextPage", InputPrimitiveType.String); - var response = InputFactory.OperationResponse( - [200], - InputFactory.Model( - "page", - properties: [catsProperty, nextCatProperty])); - var operation = InputFactory.Operation("getCats", parameters: [parameter], responses: [response]); + var thingsProperty = InputFactory.Property("things", InputFactory.Array(thingModel)); + var nextProperty = InputFactory.Property("next", InputPrimitiveType.Url); + var pageModel = InputFactory.Model("page", properties: [thingsProperty, nextProperty]); + var response = InputFactory.OperationResponse([200], pageModel); - // Mutate the operation name after creation - operation.Update(name: "listCats"); + var pagingMetadata = InputFactory.NextLinkPagingMetadata(["things"], ["next"], InputResponseLocation.Body); - // OriginalName should still be the original name - Assert.AreEqual("getCats", operation.OriginalName); - Assert.AreEqual("listCats", operation.Name); + // "list" will be renamed to "GetAll", "listAll" will also be renamed to "GetAll" + var listOperation = InputFactory.Operation("list", responses: [response]); + var listAllOperation = InputFactory.Operation("listAll", responses: [response]); - // The service method name "getCats" is independent from the operation name which was mutated to "listCats" - var inputServiceMethod = InputFactory.PagingServiceMethod("getCats", operation, pagingMetadata: pagingMetadata); - var client = InputFactory.Client("catClient", methods: [inputServiceMethod]); + var listServiceMethod = InputFactory.PagingServiceMethod("list", listOperation, pagingMetadata: pagingMetadata); + var listAllServiceMethod = InputFactory.PagingServiceMethod("listAll", listAllOperation, pagingMetadata: pagingMetadata); - MockHelpers.LoadMockGenerator(inputModels: () => [inputModel], clients: () => [client]); + var client = InputFactory.Client("FooClient", methods: [listServiceMethod, listAllServiceMethod]); + + MockHelpers.LoadMockGenerator(inputModels: () => [thingModel], clients: () => [client]); - // The CollectionResult name should use the original operation name "getCats", not the mutated name "listCats" + var collectionResults = ScmCodeModelGenerator.Instance.OutputLibrary.TypeProviders + .Where(t => t is CollectionResultDefinition) + .ToList(); + + // Should have 4 CollectionResult types (2 sync + 2 async) and they should all have unique names + var collectionResultNames = collectionResults.Select(t => t.Name).ToList(); + Assert.AreEqual(collectionResultNames.Distinct().Count(), collectionResultNames.Count, + $"CollectionResult names should be unique but found duplicates: {string.Join(", ", collectionResultNames)}"); + + // Both should use the original names for disambiguation + Assert.IsTrue(collectionResultNames.Any(n => n == "FooClientListCollectionResult"), + $"Expected 'FooClientListCollectionResult' in [{string.Join(", ", collectionResultNames)}]"); + Assert.IsTrue(collectionResultNames.Any(n => n == "FooClientListAllCollectionResult"), + $"Expected 'FooClientListAllCollectionResult' in [{string.Join(", ", collectionResultNames)}]"); + } + + [Test] + public void TestCollectionResultNameUsesCurrentNameWhenNoCollision() + { + // A single paging operation should use the current (cleaned) name, not the original name. + var thingModel = InputFactory.Model("thing", properties: + [ + InputFactory.Property("name", InputPrimitiveType.String, isRequired: true), + ]); + var thingsProperty = InputFactory.Property("things", InputFactory.Array(thingModel)); + var nextProperty = InputFactory.Property("next", InputPrimitiveType.Url); + var pageModel = InputFactory.Model("page", properties: [thingsProperty, nextProperty]); + var response = InputFactory.OperationResponse([200], pageModel); + + var pagingMetadata = InputFactory.NextLinkPagingMetadata(["things"], ["next"], InputResponseLocation.Body); + + // "listAll" gets renamed to "GetAll" by CleanOperationNames, no collision + var listAllOperation = InputFactory.Operation("listAll", responses: [response]); + var listAllServiceMethod = InputFactory.PagingServiceMethod("listAll", listAllOperation, pagingMetadata: pagingMetadata); + + var client = InputFactory.Client("FooClient", methods: [listAllServiceMethod]); + + MockHelpers.LoadMockGenerator(inputModels: () => [thingModel], clients: () => [client]); + + // When there's no collision, the cleaned name "GetAll" should be used var collectionResultDefinition = ScmCodeModelGenerator.Instance.OutputLibrary.TypeProviders.FirstOrDefault( - t => t is CollectionResultDefinition && t.Name == "CatClientGetCatsCollectionResult") as CollectionResultDefinition; - Assert.IsNotNull(collectionResultDefinition); + t => t is CollectionResultDefinition && t.Name == "FooClientGetAllCollectionResult") as CollectionResultDefinition; + Assert.IsNotNull(collectionResultDefinition, + "CollectionResult should use cleaned name 'GetAll' when there's no collision"); } internal static void CreatePagingOperation(InputResponseLocation responseLocation, bool isNested = false) From 48314733e0eaf52034856655e56ab15a9ccaba01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:12:15 +0000 Subject: [PATCH 05/11] =?UTF-8?q?Fix=20test=20assertion:=20expect=208=20Co?= =?UTF-8?q?llectionResult=20types=20(typed+untyped=20=C3=97=20sync+async?= =?UTF-8?q?=20=C3=97=202=20ops)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../CollectionResultDefinitionTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs index 24f567d6327..cd8683227d4 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/CollectionResultDefinitions/CollectionResultDefinitionTests.cs @@ -236,7 +236,9 @@ public void TestCollectionResultNamesDoNotCollideWhenOperationsAreRenamed() .Where(t => t is CollectionResultDefinition) .ToList(); - // Should have 4 CollectionResult types (2 sync + 2 async) and they should all have unique names + // Should have 8 CollectionResult types (2 ops × 2 sync/async × 2 typed/untyped) and they should all have unique names + Assert.AreEqual(8, collectionResults.Count, + $"Expected 8 CollectionResult types but found {collectionResults.Count}"); var collectionResultNames = collectionResults.Select(t => t.Name).ToList(); Assert.AreEqual(collectionResultNames.Distinct().Count(), collectionResultNames.Count, $"CollectionResult names should be unique but found duplicates: {string.Join(", ", collectionResultNames)}"); From 6d228f2163b204078867765a69b8f54449cc7329 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:16:11 +0000 Subject: [PATCH 06/11] Add XML doc comment to OriginalName property Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/InputTypes/InputOperation.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs index 7f5f7e0a573..6c8281219fa 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs @@ -74,6 +74,11 @@ public InputOperation() : this( { } public string Name { get; internal set; } + + /// + /// Gets the original name of the operation as defined in the TypeSpec before any mutations (e.g., renaming by CleanOperationNames). + /// This value is set once at construction and is never modified by . + /// public string OriginalName { get; internal set; } public string? ResourceName { get; internal set; } public string? Summary { get; internal set; } From 91dc5f4ee3ae025b0862006d224bf37a0b115bf4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:20:02 +0000 Subject: [PATCH 07/11] Simplify HasPagingOperationNameCollision to use Operation.Name directly Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CollectionResultDefinition.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 89065fe50c1..aef2f999ec1 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 @@ -186,20 +186,20 @@ protected override string BuildName() var operationName = Operation.Name.ToIdentifierName(); // Check if there is another paging operation in the same client whose name would produce a collision. // If so, use the OriginalName to differentiate. - if (HasPagingOperationNameCollision(operationName)) + if (HasPagingOperationNameCollision()) { operationName = Operation.OriginalName.ToIdentifierName(); } return $"{Client.Type.Name}{operationName}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; } - private bool HasPagingOperationNameCollision(string operationName) + private bool HasPagingOperationNameCollision() { var pagingMethods = Client.InputClient.Methods.OfType(); int count = 0; foreach (var method in pagingMethods) { - if (method.Operation.Name.ToIdentifierName() == operationName) + if (method.Operation.Name == Operation.Name) { count++; if (count > 1) From 4d46e0349dc9ebf8afac776300854796c62abe01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:22:10 +0000 Subject: [PATCH 08/11] Simplify OriginalName XML doc comment Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/InputTypes/InputOperation.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs index 6c8281219fa..8c7ece5ef18 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs @@ -76,8 +76,7 @@ public InputOperation() : this( public string Name { get; internal set; } /// - /// Gets the original name of the operation as defined in the TypeSpec before any mutations (e.g., renaming by CleanOperationNames). - /// This value is set once at construction and is never modified by . + /// Gets the original name of the operation as defined in the TypeSpec before any mutations. /// public string OriginalName { get; internal set; } public string? ResourceName { get; internal set; } From 39b3969207c6e9e25c77dd234b88dff343f6ee21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:30:13 +0000 Subject: [PATCH 09/11] Move OriginalName assignment out of constructor, set only in converter and test factory Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/InputTypes/InputOperation.cs | 3 +-- .../Microsoft.TypeSpec.Generator/test/common/InputFactory.cs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs index 8c7ece5ef18..35d58dea21f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs @@ -32,7 +32,6 @@ public InputOperation( string? ns) { Name = name; - OriginalName = name; ResourceName = resourceName; Summary = summary; Doc = doc; @@ -78,7 +77,7 @@ public InputOperation() : this( /// /// Gets the original name of the operation as defined in the TypeSpec before any mutations. /// - public string OriginalName { get; internal set; } + public string OriginalName { get; internal set; } = string.Empty; public string? ResourceName { get; internal set; } public string? Summary { get; internal set; } public string? Doc { get; internal set; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index 53c8b2228c8..85632b4ee25 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -639,7 +639,7 @@ public static InputOperation Operation( bool generateConvenienceMethod = true, string? ns = null) { - return new InputOperation( + var operation = new InputOperation( name, null, "", @@ -658,6 +658,8 @@ public static InputOperation Operation( generateConvenienceMethod, name, ns); + operation.OriginalName = name; + return operation; } public static InputPagingServiceMetadata NextLinkPagingMetadata( From 05556e7792b429b77775d8509408800a343efc3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:38:18 +0000 Subject: [PATCH 10/11] Remove default assignment from OriginalName, make it nullable string? Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CollectionResultDefinition.cs | 2 +- .../src/InputTypes/InputOperation.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 aef2f999ec1..dd9491340fc 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 @@ -188,7 +188,7 @@ protected override string BuildName() // If so, use the OriginalName to differentiate. if (HasPagingOperationNameCollision()) { - operationName = Operation.OriginalName.ToIdentifierName(); + operationName = (Operation.OriginalName ?? Operation.Name).ToIdentifierName(); } return $"{Client.Type.Name}{operationName}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs index 35d58dea21f..6db80119d68 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputOperation.cs @@ -77,7 +77,7 @@ public InputOperation() : this( /// /// Gets the original name of the operation as defined in the TypeSpec before any mutations. /// - public string OriginalName { get; internal set; } = string.Empty; + public string? OriginalName { get; internal set; } public string? ResourceName { get; internal set; } public string? Summary { get; internal set; } public string? Doc { get; internal set; } From d1f9a287f360061969c02a0b1efa90b97a69e9a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 20:06:41 +0000 Subject: [PATCH 11/11] Revert HasPagingOperationNameCollision to use identifierName parameter Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CollectionResultDefinition.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 dd9491340fc..453815faea3 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 @@ -186,20 +186,20 @@ protected override string BuildName() var operationName = Operation.Name.ToIdentifierName(); // Check if there is another paging operation in the same client whose name would produce a collision. // If so, use the OriginalName to differentiate. - if (HasPagingOperationNameCollision()) + if (HasPagingOperationNameCollision(operationName)) { operationName = (Operation.OriginalName ?? Operation.Name).ToIdentifierName(); } return $"{Client.Type.Name}{operationName}{(IsAsync ? "Async" : "")}CollectionResult{(ItemModelType == null ? "" : "OfT")}"; } - private bool HasPagingOperationNameCollision() + private bool HasPagingOperationNameCollision(string operationName) { var pagingMethods = Client.InputClient.Methods.OfType(); int count = 0; foreach (var method in pagingMethods) { - if (method.Operation.Name == Operation.Name) + if (method.Operation.Name.ToIdentifierName() == operationName) { count++; if (count > 1)