Commit 75e4955
Fix API version enum collisions in multservice clients (#10108)
PR #10061 unconditionally used the full namespace for API version enum
names in multi-service scenarios. This produces unnecessarily verbose
names when services have distinct last namespace segments. This PR
changes the logic to only use the full namespace when there's an actual
collision, and restores the `ClientHelper.BuildNameForService` helper
for proper prefix/suffix-aware naming. The collision-aware naming
applies to all multi-service generated members — enum type names,
version property names, and latest version field names all use
`BuildNameForService` by default, falling back to a segment-by-segment
resolution when last segments collide. The enum type naming follows the
`{X}ServiceVersion` pattern (e.g., `KeyVaultServiceVersion`) rather than
`Service{X}Version`.
When last segments collide, the new
`ClientHelper.GetShortestUniqueNamespacePrefix` method progressively
adds namespace segments from right to left until a unique suffix is
found, producing shorter names than the previous full-namespace
approach. When multiple enums share the exact same full namespace (e.g.,
when the emitter remaps both services to the same C# output namespace),
the enum's input name is appended for disambiguation to prevent
duplicate member names.
### Behavior
| Namespaces | Member | Before (PR #10061) | After (no collision) |
After (last segment collision) | After (full namespace collision) |
|---|---|---|---|---|---|
| `Sample.KeyVault`, `Sample.Storage` | Enum type |
`SampleKeyVaultVersion` | `KeyVaultServiceVersion` | — | — |
| `Sample.KeyVault`, `Sample.Storage` | Version property |
`SampleKeyVaultApiVersion` | `KeyVaultApiVersion` | — | — |
| `Sample.KeyVault`, `Sample.Storage` | Latest field |
`LatestServiceKeyVaultVersion` | `LatestKeyVaultVersion` | — | — |
| `Azure.One.Tests`, `Azure.Two.Tests` | Enum type |
`AzureOneTestsVersion` | — | `ServiceOneTestsVersion` (shortest unique:
2 segments) | — |
| `Azure.One.Tests`, `Azure.Two.Tests` | Version property |
`AzureOneTestsApiVersion` | — | `ServiceOneTestsApiVersion` (shortest
unique: 2 segments) | — |
| Same namespace for both enums | Enum type | — | — | — |
`{Namespace}{EnumName}Version` (disambiguated by input name) |
### Changes
- **`ClientHelper.cs`** — restored `BuildNameForService` helper (removed
in PR #10061) that extracts the last namespace segment and ensures
proper prefix/suffix without duplication; added shared
`GetLastNamespaceSegment` and `HasLastSegmentCollision` static helpers;
added `GetShortestUniqueNamespacePrefix` that progressively adds
segments from right to left until finding a unique suffix, falling back
to appending the enum input name when namespaces are identical
- **`ClientHelperTests.cs`** — restored all 22 tests for
`BuildNameForService`
- **`ApiVersionEnumProvider.BuildName()`** — uses
`ClientHelper.BuildNameForService` with empty prefix and
`"ServiceVersion"` suffix for the non-collision case, producing
`{X}ServiceVersion` names; uses `GetShortestUniqueNamespacePrefix` for
segment-by-segment resolution when last segments collide
- **`ClientOptionsProvider.BuildVersionProperties()`** — uses
`ClientHelper.BuildNameForService` for version property names in the
non-collision case; uses `GetShortestUniqueNamespacePrefix` when last
segments collide
- **`ClientOptionsProvider.BuildLatestVersionsFields()`** — uses
`ClientHelper.BuildNameForService` for latest version field names in the
non-collision case; uses `GetShortestUniqueNamespacePrefix` when last
segments collide
- **Tests** — updated assertions and expected test data files
(ClientOptionsProvider, ClientProvider, RestClientProvider) for member
name changes; added
`MultiServiceClient_WithCollidingLastSegments_UsesShortestUniquePrefix`
test with TestData golden file validation; added
`MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums` test;
added `MultiServiceClient_UniqueNamespaces_ProducesUniqueVersionEnums`
test simulating distinct service namespaces; added
`MultiServiceClient_SameNamespace_ProducesUniqueVersionEnums` test for
the same-namespace scenario where the emitter remaps both services to
the same C# output namespace
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Only Use Full Namespace for Api Version Enum When There
are Conflicts</issue_title>
> <issue_description>Follow up to
#10061.
>
> This PR introduced a change to avoid collisions in the generated api
version enums in the multi-service scenario by using the full namespace
of the enum as the name. We should update this to only do this whenever
there is a collision in the generated names.</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixes #10107
<!-- START COPILOT CODING AGENT TIPS -->
---
📱 Kick off Copilot coding agent tasks wherever you are with [GitHub
Mobile](https://gh.io/cca-mobile-docs), available on iOS and Android.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>1 parent 096443e commit 75e4955
22 files changed
Lines changed: 905 additions & 150 deletions
File tree
- packages/http-client-csharp/generator
- Microsoft.TypeSpec.Generator.ClientModel
- src/Providers
- test/Providers
- ClientProviders
- TestData/ClientProviderTests
- RestClientProviders/TestData/RestClientProviderTests
- TestData/ClientOptionsProviderTests
- Microsoft.TypeSpec.Generator
- src
- Providers
- test
- Providers/EnumProviders
- TestData/ApiVersionEnumProviderTests
Lines changed: 43 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
123 | 124 | | |
124 | 125 | | |
125 | 126 | | |
126 | | - | |
| 127 | + | |
127 | 128 | | |
128 | 129 | | |
129 | 130 | | |
| |||
133 | 134 | | |
134 | 135 | | |
135 | 136 | | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
141 | 157 | | |
142 | 158 | | |
143 | 159 | | |
| |||
161 | 177 | | |
162 | 178 | | |
163 | 179 | | |
164 | | - | |
| 180 | + | |
165 | 181 | | |
166 | | - | |
167 | | - | |
168 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
169 | 202 | | |
170 | 203 | | |
171 | 204 | | |
| |||
Lines changed: 157 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
752 | 752 | | |
753 | 753 | | |
754 | 754 | | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
755 | 912 | | |
756 | 913 | | |
757 | 914 | | |
| |||
Lines changed: 8 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3678 | 3678 | | |
3679 | 3679 | | |
3680 | 3680 | | |
3681 | | - | |
| 3681 | + | |
3682 | 3682 | | |
3683 | 3683 | | |
3684 | 3684 | | |
3685 | 3685 | | |
3686 | | - | |
| 3686 | + | |
3687 | 3687 | | |
3688 | 3688 | | |
3689 | 3689 | | |
| |||
3814 | 3814 | | |
3815 | 3815 | | |
3816 | 3816 | | |
3817 | | - | |
| 3817 | + | |
3818 | 3818 | | |
3819 | 3819 | | |
3820 | 3820 | | |
3821 | | - | |
| 3821 | + | |
3822 | 3822 | | |
3823 | 3823 | | |
3824 | 3824 | | |
| |||
3883 | 3883 | | |
3884 | 3884 | | |
3885 | 3885 | | |
3886 | | - | |
| 3886 | + | |
3887 | 3887 | | |
3888 | 3888 | | |
3889 | 3889 | | |
3890 | 3890 | | |
3891 | 3891 | | |
3892 | 3892 | | |
3893 | 3893 | | |
3894 | | - | |
3895 | | - | |
3896 | | - | |
| 3894 | + | |
| 3895 | + | |
| 3896 | + | |
3897 | 3897 | | |
3898 | 3898 | | |
3899 | 3899 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
48 | | - | |
| 47 | + | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | | - | |
| 64 | + | |
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
0 commit comments