Skip to content

Commit

Permalink
fix: consider a type as immutable only if it is a read only type or a…
Browse files Browse the repository at this point in the history
… string (#9)
  • Loading branch information
latonz committed Feb 15, 2022
1 parent 31439ce commit 93d8eec
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/Riok.Mapperly/Descriptors/DescriptorBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class DescriptorBuilder
private static readonly IReadOnlyCollection<MappingBuilder> _mappingBuilders = new MappingBuilder[]
{
SpecialTypeMappingBuilder.TryBuildMapping,
ValueTypeMappingBuilder.TryBuildMapping,
ImmutableTypeMappingBuilder.TryBuildMapping,
DictionaryMappingBuilder.TryBuildMapping,
EnumerableMappingBuilder.TryBuildMapping,
ImplicitCastMappingBuilder.TryBuildMapping,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using Microsoft.CodeAnalysis.CSharp;
using Riok.Mapperly.Descriptors.TypeMappings;
using Riok.Mapperly.Helpers;

namespace Riok.Mapperly.Descriptors.MappingBuilder;

public static class ExplicitCastMappingBuilder
{
public static CastMapping? TryBuildMapping(MappingBuilderContext ctx)
{
if (!ctx.Source.IsImmutable() && !ctx.Target.IsImmutable())
return null;

var conversion = ctx.Compilation.ClassifyConversion(ctx.Source, ctx.Target);

// only allow user defined explicit reference conversions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using Microsoft.CodeAnalysis;
using Riok.Mapperly.Descriptors.TypeMappings;
using Riok.Mapperly.Helpers;

namespace Riok.Mapperly.Descriptors.MappingBuilder;

public static class ValueTypeMappingBuilder
public static class ImmutableTypeMappingBuilder
{
public static TypeMapping? TryBuildMapping(MappingBuilderContext ctx)
{
return SymbolEqualityComparer.Default.Equals(ctx.Source, ctx.Target) && ctx.Source.IsValueType
return SymbolEqualityComparer.IncludeNullability.Equals(ctx.Source, ctx.Target) && ctx.Source.IsImmutable()
? new DirectAssignmentMapping(ctx.Source)
: null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using Microsoft.CodeAnalysis.CSharp;
using Riok.Mapperly.Descriptors.TypeMappings;
using Riok.Mapperly.Helpers;

namespace Riok.Mapperly.Descriptors.MappingBuilder;

public static class ImplicitCastMappingBuilder
{
public static CastMapping? TryBuildMapping(MappingBuilderContext ctx)
{
if (!ctx.Source.IsImmutable() && !ctx.Target.IsImmutable())
return null;

var conversion = ctx.Compilation.ClassifyConversion(ctx.Source, ctx.Target);
return conversion.IsImplicit
? new CastMapping(ctx.Source, ctx.Target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public static class SpecialTypeMappingBuilder
return ctx.Target.SpecialType switch
{
SpecialType.System_Object => new CastMapping(ctx.Source, ctx.Target),
SpecialType.System_String when ctx.Source.SpecialType == SpecialType.System_String => new DirectAssignmentMapping(ctx.Source),
_ => null,
};
}
Expand Down
3 changes: 3 additions & 0 deletions src/Riok.Mapperly/Helpers/SymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ internal static class SymbolExtensions
internal static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeSymbol)
=> symbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeSymbol));

internal static bool IsImmutable(this ISymbol symbol)
=> symbol is INamedTypeSymbol namedSymbol && (namedSymbol.IsReadOnly || namedSymbol.SpecialType == SpecialType.System_String);

internal static bool IsAccessible(this ISymbol symbol)
=> symbol.DeclaredAccessibility.HasFlag(Accessibility.Protected)
|| symbol.DeclaredAccessibility.HasFlag(Accessibility.Internal)
Expand Down
27 changes: 27 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/ImmutableTypeTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Riok.Mapperly.Tests.Mapping;

public class ImmutableTypeTest
{
[Fact]
public void StringToString()
{
var source = TestSourceBuilder.Mapping(
"string",
"string");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be("return source;");
}

[Fact]
public void ReadOnlyStructToSameStruct()
{
var source = TestSourceBuilder.Mapping(
"A",
"A",
"readonly struct A {}");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be("return source;");
}
}
28 changes: 28 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/ObjectPropertyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,34 @@ public void OneSimpleProperty()
return target;".ReplaceLineEndings());
}

[Fact]
public void SameType()
{
var source = TestSourceBuilder.Mapping(
"A",
"A",
"class A { public string StringValue { get; set; } }");

TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be(@"var target = new A();
target.StringValue = source.StringValue;
return target;".ReplaceLineEndings());
}

[Fact]
public void CustomRefStructToSameCustomStruct()
{
var source = TestSourceBuilder.Mapping(
"A",
"A",
"ref struct A {}");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be(@"var target = new A();
return target;");
}

[Fact]
public void StringToIntProperty()
{
Expand Down
11 changes: 0 additions & 11 deletions test/Riok.Mapperly.Tests/Mapping/SpeicalTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,4 @@ public void CustomStructToObject()
.Should()
.Be("return (object)source;");
}

[Fact]
public void StringToString()
{
var source = TestSourceBuilder.Mapping(
"string",
"string");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be("return source;");
}
}
16 changes: 2 additions & 14 deletions test/Riok.Mapperly.Tests/Mapping/ValueTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ namespace Riok.Mapperly.Tests.Mapping;
public class ValueTypeTest
{
[Fact]
public void CustomStructToSameCustomStruct()
public void CustomReadOnlyStructToSameCustomReadOnlyStruct()
{
var source = TestSourceBuilder.Mapping(
"A",
"A",
"struct A {}");
"readonly struct A {}");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be("return source;");
Expand All @@ -26,18 +26,6 @@ public void CustomReadOnlyStructToSameCustomStruct()
.Be("return source;");
}

[Fact]
public void CustomRefStructToSameCustomStruct()
{
var source = TestSourceBuilder.Mapping(
"A",
"A",
"ref struct A {}");
TestHelper.GenerateSingleMapperMethodBody(source)
.Should()
.Be("return source;");
}

[Fact]
public void StructToSameStruct()
{
Expand Down

0 comments on commit 93d8eec

Please sign in to comment.