diff --git a/docs/docs/configuration/enum.mdx b/docs/docs/configuration/enum.mdx
index 067bde498a..f8cb6a3b7c 100644
--- a/docs/docs/configuration/enum.mdx
+++ b/docs/docs/configuration/enum.mdx
@@ -59,7 +59,7 @@ The `IgnoreCase` property allows to opt in for case insensitive mappings (defaul
## Manually mapped enum values
To explicitly map enum values the `MapEnumValueAttibute` can be used.
-Attribute is only valid on mapping methods with enums as parameters.
+Attribute is only valid on enum-to-enum, enum-to-string and string-to-enum mappings.
```csharp
[Mapper]
@@ -70,6 +70,16 @@ public partial class CarMapper
[MapEnumValue(CarFeature.AWD, CarFeatureDto.AllWheelDrive)]
// highlight-end
public partial CarFeatureDto MapFeature(CarFeature feature);
+
+ // highlight-start
+ [MapEnumValue("AWD", CarFeatureDto.AllWheelDrive)]
+ // highlight-end
+ public partial CarFeatureDto MapFeatureFromString(string feature);
+
+ // highlight-start
+ [MapEnumValue(CarFeatureDto.AllWheelDrive, "AWD")]
+ // highlight-end
+ public partial string MapFeatureToString(CarFeatureDto feature);
}
```
@@ -80,7 +90,7 @@ This is especially useful when applying [strict enum mappings](#strict-enum-mapp
```csharp
[Mapper]
-public partial class CarMapper
+public partial class FruitMapper
{
// highlight-start
[MapperIgnoreSourceValue(Fruit.Apple)]
diff --git a/src/Riok.Mapperly.Abstractions/MapEnumValueAttribute.cs b/src/Riok.Mapperly.Abstractions/MapEnumValueAttribute.cs
index 8decbd5fd0..a97d81dd0d 100644
--- a/src/Riok.Mapperly.Abstractions/MapEnumValueAttribute.cs
+++ b/src/Riok.Mapperly.Abstractions/MapEnumValueAttribute.cs
@@ -12,21 +12,21 @@ public sealed class MapEnumValueAttribute : Attribute
///
/// Customizes how enum values are mapped
///
- /// The enum value to map from
- /// The enum value to map to
+ /// The value to map from
+ /// The value to map to
public MapEnumValueAttribute(object source, object target)
{
- Source = (Enum)source;
- Target = (Enum)target;
+ Source = source;
+ Target = target;
}
///
/// What to map to
///
- public Enum Target { get; }
+ public object Target { get; }
///
/// What to map from
///
- public Enum Source { get; }
+ public object Source { get; }
}
diff --git a/src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt b/src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
index abdaf0953c..f40e11a59d 100644
--- a/src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
+++ b/src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
@@ -15,8 +15,6 @@ Riok.Mapperly.Abstractions.MapEnumAttribute.MapEnumAttribute(Riok.Mapperly.Abstr
Riok.Mapperly.Abstractions.MapEnumAttribute.Strategy.get -> Riok.Mapperly.Abstractions.EnumMappingStrategy
Riok.Mapperly.Abstractions.MapEnumValueAttribute
Riok.Mapperly.Abstractions.MapEnumValueAttribute.MapEnumValueAttribute(object! source, object! target) -> void
-Riok.Mapperly.Abstractions.MapEnumValueAttribute.Source.get -> System.Enum!
-Riok.Mapperly.Abstractions.MapEnumValueAttribute.Target.get -> System.Enum!
Riok.Mapperly.Abstractions.MapperAttribute
Riok.Mapperly.Abstractions.MapperAttribute.EnabledConversions.get -> Riok.Mapperly.Abstractions.MappingConversionType
Riok.Mapperly.Abstractions.MapperAttribute.EnabledConversions.set -> void
@@ -188,3 +186,5 @@ Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string! sou
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string![]! source, string! target) -> void
Riok.Mapperly.Abstractions.MapperAttribute.IncludedConstructors.get -> Riok.Mapperly.Abstractions.MemberVisibility
Riok.Mapperly.Abstractions.MapperAttribute.IncludedConstructors.set -> void
+Riok.Mapperly.Abstractions.MapEnumValueAttribute.Source.get -> object!
+Riok.Mapperly.Abstractions.MapEnumValueAttribute.Target.get -> object!
diff --git a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md
index d4457c6082..cdcd8920d0 100644
--- a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md
+++ b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md
@@ -186,6 +186,7 @@ RMG038 | Mapper | Warning | An enum member could not be found on the target
RMG081 | Mapper | Error | A mapping method with additional parameters cannot be a default mapping
RMG082 | Mapper | Warning | An additional mapping method parameter is not mapped
RMG083 | Mapper | Info | Cannot map to read only type
+RMG084 | Mapper | Error | Multiple mappings are configured for the same source string
### Removed Rules
@@ -195,4 +196,3 @@ RMG017 | Mapper | Warning | An init only member can have one configuration a
RMG026 | Mapper | Info | Cannot map from indexed member
RMG027 | Mapper | Warning | A constructor parameter can have one configuration at max
RMG028 | Mapper | Warning | Constructor parameter cannot handle target paths
-
diff --git a/src/Riok.Mapperly/Configuration/EnumValueMappingConfiguration.cs b/src/Riok.Mapperly/Configuration/EnumValueMappingConfiguration.cs
index 53b7f3a7f4..4aec1630fa 100644
--- a/src/Riok.Mapperly/Configuration/EnumValueMappingConfiguration.cs
+++ b/src/Riok.Mapperly/Configuration/EnumValueMappingConfiguration.cs
@@ -1,4 +1,3 @@
-using Microsoft.CodeAnalysis;
using Riok.Mapperly.Abstractions;
namespace Riok.Mapperly.Configuration;
@@ -9,4 +8,4 @@ namespace Riok.Mapperly.Configuration;
///
/// The source constant of the enum value mapping.
/// The target constant of the enum value mapping.
-public record EnumValueMappingConfiguration(IFieldSymbol Source, IFieldSymbol Target);
+public record EnumValueMappingConfiguration(AttributeValue Source, AttributeValue Target);
diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/EnumMappingDiagnosticReporter.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/EnumMappingDiagnosticReporter.cs
new file mode 100644
index 0000000000..c4a31174df
--- /dev/null
+++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/EnumMappingDiagnosticReporter.cs
@@ -0,0 +1,88 @@
+using Microsoft.CodeAnalysis;
+using Riok.Mapperly.Abstractions;
+using Riok.Mapperly.Diagnostics;
+
+namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
+
+internal static class EnumMappingDiagnosticReporter
+{
+ public static void AddUnmatchedSourceIgnoredMembers(MappingBuilderContext ctx, ISet ignoredSourceMembers)
+ {
+ var sourceFields = ctx.SymbolAccessor.GetAllFields(ctx.Source).ToHashSet();
+ var unmatchedSourceMembers = ignoredSourceMembers.Where(m => !sourceFields.Contains(m));
+
+ foreach (var member in unmatchedSourceMembers)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.IgnoredEnumSourceMemberNotFound,
+ member.Name,
+ member.ConstantValue!,
+ ctx.Source,
+ ctx.Target
+ );
+ }
+ }
+
+ public static void AddUnmatchedTargetIgnoredMembers(MappingBuilderContext ctx, ISet ignoredTargetMembers)
+ {
+ var targetFields = ctx.SymbolAccessor.GetAllFields(ctx.Target).ToHashSet();
+ var unmatchedTargetMembers = ignoredTargetMembers.Where(m => !targetFields.Contains(m));
+
+ foreach (var member in unmatchedTargetMembers)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.IgnoredEnumTargetMemberNotFound,
+ member.Name,
+ member.ConstantValue!,
+ ctx.Source,
+ ctx.Target
+ );
+ }
+ }
+
+ public static void AddUnmappedTargetMembersDiagnostics(
+ MappingBuilderContext ctx,
+ ISet mappings,
+ IEnumerable targetMembers
+ )
+ {
+ if (!ctx.Configuration.Enum.RequiredMappingStrategy.HasFlag(RequiredMappingStrategy.Target))
+ return;
+
+ var missingTargetMembers = targetMembers.Where(field =>
+ !mappings.Contains(field) && ctx.Configuration.Enum.FallbackValue?.ConstantValue?.Equals(field.ConstantValue) != true
+ );
+ foreach (var member in missingTargetMembers)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.TargetEnumValueNotMapped,
+ member.Name,
+ member.ConstantValue!,
+ ctx.Target,
+ ctx.Source
+ );
+ }
+ }
+
+ public static void AddUnmappedSourceMembersDiagnostics(
+ MappingBuilderContext ctx,
+ ISet mappings,
+ IEnumerable sourceMembers
+ )
+ {
+ if (!ctx.Configuration.Enum.RequiredMappingStrategy.HasFlag(RequiredMappingStrategy.Source))
+ return;
+
+ var missingSourceMembers = sourceMembers.Where(field => !mappings.Contains(field));
+ foreach (var member in missingSourceMembers)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.SourceEnumValueNotMapped,
+ member.Name,
+ member.ConstantValue!,
+ ctx.Source,
+ ctx.Target
+ );
+ }
+ }
+}
diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToEnumMappingBuilder.cs
similarity index 67%
rename from src/Riok.Mapperly/Descriptors/MappingBuilders/EnumMappingBuilder.cs
rename to src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToEnumMappingBuilder.cs
index 437852ddd8..ae8f1e0a80 100644
--- a/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumMappingBuilder.cs
+++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToEnumMappingBuilder.cs
@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis;
using Riok.Mapperly.Abstractions;
+using Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Descriptors.Mappings.Enums;
using Riok.Mapperly.Diagnostics;
@@ -7,7 +8,7 @@
namespace Riok.Mapperly.Descriptors.MappingBuilders;
-public static class EnumMappingBuilder
+public static class EnumToEnumMappingBuilder
{
public static INewInstanceMapping? TryBuildMapping(MappingBuilderContext ctx)
{
@@ -134,16 +135,8 @@ params IEqualityComparer[] propertyComparer
var explicitMappings = ignoreExplicitAndIgnoredMappings
? new Dictionary(SymbolEqualityComparer.Default)
: BuildExplicitValueMappings(ctx);
- var sourceMembers = ctx
- .Source.GetMembers()
- .OfType()
- .Where(x => !ignoredSourceMembers.Remove(x))
- .ToHashSet(SymbolTypeEqualityComparer.FieldDefault);
- var targetMembers = ctx
- .Target.GetMembers()
- .OfType()
- .Where(x => !ignoredTargetMembers.Remove(x))
- .ToHashSet(SymbolTypeEqualityComparer.FieldDefault);
+ var sourceMembers = ctx.SymbolAccessor.GetFieldsExcept(ctx.Source, ignoredSourceMembers);
+ var targetMembers = ctx.SymbolAccessor.GetFieldsExcept(ctx.Target, ignoredTargetMembers);
var targetMembersByProperty = propertyComparer
.Select(pc => targetMembers.DistinctBy(propertySelector, pc).ToDictionary(propertySelector, x => x, pc))
@@ -170,98 +163,13 @@ params IEqualityComparer[] propertyComparer
mappedTargetMembers.Add(targetMember);
}
- AddUnmappedMembersDiagnostics(ctx, mappings, mappedTargetMembers, sourceMembers, targetMembers);
- AddUnmatchedIgnoredMembers(ctx, ignoredSourceMembers, ignoredTargetMembers);
+ EnumMappingDiagnosticReporter.AddUnmappedSourceMembersDiagnostics(ctx, mappings.Keys.ToHashSet(), sourceMembers);
+ EnumMappingDiagnosticReporter.AddUnmappedTargetMembersDiagnostics(ctx, mappedTargetMembers, targetMembers);
+ EnumMappingDiagnosticReporter.AddUnmatchedSourceIgnoredMembers(ctx, ignoredSourceMembers);
+ EnumMappingDiagnosticReporter.AddUnmatchedTargetIgnoredMembers(ctx, ignoredTargetMembers);
return new EnumMemberMappings(mappings, explicitMappings, targetMembers);
}
- private static void AddUnmatchedIgnoredMembers(
- MappingBuilderContext ctx,
- ISet ignoredUnmatchedSourceMembers,
- ISet ignoredUnmatchedTargetMembers
- )
- {
- foreach (var member in ignoredUnmatchedSourceMembers)
- {
- ctx.ReportDiagnostic(
- DiagnosticDescriptors.IgnoredEnumSourceMemberNotFound,
- member.Name,
- member.ConstantValue!,
- ctx.Source,
- ctx.Target
- );
- }
-
- foreach (var member in ignoredUnmatchedTargetMembers)
- {
- ctx.ReportDiagnostic(
- DiagnosticDescriptors.IgnoredEnumTargetMemberNotFound,
- member.Name,
- member.ConstantValue!,
- ctx.Source,
- ctx.Target
- );
- }
- }
-
- private static void AddUnmappedMembersDiagnostics(
- MappingBuilderContext ctx,
- IReadOnlyDictionary mappings,
- ISet mappedTargetMembers,
- IEnumerable sourceMembers,
- IEnumerable targetMembers
- )
- {
- AddUnmappedSourceMembersDiagnostics(ctx, mappings, sourceMembers);
- AddUnmappedTargetMembersDiagnostics(ctx, mappedTargetMembers, targetMembers);
- }
-
- private static void AddUnmappedTargetMembersDiagnostics(
- MappingBuilderContext ctx,
- ISet mappedTargetMembers,
- IEnumerable targetMembers
- )
- {
- if (!ctx.Configuration.Enum.RequiredMappingStrategy.HasFlag(RequiredMappingStrategy.Target))
- return;
-
- var missingTargetMembers = targetMembers.Where(field =>
- !mappedTargetMembers.Contains(field) && ctx.Configuration.Enum.FallbackValue?.ConstantValue?.Equals(field.ConstantValue) != true
- );
- foreach (var member in missingTargetMembers)
- {
- ctx.ReportDiagnostic(
- DiagnosticDescriptors.TargetEnumValueNotMapped,
- member.Name,
- member.ConstantValue!,
- ctx.Target,
- ctx.Source
- );
- }
- }
-
- private static void AddUnmappedSourceMembersDiagnostics(
- MappingBuilderContext ctx,
- IReadOnlyDictionary mappings,
- IEnumerable sourceMembers
- )
- {
- if (!ctx.Configuration.Enum.RequiredMappingStrategy.HasFlag(RequiredMappingStrategy.Source))
- return;
-
- var missingSourceMembers = sourceMembers.Where(field => !mappings.ContainsKey(field));
- foreach (var member in missingSourceMembers)
- {
- ctx.ReportDiagnostic(
- DiagnosticDescriptors.SourceEnumValueNotMapped,
- member.Name,
- member.ConstantValue!,
- ctx.Source,
- ctx.Target
- );
- }
- }
-
private static EnumFallbackValueMapping BuildFallbackMapping(MappingBuilderContext ctx)
{
var fallbackValue = ctx.Configuration.Enum.FallbackValue;
@@ -283,44 +191,72 @@ private static EnumFallbackValueMapping BuildFallbackMapping(MappingBuilderConte
private static IReadOnlyDictionary BuildExplicitValueMappings(MappingBuilderContext ctx)
{
- var targetFieldsByExplicitValue = new Dictionary(SymbolEqualityComparer.Default);
+ var explicitMappings = new Dictionary(SymbolEqualityComparer.Default);
+ var sourceFields = ctx.SymbolAccessor.GetEnumFields(ctx.Source);
+ var targetFields = ctx.SymbolAccessor.GetEnumFields(ctx.Target);
foreach (var (source, target) in ctx.Configuration.Enum.ExplicitMappings)
{
- if (!SymbolEqualityComparer.Default.Equals(source.Type, ctx.Source))
+ if (source.ConstantValue.Kind is not TypedConstantKind.Enum)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.MapValueTypeMismatch,
+ source.Expression.ToFullString(),
+ source.ConstantValue.Type?.ToDisplayString() ?? "unknown",
+ ctx.Source
+ );
+ continue;
+ }
+
+ if (target.ConstantValue.Kind is not TypedConstantKind.Enum)
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.MapValueTypeMismatch,
+ target.Expression.ToFullString(),
+ target.ConstantValue.Type?.ToDisplayString() ?? "unknown",
+ ctx.Target
+ );
+ continue;
+ }
+
+ if (!SymbolEqualityComparer.Default.Equals(source.ConstantValue.Type, ctx.Source))
{
ctx.ReportDiagnostic(
DiagnosticDescriptors.SourceEnumValueDoesNotMatchSourceEnumType,
- source,
- source.ConstantValue ?? 0,
- source.Type,
+ target.Expression.ToFullString(),
+ target.ConstantValue.Value ?? 0,
+ target.ConstantValue.Type?.ToDisplayString() ?? "unknown",
ctx.Source
);
continue;
}
- if (!SymbolEqualityComparer.Default.Equals(target.Type, ctx.Target))
+ if (!SymbolEqualityComparer.Default.Equals(target.ConstantValue.Type, ctx.Target))
{
ctx.ReportDiagnostic(
DiagnosticDescriptors.TargetEnumValueDoesNotMatchTargetEnumType,
- target,
- target.ConstantValue ?? 0,
- target.Type,
+ source.Expression.ToFullString(),
+ source.ConstantValue.Value ?? 0,
+ source.ConstantValue.Type?.ToDisplayString() ?? "unknown",
ctx.Target
);
continue;
}
- if (targetFieldsByExplicitValue.ContainsKey(source))
+ if (
+ !sourceFields.TryGetValue(source.ConstantValue.Value!, out var sourceField)
+ || !targetFields.TryGetValue(target.ConstantValue.Value!, out var targetField)
+ )
{
- ctx.ReportDiagnostic(DiagnosticDescriptors.EnumSourceValueDuplicated, source, ctx.Source, ctx.Target);
+ continue;
}
- else
+
+ if (!explicitMappings.TryAdd(sourceField, targetField))
{
- targetFieldsByExplicitValue.Add(source, target);
+ ctx.ReportDiagnostic(DiagnosticDescriptors.EnumSourceValueDuplicated, sourceField, ctx.Source, ctx.Target);
}
}
- return targetFieldsByExplicitValue;
+ return explicitMappings;
}
private record EnumMemberMappings(
diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToStringMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToStringMappingBuilder.cs
index d2108761aa..17822cec4d 100644
--- a/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToStringMappingBuilder.cs
+++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/EnumToStringMappingBuilder.cs
@@ -1,7 +1,10 @@
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Riok.Mapperly.Abstractions;
+using Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Descriptors.Mappings.Enums;
+using Riok.Mapperly.Diagnostics;
using Riok.Mapperly.Helpers;
namespace Riok.Mapperly.Descriptors.MappingBuilders;
@@ -18,6 +21,47 @@ public static class EnumToStringMappingBuilder
// to string => use an optimized method of Enum.ToString which would use slow reflection
// use Enum.ToString as fallback (for ex. for flags)
- return new EnumToStringMapping(ctx.Source, ctx.Target, ctx.SymbolAccessor.GetAllFields(ctx.Source));
+ return BuildEnumToStringMapping(ctx);
+ }
+
+ private static EnumToStringMapping BuildEnumToStringMapping(MappingBuilderContext ctx)
+ {
+ var ignoredSourceMembers = ctx.Configuration.Enum.IgnoredSourceMembers.ToHashSet(SymbolTypeEqualityComparer.FieldDefault);
+ var explicitMappings = BuildExplicitValueMappings(ctx);
+
+ EnumMappingDiagnosticReporter.AddUnmatchedSourceIgnoredMembers(ctx, ignoredSourceMembers);
+ return new EnumToStringMapping(ctx.Source, ctx.Target, ctx.SymbolAccessor.GetAllFields(ctx.Source), explicitMappings);
+ }
+
+ private static IReadOnlyDictionary BuildExplicitValueMappings(MappingBuilderContext ctx)
+ {
+ var explicitMappings = new Dictionary(SymbolEqualityComparer.Default);
+ var sourceFields = ctx.SymbolAccessor.GetEnumFields(ctx.Source);
+ foreach (var (source, target) in ctx.Configuration.Enum.ExplicitMappings)
+ {
+ if (!SymbolEqualityComparer.Default.Equals(source.ConstantValue.Type, ctx.Source))
+ {
+ ctx.ReportDiagnostic(
+ DiagnosticDescriptors.SourceEnumValueDoesNotMatchSourceEnumType,
+ source.Expression.ToFullString(),
+ source.ConstantValue.Value ?? 0,
+ source.ConstantValue.Type?.ToDisplayString() ?? "unknown",
+ ctx.Source
+ );
+ continue;
+ }
+
+ if (!sourceFields.TryGetValue(source.ConstantValue.Value!, out var sourceField))
+ {
+ continue;
+ }
+
+ if (!explicitMappings.TryAdd(sourceField, target.Expression))
+ {
+ ctx.ReportDiagnostic(DiagnosticDescriptors.EnumSourceValueDuplicated, sourceField, ctx.Source, ctx.Target);
+ }
+ }
+
+ return explicitMappings;
}
}
diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/MappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/MappingBuilder.cs
index a9a098fcb6..1045ccc1d8 100644
--- a/src/Riok.Mapperly/Descriptors/MappingBuilders/MappingBuilder.cs
+++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/MappingBuilder.cs
@@ -26,7 +26,7 @@ public class MappingBuilder(MappingCollection mappings, MapperDeclaration mapper
CtorMappingBuilder.TryBuildMapping,
StringToEnumMappingBuilder.TryBuildMapping,
EnumToStringMappingBuilder.TryBuildMapping,
- EnumMappingBuilder.TryBuildMapping,
+ EnumToEnumMappingBuilder.TryBuildMapping,
DateTimeToDateOnlyMappingBuilder.TryBuildMapping,
DateTimeToTimeOnlyMappingBuilder.TryBuildMapping,
ExplicitCastMappingBuilder.TryBuildMapping,
diff --git a/src/Riok.Mapperly/Descriptors/MappingBuilders/StringToEnumMappingBuilder.cs b/src/Riok.Mapperly/Descriptors/MappingBuilders/StringToEnumMappingBuilder.cs
index 92849ed084..5c3c0b99ec 100644
--- a/src/Riok.Mapperly/Descriptors/MappingBuilders/StringToEnumMappingBuilder.cs
+++ b/src/Riok.Mapperly/Descriptors/MappingBuilders/StringToEnumMappingBuilder.cs
@@ -1,5 +1,7 @@
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Riok.Mapperly.Abstractions;
+using Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext;
using Riok.Mapperly.Descriptors.Mappings;
using Riok.Mapperly.Descriptors.Mappings.Enums;
using Riok.Mapperly.Diagnostics;
@@ -33,6 +35,17 @@ public static class StringToEnumMappingBuilder
);
}
+ return BuildEnumFromStringSwitchMapping(ctx, genericEnumParseMethodSupported);
+ }
+
+ private static EnumFromStringSwitchMapping BuildEnumFromStringSwitchMapping(
+ MappingBuilderContext ctx,
+ bool genericEnumParseMethodSupported
+ )
+ {
+ var ignoredTargetMembers = ctx.Configuration.Enum.IgnoredTargetMembers.ToHashSet(SymbolTypeEqualityComparer.FieldDefault);
+ var explicitMappings = BuildExplicitValueMappings(ctx);
+
// from string => use an optimized method of Enum.Parse which would use slow reflection
// however we currently don't support all features of Enum.Parse yet (ex. flags)
// therefore we use Enum.Parse as fallback.
@@ -44,7 +57,15 @@ public static class StringToEnumMappingBuilder
members = members.Where(x => fallbackMapping.FallbackMember.ConstantValue?.Equals(x.ConstantValue) != true);
}
- return new EnumFromStringSwitchMapping(ctx.Source, ctx.Target, members, ctx.Configuration.Enum.IgnoreCase, fallbackMapping);
+ EnumMappingDiagnosticReporter.AddUnmatchedTargetIgnoredMembers(ctx, ignoredTargetMembers);
+ return new EnumFromStringSwitchMapping(
+ ctx.Source,
+ ctx.Target,
+ members,
+ ctx.Configuration.Enum.IgnoreCase,
+ fallbackMapping,
+ explicitMappings
+ );
}
private static EnumFallbackValueMapping BuildFallbackParseMapping(MappingBuilderContext ctx, bool genericEnumParseMethodSupported)
@@ -75,4 +96,52 @@ private static EnumFallbackValueMapping BuildFallbackParseMapping(MappingBuilder
new EnumFromStringParseMapping(ctx.Source, ctx.Target, genericEnumParseMethodSupported, ctx.Configuration.Enum.IgnoreCase)
);
}
+
+ private static IReadOnlyDictionary> BuildExplicitValueMappings(MappingBuilderContext ctx)
+ {
+ var explicitMappings = new Dictionary>(SymbolTypeEqualityComparer.FieldDefault);
+ var checkedSources = new HashSet