Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash when object to object mapping #340

Merged
merged 1 commit into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Riok.Mapperly/AnalyzerReleases.Shipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ Rule ID | Category | Severity | Notes
RMG029 | Mapper | Error | Queryable projection mappings do not support reference handling
RMG030 | Mapper | Error | Reference loop detected while mapping to an init only property
RMG031 | Mapper | Warning | Reference loop detected while mapping to a constructor property
RMG032 | Mapper | Warning | The enum mapping strategy ByName cannot be used in projection mappings
RMG032 | Mapper | Warning | The enum mapping strategy ByName cannot be used in projection mappings
RMG033 | Mapper | Info | Object mapped to another object without deep clone
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;
using Riok.Mapperly.Abstractions;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Diagnostics;

namespace Riok.Mapperly.Descriptors.MappingBuilders;

Expand All @@ -13,10 +14,18 @@ public static class SpecialTypeMappingBuilder

return ctx.Target.SpecialType switch
{
SpecialType.System_Object when ctx.MapperConfiguration.UseDeepCloning && ctx.Source.SpecialType == SpecialType.System_Object
=> BuildDeepCloneObjectToObjectMapping(ctx),
SpecialType.System_Object when ctx.MapperConfiguration.UseDeepCloning
=> new CastMapping(ctx.Source, ctx.Target, ctx.FindOrBuildMapping(ctx.Source, ctx.Source)),
SpecialType.System_Object => new CastMapping(ctx.Source, ctx.Target),
_ => null,
};
}

private static DirectAssignmentMapping BuildDeepCloneObjectToObjectMapping(MappingBuilderContext ctx)
{
ctx.ReportDiagnostic(DiagnosticDescriptors.MappedObjectToObjectWithoutDeepClone, ctx.Source.Name, ctx.Target.Name);
return new DirectAssignmentMapping(ctx.Source);
}
}
8 changes: 8 additions & 0 deletions src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,12 @@ internal static class DiagnosticDescriptors
DiagnosticCategories.Mapper,
DiagnosticSeverity.Warning,
true);

public static readonly DiagnosticDescriptor MappedObjectToObjectWithoutDeepClone = new DiagnosticDescriptor(
"RMG033",
"Object mapped to another object without deep clone",
"Object mapped to another object without deep clone, consider implementing the mapping manually",
DiagnosticCategories.Mapper,
DiagnosticSeverity.Info,
true);
}
28 changes: 28 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/SpecialTypeTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Riok.Mapperly.Diagnostics;

namespace Riok.Mapperly.Tests.Mapping;

public class SpecialTypeTest
Expand Down Expand Up @@ -27,6 +29,32 @@ public void ClassToObjectDeepCloning()
.HaveMapMethodBody("return (object)MapToA(source);");
}

[Fact]
public void ObjectToObjectDeepCloning()
{
var source = TestSourceBuilder.Mapping(
"object",
"object",
TestSourceBuilderOptions.WithDeepCloning);
TestHelper.GenerateMapper(source, TestHelperOptions.AllowInfoDiagnostics)
.Should()
.HaveMapMethodBody("return source;")
.HaveDiagnostic(new(DiagnosticDescriptors.MappedObjectToObjectWithoutDeepClone));
}

[Fact]
public void NullableObjectToNullableObjectDeepCloning()
{
var source = TestSourceBuilder.Mapping(
"object?",
"object?",
TestSourceBuilderOptions.WithDeepCloning);
TestHelper.GenerateMapper(source, TestHelperOptions.AllowInfoDiagnostics)
.Should()
.HaveMapMethodBody("return source == null ? default : source;")
.HaveDiagnostic(new(DiagnosticDescriptors.MappedObjectToObjectWithoutDeepClone));
}

[Fact]
public void StringToObject()
{
Expand Down