From 8ba80619d28127e04e96170623d7afcc1619c512 Mon Sep 17 00:00:00 2001 From: latonz Date: Mon, 14 Oct 2024 19:19:49 +0200 Subject: [PATCH] allow assignments of MapValue constant value types to nullable value types --- .../MappingBodyBuilders/SourceValueBuilder.cs | 6 ++- .../Mapping/ObjectPropertyValueTest.cs | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/SourceValueBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/SourceValueBuilder.cs index ddd4290b43..6ebf0f1f78 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/SourceValueBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/SourceValueBuilder.cs @@ -114,7 +114,9 @@ private static bool TryBuildConstantSourceValue( return true; } - if (!SymbolEqualityComparer.Default.Equals(value.ConstantValue.Type, memberMappingInfo.TargetMember.MemberType)) + // use non-nullable target type to allow non-null value type assignments + // to nullable value types + if (!SymbolEqualityComparer.Default.Equals(value.ConstantValue.Type, memberMappingInfo.TargetMember.MemberType.NonNullable())) { ctx.BuilderContext.ReportDiagnostic( DiagnosticDescriptors.MapValueTypeMismatch, @@ -135,7 +137,7 @@ private static bool TryBuildConstantSourceValue( // expand enum member access to fully qualified identifier // use simple member name approach instead of slower visitor pattern on the expression var enumMemberName = ((MemberAccessExpressionSyntax)value.Expression).Name.Identifier.Text; - var enumTypeFullName = FullyQualifiedIdentifier(memberMappingInfo.TargetMember.MemberType); + var enumTypeFullName = FullyQualifiedIdentifier(memberMappingInfo.TargetMember.MemberType.NonNullable()); sourceValue = new ConstantSourceValue(MemberAccess(enumTypeFullName, enumMemberName)); return true; case TypedConstantKind.Type: diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyValueTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyValueTest.cs index f8d94cc84f..9cb7da5409 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyValueTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyValueTest.cs @@ -530,6 +530,27 @@ public void ExplicitNullToValuePropertyShouldDiagnostic() ); } + [Fact] + public void IntToNullableValueProperty() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """[MapValue("IntValue", 1)] partial B Map(A source);""", + "class A;", + "class B { public int? IntValue { get; set; } }" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveSingleMethodBody( + """ + var target = new global::B(); + target.IntValue = 1; + return target; + """ + ); + } + [Fact] public void ExplicitNullToNullableValueProperty() { @@ -651,6 +672,30 @@ public void MapValueDuplicateForSameTargetMemberShouldDiagnostic() ); } + [Fact] + public void EnumToNestedNullableProperty() + { + var source = TestSourceBuilder.MapperWithBodyAndTypes( + """[MapValue("Nested.Value", E.E1)] partial B Map(A source);""", + "class A;", + "class B { public C? Nested { get; set; } }", + "class C { public E? Value { get; set; } }", + "enum E { E1 }" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveSingleMethodBody( + """ + var target = new global::B(); + target.Nested ??= new global::C(); + target.Nested.Value = global::E.E1; + return target; + """ + ); + } + [Fact] public void MapValueAndPropertyAttributeForSameTargetShouldDiagnostic() {