Skip to content

fix: guard nullable paths in existing target mappings#2373

Open
AmirTahan80 wants to merge 1 commit into
riok:mainfrom
AmirTahan80:fix/2303-nested-readonly-list-null-check
Open

fix: guard nullable paths in existing target mappings#2373
AmirTahan80 wants to merge 1 commit into
riok:mainfrom
AmirTahan80:fix/2303-nested-readonly-list-null-check

Conversation

@AmirTahan80

Copy link
Copy Markdown

Fixes #2303.

Summary

Existing-target mappings for nested collections could dereference a nullable intermediate source member while evaluating the generated null guard. For example, Mapperly generated source.Nested.Items != null, which throws when source.Nested is null.

Root cause

MemberExistingTargetMapping passed the same direct member-access expression to both the null guard and the mapping body. The mapping body should use direct access after the guard has succeeded, but the guard itself needs null-conditional access across nullable intermediate members.

Changes

  • Allow NullDelegateExistingTargetMapping to receive a separate source expression for its null check.
  • Build that guard expression with null-conditional member access in MemberExistingTargetMapping.
  • Keep direct source access inside the guarded mapping body, preserving non-null flow and avoiding redundant conditional access.
  • Add regression coverage for both disabled-nullability code and nullable-aware code.

Impact

Generated mappings now safely check paths such as source.Nested?.Items before populating an existing readonly target collection. When an intermediate source object is null, the collection mapping is skipped instead of throwing NullReferenceException.

Validation

  • dotnet build Riok.Mapperly.slnx /p:TreatWarningsAsErrors=true --no-restore
  • dotnet test Riok.Mapperly.slnx --no-build --no-restore
  • 1,727 tests passed, 2 skipped, 0 failed
  • CSharpier, style, and analyzer checks passed

Use null-conditional source access when building existing-target null guards so nullable intermediate members are not dereferenced. Add regression coverage for nullable-aware and disabled-nullability contexts.
@AmirTahan80

Copy link
Copy Markdown
Author

Implementation note: the generated null guard and mapping body intentionally use different source expressions.

  • Guard: source.Nested?.Items != null safely traverses nullable intermediate members.
  • Guarded body: source.Nested.Items preserves the non-null flow established by the guard and avoids nullable expressions in TryGetNonEnumeratedCount and foreach.

The regression tests cover the original disabled-nullability reproduction from #2303 and an explicit nullable intermediate-member variant. Full local validation completed with 1,727 tests passed, 2 skipped, and 0 failed.

@AmirTahan80
AmirTahan80 marked this pull request as ready for review July 18, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mapping a nested list onto a readonly list can lead to nullreference exception when the source list is null.

1 participant