Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ IEnumerable<ITypeMapping> childMappings
.ThenBy(x => x.TargetType.IsNullable())
.GroupBy(x => new TypeMappingKey(x, includeNullability: false))
.Select(x => x.First())
.Select(x => new RuntimeTargetTypeMapping(x, ctx.Compilation.HasImplicitConversion(x.TargetType, ctx.Target)))
.Select(x => new RuntimeTargetTypeMapping(
x,
ctx.Compilation.HasImplicitConversion(x.TargetType, ctx.Target),
(x as UserDefinedNewInstanceMethodMapping)?.IsDerivedTypeMapping == true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer pattern matching x is UserDefinedNewInstanceMethodMapping { IsDerivedTypeMapping: true }

))
.ToList();

if (runtimeTargetTypeMappings.Count == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ public class UserDefinedNewInstanceMethodMapping(
MethodParameter sourceParameter,
MethodParameter? referenceHandlerParameter,
ITypeSymbol targetType,
bool enableReferenceHandling
bool enableReferenceHandling,
bool isDerivedTypeMapping
) : NewInstanceMethodMapping(method, sourceParameter, referenceHandlerParameter, targetType), INewInstanceUserMapping
{
private INewInstanceMapping? _delegateMapping;

public new IMethodSymbol Method { get; } = method;

public bool IsDerivedTypeMapping => isDerivedTypeMapping;

private MethodMapping? DelegateMethodMapping => _delegateMapping as MethodMapping;

public bool? Default { get; } = isDefault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,16 @@ public override IEnumerable<StatementSyntax> BuildBody(TypeMappingBuildContext c

protected virtual ExpressionSyntax? BuildSwitchArmWhenClause(ExpressionSyntax runtimeTargetType, RuntimeTargetTypeMapping mapping)
{
// targetType.IsAssignableFrom(typeof(ADto))
var mappingTargetType = TypeOfExpression(FullyQualifiedIdentifier(mapping.Mapping.TargetType.NonNullable()));

// Derived type mapping: A => ADto (runtime target type) or A => BaseDto (runtime target type), BaseDto (mapping target type).
// typeof(BaseDto).IsAssignableFrom(runtimeTargetType)

// Non-derived type mapping: A => ADto (runtime target type) or A => BaseDto (runtime target type), ADto (mapping target type).
// runtimeTargetType.IsAssignableFrom(ADto)
return InvocationWithoutIndention(
MemberAccess(runtimeTargetType, IsAssignableFromMethodName),
TypeOfExpression(FullyQualifiedIdentifier(mapping.Mapping.TargetType.NonNullable()))
MemberAccess(mapping.IsDerivedTypeMapping ? mappingTargetType : runtimeTargetType, IsAssignableFromMethodName),
mapping.IsDerivedTypeMapping ? runtimeTargetType : mappingTargetType
Comment on lines +102 to +103
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably is a breaking change, isn't it? Document it in the breaking change docs.

);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Riok.Mapperly/Descriptors/UserMethodMappingExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ string sourceParameterName
parameters.Source,
parameters.ReferenceHandler,
ctx.SymbolAccessor.UpgradeNullable(methodSymbol.ReturnType),
ctx.Configuration.Mapper.UseReferenceHandling
ctx.Configuration.Mapper.UseReferenceHandling,
ctx.AttributeAccessor.HasAttribute<MapDerivedTypeAttribute<object, object>>(methodSymbol)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the correct location to set this would be DerivedTypeMappingBuilder

)
{
AdditionalSourceParameters = parameters.AdditionalParameters,
Expand Down
2 changes: 1 addition & 1 deletion src/Riok.Mapperly/Symbols/RuntimeTargetTypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

namespace Riok.Mapperly.Symbols;

public record RuntimeTargetTypeMapping(INewInstanceMapping Mapping, bool IsAssignableToMethodTargetType);
public record RuntimeTargetTypeMapping(INewInstanceMapping Mapping, bool IsAssignableToMethodTargetType, bool IsDerivedTypeMapping);
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ string x when targetType.IsAssignableFrom(typeof(int)) => ParseableInt(x),
global::Riok.Mapperly.IntegrationTests.Models.AssemblyScopedModel x when targetType.IsAssignableFrom(typeof(global::Riok.Mapperly.IntegrationTests.Dto.AssemblyScopedDto)) => global::Riok.Mapperly.IntegrationTests.Mapper.AssemblyScopedMappers.ToDto(x),
global::System.Collections.Generic.IReadOnlyCollection<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<string>>> x when targetType.IsAssignableFrom(typeof(global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<int>>>)) => MapNestedLists(x),
global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Models.TestObject> x when targetType.IsAssignableFrom(typeof(global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Dto.TestObjectDto>)) => MapAllDtos(x),
object x when targetType.IsAssignableFrom(typeof(object)) => DerivedTypes(x),
object x when typeof(object).IsAssignableFrom(targetType) => DerivedTypes(x),
_ => throw new global::System.ArgumentException($"Cannot map {source.GetType()} to {targetType} as there is no known type mapping", nameof(source)),
};
}
Expand All @@ -817,7 +817,7 @@ string x when targetType.IsAssignableFrom(typeof(int)) => ParseableInt(x),
global::Riok.Mapperly.IntegrationTests.Models.AssemblyScopedModel x when targetType.IsAssignableFrom(typeof(global::Riok.Mapperly.IntegrationTests.Dto.AssemblyScopedDto)) => global::Riok.Mapperly.IntegrationTests.Mapper.AssemblyScopedMappers.ToDto(x),
global::System.Collections.Generic.IReadOnlyCollection<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<string>>> x when targetType.IsAssignableFrom(typeof(global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<int>>>)) => MapNestedLists(x),
global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Models.TestObject> x when targetType.IsAssignableFrom(typeof(global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Dto.TestObjectDto>)) => MapAllDtos(x),
object x when targetType.IsAssignableFrom(typeof(object)) => DerivedTypes(x),
object x when typeof(object).IsAssignableFrom(targetType) => DerivedTypes(x),
null => default,
_ => throw new global::System.ArgumentException($"Cannot map {source.GetType()} to {targetType} as there is no known type mapping", nameof(source)),
};
Expand Down Expand Up @@ -845,7 +845,7 @@ string x when typeof(TTarget).IsAssignableFrom(typeof(int)) => (TTarget)(object)
global::Riok.Mapperly.IntegrationTests.Models.AssemblyScopedModel x when typeof(TTarget).IsAssignableFrom(typeof(global::Riok.Mapperly.IntegrationTests.Dto.AssemblyScopedDto)) => (TTarget)(object)global::Riok.Mapperly.IntegrationTests.Mapper.AssemblyScopedMappers.ToDto(x),
global::System.Collections.Generic.IReadOnlyCollection<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<string>>> x when typeof(TTarget).IsAssignableFrom(typeof(global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.IReadOnlyCollection<int>>>)) => (TTarget)(object)MapNestedLists(x),
global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Models.TestObject> x when typeof(TTarget).IsAssignableFrom(typeof(global::System.Collections.Generic.IEnumerable<global::Riok.Mapperly.IntegrationTests.Dto.TestObjectDto>)) => (TTarget)(object)MapAllDtos(x),
object x when typeof(TTarget).IsAssignableFrom(typeof(object)) => (TTarget)(object)DerivedTypes(x),
object x when typeof(object).IsAssignableFrom(typeof(TTarget)) => (TTarget)(object)DerivedTypes(x),
null => throw new global::System.ArgumentNullException(nameof(source)),
_ => throw new global::System.ArgumentException($"Cannot map {source.GetType()} to {typeof(TTarget)} as there is no known type mapping", nameof(source)),
};
Expand Down
2 changes: 1 addition & 1 deletion test/Riok.Mapperly.Tests/Mapping/GenericDerivedTypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void GenericWithDerivedTypes()
"""
return source switch
{
global::Base x when typeof(TTarget).IsAssignableFrom(typeof(global::BaseDto)) => (TTarget)(object)MapDerivedTypes(x),
global::Base x when typeof(global::BaseDto).IsAssignableFrom(typeof(TTarget)) => (TTarget)(object)MapDerivedTypes(x),
null => throw new global::System.ArgumentNullException(nameof(source)),
_ => throw new global::System.ArgumentException($"Cannot map {source.GetType()} to {typeof(TTarget)} as there is no known type mapping", nameof(source)),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void WithDerivedTypesShouldUseBaseType()
"""
return source switch
{
global::Base x when targetType.IsAssignableFrom(typeof(global::BaseDto)) => MapDerivedTypes(x),
global::Base x when typeof(global::BaseDto).IsAssignableFrom(targetType) => MapDerivedTypes(x),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a new test case reflecting the exact use-case from the referenced issue.

_ => throw new global::System.ArgumentException($"Cannot map {source.GetType()} to {targetType} as there is no known type mapping", nameof(source)),
};
"""
Expand Down
Loading