From 50ca837c395b51b2c8e4b9efa7173197edfd4a2d Mon Sep 17 00:00:00 2001 From: Jorge Rangel Date: Mon, 10 Aug 2026 12:05:24 -0500 Subject: [PATCH] fix: fallback to positional match for back compat renames --- .../src/Utilities/BackCompatHelper.cs | 7 +---- ...ynthesizedParameterNameBySignatureMatch.cs | 15 ++++++++++ .../TestClient.cs | 7 +++++ .../test/Providers/TypeProviderTests.cs | 30 +++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch/TestClient.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs index 000c664e000..e96b86918d2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs @@ -184,13 +184,8 @@ public static void RestorePreviousParameterNames( string? preservedName = null; var inputParameter = parameter.InputParameter; - if (inputParameter is not null) + if (inputParameter is not null && string.Equals(parameter.Name, inputParameter.Name, StringComparison.Ordinal)) { - if (!string.Equals(parameter.Name, inputParameter.Name, StringComparison.Ordinal)) - { - continue; - } - var originalName = inputParameter.OriginalName; if (!string.IsNullOrEmpty(originalName)) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch.cs new file mode 100644 index 00000000000..23272d7bc0b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch.cs @@ -0,0 +1,15 @@ +// + +#nullable disable + +namespace Test +{ + public partial class TestClient + { + public string Foo(string defaultName) + { + this.Validate(defaultName); + return defaultName; + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch/TestClient.cs new file mode 100644 index 00000000000..4b06d37c36d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch/TestClient.cs @@ -0,0 +1,7 @@ +namespace Test +{ + public class TestClient + { + public string Foo(string defaultName) { return null; } + } +} \ No newline at end of file diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs index 0d702ffcc2f..4a2148af136 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs @@ -970,6 +970,36 @@ public async Task BuildMethodsForBackCompatibilityRestoresRenamedParameterBySign Assert.AreEqual(Helpers.GetExpectedFromFile(), actual); } + // Validates that synthesized parameters retain the positional fallback even when their public name + // differs from the InputParameter they originated from. + [Test] + public async Task BuildMethodsForBackCompatibilityRestoresSynthesizedParameterNameBySignatureMatch() + { + await MockHelpers.LoadMockGeneratorAsync(lastContractCompilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var inputParameter = InputFactory.QueryParameter("wireName", InputPrimitiveType.String, isRequired: true); + var parameter = new ParameterProvider( + "default", + $"", + new CSharpType(typeof(string)), + inputParameter: inputParameter); + var fooMethod = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public, new CSharpType(typeof(string)), $"", [parameter]), + new MethodBodyStatement[] + { + Snippet.This.Invoke("Validate", parameter).Terminate(), + Snippet.Return(parameter), + }, + new TestTypeProvider()); + + var typeProvider = new TestTypeProvider(name: "TestClient", methods: [fooMethod]); + + typeProvider.ProcessTypeForBackCompatibility(); + + var actual = new TypeProviderWriter(typeProvider).Write().Content; + Assert.AreEqual(Helpers.GetExpectedFromFile(), actual); + } + // When the restored name is used both as an argument (AsArgument -> _asArgument) and // as a variable (-> _asVariable), materializing both cached expressions before the rename, the // rename must keep them sharing one declaration. Otherwise the writer renames the two