Skip to content

Commit

Permalink
feat: add conditional method
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyMakkison committed Jul 17, 2023
1 parent 3cd41de commit fa8c2d3
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 24 deletions.
7 changes: 7 additions & 0 deletions src/Riok.Mapperly.Abstractions/MappingConversionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ public enum MappingConversionType
/// </summary>
Memory = 1 << 14,

/// <summary>
/// If the target is a <see cref="ValueTuple{T, U}"/> or tuple expression (A: 10, B: 12).
/// Supports positional and named mapping.
/// Only uses <see cref="ValueTuple{T, U}"/> in <see cref="IQueryable{T}"/>.
/// </summary>
Tuple = 1 << 15,

/// <summary>
/// Enables all supported conversions.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Riok.Mapperly.Abstractions.MappingConversionType.ParseMethod = 8 -> Riok.Mapperl
Riok.Mapperly.Abstractions.MappingConversionType.Span = 8192 -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MappingConversionType.StringToEnum = 32 -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MappingConversionType.ToStringMethod = 16 -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MappingConversionType.Tuple = 32768 -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MappingConversionType.Queryable = 1024 -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MapperAttribute.UseReferenceHandling.get -> bool
Riok.Mapperly.Abstractions.MapperAttribute.UseReferenceHandling.set -> void
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis;
using Riok.Mapperly.Abstractions;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Descriptors.Mappings.ExistingTarget;
using Riok.Mapperly.Helpers;
Expand Down Expand Up @@ -26,7 +27,7 @@ public static class NewInstanceObjectPropertyMappingBuilder
if (ctx.Source.IsEnum() || ctx.Target.IsEnum())
return null;

