diff --git a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md index dfc07857f8..b076403705 100644 --- a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md +++ b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md @@ -191,6 +191,8 @@ RMG085 | Mapper | Error | Invalid usage of fallback value RMG086 | Mapper | Error | The source of the explicit mapping from a string to an enum is not of type string RMG087 | Mapper | Error | The target of the explicit mapping from an enum to a string is not of type string RMG088 | Mapper | Info | The attribute to build the name of the enum member is missing +RMG089 | Mapper | Info | Mapping nullable source to non-nullable target member +RMG090 | Mapper | Info | Mapping nullable source type to non-nullable target type ### Removed Rules diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/MemberMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/MemberMappingBuilder.cs index ba88b1e63d..5648067106 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/MemberMappingBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/MemberMappingBuilder.cs @@ -73,6 +73,7 @@ public static bool TryBuild( var sourceMember = memberMappingInfo.SourceMember!; var targetMember = memberMappingInfo.TargetMember; + if (delegateMapping == null) { ctx.BuilderContext.ReportDiagnostic( @@ -84,6 +85,22 @@ public static bool TryBuild( return false; } + var memberTargetNullable = memberMappingInfo.TargetMember.MemberType.IsNullable(); + var delegateTargetNullable = delegateMapping.TargetType.IsNullable(); + var memberSourceNullable = memberMappingInfo.IsSourceNullable; + var delegateSourceNullable = delegateMapping.SourceType.IsNullable(); + + if (memberSourceNullable && !memberTargetNullable && !(delegateSourceNullable && !delegateTargetNullable)) + { + ctx.BuilderContext.ReportDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + sourceMember.MemberPath.FullName, + sourceMember.MemberPath.RootType.ToDisplayString(), + targetMember.FullName, + targetMember.RootType.ToDisplayString() + ); + } + if (codeStyle == CodeStyle.Statement) { sourceValue = BuildBlockNullHandlingMapping(ctx, delegateMapping, sourceMember.MemberPath, targetMember); diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/NullableMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/NullableMappingBuilder.cs index 1f4c2c36ef..f27d1b0e71 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBuilders/NullableMappingBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/NullableMappingBuilder.cs @@ -1,5 +1,6 @@ using Riok.Mapperly.Descriptors.Mappings; using Riok.Mapperly.Descriptors.Mappings.ExistingTarget; +using Riok.Mapperly.Diagnostics; using Riok.Mapperly.Helpers; namespace Riok.Mapperly.Descriptors.MappingBuilders; @@ -12,6 +13,7 @@ public static class NullableMappingBuilder return null; var delegateMapping = ctx.BuildMapping(mappingKey, MappingBuildingOptions.KeepUserSymbol); + return delegateMapping == null ? null : BuildNullDelegateMapping(ctx, delegateMapping); } @@ -35,12 +37,19 @@ private static bool TryBuildNonNullableMappingKey(MappingBuilderContext ctx, out } mappingKey = new TypeMappingKey(sourceNonNullable ?? ctx.Source, targetNonNullable ?? ctx.Target); + + if (sourceIsNullable && !targetIsNullable) + { + ctx.ReportDiagnostic(DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, ctx.Source, ctx.Target); + } + return true; } private static INewInstanceMapping BuildNullDelegateMapping(MappingBuilderContext ctx, INewInstanceMapping mapping) { var nullFallback = ctx.GetNullFallbackValue(); + return mapping switch { NewInstanceMethodMapping methodMapping => new NullDelegateMethodMapping(ctx.Source, ctx.Target, methodMapping, nullFallback), diff --git a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs index 2c2b571ff1..cd671a5e77 100644 --- a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs +++ b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs @@ -827,6 +827,26 @@ public static class DiagnosticDescriptors true ); + public static readonly DiagnosticDescriptor NullableSourceValueToNonNullableTargetValue = + new( + "RMG089", + "Mapping nullable source to non-nullable target member", + "Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable", + DiagnosticCategories.Mapper, + DiagnosticSeverity.Info, + true + ); + + public static readonly DiagnosticDescriptor NullableSourceTypeToNonNullableTargetType = + new( + "RMG090", + "Mapping nullable source type to non-nullable target type", + "Mapping the nullable source of type {0} to target of type {1} which is not nullable", + DiagnosticCategories.Mapper, + DiagnosticSeverity.Info, + true + ); + private static string BuildHelpUri(string id) { #if ENV_NEXT diff --git a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs index 0dc336f513..ae3fa4441d 100644 --- a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs @@ -1,4 +1,5 @@ using Riok.Mapperly.Abstractions; +using Riok.Mapperly.Diagnostics; namespace Riok.Mapperly.Tests.Mapping; @@ -72,8 +73,13 @@ public void DictionaryToDictionaryNullableToNonNullable() { var source = TestSourceBuilder.Mapping("Dictionary", "Dictionary"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type int? to target of type int which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::System.Collections.Generic.Dictionary(source.Count); @@ -98,8 +104,13 @@ TestSourceBuilderOptions.Default with } ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type int? to target of type int which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::System.Collections.Generic.Dictionary(source.Count); diff --git a/test/Riok.Mapperly.Tests/Mapping/EnumTest.cs b/test/Riok.Mapperly.Tests/Mapping/EnumTest.cs index 4961995def..90f5fe8259 100644 --- a/test/Riok.Mapperly.Tests/Mapping/EnumTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/EnumTest.cs @@ -229,8 +229,13 @@ public void NullableEnumToOtherEnumShouldCastWithNullHandling() var source = TestSourceBuilder.Mapping("E1?", "E2", "enum E1 {A, B, C}", "enum E2 {A, B, C}"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type E1? to target of type E2 which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( "return source == null ? throw new System.ArgumentNullException(nameof(source)) : (global::E2)source.Value;" ); diff --git a/test/Riok.Mapperly.Tests/Mapping/EnumerableDeepCloningTest.cs b/test/Riok.Mapperly.Tests/Mapping/EnumerableDeepCloningTest.cs index 6198f4c8b4..0b23c8018a 100644 --- a/test/Riok.Mapperly.Tests/Mapping/EnumerableDeepCloningTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/EnumerableDeepCloningTest.cs @@ -1,3 +1,5 @@ +using Riok.Mapperly.Diagnostics; + namespace Riok.Mapperly.Tests.Mapping; public class EnumerableDeepCloningTest @@ -34,8 +36,13 @@ public void ArrayOfNullablePrimitiveTypesToNonNullableArrayDeepCloning() { var source = TestSourceBuilder.Mapping("int?[]", "int[]", TestSourceBuilderOptions.WithDeepCloning); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type int? to target of type int which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new int[source.Length]; diff --git a/test/Riok.Mapperly.Tests/Mapping/EnumerableTest.cs b/test/Riok.Mapperly.Tests/Mapping/EnumerableTest.cs index c3fc1893a5..bf1ed57d3f 100644 --- a/test/Riok.Mapperly.Tests/Mapping/EnumerableTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/EnumerableTest.cs @@ -17,8 +17,13 @@ public void NullableArrayToNonNullableArray() { var source = TestSourceBuilder.Mapping("int[]?", "int[]"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type int[]? to target of type int[] which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody("return source ?? throw new System.ArgumentNullException(nameof(source));"); } @@ -27,8 +32,13 @@ public void ArrayOfNullablePrimitiveTypesToNonNullableArray() { var source = TestSourceBuilder.Mapping("int?[]", "int[]"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type int? to target of type int which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new int[source.Length]; @@ -72,8 +82,13 @@ public void ArrayCustomClassNullableToArrayCustomClassNonNullable() { var source = TestSourceBuilder.Mapping("B?[]", "B[]", "class B { public int Value { get; set; } }"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type B? to target of type B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B[source.Length]; diff --git a/test/Riok.Mapperly.Tests/Mapping/NullableTest.cs b/test/Riok.Mapperly.Tests/Mapping/NullableTest.cs index 143835b81b..9494a90458 100644 --- a/test/Riok.Mapperly.Tests/Mapping/NullableTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/NullableTest.cs @@ -1,3 +1,5 @@ +using Riok.Mapperly.Diagnostics; + namespace Riok.Mapperly.Tests.Mapping; public class NullableTest @@ -8,8 +10,13 @@ public void NullableToNonNullableShouldThrow() var source = TestSourceBuilder.Mapping("A?", "B", "class A { }", "class B { }"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type A? to target of type B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ if (source == null) @@ -76,8 +83,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type A? to target of type B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ if (source == null) @@ -116,7 +128,15 @@ TestSourceBuilderOptions.Default with "class A { }" ); - TestHelper.GenerateMapper(source).Should().HaveSingleMethodBody("return source == null ? \"\" : source.ToString();"); + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) + .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type A? to target of type string which is not nullable" + ) + .HaveAssertedAllDiagnostics() + .HaveSingleMethodBody("return source == null ? \"\" : source.ToString();"); } [Fact] @@ -131,7 +151,15 @@ TestSourceBuilderOptions.Default with } ); - TestHelper.GenerateMapper(source).Should().HaveSingleMethodBody("return source == null ? default : source.Value;"); + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) + .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type System.DateTime? to target of type System.DateTime which is not nullable" + ) + .HaveAssertedAllDiagnostics() + .HaveSingleMethodBody("return source == null ? default : source.Value;"); } [Fact] diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectNestedPropertyTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectNestedPropertyTest.cs index 39cde38784..c1ef3812be 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectNestedPropertyTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectNestedPropertyTest.cs @@ -246,8 +246,13 @@ public void NullableNestedPropertyWithMemberNameOfSource() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value.Id of A to the target property Id of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyConstructorResolverTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyConstructorResolverTest.cs index 1ad242331b..d9c74f6e21 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyConstructorResolverTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyConstructorResolverTest.cs @@ -1,3 +1,5 @@ +using Riok.Mapperly.Diagnostics; + namespace Riok.Mapperly.Tests.Mapping; public class ObjectPropertyConstructorResolverTest @@ -345,8 +347,13 @@ public void RecordToFlattenedRecordNullablePath() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B( @@ -394,8 +401,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(source.Nested?.Value ?? ""); @@ -426,8 +438,13 @@ public void RecordToRecordNullableToNonNullablePrimitive() var source = TestSourceBuilder.Mapping("A", "B", "record A(int? Value);", "record B(int Value);"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B( @@ -444,8 +461,13 @@ public void RecordToRecordNonDirectAssignmentNullHandling() var source = TestSourceBuilder.Mapping("A", "B", "record A(int? Value);", "record B(double Value);"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B( @@ -462,8 +484,13 @@ public void RecordToRecordFlattenedNonDirectAssignmentNullHandling() var source = TestSourceBuilder.Mapping("A", "B", "record A(C? Nested);", "record B(double NestedValue);", "record C(int Value);"); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B( diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyExistingInstanceTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyExistingInstanceTest.cs index e4909d1efd..0d642963da 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyExistingInstanceTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyExistingInstanceTest.cs @@ -1,3 +1,5 @@ +using Riok.Mapperly.Diagnostics; + namespace Riok.Mapperly.Tests.Mapping; public class ObjectPropertyExistingInstanceTest @@ -43,6 +45,10 @@ public class D TestHelper .GenerateMapper(source, TestHelperOptions.AllowAndIncludeAllDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value2 of C to the target property Value2 of D which is not nullable" + ) .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs index 4491c343fd..ed07c765b5 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs @@ -244,8 +244,13 @@ public void AutoFlattenedPropertyNullablePath() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value.Id of A to the target property ValueId of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -270,8 +275,17 @@ public void AutoFlattenedMultiplePropertiesNullablePath() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value.Id of A to the target property ValueId of B which is not nullable" + ) + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value.Name of A to the target property ValueName of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -296,8 +310,13 @@ public void AutoFlattenedPropertyNullableValueTypePath() "public class C { public int? Value { get; set; } }" ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Id.Value of A to the target property IdValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -321,8 +340,13 @@ public void AutoFlattenedPropertyNullableValueTypePathShouldResolve() "public struct C { public int Integer { get; set; } }" ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Prop.Integer of A to the target property PropInteger of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFromSourceTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFromSourceTest.cs index 617858bc48..3de902da37 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFromSourceTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFromSourceTest.cs @@ -195,8 +195,13 @@ public void NullableNestedPropertyWithMemberNameOfSource() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceTypeToNonNullableTargetType, + "Mapping the nullable source of type A? to target of type B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ if (source == null) diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyInitPropertyTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyInitPropertyTest.cs index ccc3a49370..0e0b1c6562 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyInitPropertyTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyInitPropertyTest.cs @@ -65,8 +65,13 @@ public void InitOnlyPropertyWithNullableSource() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B() @@ -93,8 +98,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B() @@ -165,8 +175,13 @@ public void InitOnlyPropertyWithAutoFlattenedNullablePath() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B() diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs index 7fd5853a59..06c74959d3 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs @@ -37,8 +37,13 @@ public void NullableIntToNonNullableIntProperty() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -66,8 +71,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -96,8 +106,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -125,8 +140,13 @@ public void NullableStringToNonNullableStringProperty() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -152,8 +172,13 @@ public void NullableClassToNonNullableClassProperty() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ var target = new global::B(); @@ -409,8 +434,13 @@ public void DisabledNullableClassPropertyToNonNullableProperty() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ var target = new global::B(); @@ -500,8 +530,13 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value of A to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ var target = new global::B(); @@ -618,6 +653,10 @@ TestSourceBuilderOptions.Default with DiagnosticDescriptors.SourceMemberNotMapped, "The member Flattened on the mapping source type C is not mapped to any member on the mapping target type D" ) + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Value.Flattened of A to the target property ValueFlattened of B which is not nullable" + ) .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ @@ -718,8 +757,13 @@ public void ShouldUseUserImplementedMappingWithNonNullableValueType() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property Test of TypeWithNullableProperty to the target property Test of NotNullableType which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ if (y == null) diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs index 0599979b21..6bec33d801 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs @@ -194,8 +194,17 @@ TestSourceBuilderOptions.Default with ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property StringValue1 of A to the target property StringValue of B which is not nullable" + ) + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property StringValue2 of A to the target property StringValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveSingleMethodBody( """ var target = new global::B(); @@ -323,6 +332,26 @@ public Task WithUnmappablePropertyShouldDiagnostic() return TestHelper.VerifyGenerator(source); } + [Fact] + public void NullableToNonNullablePropertyShouldDiagnostic() + { + var source = TestSourceBuilder.Mapping( + "A", + "B", + "class A { public string? StringValue { get; set; } }", + "class B { public string StringValue { get; set; } }" + ); + + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) + .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property StringValue of A to the target property StringValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics(); + } + [Fact] public Task WithManualNotFoundTargetPropertyShouldDiagnostic() { diff --git a/test/Riok.Mapperly.Tests/Mapping/UserMethodAdditionalParametersTest.cs b/test/Riok.Mapperly.Tests/Mapping/UserMethodAdditionalParametersTest.cs index 92cb8ed0a0..eac03d7fd8 100644 --- a/test/Riok.Mapperly.Tests/Mapping/UserMethodAdditionalParametersTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/UserMethodAdditionalParametersTest.cs @@ -62,8 +62,13 @@ public void AdditionalInitNullableIntParameter() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property value of int? to the target property Value of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ var target = new global::B() @@ -152,8 +157,13 @@ public void NullableClassFlattening() ); TestHelper - .GenerateMapper(source) + .GenerateMapper(source, TestHelperOptions.AllowDiagnostics) .Should() + .HaveDiagnostic( + DiagnosticDescriptors.NullableSourceValueToNonNullableTargetValue, + "Mapping the nullable source property nested.Value of C? to the target property NestedValue of B which is not nullable" + ) + .HaveAssertedAllDiagnostics() .HaveMapMethodBody( """ var target = new global::B() diff --git a/test/Riok.Mapperly.Tests/_snapshots/DerivedTypeTest.WithInterfaceSourceNullableShouldWork.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/DerivedTypeTest.WithInterfaceSourceNullableShouldWork.verified.txt new file mode 100644 index 0000000000..607ed1ebf9 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/DerivedTypeTest.WithInterfaceSourceNullableShouldWork.verified.txt @@ -0,0 +1,28 @@ +{ + Diagnostics: [ + { + Location: /* +{ + [MapDerivedType] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +[MapDerivedType] +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +public partial B Map(A? src); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(13,29), + Message: Mapping the nullable source of type A? to target of type B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.MapToReadOnlyCollectionPropertyFromNullable.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.MapToReadOnlyCollectionPropertyFromNullable.verified.txt new file mode 100644 index 0000000000..cc0cf622c9 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.MapToReadOnlyCollectionPropertyFromNullable.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + private partial B Map(A source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,36), + Message: Mapping the nullable source of type System.Collections.Generic.ICollection? to target of type System.Collections.Generic.ICollection which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/NullableTest.NullableToNonNullableWithNoThrowNoAccessibleCtorShouldDiagnostic.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/NullableTest.NullableToNonNullableWithNoThrowNoAccessibleCtorShouldDiagnostic.verified.txt index 405714559a..b278b22d5d 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/NullableTest.NullableToNonNullableWithNoThrowNoAccessibleCtorShouldDiagnostic.verified.txt +++ b/test/Riok.Mapperly.Tests/_snapshots/NullableTest.NullableToNonNullableWithNoThrowNoAccessibleCtorShouldDiagnostic.verified.txt @@ -6,6 +6,26 @@ private partial B Map(string? source); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } +*/ + : (11,4)-(11,42), + Message: Mapping the nullable source of type string? to target of type B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* +{ + private partial B Map(string? source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} */ : (11,4)-(11,42), Message: B has no accessible parameterless constructor, diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableIntWithAdditionalFlattenedValueToNonNullableIntProperties.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableIntWithAdditionalFlattenedValueToNonNullableIntProperties.verified.txt index 9ddf4ce133..c16b862060 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableIntWithAdditionalFlattenedValueToNonNullableIntProperties.verified.txt +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableIntWithAdditionalFlattenedValueToNonNullableIntProperties.verified.txt @@ -6,6 +6,66 @@ private partial B Map(A source); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } +*/ + : (11,4)-(11,36), + Message: Mapping the nullable source property Nested of A to the target property Nested of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* +{ + private partial B Map(A source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,36), + Message: Mapping the nullable source property Nested.Value2 of A to the target property NestedValue2 of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* +{ + private partial B Map(A source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,36), + Message: Mapping the nullable source property Value1 of C to the target property Value1 of D which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* +{ + private partial B Map(A source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} */ : (11,4)-(11,36), Message: The member Value2 on the mapping source type C is not mapped to any member on the mapping target type D, diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableToNullablePropertyWithAnotherNullableToNonNullableMappingShouldDirectAssign.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableToNullablePropertyWithAnotherNullableToNonNullableMappingShouldDirectAssign.verified.txt new file mode 100644 index 0000000000..f219cd7291 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.NullableToNullablePropertyWithAnotherNullableToNonNullableMappingShouldDirectAssign.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* + public static partial ADest? Map(A? source); +public static partial BDest MapToDestinationB(B source); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (12,0)-(12,56), + Message: Mapping the nullable source of type int? to target of type int which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.ShouldPassNullValueToNullableUserMappingMethod.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.ShouldPassNullValueToNullableUserMappingMethod.verified.txt new file mode 100644 index 0000000000..08854d0d07 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.ShouldPassNullValueToNullableUserMappingMethod.verified.txt @@ -0,0 +1,26 @@ +{ + Diagnostics: [ + { + Location: /* +{ + [MapProperty(nameof(A.Value), nameof(B.Value), Use = nameof(MapString)] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +public partial B Map(A source); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*/ + : (11,4)-(12,31), + Message: Mapping the nullable source property Value2 of A to the target property Value2 of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.UserMethodReturnsNullableShouldThrow.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.UserMethodReturnsNullableShouldThrow.verified.txt new file mode 100644 index 0000000000..a8577c4ae1 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyUseNamedMappingTest.UserMethodReturnsNullableShouldThrow.verified.txt @@ -0,0 +1,44 @@ +{ + Diagnostics: [ + { + Location: /* +{ + [MapProperty("Name", "Value", Use = nameof(ToC))] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +public partial B Map(A source); +*/ + : (11,5)-(11,52), + Message: Mapping the nullable source of type string? to target of type string which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* +{ + [MapProperty("Name", "Value", Use = nameof(ToC))] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +public partial B Map(A source); +*/ + : (11,5)-(11,52), + Message: Mapping the nullable source of type C? to target of type C which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG090, + Title: Mapping nullable source type to non-nullable target type, + MessageFormat: Mapping the nullable source of type {0} to target of type {1} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlatten.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlatten.verified.txt new file mode 100644 index 0000000000..43040543aa --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlatten.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + private partial System.Linq.IQueryable Map(System.Linq.IQueryable source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,84), + Message: Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlattenString.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlattenString.verified.txt new file mode 100644 index 0000000000..43040543aa --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathAutoFlattenString.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + private partial System.Linq.IQueryable Map(System.Linq.IQueryable source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,84), + Message: Mapping the nullable source property Nested.Value of A to the target property NestedValue of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathManuallyFlatten.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathManuallyFlatten.verified.txt new file mode 100644 index 0000000000..e33eb2daf4 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourcePathManuallyFlatten.verified.txt @@ -0,0 +1,44 @@ +{ + Diagnostics: [ + { + Location: /* + public partial System.Linq.IQueryable Map(System.Linq.IQueryable q); +[MapProperty("Nested.Nested2.Value3", "NestedValue4")] private partial B Map(A source); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (12,0)-(12,87), + Message: Mapping the nullable source property Nested.Nested2.Value3 of A to the target property NestedValue4 of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + }, + { + Location: /* + public partial System.Linq.IQueryable Map(System.Linq.IQueryable q); +[MapProperty("Nested.Nested2.Value3", "NestedValue4")] private partial B Map(A source); +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (12,0)-(12,87), + Message: Mapping the nullable source property Nested.Nested2.Value3 of A to the target property NestedValue4 of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceProperty.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceProperty.verified.txt new file mode 100644 index 0000000000..bc724deb70 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceProperty.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + private partial System.Linq.IQueryable Map(System.Linq.IQueryable source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,84), + Message: Mapping the nullable source property StringValue of A to the target property StringValue of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceValueTypeProperty.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceValueTypeProperty.verified.txt new file mode 100644 index 0000000000..172088d117 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/QueryableProjectionNullableTest.ClassToClassNullableSourceValueTypeProperty.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + private partial System.Linq.IQueryable Map(System.Linq.IQueryable source); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,84), + Message: Mapping the nullable source property IntValue of A to the target property IntValue of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/UnsafeAccessorTest.PrivateNestedNullableProperty.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/UnsafeAccessorTest.PrivateNestedNullableProperty.verified.txt new file mode 100644 index 0000000000..c49e0fcf2e --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/UnsafeAccessorTest.PrivateNestedNullableProperty.verified.txt @@ -0,0 +1,26 @@ +{ + Diagnostics: [ + { + Location: /* +{ + [MapProperty("nested.value", "value")] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +partial B Map(A source); +^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(12,24), + Message: Mapping the nullable source property nested.value of A to the target property value of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/UserMethodAdditionalParametersTest.AdditionalNullableIntParameter.verified.txt b/test/Riok.Mapperly.Tests/_snapshots/UserMethodAdditionalParametersTest.AdditionalNullableIntParameter.verified.txt new file mode 100644 index 0000000000..514bbcce2d --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/UserMethodAdditionalParametersTest.AdditionalNullableIntParameter.verified.txt @@ -0,0 +1,24 @@ +{ + Diagnostics: [ + { + Location: /* +{ + partial B Map(A src, int? value); + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} +*/ + : (11,4)-(11,37), + Message: Mapping the nullable source property value of int? to the target property Value of B which is not nullable, + Severity: Info, + WarningLevel: 1, + Descriptor: { + Id: RMG089, + Title: Mapping nullable source to non-nullable target member, + MessageFormat: Mapping the nullable source property {0} of {1} to the target property {2} of {3} which is not nullable, + Category: Mapper, + DefaultSeverity: Info, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file