Fix #672: MultipleInterfaces ByTag method naming scoped per-interface#922
Conversation
📝 WalkthroughWalkthroughTwo files modified to improve nullable property handling and fix method name generation in multi-interface scenarios. A conditional assignment enables nullable properties when nullable reference types are enabled. Per-interface method name tracking replaces global tracking to prevent increments from bleeding across different interface groups. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/Refitter.Core/RefitMultipleInterfaceByTagGenerator.cs`:
- Around line 165-177: The collision check uses IdentifierUtils.Counted(...,
parent: interfaceName) which expects keys formatted with the interface prefix
(e.g., "IUsersApi.GetAll"), but the code then stores only the short name into
the set; update the storage to match the same keyed format used by the collision
check (i.e., when calling interfaceIdentifiers.Add(...) append or compose the
interfaceName prefix the same way Counted expects) so the generated name key
stored in _methodIdentifiersByInterface[interfaceName] matches the format used
by IdentifierUtils.Counted (refer to IdentifierUtils.Counted,
GenerateOperationName, and the
_methodIdentifiersByInterface/interfaceIdentifiers.Add call to locate the
change).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Refitter.Core/CSharpClientGeneratorFactory.cssrc/Refitter.Core/RefitMultipleInterfaceByTagGenerator.cs
| // Initialize per-interface tracking if needed | ||
| if (!_methodIdentifiersByInterface!.ContainsKey(interfaceName)) | ||
| { | ||
| _methodIdentifiersByInterface[interfaceName] = new HashSet<string>(); | ||
| } | ||
|
|
||
| var interfaceIdentifiers = _methodIdentifiersByInterface[interfaceName]; | ||
| var generatedName = IdentifierUtils.Counted( | ||
| interfaceIdentifiers, | ||
| GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true), | ||
| parent: interfaceName); | ||
|
|
||
| interfaceIdentifiers.Add(generatedName); |
There was a problem hiding this comment.
Method-collision detection is broken by mismatched identifier keys.
At Line 172, IdentifierUtils.Counted(...) is called with parent: interfaceName, so it checks keys like IUsersApi.GetAll.
But at Line 177, the set stores only GetAll. This means duplicates in the same interface won’t be detected.
🐛 Proposed fix
- var generatedName = IdentifierUtils.Counted(
- interfaceIdentifiers,
- GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true),
- parent: interfaceName);
+ var generatedName = IdentifierUtils.Counted(
+ interfaceIdentifiers,
+ GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true));This keeps collision checks and stored identifiers in the same format.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Initialize per-interface tracking if needed | |
| if (!_methodIdentifiersByInterface!.ContainsKey(interfaceName)) | |
| { | |
| _methodIdentifiersByInterface[interfaceName] = new HashSet<string>(); | |
| } | |
| var interfaceIdentifiers = _methodIdentifiersByInterface[interfaceName]; | |
| var generatedName = IdentifierUtils.Counted( | |
| interfaceIdentifiers, | |
| GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true), | |
| parent: interfaceName); | |
| interfaceIdentifiers.Add(generatedName); | |
| // Initialize per-interface tracking if needed | |
| if (!_methodIdentifiersByInterface!.ContainsKey(interfaceName)) | |
| { | |
| _methodIdentifiersByInterface[interfaceName] = new HashSet<string>(); | |
| } | |
| var interfaceIdentifiers = _methodIdentifiersByInterface[interfaceName]; | |
| var generatedName = IdentifierUtils.Counted( | |
| interfaceIdentifiers, | |
| GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true)); | |
| interfaceIdentifiers.Add(generatedName); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Refitter.Core/RefitMultipleInterfaceByTagGenerator.cs` around lines 165 -
177, The collision check uses IdentifierUtils.Counted(..., parent:
interfaceName) which expects keys formatted with the interface prefix (e.g.,
"IUsersApi.GetAll"), but the code then stores only the short name into the set;
update the storage to match the same keyed format used by the collision check
(i.e., when calling interfaceIdentifiers.Add(...) append or compose the
interfaceName prefix the same way Counted expects) so the generated name key
stored in _methodIdentifiersByInterface[interfaceName] matches the format used
by IdentifierUtils.Counted (refer to IdentifierUtils.Counted,
GenerateOperationName, and the
_methodIdentifiersByInterface/interfaceIdentifiers.Add call to locate the
change).
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #672, where MultipleInterfaces.ByTag was incorrectly using a single global HashSet<string> to track method name collisions across all generated interfaces, causing numeric suffixes (e.g., GetAll2, GetAll3) to be appended globally rather than per-interface.
Changes:
- Introduces per-interface method identifier tracking via a
Dictionary<string, HashSet<string>>inRefitMultipleInterfaceByTagGenerator - Adds an
elsebranch to correctly retrieve the existinginterfaceNamefor subsequent operations in the same tag group (fixing a pre-existingnull!issue) - Adds an unrelated auto-enablement of
GenerateOptionalPropertiesAsNullablewhenGenerateNullableReferenceTypesis enabled inCSharpClientGeneratorFactory
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/Refitter.Core/RefitMultipleInterfaceByTagGenerator.cs |
Replaces global identifier set with per-interface dictionary; adds missing else branch to retrieve existing interface name |
src/Refitter.Core/CSharpClientGeneratorFactory.cs |
Unrelated change: auto-enables GenerateOptionalPropertiesAsNullable when NRT is on |
The review found the following issues:
Critical bug in RefitMultipleInterfaceByTagGenerator.cs line 177: The new code calls interfaceIdentifiers.Add(generatedName) storing just the bare method name (e.g., "GetAll"). However, IdentifierUtils.Counted looks for $"{parent}.{name}" (e.g., "IFooApi.GetAll") in the set when parent is non-empty. Because the stored key doesn't match the lookup pattern, intra-interface duplicate detection is fully broken — two operations within the same interface that map to the same name will both be returned as "GetAll", causing a compilation error in the generated code. The fix requires storing $"{interfaceName}.{generatedName}" to match the original pattern (and how GetInterfaceName still correctly stores generatedName in knownIdentifiers because that call uses no parent).
Unrelated and undocumented behavioral change in CSharpClientGeneratorFactory.cs lines 65–69: The GenerateOptionalPropertiesAsNullable = true auto-enable is not mentioned in the PR description and silently changes behavior for all users who have GenerateNullableReferenceTypes = true. Since MapCSharpGeneratorSettings skips default-valued properties (default for GenerateOptionalPropertiesAsNullable is false), a user cannot opt out of this auto-override.
Missing test coverage: No test exercises the exact scenario in #672 (same operation name generated for two different tag-grouped interfaces), meaning the per-interface scoping fix is not validated by any test in the suite.
| GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true), | ||
| parent: interfaceName); | ||
|
|
||
| interfaceIdentifiers.Add(generatedName); |
There was a problem hiding this comment.
The interfaceIdentifiers.Add(generatedName) call stores only the bare method name (e.g., "GetAll"), but IdentifierUtils.Counted checks for the qualified form $"{parent}.{name}" (e.g., "IFooApi.GetAll") when parent is non-empty. Because the stored key never matches what the lookup expects, intra-interface duplicate detection is broken: if two operations within the same interface resolve to the same name, Counted will return the same name twice rather than appending a counter. The fix is to store the qualified form $"{interfaceName}.{generatedName}" to match the original pattern, as was done before this change.
| interfaceIdentifiers.Add(generatedName); | |
| interfaceIdentifiers.Add($"{interfaceName}.{generatedName}"); |
| // Auto-enable optional properties as nullable when nullable reference types enabled | ||
| if (generator.Settings.CSharpGeneratorSettings.GenerateNullableReferenceTypes) | ||
| { | ||
| generator.Settings.CSharpGeneratorSettings.GenerateOptionalPropertiesAsNullable = true; | ||
| } |
There was a problem hiding this comment.
This change silently overrides the user's GenerateOptionalPropertiesAsNullable setting whenever GenerateNullableReferenceTypes is enabled, with no way for the user to opt out. Since MapCSharpGeneratorSettings skips properties that match the default value (false), a user who explicitly wants GenerateOptionalPropertiesAsNullable = false while using GenerateNullableReferenceTypes = true cannot prevent this override. This is a breaking behavioral change for existing users who have GenerateNullableReferenceTypes = true. The PR description does not mention this change at all — it only describes the ByTag method naming fix — making it even harder for users to anticipate this new behavior. This change should either be reverted if unintentional, or at minimum, it should only apply when the user has not explicitly set GenerateOptionalPropertiesAsNullable in their settings.
| private string GetOperationName( | ||
| string interfaceName, | ||
| string name, | ||
| string verb, | ||
| OpenApiOperation operation) | ||
| { | ||
| var generatedName = IdentifierUtils.Counted(knownIdentifiers, GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true), parent: interfaceName); | ||
| knownIdentifiers.Add($"{interfaceName}.{generatedName}"); | ||
| // Initialize per-interface tracking if needed | ||
| if (!_methodIdentifiersByInterface!.ContainsKey(interfaceName)) | ||
| { | ||
| _methodIdentifiersByInterface[interfaceName] = new HashSet<string>(); | ||
| } | ||
|
|
||
| var interfaceIdentifiers = _methodIdentifiersByInterface[interfaceName]; | ||
| var generatedName = IdentifierUtils.Counted( | ||
| interfaceIdentifiers, | ||
| GenerateOperationName(name, verb, operation, capitalizeFirstCharacter: true), | ||
| parent: interfaceName); | ||
|
|
||
| interfaceIdentifiers.Add(generatedName); | ||
| return generatedName; | ||
| } |
There was a problem hiding this comment.
There are no tests covering the exact scenario described in issue #672: multiple interfaces (from different tags) that each have an operation resolving to the same method name. The existing tests only use unique operation IDs across all tags, so the per-interface scoping fix is never exercised. A regression test should be added with two tags both containing an endpoint that would produce the same generated operation name (e.g., the same operationId or same verb/path pattern) to verify that both interfaces produce GetAll() instead of one getting GetAll() and the other GetAll2().
| internal class RefitMultipleInterfaceByTagGenerator : RefitInterfaceGenerator | ||
| { | ||
| private readonly HashSet<string> knownIdentifiers = new(); | ||
| private Dictionary<string, HashSet<string>>? _methodIdentifiersByInterface; |
There was a problem hiding this comment.
The existing private field knownIdentifiers uses camelCase without an underscore prefix, but the new field _methodIdentifiersByInterface uses the _camelCase convention with a leading underscore. These two private fields in the same class follow inconsistent naming conventions. The new field should be renamed to methodIdentifiersByInterface to be consistent with the existing codebase convention in this file.
|
Oh sweet you eventually got around to implementing this on your own. Sorry I kinda abandoned my attempt, life kept getting in the way. |
I know exactly what you mean |
Updated [refitter](https://github.com/christianhelle/refitter) from 1.7.1 to 2.0.0. <details> <summary>Release notes</summary> _Sourced from [refitter's releases](https://github.com/christianhelle/refitter/releases)._ ## 2.0.0 ## What's Changed * Fix numeric format with pattern quirk - infer type from format for all numeric types by @Copilot in christianhelle/refitter#869 * Read group documentation from document tags. by @DJ4ddi in christianhelle/refitter#887 * Fix null reference and XML escaping in XmlDocumentationGenerator by @Copilot in christianhelle/refitter#890 * Fix build workflow: add dotnet restore before dotnet msbuild in Prepare step by @Copilot in christianhelle/refitter#892 christianhelle/refitter#895 * Fix MSBuild workflow by @christianhelle in christianhelle/refitter#898 * Add support for generating a single client from multiple OpenAPI specifications by @Copilot in christianhelle/refitter#904 * Migrate from Microsoft.OpenApi.Readers 1.x to Microsoft.OpenApi 3.x by @vgmello in christianhelle/refitter#907 * Improve Smoke Tests execution time by @christianhelle in christianhelle/refitter#915 * Fix #580: Nullable strings marked correctly by @christianhelle in christianhelle/refitter#921 * Fix #672: MultipleInterfaces ByTag method naming scoped per-interface by @christianhelle in christianhelle/refitter#922 * Fix #635: Refactor source generator to use context.AddSource() by @christianhelle in christianhelle/refitter#923 * Add custom format mappings configuration by @christianhelle in christianhelle/refitter#927 * Fix multipart form-data parameter extraction by @christianhelle in christianhelle/refitter#928 christianhelle/refitter#911 christianhelle/refitter#902 * Fix smoke tests: --interface-only variant missing using directive for contract types by @Copilot in christianhelle/refitter#933 * Fix SonarCloud Code Quality Issues by @Copilot in christianhelle/refitter#932 * Add debug logging for source generator when searching for .refitter files by @codymullins in christianhelle/refitter#743 * Fix: Base type not generated for types using oneOf with discriminator by @Copilot in christianhelle/refitter#906 * Add option for Method Level Authorization header attribute by @Roflincopter in christianhelle/refitter#897 * Fix PR #897 review feedback and add comprehensive bearer auth tests by @christianhelle in christianhelle/refitter#936 * Fix numeric suffix added to interface method names in ByTag mode by @Copilot in christianhelle/refitter#914 * Improve OpenAPI parse + codegen throughput by removing avoidable allocations and repeated regex work by @Copilot in christianhelle/refitter#937 * Move [JsonConverter] from enum properties to enum types by @christianhelle in christianhelle/refitter#938 * Fix broken CLI tool help text by @christianhelle in christianhelle/refitter#940 * Improve code coverage to >90% by @christianhelle in christianhelle/refitter#941 * Microsoft.OpenApi v3.4 by @christianhelle in christianhelle/refitter#945 * Add Unicode support for XML doc comment generation by @christianhelle in christianhelle/refitter#948 * Add PropertyNamingPolicy support for JSON property naming by @christianhelle in christianhelle/refitter#969 christianhelle/refitter#966 * Fix recursive schema stack overflows by @christianhelle in christianhelle/refitter#971 * Made Header Parameters for Security Schemes safe to use as C# variable name by @smoerijf in christianhelle/refitter#977 * Enhance schema alias handling and property name generation by @christianhelle in christianhelle/refitter#996 * Verify alias handling and sanitize PascalCase properties by @christianhelle in christianhelle/refitter#997 * Harden .refitter settings deserialization and output path handling by @christianhelle in christianhelle/refitter#1000 * Special-case the default .refitter filename before deriving OutputFilename by @coderabbitai[bot] in christianhelle/refitter#1002 * [v2.0 audit] Fix pre-release regressions from #1057 by @christianhelle in christianhelle/refitter#1064 * Resolve high-severity audit findings from #1057 by @christianhelle in christianhelle/refitter#1067 * [v2.0 audit] Close remaining verified #1057 regressions by @christianhelle in christianhelle/refitter#1070 * Harden generation flows by @christianhelle in christianhelle/refitter#1071 * Breaking changes and Migration Guide for v2.0.0 by @christianhelle in christianhelle/refitter#1009 * Handle equivalent duplicate schemas in multi-spec merge by @christianhelle in christianhelle/refitter#1076 * Tighten warning handling across Refitter builds by @christianhelle in christianhelle/refitter#1079 * Fix default solution path and update .NET version in VS Code config by @christianhelle in christianhelle/refitter#1082 * Fix docker smoke tests by @christianhelle in christianhelle/refitter#1081 * Sanitize malformed schema type names without renaming clean schemas by @christianhelle in christianhelle/refitter#1085 ... (truncated) ## 1.7.3 ## What's Changed * Add support for systems running only .NET 10.0 (without .NET 8.0 or 9.0) in Refitter.MSBuild by @christianhelle in christianhelle/refitter#882 * Update to return HttpResponseMessage for file downloads by @frogcrush in christianhelle/refitter#877 ## New Contributors * @frogcrush made their first contribution in christianhelle/refitter#877 **Full Changelog**: christianhelle/refitter@1.7.2...1.7.3 ## 1.7.2 **Implemented enhancements:** - Improve Immutable Records ergonomics [\#844](christianhelle/refitter#844) - Omit certain operation headers and include all others [\#840](christianhelle/refitter#840) - Create .refitter settings file as part of output [\#859](christianhelle/refitter#859) by @[christianhelle - Fix integerType enum deserialization issue [\#855](christianhelle/refitter#855) ([christianhelle](https://github.com/christianhelle)) - support custom nswag template directory \#844 [\#854](christianhelle/refitter#854) by @kmc059000 - Fix missing method parameter XML code-documentation [\#850](christianhelle/refitter#850) ([christianhelle](https://github.com/christianhelle)) **Fixed bugs:** - integerType parsing in settings file fails [\#851](christianhelle/refitter#851) - CS1573 : Method parameter has no matching XML comment [\#846](christianhelle/refitter#846) **Merged pull requests:** - docs: add frogcrush as a contributor for code [\#878](christianhelle/refitter#878) ([allcontributors[bot]](https://github.com/apps/allcontributors)) - Migrate solution files from .sln to .slnx format [\#876](christianhelle/refitter#876) ([Copilot](https://github.com/apps/copilot-swe-agent)) - Fix issue with randomly failing tests to due parallel execution [\#872](christianhelle/refitter#872) ([christianhelle](https://github.com/christianhelle)) - chore\(deps\): update dependency tunit to 1.9.2 [\#863](christianhelle/refitter#863) ([renovate[bot]](https://github.com/apps/renovate)) - chore\(deps\): update dependency tunit to 1.7.7 [\#862](christianhelle/refitter#862) ([renovate[bot]](https://github.com/apps/renovate)) - Add unit tests for WriteRefitterSettingsFile functionality [\#860](christianhelle/refitter#860) ([Copilot](https://github.com/apps/copilot-swe-agent)) - chore\(deps\): update dependency ruby to v4 [\#858](christianhelle/refitter#858) ([renovate[bot]](https://github.com/apps/renovate)) - chore\(deps\): update dependency tunit to 1.6.28 [\#857](christianhelle/refitter#857) ([renovate[bot]](https://github.com/apps/renovate)) - docs: add 0x2badc0de as a contributor for bug [\#856](christianhelle/refitter#856) ([allcontributors[bot]](https://github.com/apps/allcontributors)) - chore\(deps\): update dependency swashbuckle.aspnetcore to 10.1.0 [\#853](christianhelle/refitter#853) ([renovate[bot]](https://github.com/apps/renovate)) - chore\(deps\): update dependency tunit to 1.6.0 [\#852](christianhelle/refitter#852) ([renovate[bot]](https://github.com/apps/renovate)) - docs: add lilinus as a contributor for code [\#849](christianhelle/refitter#849) ([allcontributors[bot]](https://github.com/apps/allcontributors)) - chore\(deps\): update dependency ruby to v3.4.8 [\#845](christianhelle/refitter#845) ([renovate[bot]](https://github.com/apps/renovate)) - chore\(deps\): update dependency tunit to 1.5.70 [\#837](christianhelle/refitter#837) ([renovate[bot]](https://github.com/apps/renovate)) **Full Changelog**: christianhelle/refitter@1.7.1...1.7.2 Commits viewable in [compare view](christianhelle/refitter@1.7.1...2.0.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updated [Refitter.MSBuild](https://github.com/christianhelle/refitter) from 1.7.3 to 2.0.0. <details> <summary>Release notes</summary> _Sourced from [Refitter.MSBuild's releases](https://github.com/christianhelle/refitter/releases)._ ## 2.0.0 ## What's Changed * Fix numeric format with pattern quirk - infer type from format for all numeric types by @Copilot in christianhelle/refitter#869 * Read group documentation from document tags. by @DJ4ddi in christianhelle/refitter#887 * Fix null reference and XML escaping in XmlDocumentationGenerator by @Copilot in christianhelle/refitter#890 * Fix build workflow: add dotnet restore before dotnet msbuild in Prepare step by @Copilot in christianhelle/refitter#892 christianhelle/refitter#895 * Fix MSBuild workflow by @christianhelle in christianhelle/refitter#898 * Add support for generating a single client from multiple OpenAPI specifications by @Copilot in christianhelle/refitter#904 * Migrate from Microsoft.OpenApi.Readers 1.x to Microsoft.OpenApi 3.x by @vgmello in christianhelle/refitter#907 * Improve Smoke Tests execution time by @christianhelle in christianhelle/refitter#915 * Fix #580: Nullable strings marked correctly by @christianhelle in christianhelle/refitter#921 * Fix #672: MultipleInterfaces ByTag method naming scoped per-interface by @christianhelle in christianhelle/refitter#922 * Fix #635: Refactor source generator to use context.AddSource() by @christianhelle in christianhelle/refitter#923 * Add custom format mappings configuration by @christianhelle in christianhelle/refitter#927 * Fix multipart form-data parameter extraction by @christianhelle in christianhelle/refitter#928 christianhelle/refitter#911 christianhelle/refitter#902 * Fix smoke tests: --interface-only variant missing using directive for contract types by @Copilot in christianhelle/refitter#933 * Fix SonarCloud Code Quality Issues by @Copilot in christianhelle/refitter#932 * Add debug logging for source generator when searching for .refitter files by @codymullins in christianhelle/refitter#743 * Fix: Base type not generated for types using oneOf with discriminator by @Copilot in christianhelle/refitter#906 * Add option for Method Level Authorization header attribute by @Roflincopter in christianhelle/refitter#897 * Fix PR #897 review feedback and add comprehensive bearer auth tests by @christianhelle in christianhelle/refitter#936 * Fix numeric suffix added to interface method names in ByTag mode by @Copilot in christianhelle/refitter#914 * Improve OpenAPI parse + codegen throughput by removing avoidable allocations and repeated regex work by @Copilot in christianhelle/refitter#937 * Move [JsonConverter] from enum properties to enum types by @christianhelle in christianhelle/refitter#938 * Fix broken CLI tool help text by @christianhelle in christianhelle/refitter#940 * Improve code coverage to >90% by @christianhelle in christianhelle/refitter#941 * Microsoft.OpenApi v3.4 by @christianhelle in christianhelle/refitter#945 * Add Unicode support for XML doc comment generation by @christianhelle in christianhelle/refitter#948 * Add PropertyNamingPolicy support for JSON property naming by @christianhelle in christianhelle/refitter#969 christianhelle/refitter#966 * Fix recursive schema stack overflows by @christianhelle in christianhelle/refitter#971 * Made Header Parameters for Security Schemes safe to use as C# variable name by @smoerijf in christianhelle/refitter#977 * Enhance schema alias handling and property name generation by @christianhelle in christianhelle/refitter#996 * Verify alias handling and sanitize PascalCase properties by @christianhelle in christianhelle/refitter#997 * Harden .refitter settings deserialization and output path handling by @christianhelle in christianhelle/refitter#1000 * Special-case the default .refitter filename before deriving OutputFilename by @coderabbitai[bot] in christianhelle/refitter#1002 * [v2.0 audit] Fix pre-release regressions from #1057 by @christianhelle in christianhelle/refitter#1064 * Resolve high-severity audit findings from #1057 by @christianhelle in christianhelle/refitter#1067 * [v2.0 audit] Close remaining verified #1057 regressions by @christianhelle in christianhelle/refitter#1070 * Harden generation flows by @christianhelle in christianhelle/refitter#1071 * Breaking changes and Migration Guide for v2.0.0 by @christianhelle in christianhelle/refitter#1009 * Handle equivalent duplicate schemas in multi-spec merge by @christianhelle in christianhelle/refitter#1076 * Tighten warning handling across Refitter builds by @christianhelle in christianhelle/refitter#1079 * Fix default solution path and update .NET version in VS Code config by @christianhelle in christianhelle/refitter#1082 * Fix docker smoke tests by @christianhelle in christianhelle/refitter#1081 * Sanitize malformed schema type names without renaming clean schemas by @christianhelle in christianhelle/refitter#1085 ... (truncated) Commits viewable in [compare view](christianhelle/refitter@1.7.3...2.0.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>



Fixes #672: MultipleInterfaces ByTag increments method names globally
Problem:
When using
--multiple-interfaces ByTag, method names were getting global numericsuffixes across all interfaces instead of being scoped per-interface.
Example:
Root Cause:
Single global
HashSet<string> knownIdentifierswas used for all interfaces.Method name collision detection needs to be per-interface, not global.
Solution:
Implemented per-interface scoped identifier tracking using a Dictionary of HashSets.
Each interface now tracks its own method names for conflict resolution independently.
Changes:
Validation:
✅ Each interface has methods like GetAll() without global counter
✅ No GetAll2, GetAll3 across different interfaces
✅ Generated code compiles
✅ Build succeeds
Summary by CodeRabbit