Skip to content

Harden MappingConfiguration generator for real-world type scenarios - #12

Merged
davidkallesen merged 9 commits into
mainfrom
feature/ATCMCF014
Mar 13, 2026
Merged

davidkallesen merged 9 commits into
mainfrom
feature/ATCMCF014

Conversation

@davidkallesen

Copy link
Copy Markdown
Contributor

Summary

This PR significantly improves the MappingConfiguration and Object Mapping generators to handle real-world type
scenarios encountered when mapping between generated API types (from Atc.Rest.Api.SourceGenerator) and domain
types. It fixes multiple issues with positional records, struct handling, nullable types, and metadata-loaded
types, while adding new built-in type conversions and auto-generated nested mapping sub-methods.

Changes

✨ Features

  • Add ATCMCF014 diagnostic warning when types cannot be resolved (sibling source generator limitation)
  • Support partial constructor matching for positional records with default values
  • Add string ↔ Uri built-in type conversions with nullable safety
  • Add string ↔ enum conversions using Enum.TryParse
  • Auto-generate private mapping sub-methods for nested and collection element types not declared as top-level
    mappings
  • Support nullable type unwrapping (Nullable<T>) across all type analysis
  • Add underscore-normalized enum value matching (Block_DE_L2 → BlockDEL2)

🐛 Fixes

  • Fix null-conditional operator (?.) on value type nested mappings — use direct call for struct sources
  • Fix ref-to-struct nested mapping — use ternary pattern instead of ?.MapToX()! which produces T?
  • Fix null guard (if (source is null)) emitted for struct input parameters
  • Fix [MapConfigProperty] generating object initializer instead of constructor for positional records with
    renamed properties
  • Fix numeric type conversions (uint → int, etc.) rejected in constructor matching
  • Fix collection type compatibility (IList<A> → List<B>) rejected in constructor matching
  • Fix positional records with collection enum properties falling back to object initializer
  • Fix private-setter properties invisible from metadata-loaded types (compiled assembly references)
  • Fix built-in type conversions incorrectly detected as nested mappings

♻️ Refactoring

  • Extract UnwrapNullable and IsNullableValueType helpers into shared MappingTypeAnalyzer
  • Add SourceCollectionElementType to PropertyMapping record for same-element-type detection
  • Add ConstructorDefaultParameter record for partial constructor matching with defaults

Notes

  • The private-setter fix resolves the root cause of the previously unreproducible "int params with defaults
    skipped" issue — the real problem was Roslyn hiding SetMethod on metadata-loaded types
  • Test infrastructure now includes CompileToAssembly and GetGeneratedOutputWithAssemblyReference helpers for
    testing metadata-vs-source symbol behavior

@davidkallesen
davidkallesen merged commit ad8c78d into main Mar 13, 2026
4 checks passed
@davidkallesen
davidkallesen deleted the feature/ATCMCF014 branch March 13, 2026 23:16
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.

1 participant