refactor + fix: cut ClonerToExprGenerator complexity, clear Codacy findings, deep clone readonly structs - #5
Merged
Merged
Conversation
… Codacy findings - ClonerToExprGenerator: split GenerateProcessMethod, the 1D/2D/N-D array cloners and the index odometer into small methods; add braces everywhere; drop the dead assignments and commented-out code. Behaviour is unchanged (same results as the original on every test, including the new struct-array case). - ShallowClonerGenerator: braces - Tests: scoped suppressions with reasons for deliberate public fields (S1104, S2357) and a deliberately throwing Equals (S3877); add a 2D struct-array CopyTo test - .codacy.yml: exclude the vendored Imported/ FastDeepCloner comparison code - CLAUDE.md: split the compound boundaries bullet Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 13 |
| Duplication | 2 |
🟢 Coverage 85.00% diff coverage · -0.10% coverage variation
Metric Results Coverage variation ✅ -0.10% coverage variation (-1.00%) Diff coverage ✅ 85.00% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (6966fc5) 1054 862 81.78% Head commit (5077a3a) 1108 (+54) 905 (+43) 81.68% (-0.10%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#5) 160 136 85.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
For a readonly (init-only) field the generated cloner boxed the struct local, wrote the cloned value into the box via FieldInfo.SetValue, and discarded the box, so the clone kept the source's reference. DeepClone and DeepCloneTo of any readonly struct (including readonly record structs), alone, nested in a class, or as array elements, were silently shallow. Box once, set the field on the box, unbox back into the struct local. Classes are unaffected. Adds ReadonlyStructSpec (6 of its 8 tests failed before the fix) and strengthens the 2D struct-array CopyTo test. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Summary
GenerateProcessMethod, the 1D/2D/N-D array cloners and the index odometer into small methods; braces everywhere; removed dead assignments and commented-out code. Behaviour is unchanged.Equals(S3877).codacy.yml: excludes the vendoredImported/FastDeepCloner comparison codeDeepClone/DeepCloneTodid not deep clone reference-type fields of readonly structs (details below)Bug: readonly structs were silently shallow-cloned
DeepClone()andDeepCloneTo()left the reference-type fields of a readonly struct (includingreadonly record struct) pointing at the same objects as the source.It also affected readonly structs holding class instances, nested in a class, and as 1D/2D array elements (
DeepCloneandDeepCloneTo). Mutable structs andShallowClonewere correct, so the trigger is the fields beingreadonly/init-only.Cause: for a readonly field,
DeepClonerExprGenerator.AddFieldCloneExpressionemittedFieldInfo.SetValue(Convert(toLocal, typeof(object)), value). For a structtoLocal,Convertboxes a copy;SetValuewrote the cloned value into the copy, which was then discarded. Both theSetValueandForceSetFieldpaths had this. Classes were unaffected.Fix: box once, set the field on the box, unbox back into the struct local (
SetReadonlyField).Found by exercising the struct branch of the 2D array cloner while refactoring. The original code behaves identically, so this is long-standing, not a regression. (Issues are disabled on this repository, so the write-up lives here.)
Behaviour preserved by the refactor
Swapped the original ClonerToExprGenerator back in and ran the new struct-array test: identical before and after.
Not changed
Test plan
ReadonlyStructSpec: 6 of 8 tests failed before the fix, all pass after🤖 Generated with Claude Code