fix: name generated helper types per assembly to avoid InternalsVisibleTo conflicts#2257
Merged
Merged
Conversation
…leTo conflicts - Fold the sanitized, Pascal-cased assembly name into the generated implementation container type and the internal PreserveAttribute namespace, so each assembly emits distinctly named copies instead of the shared Refit.Implementation.Generated and RefitInternalGenerated names that collide under [InternalsVisibleTo] (CS0436) - Reconstruct the identical container name in UniqueName.ForType with a runtime sanitizer that mirrors the generator, keeping reflection resolution and the derived IHttpClientFactory client key in sync - Wrap the generated factory registrations and DynamicDependency attribute so emitted lines stay within the line-length limit for long assembly names - Add a two-assembly InternalsVisibleTo generator test (no duplicate-type diagnostic), a reflection-resolution parity test, and sanitizer tests Closes #2254
glennawatson
force-pushed
the
fix/generated-type-ivt-collision
branch
from
July 18, 2026 04:32
1bb964f to
e3d6992
Compare
… instead - remove the upper-casing transform from the generator and UniqueName sanitizers; real assembly names are already PascalCase, and the transform only existed to prettify the lowercase test default - name the generator test compilation `Compilation` (via nameof) so the scoped output stays PascalCase with no production transform; generated output is byte-identical (snapshots unchanged) - update the sanitizer expectations to the preserved-case form
- UnnamedCompilationEmitsUnscopedContainerName joined generated sources with \n but each source keeps CRLF on Windows runners, so the "...RefitInternalGenerated\n" needle never matched there - Replace CRLF with LF on the joined output so the assertion holds on both Windows and Linux; test-only, generator emission unchanged
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2257 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 183 184 +1
Lines 9566 9600 +34
Branches 1803 1810 +7
=========================================
+ Hits 9566 9600 +34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
ChrisPulman
approved these changes
Jul 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What kind of change does this PR introduce?
Bug fix (source generator + runtime).
What is the new behavior?
PreserveAttributenamespace, so each assembly emits distinctly named copies (e.g.Refit.Implementation.GeneratedMyApp).[InternalsVisibleTo]that both use Refit now compile cleanly.UniqueName.ForTypereconstructs the identical container name at runtime (its own sanitizer, mirroring the generator), so reflection-based resolution and the derivedIHttpClientFactoryclient key stay in sync with the emitted code.What is the current behavior?
Every assembly emitted the same
Refit.Implementation.Generatedcontainer andRefitInternalGenerated.PreserveAttribute. Under[InternalsVisibleTo]the second compilation imported those alongside the ones it generated, producingCS0436duplicate-type warnings that fail aTreatWarningsAsErrorsbuild.Closes #2254
What might this PR break?
UniqueName.ForType<T>()(and theIHttpClientFactoryclient key derived from it) returns a different string - it now includes the interface's assembly name. The value is computed at runtime, never hardcoded, so no consumer code change is needed. v14 is still beta.Checklist
mainbranchAdditional information
The scope segment maps every non-identifier character to
_and upper-cases the first character; a null/blank assembly name yields no segment (unnamed compilations keep the historicGeneratedname). The generator builds it and the runtimeUniqueNamereconstructs it independently - a mirrored pair guarded by a parity test that resolves a generic interface against the real emitted assembly.dotnet test -c Releasefrom./src: 7065 passed, 0 failed (net8-net11);UniqueName.csis 100 percent line and branch.