if (ctx.Target is INamedTypeSymbol { IsTupleType: true })
if (ctx.IsConversionEnabled(MappingConversionType.Enumerable) && ctx.Target.IsTupleType)
{
// inline expressions don't support tuple expressions so ValueTuple is used instead
return ctx.IsExpression
Expand Down
2 changes: 1 addition & 1 deletion src/Riok.Mapperly/Descriptors/Mappings/MethodMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ ITypeSymbol targetType
public override ExpressionSyntax Build(TypeMappingBuildContext ctx) =>
Invocation(MethodName, SourceParameter.WithArgument(ctx.Source), ReferenceHandlerParameter?.WithArgument(ctx.ReferenceHandler));

public virtual MethodDeclarationSyntax BuildMethod(SourceEmitterContext ctx)
public virtual MethodDeclarationSyntax? BuildMethod(SourceEmitterContext ctx)
{
var returnType = FullyQualifiedIdentifier(_returnType);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Riok.Mapperly.Descriptors.Mappings.MemberMappings;
using Riok.Mapperly.Emit;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using static Riok.Mapperly.Emit.SyntaxFactoryHelper;

Expand All @@ -21,6 +22,22 @@ public NewValueTupleExpressionMapping(ITypeSymbol sourceType, ITypeSymbol target

public void AddConstructorParameterMapping(ValueTupleConstructorParameterMapping mapping) => _constructorPropertyMappings.Add(mapping);

public override MethodDeclarationSyntax? BuildMethod(SourceEmitterContext ctx)
{
return HasMemberMappings() ? base.BuildMethod(ctx) : null;
}

public override ExpressionSyntax Build(TypeMappingBuildContext ctx)
{
if (HasMemberMappings())
{
return base.Build(ctx);
}

var ctorArgs = _constructorPropertyMappings.Select(x => x.BuildArgument(ctx, insideExpression: false)).ToArray();
return TupleExpression(SeparatedList(ctorArgs));
}

public override IEnumerable<StatementSyntax> BuildBody(TypeMappingBuildContext ctx)
{
// (Name:.. ,..);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ITypeSymbol objectType

public GenericMappingTypeParameters TypeParameters { get; }

public override MethodDeclarationSyntax BuildMethod(SourceEmitterContext ctx) =>
public override MethodDeclarationSyntax? BuildMethod(SourceEmitterContext ctx) =>
base.BuildMethod(ctx).WithTypeParameterList(TypeParameterList(TypeParameters.SourceType, TypeParameters.TargetType));

protected override ExpressionSyntax BuildTargetType()
Expand Down
3 changes: 2 additions & 1 deletion src/Riok.Mapperly/Emit/SourceEmitter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Riok.Mapperly.Descriptors;
using Riok.Mapperly.Helpers;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using static Riok.Mapperly.Emit.SyntaxFactoryHelper;

Expand All @@ -23,7 +24,7 @@ public static CompilationUnitSyntax Build(MapperDescriptor descriptor)

private static IEnumerable<MemberDeclarationSyntax> BuildMembers(MapperDescriptor descriptor, SourceEmitterContext sourceEmitterContext)
{
return descriptor.MethodTypeMappings.Select(mapping => mapping.BuildMethod(sourceEmitterContext));
return descriptor.MethodTypeMappings.Select(mapping => mapping.BuildMethod(sourceEmitterContext)).WhereNotNull();
}

private static MemberDeclarationSyntax WrapInClassesAsNeeded(INamedTypeSymbol symbol, MemberDeclarationSyntax syntax)
Expand Down
37 changes: 17 additions & 20 deletions test/Riok.Mapperly.Tests/Mapping/ValueTupleTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public void TupleToTupleWithUnmappedSourceShouldDiagnostic()
"""
);

TestHelper.GenerateMapper(source, TestHelperOptions.AllowDiagnostics).Should().HaveSingleMethodBody("return (source.A, source.B);");
TestHelper.GenerateMapper(source).Should().HaveSingleMethodBody("return (source.A, source.B);");
}

[Fact]
Expand Down Expand Up @@ -253,10 +253,7 @@ public void TupleToTupleWithMapProperty()
"""
);

TestHelper
.GenerateMapper(source, TestHelperOptions.AllowDiagnostics)
.Should()
.HaveSingleMethodBody("return (A: source.C, source.Item3);");
TestHelper.GenerateMapper(source).Should().HaveSingleMethodBody("return (A: source.C, source.Item3);");
}

[Fact]
Expand All @@ -270,14 +267,14 @@ public void TuplePropertyToTupleProperty()
);

TestHelper
.GenerateMapper(source, TestHelperOptions.AllowDiagnostics)
.GenerateMapper(source)
.Should()
.HaveSingleMethodBody(
"""
var target = new global::B();
target.Value = (A: source.Value.A.ToString(), source.Value.Item2);
return target;
"""
var target = new global::B();
target.Value = (A: source.Value.A.ToString(), source.Value.Item2);
return target;
"""
);
}

Expand All @@ -286,9 +283,9 @@ public Task TuplePropertyToTupleProperty1()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("Item2", "Item1.Value")]
partial (A, int) Map((B, string) source);
""",
[MapProperty("Item2", "Item1.Value")]
partial (A, int) Map((B, string) source);
""",
"class A { public int Value { get; set; } }",
"class B { public int Value { get; set; } }"
);
Expand Down Expand Up @@ -359,10 +356,10 @@ public void TupleToTupleWithManyMapPropertyShouldDiagnostic()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("B", "A")]
[MapProperty("B", "A")]
partial (int A, int) Map((int, string B) source);
"""
[MapProperty("B", "A")]
[MapProperty("B", "A")]
partial (int A, int) Map((int, string B) source);
"""
);

TestHelper
Expand All @@ -376,9 +373,9 @@ public void TupleToTupleWithMapPropertyWithImplicitNameShouldDiagnostic()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("Item2", "Item1")]
partial (int A, int B) Map((int C, int D) source);
"""
[MapProperty("Item2", "Item1")]
partial (int A, int B) Map((int C, int D) source);
"""
);

TestHelper
Expand Down

0 comments on commit fa8c2d3

Please sign in to comment.