From 4277834f1230598a93141a8edf0ca5b200cc22ad Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Wed, 22 Dec 2021 12:15:28 +0100 Subject: [PATCH 01/14] Move inverse method full name to MethodMetadata as property. --- .../Matchers/AttributesMatchers.cs | 13 ------------- .../Metadata/MethodMetadata.cs | 7 +++++++ .../Processors/ClassProcessorStrategy.cs | 2 +- .../Processors/IProcessorStrategy.cs | 2 +- .../Processors/InterfaceProcessorStrategy.cs | 2 +- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs b/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs index 0536651..8ddeb28 100644 --- a/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs +++ b/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs @@ -58,18 +58,5 @@ internal static bool IsInverseMethod(IMethodMetadata methodMetadata) { return !string.IsNullOrEmpty(methodMetadata.InverseMethodName); } - - /// - /// Method returns full inverse method name based on - /// - /// Method metadata - /// - internal static string GetInverseMethodFullName(IMethodMetadata methodMetadata) - { - var inverseMethodFullName = - $"{methodMetadata.Parameters.First().FullName} {methodMetadata.InverseMethodName} ({methodMetadata.ReturnType.FullName} {methodMetadata.Parameters.First().Name})"; - - return inverseMethodFullName; - } } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Metadata/MethodMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/MethodMetadata.cs index 2c10a5a..f90f82a 100644 --- a/Compentio.SourceMapper.Generator/Metadata/MethodMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/MethodMetadata.cs @@ -31,6 +31,11 @@ internal interface IMethodMetadata : IMetadata /// string InverseMethodName { get; } + /// + /// Method returns full inverse method name based on + /// + string InverseMethodFullName { get; } + /// /// Attributes that used for mappings /// @@ -93,6 +98,8 @@ public string InverseMethodName } } + public string InverseMethodFullName => $"{Parameters.First().FullName} {InverseMethodName} ({ReturnType.FullName} {Parameters.First().Name})"; + public Location? Location => _methodSymbol.Locations.FirstOrDefault(); } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs index 0baf5b4..1ef41d5 100644 --- a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs @@ -64,7 +64,7 @@ private string GeneratePartialClassMethods(IMapperMetadata sourceMetadata) private string GeneratePartialClassMethod(IMethodMetadata methodMetadata) { - return $"public abstract {AttributesMatchers.GetInverseMethodFullName(methodMetadata)};"; + return $"public abstract {methodMetadata.InverseMethodFullName};"; } protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) diff --git a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs index b6a0c57..4447f71 100644 --- a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs @@ -93,7 +93,7 @@ protected string GenerateMethod(IMapperMetadata sourceMetadata, IMethodMetadata protected string GenerateInverseMethod(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata) { - return @$"public {Modifier} {AttributesMatchers.GetInverseMethodFullName(methodMetadata)} + return @$"public {Modifier} {methodMetadata.InverseMethodFullName} {{ if ({methodMetadata.Parameters.First().Name} == null) return null; diff --git a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs index 20a7852..11e2e5f 100644 --- a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs @@ -65,7 +65,7 @@ private string GenerateInterfaceMethods(IMapperMetadata sourceMetadata) private string GenerateInterfaceMethod(IMethodMetadata methodMetadata) { - return $"{AttributesMatchers.GetInverseMethodFullName(methodMetadata)};"; + return $"{methodMetadata.InverseMethodFullName};"; } protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) From 4b1398e723f4830813745c0c75dbb3c98a56b406 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Wed, 22 Dec 2021 15:25:26 +0100 Subject: [PATCH 02/14] Add fields metadata. --- .../Metadata/FieldMetadata.cs | 34 +++++++++++++++++++ .../Metadata/TypeMetadata.cs | 15 +++++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs diff --git a/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs new file mode 100644 index 0000000..f9702f7 --- /dev/null +++ b/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs @@ -0,0 +1,34 @@ +using Microsoft.CodeAnalysis; +using System.Linq; + +namespace Compentio.SourceMapper.Metadata +{ + /// + /// Encapsulates a field that is mapped + /// + internal interface IFieldMetadata : IMetadata + { + /// + /// Full name with namespace of the field + /// + string FullName { get; } + } + + internal class FieldMetadata : IFieldMetadata + { + private readonly IFieldSymbol _fieldSymbol; + + internal FieldMetadata(IFieldSymbol fieldSymbol) + { + _fieldSymbol = fieldSymbol; + } + + public string Name => _fieldSymbol.Name; + + public string FullName => Type.FullName; + + public Location? Location => _fieldSymbol.Locations.FirstOrDefault(); + + private ITypeMetadata Type => new TypeMetadata(_fieldSymbol.Type); + } +} \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs index 6a40b8c..02d7453 100644 --- a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs @@ -15,10 +15,15 @@ internal interface ITypeMetadata : IMetadata string FullName { get; } /// - /// Object lis of properties + /// Object list of properties /// IEnumerable Properties { get; } + /// + /// Object list of fields + /// + IEnumerable Fields { get; } + /// /// Recurrent method that return flatten list of properties tree for the object /// @@ -43,6 +48,10 @@ internal ParameterTypeMetadata(IParameterSymbol parameterSymbol) .Where(member => member as IPropertySymbol is not null) .Select(member => new PropertyMetadata(member as IPropertySymbol)); + public IEnumerable Fields => _parameterSymbol.Type.GetMembers() + .Where(member => member as IFieldSymbol is not null) + .Select(member => new FieldMetadata(member as IFieldSymbol)); + public Location? Location => _parameterSymbol.Locations.FirstOrDefault(); public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => @@ -67,6 +76,10 @@ internal TypeMetadata(ITypeSymbol typeSymbol) .Where(member => member.Kind == SymbolKind.Property && !member.IsStatic) .Select(member => new PropertyMetadata(member as IPropertySymbol)); + public IEnumerable Fields => _typeSymbol.GetMembers() + .Where(member => member.Kind == SymbolKind.Field && member.IsStatic) + .Select(member => new FieldMetadata(member as IFieldSymbol)); + public Location? Location => _typeSymbol.Locations.FirstOrDefault(); public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => From e7e4d8449aa0d9c11fecd4fafa0e5729e2b6eeee Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Thu, 23 Dec 2021 15:37:01 +0100 Subject: [PATCH 03/14] Correct fields recognition. --- Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs index 02d7453..189c2df 100644 --- a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs @@ -49,7 +49,7 @@ internal ParameterTypeMetadata(IParameterSymbol parameterSymbol) .Select(member => new PropertyMetadata(member as IPropertySymbol)); public IEnumerable Fields => _parameterSymbol.Type.GetMembers() - .Where(member => member as IFieldSymbol is not null) + .Where(member => member is IFieldSymbol && member.CanBeReferencedByName) .Select(member => new FieldMetadata(member as IFieldSymbol)); public Location? Location => _parameterSymbol.Locations.FirstOrDefault(); @@ -77,7 +77,7 @@ internal TypeMetadata(ITypeSymbol typeSymbol) .Select(member => new PropertyMetadata(member as IPropertySymbol)); public IEnumerable Fields => _typeSymbol.GetMembers() - .Where(member => member.Kind == SymbolKind.Field && member.IsStatic) + .Where(member => member.Kind == SymbolKind.Field && member.CanBeReferencedByName) .Select(member => new FieldMetadata(member as IFieldSymbol)); public Location? Location => _typeSymbol.Locations.FirstOrDefault(); From eb16348e5e0e59d4653da51ccc0983ec3d0ed76d Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Fri, 24 Dec 2021 11:24:41 +0100 Subject: [PATCH 04/14] Mapping regular and static fields. --- .../AnalyzerReleases.Unshipped.md | 1 + .../Diagnostics/SourceMapperDescriptors.cs | 4 + .../Matchers/AttributesMatchers.cs | 4 +- .../Matchers/MembersMatchers.cs | 6 +- .../Metadata/FieldMetadata.cs | 34 ++++++- .../Metadata/TypeMetadata.cs | 4 +- .../Processors/ClassProcessorStrategy.cs | 8 +- .../Processors/IProcessorStrategy.cs | 91 ++++++++++++++++++- .../Processors/InterfaceProcessorStrategy.cs | 8 +- .../Entities/UserDao.cs | 2 + .../Entities/UserInfo.cs | 2 + .../Mappings/InterfaceUserMappers.cs | 2 + 12 files changed, 145 insertions(+), 21 deletions(-) diff --git a/Compentio.SourceMapper.Generator/AnalyzerReleases.Unshipped.md b/Compentio.SourceMapper.Generator/AnalyzerReleases.Unshipped.md index e880452..26ab822 100644 --- a/Compentio.SourceMapper.Generator/AnalyzerReleases.Unshipped.md +++ b/Compentio.SourceMapper.Generator/AnalyzerReleases.Unshipped.md @@ -5,6 +5,7 @@ Rule ID | Category | Severity | Notes --------|----------|----------|------- SMAP0004 | Design | Warning | SourceMapperDescriptors, [Documentation](https://github.com/alekshura/SourceMapper/wiki/Diagnostics##smap0004) +SMAP0005 | Design | Warning | SourceMapperDescriptors, [Documentation](https://github.com/alekshura/SourceMapper/wiki/Diagnostics##smap0005) ### Changed Rules Rule ID | New Category | New Severity | Old Category | Old Severity | Notes diff --git a/Compentio.SourceMapper.Generator/Diagnostics/SourceMapperDescriptors.cs b/Compentio.SourceMapper.Generator/Diagnostics/SourceMapperDescriptors.cs index e8528e0..9e9e66a 100644 --- a/Compentio.SourceMapper.Generator/Diagnostics/SourceMapperDescriptors.cs +++ b/Compentio.SourceMapper.Generator/Diagnostics/SourceMapperDescriptors.cs @@ -28,5 +28,9 @@ public static class SourceMapperDescriptors public static readonly DiagnosticDescriptor DependencyInjectionNotUsed = new("SMAP0004", "Dependency Injection not used", "No Dependency Injection mechanism used in project. '{0}'.", "Design", DiagnosticSeverity.Warning, true, "SourceMapper based on Dependency Injection, but no used in project.", $"{DiagnosticsDescriptorsUri}#smap0004"); + + public static readonly DiagnosticDescriptor FieldIsNotMapped = + new("SMAP0005", "Field is not mapped", "The field '{0}' is not mapped", "Design", DiagnosticSeverity.Warning, true, + "Source field for defined target field not found, thus field does not mapped.", $"{DiagnosticsDescriptorsUri}#smap0005"); } } diff --git a/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs b/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs index 8ddeb28..747f644 100644 --- a/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs +++ b/Compentio.SourceMapper.Generator/Matchers/AttributesMatchers.cs @@ -13,7 +13,7 @@ internal static class AttributesMatchers /// Attributes collection /// Target property to match /// Matched attribute - internal static MappingAttribute MatchTargetAttribute(this IEnumerable attributes, IPropertyMetadata targetProperty) + internal static MappingAttribute MatchTargetAttribute(this IEnumerable attributes, IMetadata targetProperty) { return attributes.FirstOrDefault(attribute => attribute?.Target == targetProperty?.Name); } @@ -26,7 +26,7 @@ internal static MappingAttribute MatchTargetAttribute(this IEnumerable /// /// - internal static MappingAttribute MatchExpressionAttribute(this IEnumerable attributes, IPropertyMetadata targetProperty, IPropertyMetadata sourceProperty) + internal static MappingAttribute MatchExpressionAttribute(this IEnumerable attributes, IMetadata targetProperty, IMetadata sourceProperty) { var matchedExpressionAttribute = attributes.FirstOrDefault(attribute => attribute?.Target == targetProperty?.Name && attribute?.Source == sourceProperty?.Name diff --git a/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs b/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs index 76e7f9f..9f25a37 100644 --- a/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs +++ b/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs @@ -14,7 +14,7 @@ internal static class MembersMatchers /// Collection of all defined mapping attributes /// Target member /// Matched source member - internal static IPropertyMetadata MatchSourceMember(this IEnumerable sourceMembers, IEnumerable mappingAttributes, IPropertyMetadata targetMember) + internal static IMetadata MatchSourceMember(this IEnumerable sourceMembers, IEnumerable mappingAttributes, IMetadata targetMember) { var matchedAttribute = mappingAttributes.MatchTargetAttribute(targetMember); var matchedSourceMember = sourceMembers.FirstOrDefault(member => member?.Name == matchedAttribute?.Source); @@ -30,7 +30,7 @@ internal static IPropertyMetadata MatchSourceMember(this IEnumerableCollection of source properties /// Target member /// Matched source member - internal static IPropertyMetadata MatchSourceMember(this IEnumerable members, IPropertyMetadata targetMember) + internal static IMetadata MatchSourceMember(this IEnumerable members, IMetadata targetMember) { return members.FirstOrDefault(member => member?.Name == targetMember?.Name); } @@ -41,7 +41,7 @@ internal static IPropertyMetadata MatchSourceMember(this IEnumerableCollection of all defined mapping attributes /// Target member /// Matched target member - internal static IPropertyMetadata MatchTargetMember(this IEnumerable targetMembers, IEnumerable mappingAttributes, IPropertyMetadata targetMember) + internal static IMetadata MatchTargetMember(this IEnumerable targetMembers, IEnumerable mappingAttributes, IMetadata targetMember) { var matchedAttribute = mappingAttributes.MatchTargetAttribute(targetMember); var matchedTargetMember = targetMembers.FirstOrDefault(member => member?.Name == matchedAttribute?.Target); diff --git a/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs index f9702f7..fca81f7 100644 --- a/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using Compentio.SourceMapper.Attributes; +using Microsoft.CodeAnalysis; using System.Linq; namespace Compentio.SourceMapper.Metadata @@ -12,6 +13,21 @@ internal interface IFieldMetadata : IMetadata /// Full name with namespace of the field /// string FullName { get; } + + /// + /// Indicates whether the field is user defined class or no + /// + bool IsClass { get; } + + /// + /// Indicates whether the field is static + /// + bool IsStatic { get; } + + /// + /// Indicate that field should be ignored during mapping generating, due to + /// + bool IgnoreInMapping { get; } } internal class FieldMetadata : IFieldMetadata @@ -27,8 +43,24 @@ internal FieldMetadata(IFieldSymbol fieldSymbol) public string FullName => Type.FullName; + public bool IsClass => _fieldSymbol.Type.SpecialType == SpecialType.None && _fieldSymbol.Type.TypeKind == TypeKind.Class; + + public bool IsStatic => _fieldSymbol.IsStatic; + public Location? Location => _fieldSymbol.Locations.FirstOrDefault(); private ITypeMetadata Type => new TypeMetadata(_fieldSymbol.Type); + + /// + /// Indicate that field should be ignored during mapping generating, due to + /// + public bool IgnoreInMapping + { + get + { + var attribute = _fieldSymbol.GetAttributes().FirstOrDefault(attribute => attribute is not null && attribute.AttributeClass?.Name == nameof(IgnoreMappingAttribute)); + return attribute != null; + } + } } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs index 189c2df..98f3cac 100644 --- a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs @@ -49,7 +49,7 @@ internal ParameterTypeMetadata(IParameterSymbol parameterSymbol) .Select(member => new PropertyMetadata(member as IPropertySymbol)); public IEnumerable Fields => _parameterSymbol.Type.GetMembers() - .Where(member => member is IFieldSymbol && member.CanBeReferencedByName) + .Where(member => member is IFieldSymbol && member.CanBeReferencedByName && !((IFieldSymbol)member).IsConst) .Select(member => new FieldMetadata(member as IFieldSymbol)); public Location? Location => _parameterSymbol.Locations.FirstOrDefault(); @@ -77,7 +77,7 @@ internal TypeMetadata(ITypeSymbol typeSymbol) .Select(member => new PropertyMetadata(member as IPropertySymbol)); public IEnumerable Fields => _typeSymbol.GetMembers() - .Where(member => member.Kind == SymbolKind.Field && member.CanBeReferencedByName) + .Where(member => member.Kind == SymbolKind.Field && member.CanBeReferencedByName && !((IFieldSymbol)member).IsConst) .Select(member => new FieldMetadata(member as IFieldSymbol)); public Location? Location => _typeSymbol.Locations.FirstOrDefault(); diff --git a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs index 2108f08..93ae913 100644 --- a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs @@ -67,7 +67,7 @@ private string GeneratePartialClassMethod(IMethodMetadata methodMetadata) return $"public abstract {methodMetadata.InverseMethodFullName};"; } - protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) + protected override string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) { var mappingsStringBuilder = new StringBuilder(); var sourceMembers = methodMetadata.Parameters.First().Properties; @@ -75,8 +75,8 @@ protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMeth foreach (var targetMember in targetMemebers) { - var matchedSourceMember = sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); + var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); + var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; @@ -91,7 +91,7 @@ protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMeth continue; } - mappingsStringBuilder.Append(GenerateMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); + mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); } return mappingsStringBuilder.ToString(); diff --git a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs index e373b39..e08727e 100644 --- a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs @@ -57,7 +57,7 @@ public IResult GenerateCode(IMapperMetadata mapperMetadata) protected abstract string GenerateMapperCode(IMapperMetadata mapperMetadata); - protected abstract string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false); + protected abstract string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false); protected string GenerateMethods(IMapperMetadata sourceMetadata) { @@ -85,7 +85,8 @@ protected string GenerateMethod(IMapperMetadata sourceMetadata, IMethodMetadata var target = new {methodMetadata.ReturnType.FullName}(); - {GenerateMappings(sourceMetadata, methodMetadata)} + {GenerateFieldsMappings(sourceMetadata, methodMetadata)} + {GeneratePropertiesMappings(sourceMetadata, methodMetadata)} return target; }}"; @@ -100,13 +101,65 @@ protected string GenerateInverseMethod(IMapperMetadata sourceMetadata, IMethodMe var target = new {methodMetadata.Parameters.First().FullName}(); - {GenerateMappings(sourceMetadata, methodMetadata, true)} + {GenerateFieldsMappings(sourceMetadata, methodMetadata, true)} + {GeneratePropertiesMappings(sourceMetadata, methodMetadata, true)} return target; }}"; } - protected string GenerateMapping(IMapperMetadata sourceMetadata, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, bool inverseMapping = false) + protected string GenerateFieldsMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) + { + var mappingsStringBuilder = new StringBuilder(); + var sourceMembers = methodMetadata.Parameters.First().Fields; + var targetMemebers = methodMetadata.ReturnType.Fields; + + foreach (var targetMember in targetMemebers) + { + var matchedSourceMember = (IFieldMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); + var matchedTargetMember = (IFieldMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); + + if (IgnoreFieldMapping(matchedSourceMember, matchedTargetMember)) continue; + + mappingsStringBuilder.Append(GenerateFieldMapping(sourceMetadata, methodMetadata, matchedSourceMember, matchedTargetMember, inverseMapping)); + } + + return mappingsStringBuilder.ToString(); + } + + protected string GenerateFieldMapping(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, IFieldMetadata matchedSourceMember, IFieldMetadata matchedTargetMember, bool inverseMapping = false) + { + if (inverseMapping) ObjectHelper.Swap(ref matchedSourceMember, ref matchedTargetMember); + + if (matchedTargetMember is null && matchedSourceMember is not null) + { + FieldMappingWarning(matchedSourceMember); + } + + if (matchedSourceMember is null || matchedTargetMember is null) + { + FieldMappingWarning(matchedSourceMember ?? matchedTargetMember); + return string.Empty; + } + + var mapping = new StringBuilder(); + + if (matchedSourceMember.IsStatic && matchedTargetMember.IsStatic) + { + mapping.AppendLine(MapStaticProperty(matchedSourceMember, matchedTargetMember, methodMetadata, inverseMapping)); + return mapping.ToString(); + } + + if (!matchedSourceMember.IsClass && !matchedTargetMember.IsClass) + { + mapping.AppendLine(MapProperty(matchedSourceMember, matchedTargetMember, methodMetadata.Parameters.First())); + return mapping.ToString(); + } + + return mapping.ToString(); + } + + protected string GeneratePropertyMapping(IMapperMetadata sourceMetadata, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, bool inverseMapping = false) { if (inverseMapping) ObjectHelper.Swap(ref matchedSourceMember, ref matchedTargetMember); @@ -135,11 +188,19 @@ protected string GenerateMapping(IMapperMetadata sourceMetadata, ITypeMetadata p return mapping.ToString(); } - protected string MapProperty(IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, ITypeMetadata parameter) + protected string MapProperty(IMetadata matchedSourceMember, IMetadata matchedTargetMember, ITypeMetadata parameter) { return $"target.{matchedTargetMember?.Name} = {parameter.Name}.{matchedSourceMember?.Name};"; } + private string MapStaticProperty(IFieldMetadata matchedSourceMember, IFieldMetadata matchedTargetMember, IMethodMetadata methodMetadata, bool inverseMapping) + { + if (inverseMapping) + return $"{methodMetadata.Parameters.First().FullName}.{matchedTargetMember?.Name} = {methodMetadata.ReturnType.FullName}.{matchedSourceMember?.Name};"; + else + return $"{methodMetadata.ReturnType.FullName}.{matchedTargetMember?.Name} = {methodMetadata.Parameters.First().FullName}.{matchedSourceMember?.Name};"; + } + protected string MapClass(IMapperMetadata sourceMetadata, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, ITypeMetadata parameter, bool inverseMapping) { var method = GetDefinedMethod(sourceMetadata, matchedSourceMember, matchedTargetMember, inverseMapping); @@ -182,6 +243,17 @@ protected bool IgnorePropertyMapping(IPropertyMetadata? sourcePropertyMetadata, return (sourcePropertyMetadata?.IgnoreInMapping is true || targetPropertyMetadata?.IgnoreInMapping is true); } + /// + /// Metchod checks that field metadata should be ignored during mapping due to + /// + /// + /// + /// + protected bool IgnoreFieldMapping(IFieldMetadata? sourceFieldMetadata, IFieldMetadata? targetFieldMetadata) + { + return (sourceFieldMetadata?.IgnoreInMapping is true || targetFieldMetadata?.IgnoreInMapping is true); + } + protected void PropertyMappingWarning(IPropertyMetadata metadata) { _diagnostics.Add(new DiagnosticsInfo @@ -190,5 +262,14 @@ protected void PropertyMappingWarning(IPropertyMetadata metadata) Metadata = metadata }); } + + protected void FieldMappingWarning(IFieldMetadata metadata) + { + _diagnostics.Add(new DiagnosticsInfo + { + DiagnosticDescriptor = SourceMapperDescriptors.FieldIsNotMapped, + Metadata = metadata + }); + } } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs index 0d3487e..d8c749a 100644 --- a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs @@ -68,7 +68,7 @@ private string GenerateInterfaceMethod(IMethodMetadata methodMetadata) return $"{methodMetadata.InverseMethodFullName};"; } - protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) + protected override string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) { var mappingsStringBuilder = new StringBuilder(); var sourceMembers = methodMetadata.Parameters.First().Properties; @@ -76,12 +76,12 @@ protected override string GenerateMappings(IMapperMetadata sourceMetadata, IMeth foreach (var targetMember in targetMemebers) { - var matchedSourceMember = sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); + var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); + var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; - mappingsStringBuilder.Append(GenerateMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); + mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); } return mappingsStringBuilder.ToString(); diff --git a/Compentio.SourceMapper.Tests/Entities/UserDao.cs b/Compentio.SourceMapper.Tests/Entities/UserDao.cs index fd98776..e7c29cf 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserDao.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserDao.cs @@ -6,6 +6,8 @@ namespace Compentio.SourceMapper.Tests.Entities { public class UserDao { + public static string StringStaticValueDao = "StringStaticValueDao"; + public string StringFieldValueDao = "StringFieldValueDao"; public long UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } diff --git a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs index 33988b0..c18a878 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs @@ -6,6 +6,8 @@ namespace Compentio.SourceMapper.Tests.Entities { public class UserInfo { + public static string StringStaticValueInfo = "StringStaticValueInfo"; + public string StringFieldValueInfo = "StringFieldValueInfo"; public int Id { get; set; } public string Name { get; set; } public Sex Sex { get; set; } diff --git a/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs b/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs index 896d704..edd4e07 100644 --- a/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs +++ b/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs @@ -7,6 +7,8 @@ namespace Compentio.SourceMapper.Tests.Mappings [Mapper(ClassName = "InterfaceUserDaoMapper")] public partial interface IUserDaoMapper { + [Mapping(Source = nameof(UserDao.StringStaticValueDao), Target = nameof(UserInfo.StringStaticValueInfo))] + [Mapping(Source = nameof(UserDao.StringFieldValueDao), Target = nameof(UserInfo.StringFieldValueInfo))] [Mapping(Source = nameof(UserDao.FirstName), Target = nameof(UserInfo.Name))] [InverseMapping(InverseMethodName = "MapToDatabaseModel")] UserInfo MapToDomainModel(UserDao source); From 0c7e3f0d511bf3350da863e9bd9889a0ac73fe52 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Fri, 24 Dec 2021 11:55:06 +0100 Subject: [PATCH 05/14] Quality update. --- .../Processors/ClassProcessorStrategy.cs | 52 +----------------- .../Processors/IProcessorStrategy.cs | 54 +++++++++++++++++-- .../Processors/InterfaceProcessorStrategy.cs | 19 ------- 3 files changed, 52 insertions(+), 73 deletions(-) diff --git a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs index 93ae913..f06f45f 100644 --- a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs @@ -1,5 +1,4 @@ -using Compentio.SourceMapper.Attributes; -using Compentio.SourceMapper.Matchers; +using Compentio.SourceMapper.Matchers; using Compentio.SourceMapper.Metadata; using System.Linq; using System.Text; @@ -66,54 +65,5 @@ private string GeneratePartialClassMethod(IMethodMetadata methodMetadata) { return $"public abstract {methodMetadata.InverseMethodFullName};"; } - - protected override string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) - { - var mappingsStringBuilder = new StringBuilder(); - var sourceMembers = methodMetadata.Parameters.First().Properties; - var targetMemebers = methodMetadata.ReturnType.Properties; - - foreach (var targetMember in targetMemebers) - { - var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); - - if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; - - var expressionAttribute = methodMetadata.MappingAttributes.MatchExpressionAttribute(targetMember, matchedSourceMember); - var expressionMapping = MapExpression(expressionAttribute, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember); - - if (!string.IsNullOrEmpty(expressionMapping)) - { - if (inverseMapping) continue; - - mappingsStringBuilder.Append(expressionMapping); - continue; - } - - mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); - } - - return mappingsStringBuilder.ToString(); - } - - private string MapExpression(MappingAttribute expressionAttribute, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember) - { - var mapping = new StringBuilder(); - - if (expressionAttribute is not null && matchedSourceMember is not null) - { - mapping.AppendLine($"target.{expressionAttribute?.Target} = {expressionAttribute?.Expression}({parameter.Name}.{matchedSourceMember.Name});"); - return mapping.ToString(); - } - - if (expressionAttribute is not null && matchedTargetMember is not null && matchedSourceMember is null) - { - mapping.AppendLine($"target.{expressionAttribute?.Target} = {expressionAttribute?.Expression}({parameter.Name});"); - return mapping.ToString(); - } - - return mapping.ToString(); - } } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs index e08727e..fc8add6 100644 --- a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs @@ -1,4 +1,5 @@ -using Compentio.SourceMapper.Diagnostics; +using Compentio.SourceMapper.Attributes; +using Compentio.SourceMapper.Diagnostics; using Compentio.SourceMapper.Helpers; using Compentio.SourceMapper.Matchers; using Compentio.SourceMapper.Metadata; @@ -57,8 +58,6 @@ public IResult GenerateCode(IMapperMetadata mapperMetadata) protected abstract string GenerateMapperCode(IMapperMetadata mapperMetadata); - protected abstract string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false); - protected string GenerateMethods(IMapperMetadata sourceMetadata) { var methodsStringBuilder = new StringBuilder(); @@ -159,6 +158,36 @@ protected string GenerateFieldMapping(IMapperMetadata sourceMetadata, IMethodMet return mapping.ToString(); } + protected string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) + { + var mappingsStringBuilder = new StringBuilder(); + var sourceMembers = methodMetadata.Parameters.First().Properties; + var targetMemebers = methodMetadata.ReturnType.Properties; + + foreach (var targetMember in targetMemebers) + { + var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); + var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); + + if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; + + var expressionAttribute = methodMetadata.MappingAttributes.MatchExpressionAttribute(targetMember, matchedSourceMember); + var expressionMapping = MapExpression(expressionAttribute, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember); + + if (!string.IsNullOrEmpty(expressionMapping)) + { + if (inverseMapping) continue; + + mappingsStringBuilder.Append(expressionMapping); + continue; + } + + mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); + } + + return mappingsStringBuilder.ToString(); + } + protected string GeneratePropertyMapping(IMapperMetadata sourceMetadata, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, bool inverseMapping = false) { if (inverseMapping) ObjectHelper.Swap(ref matchedSourceMember, ref matchedTargetMember); @@ -201,6 +230,25 @@ private string MapStaticProperty(IFieldMetadata matchedSourceMember, IFieldMetad return $"{methodMetadata.ReturnType.FullName}.{matchedTargetMember?.Name} = {methodMetadata.Parameters.First().FullName}.{matchedSourceMember?.Name};"; } + private string MapExpression(MappingAttribute expressionAttribute, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember) + { + var mapping = new StringBuilder(); + + if (expressionAttribute is not null && matchedSourceMember is not null) + { + mapping.AppendLine($"target.{expressionAttribute?.Target} = {expressionAttribute?.Expression}({parameter.Name}.{matchedSourceMember.Name});"); + return mapping.ToString(); + } + + if (expressionAttribute is not null && matchedTargetMember is not null && matchedSourceMember is null) + { + mapping.AppendLine($"target.{expressionAttribute?.Target} = {expressionAttribute?.Expression}({parameter.Name});"); + return mapping.ToString(); + } + + return mapping.ToString(); + } + protected string MapClass(IMapperMetadata sourceMetadata, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, ITypeMetadata parameter, bool inverseMapping) { var method = GetDefinedMethod(sourceMetadata, matchedSourceMember, matchedTargetMember, inverseMapping); diff --git a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs index d8c749a..ca2cd01 100644 --- a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs @@ -67,24 +67,5 @@ private string GenerateInterfaceMethod(IMethodMetadata methodMetadata) { return $"{methodMetadata.InverseMethodFullName};"; } - - protected override string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) - { - var mappingsStringBuilder = new StringBuilder(); - var sourceMembers = methodMetadata.Parameters.First().Properties; - var targetMemebers = methodMetadata.ReturnType.Properties; - - foreach (var targetMember in targetMemebers) - { - var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); - - if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; - - mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); - } - - return mappingsStringBuilder.ToString(); - } } } \ No newline at end of file From 5eda09e2d9ac3af7ff24acb6a998d3d57cc6e43e Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Mon, 27 Dec 2021 09:53:53 +0100 Subject: [PATCH 06/14] Member metadata instead PropertyMetadata and FieldMetadata. --- .../Metadata/MemberMetadata.cs | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs diff --git a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs new file mode 100644 index 0000000..e60832a --- /dev/null +++ b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs @@ -0,0 +1,114 @@ +using Compentio.SourceMapper.Attributes; +using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; + +namespace Compentio.SourceMapper.Metadata +{ + /// + /// Encapsulates a member that is mapped + /// + internal interface IMemberMetadata : IMetadata + { + /// + /// Indicate that class is a field and implements field symbol + /// + bool IsField { get; } + + /// + /// Indicate that class is a property and implements property symbol + /// + bool IsProperty { get; } + + /// + /// Full name with namespace of the member + /// + string FullName { get; } + + /// + /// Indicates whether the member is user defined class or no + /// + bool IsClass { get; } + + /// + /// Indicates whether the member is static + /// + bool IsStatic { get; } + + /// + /// Indicate that field should be ignored during mapping generating, due to + /// + bool IgnoreInMapping { get; } + + /// + /// List of properties. It is empty in a case when the property is not user defined class: IsClass == false or is a field: IsField == true + /// + /// + /// + IEnumerable Properties { get; } + } + + internal class MemberMetadata : IMemberMetadata + { + private readonly ISymbol _symbol; + + internal MemberMetadata(ISymbol symbol) + { + _symbol = symbol; + } + + public bool IsField => _symbol is IFieldSymbol; + + public bool IsProperty => _symbol is IPropertySymbol; + + public string FullName => TypeMetadata.FullName; + + public bool IsClass => Type.SpecialType == SpecialType.None && Type.TypeKind == TypeKind.Class; + + public bool IsStatic => _symbol.IsStatic; + + public bool IgnoreInMapping + { + get + { + var attribute = _symbol.GetAttributes().FirstOrDefault(attribute => attribute is not null && attribute.AttributeClass?.Name == nameof(IgnoreMappingAttribute)); + return attribute != null; + } + } + + public IEnumerable Properties + { + get + { + if (!IsClass || !IsProperty) + return Enumerable.Empty(); + + return Type.GetMembers() + .Where(member => member.Kind == SymbolKind.Property && !member.IsStatic) + .Select(member => new MemberMetadata(member as IPropertySymbol)); + } + } + + public Location? Location => _symbol.Locations.FirstOrDefault(); + + public string Name => _symbol.Name; + + private ITypeSymbol Type + { + get + { + if (IsField) return ((IFieldSymbol)_symbol).Type; + else return ((IPropertySymbol)_symbol).Type; + } + } + + private ITypeMetadata TypeMetadata + { + get + { + if (IsField) return new TypeMetadata(Type); + else return new TypeMetadata(Type); + } + } + } +} \ No newline at end of file From 1fd66a21e3610092739f42f8152d01fe67012f59 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Mon, 27 Dec 2021 10:00:03 +0100 Subject: [PATCH 07/14] Update MemberMetadata implementation. --- .../Metadata/MemberMetadata.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs index e60832a..b17c8b7 100644 --- a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs @@ -102,13 +102,6 @@ private ITypeSymbol Type } } - private ITypeMetadata TypeMetadata - { - get - { - if (IsField) return new TypeMetadata(Type); - else return new TypeMetadata(Type); - } - } + private ITypeMetadata TypeMetadata => new TypeMetadata(Type); } } \ No newline at end of file From 9f25fb46491de03e2fe5e58bf0d100ab52fd88eb Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Mon, 27 Dec 2021 14:55:33 +0100 Subject: [PATCH 08/14] MemberMetadata implementation and apply. --- .../Metadata/FieldMetadata.cs | 66 --------------- .../Metadata/PropertyMetadata.cs | 80 ------------------- 2 files changed, 146 deletions(-) delete mode 100644 Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs delete mode 100644 Compentio.SourceMapper.Generator/Metadata/PropertyMetadata.cs diff --git a/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs deleted file mode 100644 index fca81f7..0000000 --- a/Compentio.SourceMapper.Generator/Metadata/FieldMetadata.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Compentio.SourceMapper.Attributes; -using Microsoft.CodeAnalysis; -using System.Linq; - -namespace Compentio.SourceMapper.Metadata -{ - /// - /// Encapsulates a field that is mapped - /// - internal interface IFieldMetadata : IMetadata - { - /// - /// Full name with namespace of the field - /// - string FullName { get; } - - /// - /// Indicates whether the field is user defined class or no - /// - bool IsClass { get; } - - /// - /// Indicates whether the field is static - /// - bool IsStatic { get; } - - /// - /// Indicate that field should be ignored during mapping generating, due to - /// - bool IgnoreInMapping { get; } - } - - internal class FieldMetadata : IFieldMetadata - { - private readonly IFieldSymbol _fieldSymbol; - - internal FieldMetadata(IFieldSymbol fieldSymbol) - { - _fieldSymbol = fieldSymbol; - } - - public string Name => _fieldSymbol.Name; - - public string FullName => Type.FullName; - - public bool IsClass => _fieldSymbol.Type.SpecialType == SpecialType.None && _fieldSymbol.Type.TypeKind == TypeKind.Class; - - public bool IsStatic => _fieldSymbol.IsStatic; - - public Location? Location => _fieldSymbol.Locations.FirstOrDefault(); - - private ITypeMetadata Type => new TypeMetadata(_fieldSymbol.Type); - - /// - /// Indicate that field should be ignored during mapping generating, due to - /// - public bool IgnoreInMapping - { - get - { - var attribute = _fieldSymbol.GetAttributes().FirstOrDefault(attribute => attribute is not null && attribute.AttributeClass?.Name == nameof(IgnoreMappingAttribute)); - return attribute != null; - } - } - } -} \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Metadata/PropertyMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/PropertyMetadata.cs deleted file mode 100644 index bcd0f61..0000000 --- a/Compentio.SourceMapper.Generator/Metadata/PropertyMetadata.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Compentio.SourceMapper.Attributes; -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; - -namespace Compentio.SourceMapper.Metadata -{ - /// - /// Encapsulates a property that is mapped - /// - internal interface IPropertyMetadata : IMetadata - { - /// - /// Full name with namespace of the property - /// - string FullName { get; } - - /// - /// Indicates whether the property is user defined class or no - /// - /// - bool IsClass { get; } - - /// - /// Indicate that property should be ignored during mapping generating, due to - /// - bool IgnoreInMapping { get; } - - /// - /// List of properties. It is empty in a case when the property is not user defined class: IsClass == false - /// - /// - IEnumerable Properties { get; } - } - - internal class PropertyMetadata : IPropertyMetadata - { - private readonly IPropertySymbol _propertySymbol; - - internal PropertyMetadata(IPropertySymbol propertySymbol) - { - _propertySymbol = propertySymbol; - } - - public string Name => _propertySymbol.Name; - - public string FullName => Type.FullName; - - public bool IsClass => _propertySymbol.Type.SpecialType == SpecialType.None && _propertySymbol.Type.TypeKind == TypeKind.Class; - - private ITypeMetadata Type => new TypeMetadata(_propertySymbol.Type); - - public IEnumerable Properties - { - get - { - if (!IsClass) - return Enumerable.Empty(); - - return _propertySymbol.Type.GetMembers() - .Where(member => member.Kind == SymbolKind.Property && !member.IsStatic) - .Select(member => new PropertyMetadata(member as IPropertySymbol)); - } - } - - public Location? Location => _propertySymbol.Locations.FirstOrDefault(); - - /// - /// Indicate that property should be ignored during mapping generating, due to - /// - public bool IgnoreInMapping - { - get - { - var attribute = _propertySymbol.GetAttributes().FirstOrDefault(attribute => attribute is not null && attribute.AttributeClass?.Name == nameof(IgnoreMappingAttribute)); - return attribute != null; - } - } - } -} \ No newline at end of file From ee5135b63f8a02059d9a0c39efccdc2c7b985b8f Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Mon, 27 Dec 2021 15:00:58 +0100 Subject: [PATCH 09/14] MemberMetadata implementation and apply. --- .../Matchers/MembersMatchers.cs | 16 +- .../Matchers/MethodsMatchers.cs | 6 +- .../Metadata/MemberMetadata.cs | 34 ++- .../Metadata/TypeMetadata.cs | 28 +-- .../Processors/IProcessorStrategy.cs | 193 ++++++++---------- .../Entities/UserDao.cs | 1 + .../Entities/UserInfo.cs | 1 + .../Mappings/ClassUserMappers.cs | 2 + .../Matchers/AttributesMatchersTests.cs | 8 +- .../Metadata/ParameterTypeMetadataTests.cs | 12 +- .../Metadata/PropertyMetadataTests.cs | 14 +- .../Metadata/TypeMetadataTests.cs | 12 +- .../Processors/ClassProcessorStrategyTests.cs | 11 +- .../InterfaceProcessorStrategyTests.cs | 11 +- 14 files changed, 170 insertions(+), 179 deletions(-) diff --git a/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs b/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs index 9f25a37..9da3c60 100644 --- a/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs +++ b/Compentio.SourceMapper.Generator/Matchers/MembersMatchers.cs @@ -8,13 +8,13 @@ namespace Compentio.SourceMapper.Matchers internal static class MembersMatchers { /// - /// Method searches for source member that matches value. This also should match the target property. + /// Method searches for source member that matches value. This also should match the target member. /// - /// Collection of source properties + /// Collection of source members /// Collection of all defined mapping attributes /// Target member /// Matched source member - internal static IMetadata MatchSourceMember(this IEnumerable sourceMembers, IEnumerable mappingAttributes, IMetadata targetMember) + internal static IMemberMetadata MatchSourceMember(this IEnumerable sourceMembers, IEnumerable mappingAttributes, IMemberMetadata targetMember) { var matchedAttribute = mappingAttributes.MatchTargetAttribute(targetMember); var matchedSourceMember = sourceMembers.FirstOrDefault(member => member?.Name == matchedAttribute?.Source); @@ -27,21 +27,21 @@ internal static IMetadata MatchSourceMember(this IEnumerable sourceMe /// /// Method searches for source member that name matches target member. /// - /// Collection of source properties + /// Collection of source members /// Target member /// Matched source member - internal static IMetadata MatchSourceMember(this IEnumerable members, IMetadata targetMember) + internal static IMemberMetadata MatchSourceMember(this IEnumerable members, IMemberMetadata targetMember) { return members.FirstOrDefault(member => member?.Name == targetMember?.Name); } /// - /// Method searches for target member that matches value. This also should match the target property. + /// Method searches for target member that matches value. This also should match the target member. /// - /// Collection of target properties + /// Collection of target members /// Collection of all defined mapping attributes /// Target member /// Matched target member - internal static IMetadata MatchTargetMember(this IEnumerable targetMembers, IEnumerable mappingAttributes, IMetadata targetMember) + internal static IMemberMetadata MatchTargetMember(this IEnumerable targetMembers, IEnumerable mappingAttributes, IMemberMetadata targetMember) { var matchedAttribute = mappingAttributes.MatchTargetAttribute(targetMember); var matchedTargetMember = targetMembers.FirstOrDefault(member => member?.Name == matchedAttribute?.Target); diff --git a/Compentio.SourceMapper.Generator/Matchers/MethodsMatchers.cs b/Compentio.SourceMapper.Generator/Matchers/MethodsMatchers.cs index 0fcd198..e85aed4 100644 --- a/Compentio.SourceMapper.Generator/Matchers/MethodsMatchers.cs +++ b/Compentio.SourceMapper.Generator/Matchers/MethodsMatchers.cs @@ -12,10 +12,10 @@ internal static class MethodsMatchers /// Returns method data that defined in mapping corresponds to source and target types. /// This method can be used in mappings of nested types. /// - /// Source property metadata - /// Target property metadata + /// Source member metadata + /// Target member metadata /// Matched method - internal static IMethodMetadata MatchDefinedMethod(this IMapperMetadata mapperMetadata, IPropertyMetadata source, IPropertyMetadata target) + internal static IMethodMetadata MatchDefinedMethod(this IMapperMetadata mapperMetadata, IMemberMetadata source, IMemberMetadata target) { var method = mapperMetadata.MethodsMetadata.FirstOrDefault(m => m.ReturnType.FullName == target.FullName && m.Parameters.FirstOrDefault().FullName == source.FullName); diff --git a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs index b17c8b7..35e929b 100644 --- a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs @@ -11,14 +11,9 @@ namespace Compentio.SourceMapper.Metadata internal interface IMemberMetadata : IMetadata { /// - /// Indicate that class is a field and implements field symbol + /// Indicate that member is field or property (or unknown) /// - bool IsField { get; } - - /// - /// Indicate that class is a property and implements property symbol - /// - bool IsProperty { get; } + MemberType MemberType { get; } /// /// Full name with namespace of the member @@ -57,9 +52,16 @@ internal MemberMetadata(ISymbol symbol) _symbol = symbol; } - public bool IsField => _symbol is IFieldSymbol; + public MemberType MemberType + { + get + { + if (_symbol is IFieldSymbol) return MemberType.Field; + if (_symbol is IPropertySymbol) return MemberType.Property; - public bool IsProperty => _symbol is IPropertySymbol; + return MemberType.Unknown; + } + } public string FullName => TypeMetadata.FullName; @@ -80,7 +82,7 @@ public IEnumerable Properties { get { - if (!IsClass || !IsProperty) + if (!IsClass || MemberType != MemberType.Property) return Enumerable.Empty(); return Type.GetMembers() @@ -97,11 +99,21 @@ private ITypeSymbol Type { get { - if (IsField) return ((IFieldSymbol)_symbol).Type; + if (MemberType == MemberType.Field) return ((IFieldSymbol)_symbol).Type; else return ((IPropertySymbol)_symbol).Type; } } private ITypeMetadata TypeMetadata => new TypeMetadata(Type); } + + /// + /// Types of member + /// + internal enum MemberType + { + Field, + Property, + Unknown + } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs index 98f3cac..d5d0a34 100644 --- a/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/TypeMetadata.cs @@ -17,19 +17,19 @@ internal interface ITypeMetadata : IMetadata /// /// Object list of properties /// - IEnumerable Properties { get; } + IEnumerable Properties { get; } /// - /// Object list of fields + /// Object list of fields /// - IEnumerable Fields { get; } + IEnumerable Fields { get; } /// /// Recurrent method that return flatten list of properties tree for the object /// /// List of properties /// - IEnumerable FlattenProperties(IEnumerable propertyMetadata); + IEnumerable FlattenProperties(IEnumerable propertyMetadata); } internal class ParameterTypeMetadata : ITypeMetadata @@ -44,17 +44,17 @@ internal ParameterTypeMetadata(IParameterSymbol parameterSymbol) public string Name => _parameterSymbol.Name; public string FullName => _parameterSymbol.ToDisplayString(); - public IEnumerable Properties => _parameterSymbol.Type.GetMembers() + public IEnumerable Properties => _parameterSymbol.Type.GetMembers() .Where(member => member as IPropertySymbol is not null) - .Select(member => new PropertyMetadata(member as IPropertySymbol)); + .Select(member => new MemberMetadata(member as IPropertySymbol)); - public IEnumerable Fields => _parameterSymbol.Type.GetMembers() + public IEnumerable Fields => _parameterSymbol.Type.GetMembers() .Where(member => member is IFieldSymbol && member.CanBeReferencedByName && !((IFieldSymbol)member).IsConst) - .Select(member => new FieldMetadata(member as IFieldSymbol)); + .Select(member => new MemberMetadata(member as IFieldSymbol)); public Location? Location => _parameterSymbol.Locations.FirstOrDefault(); - public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => + public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => propertyMetadata.SelectMany(c => FlattenProperties(c.Properties)).Concat(propertyMetadata); } @@ -72,17 +72,17 @@ internal TypeMetadata(ITypeSymbol typeSymbol) public ITypeSymbol Type => _typeSymbol; - public IEnumerable Properties => _typeSymbol.GetMembers() + public IEnumerable Properties => _typeSymbol.GetMembers() .Where(member => member.Kind == SymbolKind.Property && !member.IsStatic) - .Select(member => new PropertyMetadata(member as IPropertySymbol)); + .Select(member => new MemberMetadata(member as IPropertySymbol)); - public IEnumerable Fields => _typeSymbol.GetMembers() + public IEnumerable Fields => _typeSymbol.GetMembers() .Where(member => member.Kind == SymbolKind.Field && member.CanBeReferencedByName && !((IFieldSymbol)member).IsConst) - .Select(member => new FieldMetadata(member as IFieldSymbol)); + .Select(member => new MemberMetadata(member as IFieldSymbol)); public Location? Location => _typeSymbol.Locations.FirstOrDefault(); - public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => + public IEnumerable FlattenProperties(IEnumerable propertyMetadata) => propertyMetadata.SelectMany(c => FlattenProperties(c.Properties)).Concat(propertyMetadata); } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs index fc8add6..064d487 100644 --- a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs @@ -84,8 +84,8 @@ protected string GenerateMethod(IMapperMetadata sourceMetadata, IMethodMetadata var target = new {methodMetadata.ReturnType.FullName}(); - {GenerateFieldsMappings(sourceMetadata, methodMetadata)} - {GeneratePropertiesMappings(sourceMetadata, methodMetadata)} + {GenerateMappings(sourceMetadata, methodMetadata, MemberType.Field)} + {GenerateMappings(sourceMetadata, methodMetadata, MemberType.Property)} return target; }}"; @@ -100,50 +100,64 @@ protected string GenerateInverseMethod(IMapperMetadata sourceMetadata, IMethodMe var target = new {methodMetadata.Parameters.First().FullName}(); - {GenerateFieldsMappings(sourceMetadata, methodMetadata, true)} - {GeneratePropertiesMappings(sourceMetadata, methodMetadata, true)} + {GenerateMappings(sourceMetadata, methodMetadata, MemberType.Field, true)} + {GenerateMappings(sourceMetadata, methodMetadata, MemberType.Property, true)} return target; }}"; } - protected string GenerateFieldsMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) + protected string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, MemberType memberType, bool inverseMapping = false) { var mappingsStringBuilder = new StringBuilder(); - var sourceMembers = methodMetadata.Parameters.First().Fields; - var targetMemebers = methodMetadata.ReturnType.Fields; + var sourceMembers = GetSourceMembers(methodMetadata, memberType); + var targetMemebers = GetTargetMembers(methodMetadata, memberType); foreach (var targetMember in targetMemebers) { - var matchedSourceMember = (IFieldMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = (IFieldMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); + var matchedSourceMember = sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); + var matchedTargetMember = targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); - if (IgnoreFieldMapping(matchedSourceMember, matchedTargetMember)) continue; + if (IgnoreMapping(matchedSourceMember, matchedTargetMember)) continue; - mappingsStringBuilder.Append(GenerateFieldMapping(sourceMetadata, methodMetadata, matchedSourceMember, matchedTargetMember, inverseMapping)); + if (memberType == MemberType.Property) + { + var expressionAttribute = methodMetadata.MappingAttributes.MatchExpressionAttribute(targetMember, matchedSourceMember); + var expressionMapping = MapExpression(expressionAttribute, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember); + + if (!string.IsNullOrEmpty(expressionMapping)) + { + if (inverseMapping) continue; + + mappingsStringBuilder.Append(expressionMapping); + continue; + } + } + + mappingsStringBuilder.Append(GenerateMapping(sourceMetadata, methodMetadata, matchedSourceMember, matchedTargetMember, memberType, inverseMapping)); } return mappingsStringBuilder.ToString(); } - protected string GenerateFieldMapping(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, IFieldMetadata matchedSourceMember, IFieldMetadata matchedTargetMember, bool inverseMapping = false) + protected string GenerateMapping(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, IMemberMetadata matchedSourceMember, IMemberMetadata matchedTargetMember, MemberType memberType, bool inverseMapping = false) { if (inverseMapping) ObjectHelper.Swap(ref matchedSourceMember, ref matchedTargetMember); if (matchedTargetMember is null && matchedSourceMember is not null) { - FieldMappingWarning(matchedSourceMember); + MemberMappingWarning(matchedSourceMember); } if (matchedSourceMember is null || matchedTargetMember is null) { - FieldMappingWarning(matchedSourceMember ?? matchedTargetMember); + MemberMappingWarning(matchedSourceMember ?? matchedTargetMember); return string.Empty; } var mapping = new StringBuilder(); - if (matchedSourceMember.IsStatic && matchedTargetMember.IsStatic) + if (matchedSourceMember.IsStatic && matchedTargetMember.IsStatic && memberType == MemberType.Field) { mapping.AppendLine(MapStaticProperty(matchedSourceMember, matchedTargetMember, methodMetadata, inverseMapping)); return mapping.ToString(); @@ -152,77 +166,41 @@ protected string GenerateFieldMapping(IMapperMetadata sourceMetadata, IMethodMet if (!matchedSourceMember.IsClass && !matchedTargetMember.IsClass) { mapping.AppendLine(MapProperty(matchedSourceMember, matchedTargetMember, methodMetadata.Parameters.First())); - return mapping.ToString(); } - return mapping.ToString(); - } - - protected string GeneratePropertiesMappings(IMapperMetadata sourceMetadata, IMethodMetadata methodMetadata, bool inverseMapping = false) - { - var mappingsStringBuilder = new StringBuilder(); - var sourceMembers = methodMetadata.Parameters.First().Properties; - var targetMemebers = methodMetadata.ReturnType.Properties; - - foreach (var targetMember in targetMemebers) + if (matchedSourceMember.IsClass && matchedTargetMember.IsClass) { - var matchedSourceMember = (IPropertyMetadata)sourceMembers.MatchSourceMember(methodMetadata.MappingAttributes, targetMember); - var matchedTargetMember = (IPropertyMetadata)targetMemebers.MatchTargetMember(methodMetadata.MappingAttributes, targetMember); - - if (IgnorePropertyMapping(matchedSourceMember, matchedTargetMember)) continue; - - var expressionAttribute = methodMetadata.MappingAttributes.MatchExpressionAttribute(targetMember, matchedSourceMember); - var expressionMapping = MapExpression(expressionAttribute, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember); - - if (!string.IsNullOrEmpty(expressionMapping)) - { - if (inverseMapping) continue; - - mappingsStringBuilder.Append(expressionMapping); - continue; - } - - mappingsStringBuilder.Append(GeneratePropertyMapping(sourceMetadata, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember, inverseMapping)); + mapping.AppendLine(MapClass(sourceMetadata, matchedSourceMember, matchedTargetMember, methodMetadata.Parameters.First(), inverseMapping)); } - return mappingsStringBuilder.ToString(); + return mapping.ToString(); } - protected string GeneratePropertyMapping(IMapperMetadata sourceMetadata, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, bool inverseMapping = false) + protected string MapProperty(IMetadata matchedSourceMember, IMetadata matchedTargetMember, ITypeMetadata parameter) { - if (inverseMapping) ObjectHelper.Swap(ref matchedSourceMember, ref matchedTargetMember); - - if (matchedTargetMember is null && matchedSourceMember is not null) - { - PropertyMappingWarning(matchedSourceMember); - } - - if (matchedSourceMember is null || matchedTargetMember is null) - { - PropertyMappingWarning(matchedSourceMember ?? matchedTargetMember); - return string.Empty; - } + return $"target.{matchedTargetMember?.Name} = {parameter.Name}.{matchedSourceMember?.Name};"; + } - var mapping = new StringBuilder(); + protected string MapClass(IMapperMetadata sourceMetadata, IMemberMetadata matchedSourceMember, IMemberMetadata matchedTargetMember, ITypeMetadata parameter, bool inverseMapping) + { + var method = GetDefinedMethod(sourceMetadata, matchedSourceMember, matchedTargetMember, inverseMapping); - if (!matchedSourceMember.IsClass && !matchedTargetMember.IsClass) + if (method is not null) { - mapping.AppendLine(MapProperty(matchedSourceMember, matchedTargetMember, parameter)); + if (inverseMapping) + return $"target.{matchedTargetMember?.Name} = {method.InverseMethodName}({parameter.Name}.{matchedSourceMember.Name});"; + else + return $"target.{matchedTargetMember?.Name} = {method.Name}({parameter.Name}.{matchedSourceMember.Name});"; } - - if (matchedSourceMember.IsClass && matchedTargetMember.IsClass) + else { - mapping.AppendLine(MapClass(sourceMetadata, matchedSourceMember, matchedTargetMember, parameter, inverseMapping)); + MemberMappingWarning(matchedTargetMember); } - return mapping.ToString(); - } - protected string MapProperty(IMetadata matchedSourceMember, IMetadata matchedTargetMember, ITypeMetadata parameter) - { - return $"target.{matchedTargetMember?.Name} = {parameter.Name}.{matchedSourceMember?.Name};"; + return string.Empty; } - private string MapStaticProperty(IFieldMetadata matchedSourceMember, IFieldMetadata matchedTargetMember, IMethodMetadata methodMetadata, bool inverseMapping) + protected string MapStaticProperty(IMemberMetadata matchedSourceMember, IMemberMetadata matchedTargetMember, IMethodMetadata methodMetadata, bool inverseMapping) { if (inverseMapping) return $"{methodMetadata.Parameters.First().FullName}.{matchedTargetMember?.Name} = {methodMetadata.ReturnType.FullName}.{matchedSourceMember?.Name};"; @@ -230,7 +208,7 @@ private string MapStaticProperty(IFieldMetadata matchedSourceMember, IFieldMetad return $"{methodMetadata.ReturnType.FullName}.{matchedTargetMember?.Name} = {methodMetadata.Parameters.First().FullName}.{matchedSourceMember?.Name};"; } - private string MapExpression(MappingAttribute expressionAttribute, ITypeMetadata parameter, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember) + protected string MapExpression(MappingAttribute expressionAttribute, ITypeMetadata parameter, IMemberMetadata matchedSourceMember, IMemberMetadata matchedTargetMember) { var mapping = new StringBuilder(); @@ -249,26 +227,7 @@ private string MapExpression(MappingAttribute expressionAttribute, ITypeMetadata return mapping.ToString(); } - protected string MapClass(IMapperMetadata sourceMetadata, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, ITypeMetadata parameter, bool inverseMapping) - { - var method = GetDefinedMethod(sourceMetadata, matchedSourceMember, matchedTargetMember, inverseMapping); - - if (method is not null) - { - if (inverseMapping) - return $"target.{matchedTargetMember?.Name} = {method.InverseMethodName}({parameter.Name}.{matchedSourceMember.Name});"; - else - return $"target.{matchedTargetMember?.Name} = {method.Name}({parameter.Name}.{matchedSourceMember.Name});"; - } - else - { - PropertyMappingWarning(matchedTargetMember); - } - - return string.Empty; - } - - protected IMethodMetadata? GetDefinedMethod(IMapperMetadata sourceMetadata, IPropertyMetadata matchedSourceMember, IPropertyMetadata matchedTargetMember, bool inverseMapping) + protected IMethodMetadata? GetDefinedMethod(IMapperMetadata sourceMetadata, IMemberMetadata matchedSourceMember, IMemberMetadata matchedTargetMember, bool inverseMapping) { if (inverseMapping) { @@ -281,43 +240,57 @@ protected string MapClass(IMapperMetadata sourceMetadata, IPropertyMetadata matc } /// - /// Metchod checks that property metadata should be ignored during mapping due to - /// - /// - /// - /// - protected bool IgnorePropertyMapping(IPropertyMetadata? sourcePropertyMetadata, IPropertyMetadata? targetPropertyMetadata) - { - return (sourcePropertyMetadata?.IgnoreInMapping is true || targetPropertyMetadata?.IgnoreInMapping is true); - } - - /// - /// Metchod checks that field metadata should be ignored during mapping due to + /// Metchod checks that member metadata should be ignored during mapping due to /// /// /// /// - protected bool IgnoreFieldMapping(IFieldMetadata? sourceFieldMetadata, IFieldMetadata? targetFieldMetadata) + protected bool IgnoreMapping(IMemberMetadata? sourceFieldMetadata, IMemberMetadata? targetFieldMetadata) { return (sourceFieldMetadata?.IgnoreInMapping is true || targetFieldMetadata?.IgnoreInMapping is true); } - protected void PropertyMappingWarning(IPropertyMetadata metadata) + protected void MemberMappingWarning(IMemberMetadata metadata) { _diagnostics.Add(new DiagnosticsInfo { - DiagnosticDescriptor = SourceMapperDescriptors.PropertyIsNotMapped, + DiagnosticDescriptor = metadata.MemberType == MemberType.Field ? SourceMapperDescriptors.FieldIsNotMapped : SourceMapperDescriptors.PropertyIsNotMapped, Metadata = metadata }); } - protected void FieldMappingWarning(IFieldMetadata metadata) + protected IEnumerable GetSourceMembers(IMethodMetadata methodMetadata, MemberType memberType) { - _diagnostics.Add(new DiagnosticsInfo + var typeMetadata = methodMetadata.Parameters.First(); + + switch (memberType) { - DiagnosticDescriptor = SourceMapperDescriptors.FieldIsNotMapped, - Metadata = metadata - }); + case MemberType.Field: + return typeMetadata.Fields; + + case MemberType.Property: + return typeMetadata.Properties; + + default: + return Enumerable.Empty(); + } + } + + protected IEnumerable GetTargetMembers(IMethodMetadata methodMetadata, MemberType memberType) + { + var typeMetadata = methodMetadata.ReturnType; + + switch (memberType) + { + case MemberType.Field: + return typeMetadata.Fields; + + case MemberType.Property: + return typeMetadata.Properties; + + default: + return Enumerable.Empty(); + } } } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Tests/Entities/UserDao.cs b/Compentio.SourceMapper.Tests/Entities/UserDao.cs index e7c29cf..3b180be 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserDao.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserDao.cs @@ -8,6 +8,7 @@ public class UserDao { public static string StringStaticValueDao = "StringStaticValueDao"; public string StringFieldValueDao = "StringFieldValueDao"; + public long UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } diff --git a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs index c18a878..e961cad 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs @@ -8,6 +8,7 @@ public class UserInfo { public static string StringStaticValueInfo = "StringStaticValueInfo"; public string StringFieldValueInfo = "StringFieldValueInfo"; + public int Id { get; set; } public string Name { get; set; } public Sex Sex { get; set; } diff --git a/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs b/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs index 2d8f61a..418ebe9 100644 --- a/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs +++ b/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs @@ -12,6 +12,8 @@ namespace Compentio.SourceMapper.Tests.Mappings [Mapper(ClassName = "ClassUserDaoMapper")] public abstract partial class UserMapper { + [Mapping(Source = nameof(UserDao.StringStaticValueDao), Target = nameof(UserInfo.StringStaticValueInfo))] + [Mapping(Source = nameof(UserDao.StringFieldValueDao), Target = nameof(UserInfo.StringFieldValueInfo))] [Mapping(Source = nameof(UserDao.UserId), Target = nameof(UserInfo.Id), Expression = nameof(ConvertUserId))] [Mapping(Source = nameof(UserDao.UserGender), Target = nameof(UserInfo.Sex), Expression = nameof(ConvertUserGender))] [Mapping(Source = nameof(UserDao), Target = nameof(UserInfo.Name), Expression = nameof(ConvertUserName))] diff --git a/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs b/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs index 8ebc159..06b7146 100644 --- a/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs +++ b/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs @@ -15,8 +15,8 @@ public class AttributesMatchersTests private readonly IFixture _fixture; private readonly Mock _mockMethodMetadata; private readonly Mock _mockMappingAttribute; - private readonly Mock _mockTargetPropertyMetadata; - private readonly Mock _mockSourcePropertyMetadata; + private readonly Mock _mockTargetPropertyMetadata; + private readonly Mock _mockSourcePropertyMetadata; public AttributesMatchersTests() { @@ -25,8 +25,8 @@ public AttributesMatchersTests() .Customize(new SupportMutableValueTypesCustomization()); _mockMethodMetadata = _fixture.Create>(); _mockMappingAttribute = _fixture.Create>(); - _mockTargetPropertyMetadata = _fixture.Create>(); - _mockSourcePropertyMetadata = _fixture.Create>(); + _mockTargetPropertyMetadata = _fixture.Create>(); + _mockSourcePropertyMetadata = _fixture.Create>(); } [Fact] diff --git a/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs index be908c8..a5ff10e 100644 --- a/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs +++ b/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs @@ -16,7 +16,7 @@ public class ParameterTypeMetadataTests private readonly Mock _mockParameterSymbol; private readonly Mock _mockLocation; private readonly Mock _mockSymbol; - private readonly Mock _mockPropertyMetadata; + private readonly Mock _mockPropertyMetadata; public ParameterTypeMetadataTests() { @@ -26,7 +26,7 @@ public ParameterTypeMetadataTests() _mockParameterSymbol = _fixture.Create>(); _mockLocation = _fixture.Create>(); _mockSymbol = _fixture.Create>(); - _mockPropertyMetadata = _fixture.Create>(); + _mockPropertyMetadata = _fixture.Create>(); } [Fact] @@ -88,11 +88,11 @@ public void Instance_EmptyProperties() public void FlattenProperties_ValidFlatten() { // Arrange - var limitedPropertyMetadata = _fixture.Create>(); - limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); + var limitedPropertyMetadata = _fixture.Create>(); + limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); _mockPropertyMetadata.Setup(p => p.Properties).Returns( - new List + new List { limitedPropertyMetadata.Object, limitedPropertyMetadata.Object, @@ -103,7 +103,7 @@ public void FlattenProperties_ValidFlatten() // Act var parameterTypeMetadata = new ParameterTypeMetadata(_mockParameterSymbol.Object); - var result = parameterTypeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); + var result = parameterTypeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); // Assert result.Should().NotBeEmpty(); diff --git a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs index acb3098..2a1a9a8 100644 --- a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs +++ b/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs @@ -39,7 +39,7 @@ public void InstanceForClass_ValidNameField() _mockPropertySymbol.Setup(p => p.Name).Returns("Name"); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.Name.Should().Be("Name"); @@ -52,7 +52,7 @@ public void InstanceForClass_ValidFullNameField() _mockPropertySymbol.Setup(p => p.Type.ToDisplayString(It.IsAny())).Returns("FullName"); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.FullName.Should().Be("FullName"); @@ -66,7 +66,7 @@ public void InstanceForClass_ValidIsClassField() _mockPropertySymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.IsClass.Should().BeTrue(); @@ -79,7 +79,7 @@ public void InstanceForClass_ValidLocationField() _mockPropertySymbol.Setup(p => p.Locations).Returns(ImmutableArray.Create(_mockLocation.Object)); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.Location.Should().NotBeNull(); @@ -96,7 +96,7 @@ public void InstanceForClass_NotEmptyProperties() _mockSymbol.Setup(s => s.IsStatic).Returns(false); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.Properties.Should().NotBeEmpty(); @@ -109,7 +109,7 @@ public void InstanceForInterface_EmptyProperties() _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Interface); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.Properties.Should().BeEmpty(); @@ -122,7 +122,7 @@ public void InstanceForClass_ValidIgnoreInMapping() _mockPropertySymbol.Setup(p => p.GetAttributes()).Returns(GetAttributeDataMock(MockSourceCode, MockMethodName)); // Act - var propertyMetadata = new PropertyMetadata(_mockPropertySymbol.Object); + var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); // Assert propertyMetadata.IgnoreInMapping.Should().BeTrue(); diff --git a/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs index 056e7e0..ea87b48 100644 --- a/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs +++ b/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs @@ -16,7 +16,7 @@ public class TypeMetadataTests private readonly Mock _mockTypeSymbol; private readonly Mock _mockLocation; private readonly Mock _mockSymbol; - private readonly Mock _mockPropertyMetadata; + private readonly Mock _mockPropertyMetadata; public TypeMetadataTests() { @@ -26,7 +26,7 @@ public TypeMetadataTests() _mockTypeSymbol = _fixture.Create>(); _mockLocation = _fixture.Create>(); _mockSymbol = _fixture.Create>(); - _mockPropertyMetadata = _fixture.Create>(); + _mockPropertyMetadata = _fixture.Create>(); } [Fact] @@ -114,11 +114,11 @@ public void Instanc_EmptyProperties() public void FlattenProperties_ValidFlatten() { // Arrange - var limitedPropertyMetadata = _fixture.Create>(); - limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); + var limitedPropertyMetadata = _fixture.Create>(); + limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); _mockPropertyMetadata.Setup(p => p.Properties).Returns( - new List + new List { limitedPropertyMetadata.Object, limitedPropertyMetadata.Object, @@ -129,7 +129,7 @@ public void FlattenProperties_ValidFlatten() // Act var typeMetadata = new TypeMetadata(_mockTypeSymbol.Object); - var result = typeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); + var result = typeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); // Assert result.Should().NotBeEmpty(); diff --git a/Compentio.SourceMapper.Tests/Processors/ClassProcessorStrategyTests.cs b/Compentio.SourceMapper.Tests/Processors/ClassProcessorStrategyTests.cs index e5c116d..0c4d203 100644 --- a/Compentio.SourceMapper.Tests/Processors/ClassProcessorStrategyTests.cs +++ b/Compentio.SourceMapper.Tests/Processors/ClassProcessorStrategyTests.cs @@ -93,7 +93,7 @@ public void GenerateCode_UnmatchedData_ReportNotMapped() // Arrange var methodMetadata = GetValidMethodWithAttributes(_mockMappingAttribute); // Create unmatched mock source and target metadata - methodMetadata.Setup(m => m.ReturnType.Properties).Returns(_fixture.Create>()); + methodMetadata.Setup(m => m.ReturnType.Properties).Returns(_fixture.Create>()); methodMetadata.Setup(m => m.Parameters).Returns(_fixture.Create>()); _sourceMetadataMock.Setup(sourceMetadata => sourceMetadata.MethodsMetadata).Returns(new List { methodMetadata.Object }); @@ -101,7 +101,8 @@ public void GenerateCode_UnmatchedData_ReportNotMapped() var result = _processorStrategy.GenerateCode(_sourceMetadataMock.Object); // Assert - result.Diagnostics.Should().Contain(d => d.DiagnosticDescriptor == SourceMapperDescriptors.PropertyIsNotMapped); + result.Diagnostics.Should().Contain(d => d.DiagnosticDescriptor == SourceMapperDescriptors.PropertyIsNotMapped || + d.DiagnosticDescriptor == SourceMapperDescriptors.FieldIsNotMapped); } [Fact] @@ -138,13 +139,13 @@ private Mock GetValidMethodWithAttributes(Mock>(); // Create new method property - var mockProperty = _fixture.Create>(); + var mockProperty = _fixture.Create>(); mockProperty.Setup(p => p.IsClass).Returns(false); mockProperty.Setup(p => p.IgnoreInMapping).Returns(ignoreInMapping); // Inject property var mockTypeMetadata = _fixture.Create>(); - mockTypeMetadata.Setup(t => t.Properties).Returns(new List { mockProperty.Object }); + mockTypeMetadata.Setup(t => t.Properties).Returns(new List { mockProperty.Object }); var sourceParameters = mockTypeMetadata.Object; var mockParameters = GetValidMethodParameters(sourceParameters); @@ -164,7 +165,7 @@ private Mock GetValidMethodParameters(ITypeMetadata sourceTypeMet mockParameters.Setup(p => p.Name).Returns(sourceTypeMetadata.Name); mockParameters.Setup(p => p.FullName).Returns(sourceTypeMetadata.FullName); mockParameters.Setup(p => p.Location).Returns(sourceTypeMetadata.Location); - mockParameters.Setup(p => p.Properties).Returns(new List { sourceTypeMetadata.Properties.First() }); + mockParameters.Setup(p => p.Properties).Returns(new List { sourceTypeMetadata.Properties.First() }); return mockParameters; } diff --git a/Compentio.SourceMapper.Tests/Processors/InterfaceProcessorStrategyTests.cs b/Compentio.SourceMapper.Tests/Processors/InterfaceProcessorStrategyTests.cs index c7750a4..a18a37f 100644 --- a/Compentio.SourceMapper.Tests/Processors/InterfaceProcessorStrategyTests.cs +++ b/Compentio.SourceMapper.Tests/Processors/InterfaceProcessorStrategyTests.cs @@ -90,7 +90,7 @@ public void GenerateCode_UnmatchedData_ReportNotMapped() { // Arrange var methodMetadata = GetValidMethodWithAttributes(_mockMappingAttribute); - methodMetadata.Setup(m => m.ReturnType.Properties).Returns(_fixture.Create>()); + methodMetadata.Setup(m => m.ReturnType.Properties).Returns(_fixture.Create>()); methodMetadata.Setup(m => m.Parameters).Returns(_fixture.Create>()); _sourceMetadataMock.Setup(sourceMetadata => sourceMetadata.MethodsMetadata).Returns(new List { methodMetadata.Object }); @@ -98,7 +98,8 @@ public void GenerateCode_UnmatchedData_ReportNotMapped() var result = _processorStrategy.GenerateCode(_sourceMetadataMock.Object); // Assert - result.Diagnostics.Should().Contain(d => d.DiagnosticDescriptor == SourceMapperDescriptors.PropertyIsNotMapped); + result.Diagnostics.Should().Contain(d => d.DiagnosticDescriptor == SourceMapperDescriptors.PropertyIsNotMapped || + d.DiagnosticDescriptor == SourceMapperDescriptors.FieldIsNotMapped); } [Fact] @@ -135,13 +136,13 @@ private Mock GetValidMethodWithAttributes(Mock>(); // Create new method property - var mockProperty = _fixture.Create>(); + var mockProperty = _fixture.Create>(); mockProperty.Setup(p => p.IsClass).Returns(false); mockProperty.Setup(p => p.IgnoreInMapping).Returns(ignoreInMapping); // Inject property var mockTypeMetadata = _fixture.Create>(); - mockTypeMetadata.Setup(t => t.Properties).Returns(new List { mockProperty.Object }); + mockTypeMetadata.Setup(t => t.Properties).Returns(new List { mockProperty.Object }); var sourceParameters = mockTypeMetadata.Object; var mockParameters = GetValidMethodParameters(sourceParameters); @@ -161,7 +162,7 @@ private Mock GetValidMethodParameters(ITypeMetadata sourceTypeMet mockParameters.Setup(p => p.Name).Returns(sourceTypeMetadata.Name); mockParameters.Setup(p => p.FullName).Returns(sourceTypeMetadata.FullName); mockParameters.Setup(p => p.Location).Returns(sourceTypeMetadata.Location); - mockParameters.Setup(p => p.Properties).Returns(new List { sourceTypeMetadata.Properties.First() }); + mockParameters.Setup(p => p.Properties).Returns(new List { sourceTypeMetadata.Properties.First() }); return mockParameters; } From 8397ee635d24e197a746e0ec228db2c3cb2af83e Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Tue, 28 Dec 2021 09:46:43 +0100 Subject: [PATCH 10/14] Update implementation. --- .../Metadata/MemberMetadata.cs | 1 + .../Processors/ClassProcessorStrategy.cs | 2 ++ .../Processors/IProcessorStrategy.cs | 16 +++++++++++++++- .../Processors/InterfaceProcessorStrategy.cs | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs index 35e929b..528178d 100644 --- a/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs +++ b/Compentio.SourceMapper.Generator/Metadata/MemberMetadata.cs @@ -12,6 +12,7 @@ internal interface IMemberMetadata : IMetadata { /// /// Indicate that member is field or property (or unknown) + /// Based od and /// MemberType MemberType { get; } diff --git a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs index f06f45f..4091888 100644 --- a/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/ClassProcessorStrategy.cs @@ -12,6 +12,8 @@ internal class ClassProcessorStrategy : AbstractProcessorStrategy { protected override string Modifier => "override"; + protected override ProcessorType ProcessorType => ProcessorType.Class; + protected override string GenerateMapperCode(IMapperMetadata mapperMetadata) { var result = @$"// diff --git a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs index 064d487..733592c 100644 --- a/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/IProcessorStrategy.cs @@ -56,6 +56,11 @@ public IResult GenerateCode(IMapperMetadata mapperMetadata) /// protected abstract string Modifier { get; } + /// + /// Determine processor strategy type + /// + protected abstract ProcessorType ProcessorType { get; } + protected abstract string GenerateMapperCode(IMapperMetadata mapperMetadata); protected string GenerateMethods(IMapperMetadata sourceMetadata) @@ -120,7 +125,7 @@ protected string GenerateMappings(IMapperMetadata sourceMetadata, IMethodMetadat if (IgnoreMapping(matchedSourceMember, matchedTargetMember)) continue; - if (memberType == MemberType.Property) + if (ProcessorType == ProcessorType.Class && memberType == MemberType.Property) { var expressionAttribute = methodMetadata.MappingAttributes.MatchExpressionAttribute(targetMember, matchedSourceMember); var expressionMapping = MapExpression(expressionAttribute, methodMetadata.Parameters.First(), matchedSourceMember, matchedTargetMember); @@ -293,4 +298,13 @@ protected IEnumerable GetTargetMembers(IMethodMetadata methodMe } } } + + /// + /// Encapsulate processor strategy types + /// + internal enum ProcessorType + { + Class, + Interface + } } \ No newline at end of file diff --git a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs index ca2cd01..a17abf3 100644 --- a/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs +++ b/Compentio.SourceMapper.Generator/Processors/InterfaceProcessorStrategy.cs @@ -12,6 +12,8 @@ internal class InterfaceProcessorStrategy : AbstractProcessorStrategy { protected override string Modifier => "virtual"; + protected override ProcessorType ProcessorType => ProcessorType.Interface; + protected override string GenerateMapperCode(IMapperMetadata mapperMetadata) { var result = @$"// From 286201c45cd834146431c08e3651aa8093d1f852 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Tue, 28 Dec 2021 12:07:42 +0100 Subject: [PATCH 11/14] Update unit tests. --- .../Entities/UserDao.cs | 4 +- .../Entities/UserInfo.cs | 4 +- .../Mappings/ClassUserMappers.cs | 2 - .../Mappings/InterfaceUserMappers.cs | 2 - .../Matchers/AttributesMatchersTests.cs | 30 +++++++------- .../Metadata/ParameterTypeMetadataTests.cs | 22 +++++++++-- .../Metadata/TypeMetadataTests.cs | 39 +++++++++++++++++-- 7 files changed, 72 insertions(+), 31 deletions(-) diff --git a/Compentio.SourceMapper.Tests/Entities/UserDao.cs b/Compentio.SourceMapper.Tests/Entities/UserDao.cs index 3b180be..b468d4c 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserDao.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserDao.cs @@ -6,8 +6,8 @@ namespace Compentio.SourceMapper.Tests.Entities { public class UserDao { - public static string StringStaticValueDao = "StringStaticValueDao"; - public string StringFieldValueDao = "StringFieldValueDao"; + public static string UserCodeStatic = "UserCodeStaticDao"; + public string UserCode = "UserCodeDao"; public long UserId { get; set; } public string FirstName { get; set; } diff --git a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs index e961cad..bcd23c6 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs @@ -6,8 +6,8 @@ namespace Compentio.SourceMapper.Tests.Entities { public class UserInfo { - public static string StringStaticValueInfo = "StringStaticValueInfo"; - public string StringFieldValueInfo = "StringFieldValueInfo"; + public static string UserCodeStatic = "UserCodeStaticInfo"; + public string UserCode = "UserCodeInfo"; public int Id { get; set; } public string Name { get; set; } diff --git a/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs b/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs index 418ebe9..2d8f61a 100644 --- a/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs +++ b/Compentio.SourceMapper.Tests/Mappings/ClassUserMappers.cs @@ -12,8 +12,6 @@ namespace Compentio.SourceMapper.Tests.Mappings [Mapper(ClassName = "ClassUserDaoMapper")] public abstract partial class UserMapper { - [Mapping(Source = nameof(UserDao.StringStaticValueDao), Target = nameof(UserInfo.StringStaticValueInfo))] - [Mapping(Source = nameof(UserDao.StringFieldValueDao), Target = nameof(UserInfo.StringFieldValueInfo))] [Mapping(Source = nameof(UserDao.UserId), Target = nameof(UserInfo.Id), Expression = nameof(ConvertUserId))] [Mapping(Source = nameof(UserDao.UserGender), Target = nameof(UserInfo.Sex), Expression = nameof(ConvertUserGender))] [Mapping(Source = nameof(UserDao), Target = nameof(UserInfo.Name), Expression = nameof(ConvertUserName))] diff --git a/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs b/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs index edd4e07..896d704 100644 --- a/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs +++ b/Compentio.SourceMapper.Tests/Mappings/InterfaceUserMappers.cs @@ -7,8 +7,6 @@ namespace Compentio.SourceMapper.Tests.Mappings [Mapper(ClassName = "InterfaceUserDaoMapper")] public partial interface IUserDaoMapper { - [Mapping(Source = nameof(UserDao.StringStaticValueDao), Target = nameof(UserInfo.StringStaticValueInfo))] - [Mapping(Source = nameof(UserDao.StringFieldValueDao), Target = nameof(UserInfo.StringFieldValueInfo))] [Mapping(Source = nameof(UserDao.FirstName), Target = nameof(UserInfo.Name))] [InverseMapping(InverseMethodName = "MapToDatabaseModel")] UserInfo MapToDomainModel(UserDao source); diff --git a/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs b/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs index 06b7146..2a9936c 100644 --- a/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs +++ b/Compentio.SourceMapper.Tests/Matchers/AttributesMatchersTests.cs @@ -15,8 +15,8 @@ public class AttributesMatchersTests private readonly IFixture _fixture; private readonly Mock _mockMethodMetadata; private readonly Mock _mockMappingAttribute; - private readonly Mock _mockTargetPropertyMetadata; - private readonly Mock _mockSourcePropertyMetadata; + private readonly Mock _mockTargetMemberMetadata; + private readonly Mock _mockSourceMemberMetadata; public AttributesMatchersTests() { @@ -25,8 +25,8 @@ public AttributesMatchersTests() .Customize(new SupportMutableValueTypesCustomization()); _mockMethodMetadata = _fixture.Create>(); _mockMappingAttribute = _fixture.Create>(); - _mockTargetPropertyMetadata = _fixture.Create>(); - _mockSourcePropertyMetadata = _fixture.Create>(); + _mockTargetMemberMetadata = _fixture.Create>(); + _mockSourceMemberMetadata = _fixture.Create>(); } [Fact] @@ -67,10 +67,10 @@ public void MatchTargetAttribute_Match() { // Arrange IEnumerable mappingAttributes = new List { _mockMappingAttribute.Object }; - _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetPropertyMetadata.Object.Name); + _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetMemberMetadata.Object.Name); // Act - var result = mappingAttributes.MatchTargetAttribute(_mockTargetPropertyMetadata.Object); + var result = mappingAttributes.MatchTargetAttribute(_mockTargetMemberMetadata.Object); // Assert result.Should().NotBeNull(); @@ -84,7 +84,7 @@ public void MatchTargetAttribute_NotMatch() _mockMappingAttribute.Setup(m => m.Target).Returns(string.Empty); // Act - var result = mappingAttributes.MatchTargetAttribute(_mockTargetPropertyMetadata.Object); + var result = mappingAttributes.MatchTargetAttribute(_mockTargetMemberMetadata.Object); // Assert result.Should().BeNull(); @@ -95,11 +95,11 @@ public void MatchExpressionAttribute_MatchSourceAndTarget() { // Arrange IEnumerable mappingAttributes = new List { _mockMappingAttribute.Object }; - _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetPropertyMetadata.Object.Name); - _mockMappingAttribute.Setup(m => m.Source).Returns(_mockSourcePropertyMetadata.Object.Name); + _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetMemberMetadata.Object.Name); + _mockMappingAttribute.Setup(m => m.Source).Returns(_mockSourceMemberMetadata.Object.Name); // Act - var result = mappingAttributes.MatchExpressionAttribute(_mockTargetPropertyMetadata.Object, _mockSourcePropertyMetadata.Object); + var result = mappingAttributes.MatchExpressionAttribute(_mockTargetMemberMetadata.Object, _mockSourceMemberMetadata.Object); // Assert result.Should().NotBeNull(); @@ -110,10 +110,10 @@ public void MatchExpressionAttribute_MatchTarget() { // Arrange IEnumerable mappingAttributes = new List { _mockMappingAttribute.Object }; - _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetPropertyMetadata.Object.Name); + _mockMappingAttribute.Setup(m => m.Target).Returns(_mockTargetMemberMetadata.Object.Name); // Act - var result = mappingAttributes.MatchExpressionAttribute(_mockTargetPropertyMetadata.Object, _mockSourcePropertyMetadata.Object); + var result = mappingAttributes.MatchExpressionAttribute(_mockTargetMemberMetadata.Object, _mockSourceMemberMetadata.Object); // Assert result.Should().NotBeNull(); @@ -128,7 +128,7 @@ public void MatchExpressionAttribute_NotMatchSourceAndTarget() _mockMappingAttribute.Setup(m => m.Source).Returns(string.Empty); // Act - var result = mappingAttributes.MatchExpressionAttribute(_mockTargetPropertyMetadata.Object, _mockSourcePropertyMetadata.Object); + var result = mappingAttributes.MatchExpressionAttribute(_mockTargetMemberMetadata.Object, _mockSourceMemberMetadata.Object); // Assert result.Should().BeNull(); @@ -140,10 +140,10 @@ public void MatchExpressionAttribute_NotMatchTarget() // Arrange IEnumerable mappingAttributes = new List { _mockMappingAttribute.Object }; _mockMappingAttribute.Setup(m => m.Target).Returns(string.Empty); - _mockMappingAttribute.Setup(m => m.Source).Returns(_mockSourcePropertyMetadata.Object.Name); + _mockMappingAttribute.Setup(m => m.Source).Returns(_mockSourceMemberMetadata.Object.Name); // Act - var result = mappingAttributes.MatchExpressionAttribute(_mockTargetPropertyMetadata.Object, _mockSourcePropertyMetadata.Object); + var result = mappingAttributes.MatchExpressionAttribute(_mockTargetMemberMetadata.Object, _mockSourceMemberMetadata.Object); // Assert result.Should().BeNull(); diff --git a/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs index a5ff10e..ae3e203 100644 --- a/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs +++ b/Compentio.SourceMapper.Tests/Metadata/ParameterTypeMetadataTests.cs @@ -16,7 +16,7 @@ public class ParameterTypeMetadataTests private readonly Mock _mockParameterSymbol; private readonly Mock _mockLocation; private readonly Mock _mockSymbol; - private readonly Mock _mockPropertyMetadata; + private readonly Mock _mockMemberMetadata; public ParameterTypeMetadataTests() { @@ -26,7 +26,7 @@ public ParameterTypeMetadataTests() _mockParameterSymbol = _fixture.Create>(); _mockLocation = _fixture.Create>(); _mockSymbol = _fixture.Create>(); - _mockPropertyMetadata = _fixture.Create>(); + _mockMemberMetadata = _fixture.Create>(); } [Fact] @@ -84,6 +84,20 @@ public void Instance_EmptyProperties() parameterTypeMetadata.Properties.Should().BeEmpty(); } + [Fact] + public void Instance_EmptyFields() + { + // Arrange + _mockSymbol.Setup(s => s.CanBeReferencedByName).Returns(false); + _mockParameterSymbol.Setup(t => t.Type.GetMembers()).Returns(ImmutableArray.Create(_mockSymbol.Object)); + + // Act + var parameterTypeMetadata = new ParameterTypeMetadata(_mockParameterSymbol.Object); + + // Assert + parameterTypeMetadata.Fields.Should().BeEmpty(); + } + [Fact] public void FlattenProperties_ValidFlatten() { @@ -91,7 +105,7 @@ public void FlattenProperties_ValidFlatten() var limitedPropertyMetadata = _fixture.Create>(); limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); - _mockPropertyMetadata.Setup(p => p.Properties).Returns( + _mockMemberMetadata.Setup(p => p.Properties).Returns( new List { limitedPropertyMetadata.Object, @@ -103,7 +117,7 @@ public void FlattenProperties_ValidFlatten() // Act var parameterTypeMetadata = new ParameterTypeMetadata(_mockParameterSymbol.Object); - var result = parameterTypeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); + var result = parameterTypeMetadata.FlattenProperties(new List { _mockMemberMetadata.Object }); // Assert result.Should().NotBeEmpty(); diff --git a/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs index ea87b48..dc2e0a5 100644 --- a/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs +++ b/Compentio.SourceMapper.Tests/Metadata/TypeMetadataTests.cs @@ -16,7 +16,7 @@ public class TypeMetadataTests private readonly Mock _mockTypeSymbol; private readonly Mock _mockLocation; private readonly Mock _mockSymbol; - private readonly Mock _mockPropertyMetadata; + private readonly Mock _mockMemberMetadata; public TypeMetadataTests() { @@ -26,7 +26,7 @@ public TypeMetadataTests() _mockTypeSymbol = _fixture.Create>(); _mockLocation = _fixture.Create>(); _mockSymbol = _fixture.Create>(); - _mockPropertyMetadata = _fixture.Create>(); + _mockMemberMetadata = _fixture.Create>(); } [Fact] @@ -95,6 +95,23 @@ public void Instanc_NotEmptyProperties() typeMetadata.Properties.Should().NotBeEmpty(); } + [Fact] + public void Instanc_NotEmptyFields() + { + // Arrange + var mockFieldSymbol = _fixture.Create>(); + mockFieldSymbol.Setup(s => s.Kind).Returns(SymbolKind.Field); + mockFieldSymbol.Setup(s => s.CanBeReferencedByName).Returns(true); + mockFieldSymbol.Setup(s => s.IsConst).Returns(false); + _mockTypeSymbol.Setup(t => t.GetMembers()).Returns(ImmutableArray.Create(mockFieldSymbol.Object as ISymbol)); + + // Act + var typeMetadata = new TypeMetadata(_mockTypeSymbol.Object); + + // Assert + typeMetadata.Fields.Should().NotBeEmpty(); + } + [Fact] public void Instanc_EmptyProperties() { @@ -110,6 +127,20 @@ public void Instanc_EmptyProperties() typeMetadata.Properties.Should().BeEmpty(); } + [Fact] + public void Instanc_EmptyFields() + { + // Arrange + _mockTypeSymbol.Setup(t => t.GetMembers()).Returns(ImmutableArray.Create(_mockSymbol.Object)); + _mockSymbol.Setup(s => s.Kind).Returns(SymbolKind.ErrorType); + + // Act + var typeMetadata = new TypeMetadata(_mockTypeSymbol.Object); + + // Assert + typeMetadata.Fields.Should().BeEmpty(); + } + [Fact] public void FlattenProperties_ValidFlatten() { @@ -117,7 +148,7 @@ public void FlattenProperties_ValidFlatten() var limitedPropertyMetadata = _fixture.Create>(); limitedPropertyMetadata.Setup(l => l.Properties).Returns(new List()); - _mockPropertyMetadata.Setup(p => p.Properties).Returns( + _mockMemberMetadata.Setup(p => p.Properties).Returns( new List { limitedPropertyMetadata.Object, @@ -129,7 +160,7 @@ public void FlattenProperties_ValidFlatten() // Act var typeMetadata = new TypeMetadata(_mockTypeSymbol.Object); - var result = typeMetadata.FlattenProperties(new List { _mockPropertyMetadata.Object }); + var result = typeMetadata.FlattenProperties(new List { _mockMemberMetadata.Object }); // Assert result.Should().NotBeEmpty(); From a2dd00413249413ffd16d554ee0b0813358f89c8 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Tue, 28 Dec 2021 15:28:36 +0100 Subject: [PATCH 12/14] Update unit tests. --- ...aTestBase.cs => MemberMetadataTestBase.cs} | 8 +- .../Metadata/MemberMetadataTests.cs | 255 ++++++++++++++++++ .../Metadata/PropertyMetadataTests.cs | 131 --------- 3 files changed, 260 insertions(+), 134 deletions(-) rename Compentio.SourceMapper.Tests/Metadata/{PropertyMetadataTestBase.cs => MemberMetadataTestBase.cs} (90%) create mode 100644 Compentio.SourceMapper.Tests/Metadata/MemberMetadataTests.cs delete mode 100644 Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs diff --git a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTestBase.cs b/Compentio.SourceMapper.Tests/Metadata/MemberMetadataTestBase.cs similarity index 90% rename from Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTestBase.cs rename to Compentio.SourceMapper.Tests/Metadata/MemberMetadataTestBase.cs index 3c2581f..01daf7d 100644 --- a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTestBase.cs +++ b/Compentio.SourceMapper.Tests/Metadata/MemberMetadataTestBase.cs @@ -6,7 +6,7 @@ namespace Compentio.SourceMapper.Tests.Metadata { - public abstract class PropertyMetadataTestBase + public abstract class MemberMetadataTestBase { protected abstract string MockNamespace { get; } protected abstract string MockClassName { get; } @@ -27,7 +27,7 @@ protected ImmutableArray GetAttributeDataMock(string sourceCode, protected Compilation GetCompilationMock(string sourceCode) { - return CSharpCompilation.Create("PropertyMetadataTestBase", + return CSharpCompilation.Create("MemberMetadataTestBase", new[] { CSharpSyntaxTree.ParseText(sourceCode) }, new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); @@ -41,13 +41,15 @@ namespace {MockNamespace} public abstract class {MockClassName} {{ - public abstract MockTypeDto {MockMethodName}(MockTypeDao fake); + public abstract MockTypeDto {MockMethodName}(MockTypeDao mock); }} public class MockTypeDao {{ [IgnoreMapping] public virtual string PropertyToIgnore {{ get; set; }} + public static string StaticFieldProperty; + public string FieldProperty; }} {IgnoreMappingAttributeSourceCode} diff --git a/Compentio.SourceMapper.Tests/Metadata/MemberMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/MemberMetadataTests.cs new file mode 100644 index 0000000..1b15ea8 --- /dev/null +++ b/Compentio.SourceMapper.Tests/Metadata/MemberMetadataTests.cs @@ -0,0 +1,255 @@ +using AutoFixture; +using AutoFixture.AutoMoq; +using Compentio.SourceMapper.Metadata; +using FluentAssertions; +using Microsoft.CodeAnalysis; +using Moq; +using System.Collections.Immutable; +using Xunit; + +namespace Compentio.SourceMapper.Tests.Metadata +{ + public class MemberMetadataTests : MemberMetadataTestBase + { + private readonly IFixture _fixture; + private readonly Mock _mockPropertySymbol; + private readonly Mock _mockFieldSymbol; + private readonly Mock _mockLocation; + private readonly Mock _mockSymbol; + + private const string MockName = "MockName"; + private const string MockFullName = "MockFullName"; + + protected override string MockNamespace => "MockNamespace"; + + protected override string MockClassName => "MockClassName"; + + protected override string MockMethodName => "MockMethodName"; + + public MemberMetadataTests() + { + _fixture = new Fixture() + .Customize(new AutoMoqCustomization { ConfigureMembers = true }) + .Customize(new SupportMutableValueTypesCustomization()); + _mockPropertySymbol = _fixture.Create>(); + _mockFieldSymbol = _fixture.Create>(); + _mockLocation = _fixture.Create>(); + _mockSymbol = _fixture.Create>(); + } + + [Fact] + public void InstanceForProperty_ValidNameField() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Name).Returns(MockName); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.Name.Should().Be(MockName); + } + + [Fact] + public void InstanceForField_ValidNameField() + { + // Arrange + _mockFieldSymbol.Setup(p => p.Name).Returns(MockName); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.Name.Should().Be(MockName); + } + + [Fact] + public void InstanceForProperty_ValidFullNameField() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Type.ToDisplayString(It.IsAny())).Returns(MockFullName); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.FullName.Should().Be(MockFullName); + } + + [Fact] + public void InstanceForField_ValidFullNameField() + { + // Arrange + _mockFieldSymbol.Setup(p => p.Type.ToDisplayString(It.IsAny())).Returns(MockFullName); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.FullName.Should().Be(MockFullName); + } + + [Fact] + public void InstanceForProperty_ValidIsClassField() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Class); + _mockPropertySymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.IsClass.Should().BeTrue(); + } + + [Fact] + public void InstanceForField_ValidIsClassField() + { + // Arrange + _mockFieldSymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Class); + _mockFieldSymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.IsClass.Should().BeTrue(); + } + + [Fact] + public void InstanceForProperty_ValidLocationField() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Locations).Returns(ImmutableArray.Create(_mockLocation.Object)); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.Location.Should().NotBeNull(); + } + + [Fact] + public void InstanceForField_ValidLocationField() + { + // Arrange + _mockFieldSymbol.Setup(p => p.Locations).Returns(ImmutableArray.Create(_mockLocation.Object)); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.Location.Should().NotBeNull(); + } + + [Fact] + public void InstanceForProperty_NotEmptyProperties() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Class); + _mockPropertySymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); + _mockPropertySymbol.Setup(p => p.Type.GetMembers()).Returns(ImmutableArray.Create(_mockSymbol.Object)); + _mockSymbol.Setup(s => s.Kind).Returns(SymbolKind.Property); + _mockSymbol.Setup(s => s.IsStatic).Returns(false); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.Properties.Should().NotBeEmpty(); + } + + [Fact] + public void InstanceForProperty_EmptyProperties() + { + // Arrange + _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Interface); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.Properties.Should().BeEmpty(); + } + + [Fact] + public void InstanceForField_EmptyProperties() + { + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.Properties.Should().BeEmpty(); + } + + [Fact] + public void InstanceForProperty_ValidIgnoreInMapping() + { + // Arrange + _mockPropertySymbol.Setup(p => p.GetAttributes()).Returns(GetAttributeDataMock(MockSourceCode, MockMethodName)); + + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.IgnoreInMapping.Should().BeTrue(); + } + + [Fact] + public void InstanceForField_ValidIgnoreInMapping() + { + // Arrange + _mockFieldSymbol.Setup(p => p.GetAttributes()).Returns(GetAttributeDataMock(MockSourceCode, MockMethodName)); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.IgnoreInMapping.Should().BeTrue(); + } + + [Fact] + public void InstanceForField_ValidIsStatic() + { + // Arrange + _mockFieldSymbol.Setup(p => p.IsStatic).Returns(true); + + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.IsStatic.Should().BeTrue(); + } + + [Fact] + public void InstanceForProperty_IsPropertyMember() + { + // Act + var memberMetadata = new MemberMetadata(_mockPropertySymbol.Object); + + // Assert + memberMetadata.MemberType.Should().Be(MemberType.Property); + } + + [Fact] + public void InstanceForField_IsFieldMember() + { + // Act + var memberMetadata = new MemberMetadata(_mockFieldSymbol.Object); + + // Assert + memberMetadata.MemberType.Should().Be(MemberType.Field); + } + + [Fact] + public void Instance_MemberUnknown() + { + // Act + var memberMetadata = new MemberMetadata(_mockSymbol.Object); + + // Assert + memberMetadata.MemberType.Should().Be(MemberType.Unknown); + } + } +} \ No newline at end of file diff --git a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs b/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs deleted file mode 100644 index 2a1a9a8..0000000 --- a/Compentio.SourceMapper.Tests/Metadata/PropertyMetadataTests.cs +++ /dev/null @@ -1,131 +0,0 @@ -using AutoFixture; -using AutoFixture.AutoMoq; -using Compentio.SourceMapper.Metadata; -using FluentAssertions; -using Microsoft.CodeAnalysis; -using Moq; -using System.Collections.Immutable; -using Xunit; - -namespace Compentio.SourceMapper.Tests.Metadata -{ - public class PropertyMetadataTests : PropertyMetadataTestBase - { - private readonly IFixture _fixture; - private readonly Mock _mockPropertySymbol; - private readonly Mock _mockLocation; - private readonly Mock _mockSymbol; - - protected override string MockNamespace => "MockNamespace"; - - protected override string MockClassName => "MockClassName"; - - protected override string MockMethodName => "MockMethodName"; - - public PropertyMetadataTests() - { - _fixture = new Fixture() - .Customize(new AutoMoqCustomization { ConfigureMembers = true }) - .Customize(new SupportMutableValueTypesCustomization()); - _mockPropertySymbol = _fixture.Create>(); - _mockLocation = _fixture.Create>(); - _mockSymbol = _fixture.Create>(); - } - - [Fact] - public void InstanceForClass_ValidNameField() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Name).Returns("Name"); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.Name.Should().Be("Name"); - } - - [Fact] - public void InstanceForClass_ValidFullNameField() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Type.ToDisplayString(It.IsAny())).Returns("FullName"); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.FullName.Should().Be("FullName"); - } - - [Fact] - public void InstanceForClass_ValidIsClassField() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Class); - _mockPropertySymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.IsClass.Should().BeTrue(); - } - - [Fact] - public void InstanceForClass_ValidLocationField() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Locations).Returns(ImmutableArray.Create(_mockLocation.Object)); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.Location.Should().NotBeNull(); - } - - [Fact] - public void InstanceForClass_NotEmptyProperties() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Class); - _mockPropertySymbol.Setup(p => p.Type.SpecialType).Returns(SpecialType.None); - _mockPropertySymbol.Setup(p => p.Type.GetMembers()).Returns(ImmutableArray.Create(_mockSymbol.Object)); - _mockSymbol.Setup(s => s.Kind).Returns(SymbolKind.Property); - _mockSymbol.Setup(s => s.IsStatic).Returns(false); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.Properties.Should().NotBeEmpty(); - } - - [Fact] - public void InstanceForInterface_EmptyProperties() - { - // Arrange - _mockPropertySymbol.Setup(p => p.Type.TypeKind).Returns(TypeKind.Interface); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.Properties.Should().BeEmpty(); - } - - [Fact] - public void InstanceForClass_ValidIgnoreInMapping() - { - // Arrange - _mockPropertySymbol.Setup(p => p.GetAttributes()).Returns(GetAttributeDataMock(MockSourceCode, MockMethodName)); - - // Act - var propertyMetadata = new MemberMetadata(_mockPropertySymbol.Object); - - // Assert - propertyMetadata.IgnoreInMapping.Should().BeTrue(); - } - } -} \ No newline at end of file From f97701610ee2645972f61ed5f5f64f4259ecf501 Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Wed, 29 Dec 2021 10:08:44 +0100 Subject: [PATCH 13/14] Update unit tests. --- .../Entities/UserDao.cs | 4 +++ .../Entities/UserInfo.cs | 2 +- .../Processors/ClassUserMapperTests.cs | 6 ++++- .../Processors/InterfaceUserMapperTests.cs | 26 +++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Compentio.SourceMapper.Tests/Entities/UserDao.cs b/Compentio.SourceMapper.Tests/Entities/UserDao.cs index b468d4c..31f639b 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserDao.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserDao.cs @@ -8,6 +8,8 @@ public class UserDao { public static string UserCodeStatic = "UserCodeStaticDao"; public string UserCode = "UserCodeDao"; + [IgnoreMapping] + public int IgnoredField; public long UserId { get; set; } public string FirstName { get; set; } @@ -23,6 +25,8 @@ public class UserDao public class UserDataDao { + public AddressDao AddressField; + public long UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } diff --git a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs index bcd23c6..40b6455 100644 --- a/Compentio.SourceMapper.Tests/Entities/UserInfo.cs +++ b/Compentio.SourceMapper.Tests/Entities/UserInfo.cs @@ -8,7 +8,7 @@ public class UserInfo { public static string UserCodeStatic = "UserCodeStaticInfo"; public string UserCode = "UserCodeInfo"; - + public Address AddressField; public int Id { get; set; } public string Name { get; set; } public Sex Sex { get; set; } diff --git a/Compentio.SourceMapper.Tests/Processors/ClassUserMapperTests.cs b/Compentio.SourceMapper.Tests/Processors/ClassUserMapperTests.cs index 5bc8448..a71e0a9 100644 --- a/Compentio.SourceMapper.Tests/Processors/ClassUserMapperTests.cs +++ b/Compentio.SourceMapper.Tests/Processors/ClassUserMapperTests.cs @@ -36,7 +36,9 @@ public void Mapper_User_Dao_Match_Converters() mappingResult.Name.Should().Be($"{userDao.FirstName} {userDao.LastName}"); mappingResult.BirthDate.Should().Be(userDao.BirthDate); mappingResult.Id.Should().Be((int)userDao.UserId); - mappingResult.Sex.Should().Be(Sex.W); + mappingResult.Sex.Should().Be(Sex.W); + mappingResult.UserCode.Should().Be(userDao.UserCode); + UserInfo.UserCodeStatic.Should().Be(UserDao.UserCodeStatic); } [Fact] @@ -54,6 +56,8 @@ public void Mapper_User_Info_Match_Converters() // Assert mappingResult.BirthDate.Should().Be(userInfo.BirthDate); mappingResult.UserGender.Should().Be(UserGender.Female); + mappingResult.UserCode.Should().Be(userInfo.UserCode); + UserDao.UserCodeStatic.Should().Be(UserInfo.UserCodeStatic); // Not mapped mappingResult.UserId.Should().NotBe(userInfo.Id); diff --git a/Compentio.SourceMapper.Tests/Processors/InterfaceUserMapperTests.cs b/Compentio.SourceMapper.Tests/Processors/InterfaceUserMapperTests.cs index 6db63e8..d0d523e 100644 --- a/Compentio.SourceMapper.Tests/Processors/InterfaceUserMapperTests.cs +++ b/Compentio.SourceMapper.Tests/Processors/InterfaceUserMapperTests.cs @@ -31,6 +31,8 @@ public void Mapper_User_Dao_Match_Properties_And_Attributes() // Assert mappingResult.Name.Should().Be(userDao.FirstName); mappingResult.BirthDate.Should().Be(userDao.BirthDate); + mappingResult.UserCode.Should().Be(userDao.UserCode); + UserInfo.UserCodeStatic.Should().Be(UserDao.UserCodeStatic); // Not mapped mappingResult.Id.Should().NotBe((int)userDao.UserId); mappingResult.Address.Should().BeNull(); @@ -49,6 +51,8 @@ public void Mapper_User_Info_Match_Properties_And_Attributes() // Assert mappingResult.FirstName.Should().Be(userInfo.Name); mappingResult.BirthDate.Should().Be(userInfo.BirthDate); + mappingResult.UserCode.Should().Be(userInfo.UserCode); + UserDao.UserCodeStatic.Should().Be(UserInfo.UserCodeStatic); //// Not mapped mappingResult.UserId.Should().NotBe(userInfo.Id); mappingResult.City.Should().BeNull(); @@ -87,7 +91,7 @@ public void Mapper_User_Data_Dao_Match_Properties_And_Attributes() mappingResult.Name.Should().Be(userDataDao.FirstName); mappingResult.BirthDate.Should().Be(userDataDao.BirthDate); - + // Property mappingResult.Address.Should().NotBeNull(); mappingResult.Address.City.Should().Be(userDataDao.UserAddress.City); mappingResult.Address.House.Should().Be(userDataDao.UserAddress.House); @@ -96,6 +100,15 @@ public void Mapper_User_Data_Dao_Match_Properties_And_Attributes() mappingResult.Address.Region.Should().NotBeNull(); mappingResult.Address.Region.State.Should().Be(userDataDao.UserAddress.Region.State); mappingResult.Address.Region.District.Should().Be(userDataDao.UserAddress.Region.District); + // Field + mappingResult.AddressField.Should().NotBeNull(); + mappingResult.AddressField.City.Should().Be(userDataDao.AddressField.City); + mappingResult.AddressField.House.Should().Be(userDataDao.AddressField.House); + mappingResult.AddressField.Street.Should().Be(userDataDao.AddressField.Street); + + mappingResult.AddressField.Region.Should().NotBeNull(); + mappingResult.AddressField.Region.State.Should().Be(userDataDao.AddressField.Region.State); + mappingResult.AddressField.Region.District.Should().Be(userDataDao.AddressField.Region.District); } [Fact] @@ -113,7 +126,7 @@ public void Mapper_User_Data_Info_Match_Properties_And_Attributes() mappingResult.FirstName.Should().Be(userInfo.Name); mappingResult.BirthDate.Should().Be(userInfo.BirthDate); - + // Property mappingResult.UserAddress.Should().NotBeNull(); mappingResult.UserAddress.City.Should().Be(userInfo.Address.City); mappingResult.UserAddress.House.Should().Be(userInfo.Address.House); @@ -122,6 +135,15 @@ public void Mapper_User_Data_Info_Match_Properties_And_Attributes() mappingResult.UserAddress.Region.Should().NotBeNull(); mappingResult.UserAddress.Region.State.Should().Be(userInfo.Address.Region.State); mappingResult.UserAddress.Region.District.Should().Be(userInfo.Address.Region.District); + // Field + mappingResult.AddressField.Should().NotBeNull(); + mappingResult.AddressField.City.Should().Be(userInfo.AddressField.City); + mappingResult.AddressField.House.Should().Be(userInfo.AddressField.House); + mappingResult.AddressField.Street.Should().Be(userInfo.AddressField.Street); + + mappingResult.AddressField.Region.Should().NotBeNull(); + mappingResult.AddressField.Region.State.Should().Be(userInfo.AddressField.Region.State); + mappingResult.AddressField.Region.District.Should().Be(userInfo.AddressField.Region.District); } [Fact] From 230a0ee9e1fe7c8963d45198e9d519375307616b Mon Sep 17 00:00:00 2001 From: Piotr Szulc Date: Wed, 29 Dec 2021 11:00:49 +0100 Subject: [PATCH 14/14] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index be02bd0..471aecd 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ public interface INotesMapper NoteDto MapToDto(NoteDao source); } ``` -This will generate mapping class with default class name `NotesMapper` for properties that names are the same for `NoteDto` and `NoteDao` classes. +This will generate mapping class with default class name `NotesMapper` for properties and fields that names are the same for `NoteDto` and `NoteDao` classes. The generated class is in the same namespace as its base abstract class of interface. It can be found in project in Visual Studio: > Dependencies -> Analyzers -> Compentio.SourceMapper.Generators.MainSourceGenerator. -When the names are different than we can use `Source` and `Target` names of the properties: +When the names are different than we can use `Source` and `Target` names of the properties or fields: ```csharp [Mapper(ClassName = "InterfaceUserMapper")] @@ -149,13 +149,13 @@ public abstract class NotesClassMapper ``` -`Expression` - it is a name of mapping function, that can be used for additional properties mapping. +`Expression` - it is a name of mapping function, that can be used for additional properties/fields mapping. > It must be `public` or `protected`, since it is used in generated mapper class that implements abstract mapping class. ## Ignore mapping -If for any reason part of the class/interface properties should not be mapped, `IgnoreMapping` attribute should be used for that. -Added `IgnoreMapping` causes that both source and target property during mapping generation will be omitted, not generating any linked map and not reporting any warning in diagnostics. +If for any reason part of the class/interface properties or fields should not be mapped, `IgnoreMapping` attribute should be used for that. +Added `IgnoreMapping` causes that both source and target property/field during mapping generation will be omitted, not generating any linked map and not reporting any warning in diagnostics. If we have two classes `NoteDao` and `NoteDto` ```csharp