Repository: microsoft/kiota (csharp)

Issue:
Endpoints with difference only in return types are resulting in error for C# generator
I have an OpenAPI specification for TeamCity.
For example, here https://teamcity.jetbrains.com/guestAuth/app/rest/swagger.json

It compiles with error.
`  WithPathRequestBuilder.cs(60, 40): [CS0111] Type 'WithPathRequestBuilder' already defines a member called 'GetAsync' with the same parameter types`.
Generated C# code is not valid:
```csharp
        /// <summary>
        /// Get specific file zipped.
        /// </summary>
        /// <returns>A <see cref="Stream"/></returns>
        /// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
        /// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
        public async Task<Stream?> GetAsync(Action<RequestConfiguration<WithPathRequestBuilderGetQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
        {
            var requestInfo = ToGetRequestInformation(requestConfiguration);
            return await RequestAdapter.SendPrimitiveAsync<Stream>(requestInfo, default, cancellationToken).ConfigureAwait(false);
        }
        /// <summary>
        /// Get metadata of specific file.
        /// </summary>
        /// <returns>A <see cref="FileObject"/></returns>
        /// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
        /// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
        public async Task<FileObject?> GetAsync(Action<RequestConfiguration<WithPathRequestBuilderGetQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
        {
            var requestInfo = ToGetRequestInformation(requestConfiguration);
            return await RequestAdapter.SendAsync<FileObject>(requestInfo, FileObject.CreateFromDiscriminatorValue, default, cancellationToken).ConfigureAwait(false);
        }
```
C# can't have overloads with difference only in return type,

Pull request:
Fixes https://github.com/microsoft/kiota/issues/4448

`CleanupParametersFromPath` removes prefixes causing request builder collisions in scenario such as `metadata{path}` and `{path}` segments end up being mapped to the same request builder rather two separate ones.

This PR therefore improves the cleanup logic to include the prefix in scenarios where the prefix is not a parameter name(`=` is present) to improve the disambiguation and unlock generation of the description at https://teamcity.jetbrains.com/guestAuth/app/rest/swagger.json

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f008adb45..c717546586 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixed a bug where TypeScript deserialization would fail on Uppercase properties.[#4479](https://github.com/microsoft/kiota/issues/4479)
 - Changed URI template generation to reuse templates when required templates are absent across operations.
 - Updated reserved name providers for Java and Php so that "object" can be escaped.
+- Fixes request builder disambiguation when child nodes had different prefixes for different paths with same parameters.[#4448](https://github.com/microsoft/kiota/issues/4448) 
 - Do not generate CS8603 warnings when enabling backing store in CSharp generation.
 
 ## [1.13.0] - 2024-04-04
diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
index ba925d728b..c90136b87f 100644
--- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
+++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
@@ -40,7 +40,7 @@ public static string GetNodeNamespaceFromPath(this OpenApiUrlTreeNode currentNod
         return currentNode.Path.GetNamespaceFromPath(prefix);
     }
     //{id}, name(idParam={id}), name(idParam='{id}'), name(idParam='{id}',idParam2='{id2}')
-    [GeneratedRegex(@"(?:\w+)?=?'?\{(?<paramName>\w+)\}'?,?", RegexOptions.Singleline, 500)]
+    [GeneratedRegex(@"(?<prefix>\w+)?(?<equals>=?)'?\{(?<paramName>\w+)\}'?,?", RegexOptions.Singleline, 500)]
     private static partial Regex PathParametersRegex();
     // microsoft.graph.getRoleScopeTagsByIds(ids=@ids)
     [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 500)]
@@ -51,8 +51,10 @@ public static string GetNodeNamespaceFromPath(this OpenApiUrlTreeNode currentNod
     private const string RequestParametersSectionEndChar = ")";
     private const string WithKeyword = "With";
     private static readonly MatchEvaluator requestParametersMatchEvaluator = match =>
-        WithKeyword + match.Groups["paramName"].Value.ToFirstCharacterUpperCase();
-    private static string CleanupParametersFromPath(string pathSegment)
+        string.IsNullOrEmpty(match.Groups["equals"].Value) ?
+            match.Groups["prefix"].Value + WithKeyword + match.Groups["paramName"].Value.ToFirstCharacterUpperCase() :
+            WithKeyword + match.Groups["paramName"].Value.ToFirstCharacterUpperCase();
+    internal static string CleanupParametersFromPath(string pathSegment)
     {
         if (string.IsNullOrEmpty(pathSegment))
             return pathSegment;
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 5b7c2b6f0f..e067f7157e 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -705,7 +705,7 @@ private static void AddPathParametersToMethod(OpenApiUrlTreeNode currentNode, Co
                 Optional = asOptional,
                 Documentation = new()
                 {
-                    DescriptionTemplate = parameter.Description.CleanupDescription(),
+                    DescriptionTemplate = !string.IsNullOrEmpty(parameter.Description) ? parameter.Description.CleanupDescription() : $"The path parameter: {codeName}",
                 },
                 Kind = CodeParameterKind.Path,
                 SerializationName = parameter.Name.Equals(codeName, StringComparison.OrdinalIgnoreCase) ? string.Empty : parameter.Name.SanitizeParameterNameForUrlTemplate(),


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs
index dba74a113f..99fa6e6662 100644
--- a/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs
+++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs
@@ -1072,6 +1072,23 @@ public void repro4085()
         Assert.Equal("\\path\\{differentThingId-id}", differentThingId.Path);
         Assert.Equal("{+baseurl}/path/{differentThingId%2Did}", differentThingId.GetUrlTemplate());
     }
+
+    [Theory]
+    [InlineData("{path}", "WithPath")]
+    [InlineData("archived{path}", "archivedWithPath")]
+    [InlineData("files{path}", "filesWithPath")]
+    [InlineData("name(idParam='{id}')", "nameWithId")]
+    [InlineData("name(idParam={id})", "nameWithId")]
+    [InlineData("name(idParamFoo={id})", "nameWithId")] // The current implementation only uses the placeholder i.e {id} for the naming to ignore `idParamFoo`
+                                                        // and thus generates the same identifier as the previous case. This collision risk is unlikely and constrained to an odata service scenario
+                                                        // which would be invalid for functions scenario(overloads with the same parameters))
+    [InlineData("name(idParam='{id}',idParam2='{id2}')", "nameWithIdWithId2")]
+    public void CleanupParametersFromPathGeneratesDifferentResultsWithPrefixPresent(string segmentName, string expectedIdentifer)
+    {
+        var result = OpenApiUrlTreeNodeExtensions.CleanupParametersFromPath(segmentName);
+        Assert.Equal(expectedIdentifer, result);
+    }
+
     private static OpenApiUrlTreeNode GetChildNodeByPath(OpenApiUrlTreeNode node, string path)
     {
         var pathSegments = path.Split('/');