예제 #1
0
        public MappingElement MapExpression(MappingElement element, ITypeSymbol targetType, MappingPath mappingPath = null)
        {
            if (element == null)
            {
                return(null);
            }

            if (mappingPath == null)
            {
                mappingPath = new MappingPath();
            }

            if (mappingPath.AddToMapped(element.ExpressionType) == false)
            {
                return(new MappingElement()
                {
                    ExpressionType = element.ExpressionType,
                    Expression = element.Expression.WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursing mapping */"))
                });
            }

            if (IsUnrappingNeeded(targetType, element))
            {
                return(TryToUnwrapp(targetType, element));
            }


            if (element.ExpressionType.Equals(targetType) == false && ObjectHelper.IsSimpleType(targetType) == false && ObjectHelper.IsSimpleType(element.ExpressionType) == false)
            {
                return(TryToCreateMappingExpression(element, targetType, mappingPath));
            }

            return(element);
        }
예제 #2
0
        protected virtual MappingElement TryToCreateMappingExpression(MappingElement source, ITypeSymbol targetType, MappingPath mappingPath)
        {
            //TODO: If source expression is method or constructor invocation then we should extract local variable and use it im mappings as a reference
            var namedTargetType = targetType as INamedTypeSymbol;

            if (namedTargetType != null)
            {
                var directlyMappingConstructor = namedTargetType.Constructors.FirstOrDefault(c => c.Parameters.Length == 1 && c.Parameters[0].Type.Equals(source.ExpressionType));
                if (directlyMappingConstructor != null)
                {
                    var constructorParameters = SyntaxFactory.ArgumentList().AddArguments(SyntaxFactory.Argument(source.Expression));
                    var creationExpression    = syntaxGenerator.ObjectCreationExpression(targetType, constructorParameters.Arguments);
                    return(new MappingElement()
                    {
                        ExpressionType = targetType,
                        Expression = (ExpressionSyntax)creationExpression
                    });
                }
            }

            if (MappingHelper.IsMappingBetweenCollections(targetType, source.ExpressionType))
            {
                return(new MappingElement()
                {
                    ExpressionType = targetType,
                    Expression = MapCollections(source.Expression, source.ExpressionType, targetType, mappingPath.Clone()) as ExpressionSyntax
                });
            }

            var subMappingSourceFinder = new ObjectMembersMappingSourceFinder(source.ExpressionType, source.Expression, syntaxGenerator);

            if (namedTargetType != null)
            {
                //maybe there is constructor that accepts parameter matching source properties
                var constructorOverloadParameterSets = namedTargetType.Constructors.Select(x => x.Parameters);
                var matchedOverload = MethodHelper.FindBestParametersMatch(subMappingSourceFinder, constructorOverloadParameterSets);

                if (matchedOverload != null)
                {
                    var creationExpression = syntaxGenerator.ObjectCreationExpression(targetType, matchedOverload.ToArgumentListSyntax(this).Arguments);
                    return(new MappingElement()
                    {
                        ExpressionType = targetType,
                        Expression = (ExpressionSyntax)creationExpression
                    });
                }
            }


            var objectCreationExpressionSyntax = ((ObjectCreationExpressionSyntax)syntaxGenerator.ObjectCreationExpression(targetType));

            return(new MappingElement()
            {
                ExpressionType = targetType,
                Expression = AddInitializerWithMapping(objectCreationExpressionSyntax, subMappingSourceFinder, targetType, mappingPath)
            });
        }
예제 #3
0
        public ExpressionSyntax MapExpression(ExpressionSyntax sourceExpression, ITypeSymbol sourceType, ITypeSymbol destinationType)
        {
            var mappingSource = new MappingElement
            {
                Expression     = sourceExpression,
                ExpressionType = sourceType
            };

            return(MapExpression(mappingSource, destinationType).Expression);
        }
        public void AddMatch(IParameterSymbol parameter, MappingElement mappingSrc = null)
        {
            Matches.Add(new MatchedParameter()
            {
                Parameter = parameter,
                Source    = mappingSrc
            });

            if (mappingSrc?.Expression != null)
            {
                MatchedCount++;
            }
        }
        protected override MappingElement TryToCreateMappingExpression(MappingElement source, ITypeSymbol targetType, MappingPath mappingPath)
        {
            //TODO: check if source is not null (conditional member access)

            if (mappingPath.Length > 1 && source.ExpressionType.AllInterfaces.Any(x => x.Name == "ICloneable") && source.ExpressionType.SpecialType != SpecialType.System_Array)
            {
                var invokeClone  = syntaxGenerator.InvocationExpression(syntaxGenerator.MemberAccessExpression(source.Expression, "Clone"));
                var cloneMethods = targetType.GetMembers("Clone");
                if (cloneMethods.Any(IsGenericCloneMethod))
                {
                    return(new MappingElement()
                    {
                        ExpressionType = targetType,
                        Expression = invokeClone as ExpressionSyntax
                    });
                }

                var objectClone = cloneMethods.FirstOrDefault(x => x is IMethodSymbol md && md.Parameters.Length == 0);

                if (objectClone != null)
                {
                    var objectCLoneMethod = (IMethodSymbol)objectClone;

                    if (CanBeAccessedInCurrentContext(objectCLoneMethod))
                    {
                        return(new MappingElement()
                        {
                            ExpressionType = targetType,
                            Expression = syntaxGenerator.TryCastExpression(invokeClone, targetType) as ExpressionSyntax
                        });
                    }
                }

                var implicitClone = targetType.GetMembers("System.ICloneable.Clone").FirstOrDefault();
                if (implicitClone != null)
                {
                    var castedOnICloneable = syntaxGenerator.CastExpression(SyntaxFactory.ParseTypeName("ICloneable"), source.Expression);
                    return(new MappingElement()
                    {
                        ExpressionType = targetType,
                        Expression = syntaxGenerator.TryCastExpression(syntaxGenerator.InvocationExpression(syntaxGenerator.MemberAccessExpression(castedOnICloneable, "Clone")), targetType) as ExpressionSyntax
                    });
                }
            }

            return(base.TryToCreateMappingExpression(source, targetType, mappingPath));
        }
예제 #6
0
        public MappingElement MapExpression(MappingElement element, ITypeSymbol targetType, MappingPath mappingPath = null)
        {
            if (element == null)
            {
                return(null);
            }

            if (mappingPath == null)
            {
                mappingPath = new MappingPath();
            }

            var sourceType = element.ExpressionType;

            if (mappingPath.AddToMapped(sourceType) == false)
            {
                return(new MappingElement()
                {
                    ExpressionType = sourceType,
                    Expression = element.Expression.WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursive mapping */"))
                });
            }

            if (ObjectHelper.IsSimpleType(targetType) && SymbolHelper.IsNullable(sourceType, out var underlyingType))
            {
                element = new MappingElement()
                {
                    Expression     = (ExpressionSyntax)syntaxGenerator.MemberAccessExpression(element.Expression, "Value"),
                    ExpressionType = underlyingType
                };
            }

            if (IsUnwrappingNeeded(targetType, element))
            {
                return(TryToUnwrap(targetType, element));
            }


            if (ShouldCreateConversionBetweenTypes(targetType, sourceType))
            {
                return(TryToCreateMappingExpression(element, targetType, mappingPath));
            }

            return(element);
        }
예제 #7
0
 public IEnumerable <SyntaxNode> Map(MappingElement source, MappingElement target)
 {
     if (IsMappingBetweenCollections(target.ExpressionType, source.ExpressionType))
     {
         var collectionMapping = MapCollections(source.Expression, source.ExpressionType, target.ExpressionType);
         yield return(generator.CompleteAssignmentStatement(target.Expression, collectionMapping));
     }
     else if (ObjectHelper.IsSimpleType(target.ExpressionType) == false)
     {
         //TODO: What if both sides has the same type?
         //TODO: Reverse flattening
         foreach (var complexPropertyMappingNode in MapTypes(source.ExpressionType, target.ExpressionType, source.Expression, target.Expression))
         {
             yield return(complexPropertyMappingNode);
         }
     }
     else
     {
         yield return(generator.CompleteAssignmentStatement(target.Expression, source.Expression));
     }
 }
예제 #8
0
        private MappingElement TryToUnwrap(ITypeSymbol targetType, MappingElement element)
        {
            var sourceAccess = element.Expression as SyntaxNode;
            var conversion   = semanticModel.Compilation.ClassifyConversion(element.ExpressionType, targetType);

            if (conversion.Exists == false)
            {
                var wrapper = GetWrappingInfo(element.ExpressionType, targetType);
                if (wrapper.Type == WrapperInfoType.Property)
                {
                    return(new MappingElement()
                    {
                        Expression = (ExpressionSyntax)syntaxGenerator.MemberAccessExpression(sourceAccess, wrapper.UnwrappingProperty.Name),
                        ExpressionType = wrapper.UnwrappingProperty.Type
                    });
                }
                else if (wrapper.Type == WrapperInfoType.Method)
                {
                    var unwrappingMethodAccess = syntaxGenerator.MemberAccessExpression(sourceAccess, wrapper.UnwrappingMethod.Name);

                    return(new MappingElement()
                    {
                        Expression = (InvocationExpressionSyntax)syntaxGenerator.InvocationExpression(unwrappingMethodAccess),
                        ExpressionType = wrapper.UnwrappingMethod.ReturnType
                    });
                }
            }
            else if (conversion.IsExplicit)
            {
                return(new MappingElement()
                {
                    Expression = (ExpressionSyntax)syntaxGenerator.CastExpression(targetType, sourceAccess),
                    ExpressionType = targetType
                });
            }
            return(element);
        }
예제 #9
0
        public MappingElement MapExpression(MappingElement element, ITypeSymbol targetType, MappingPath mappingPath = null)
        {
            if (element == null)
            {
                return(null);
            }

            if (mappingPath == null)
            {
                mappingPath = new MappingPath();
            }

            var sourceType = element.ExpressionType;

            if (mappingPath.AddToMapped(sourceType) == false)
            {
                return(new MappingElement()
                {
                    ExpressionType = sourceType,
                    Expression = element.Expression.WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursive mapping */"))
                });
            }

            if (IsUnwrappingNeeded(targetType, element))
            {
                return(TryToUnwrap(targetType, element));
            }


            if (ShouldCreateConversionBetweenTypes(targetType, sourceType))
            {
                return(TryToCreateMappingExpression(element, targetType, mappingPath));
            }

            return(element);
        }
예제 #10
0
        public IEnumerable <SyntaxNode> MapTypes(ITypeSymbol sourceType, ITypeSymbol targetType,
                                                 SyntaxNode globalSourceAccessor, SyntaxNode globbalTargetAccessor = null, bool targetExists = false,
                                                 bool generatorContext     = false,
                                                 bool isConstructorContext = false)
        {
            if (IsMappingBetweenCollections(targetType, sourceType))
            {
                var collectionMapping = MapCollections(globalSourceAccessor, sourceType, targetType);
                if (globbalTargetAccessor == null)
                {
                    yield return(generator.ContextualReturnStatement(collectionMapping, generatorContext));
                }
                else if (targetExists == false)
                {
                    yield return(generator.CompleteAssignmentStatement(globbalTargetAccessor, collectionMapping));
                }
                yield break;
            }

            var targetLocalVariableName = globbalTargetAccessor == null?ToLocalVariableName(targetType.Name) : ToLocalVariableName(globbalTargetAccessor.ToFullString());

            var mappingSourceFinder = new ObjectMembersMappingSourceFinder(sourceType, globalSourceAccessor, generator, semanticModel);

            if (targetExists == false)
            {
                var mappingConstructorParameters = FindMappingConstructorParameters(targetType, sourceType, mappingSourceFinder, (ExpressionSyntax)globalSourceAccessor);
                if (mappingConstructorParameters != null)
                {
                    var init = generator.ObjectCreationExpression(targetType, mappingConstructorParameters.Arguments);
                    if (globbalTargetAccessor == null)
                    {
                        yield return(generator.ContextualReturnStatement(init, generatorContext));
                    }
                    else
                    {
                        yield return(generator.CompleteAssignmentStatement(globbalTargetAccessor, init));
                    }
                    yield break;
                }
                else
                {
                    var init = generator.ObjectCreationExpression(targetType);
                    yield return(generator.LocalDeclarationStatement(targetLocalVariableName, init));
                }
            }

            var localTargetIdentifier = targetExists? globbalTargetAccessor: generator.IdentifierName(targetLocalVariableName);

            foreach (var targetProperty in ObjectHelper.GetPublicPropertySymbols(targetType))
            {
                if (CanBeSet(targetProperty, globbalTargetAccessor, isConstructorContext) == false)
                {
                    continue;
                }

                var mappingSource = mappingSourceFinder.FindMappingSource(targetProperty.Name, targetProperty.Type);
                if (mappingSource == null)
                {
                    continue;
                }

                var mappingTarget = new MappingElement()
                {
                    Expression     = (ExpressionSyntax)generator.MemberAccessExpression(localTargetIdentifier, targetProperty.Name),
                    ExpressionType = targetProperty.Type
                };

                foreach (var syntaxNode in Map(mappingSource, mappingTarget))
                {
                    yield return(syntaxNode);
                }
            }

            if (globbalTargetAccessor == null)
            {
                yield return(generator.ContextualReturnStatement(localTargetIdentifier, generatorContext));
            }
            else if (targetExists == false)
            {
                yield return(generator.CompleteAssignmentStatement(globbalTargetAccessor, localTargetIdentifier));
            }
        }
예제 #11
0
 private bool IsUnwrappingNeeded(ITypeSymbol targetType, MappingElement element)
 {
     return(targetType != element.ExpressionType && ObjectHelper.IsSimpleType(targetType));
 }
예제 #12
0
        private MappingElement TryToUnwrap(ITypeSymbol targetType, MappingElement element)
        {
            var sourceAccess = element.Expression as SyntaxNode;
            var conversion   = semanticModel.Compilation.ClassifyConversion(element.ExpressionType, targetType);

            if (conversion.Exists == false)
            {
                var wrapper = GetWrappingInfo(element.ExpressionType, targetType);
                if (wrapper.Type == WrapperInfoType.Property)
                {
                    return(new MappingElement()
                    {
                        Expression = (ExpressionSyntax)syntaxGenerator.MemberAccessExpression(sourceAccess, wrapper.UnwrappingProperty.Name),
                        ExpressionType = wrapper.UnwrappingProperty.Type
                    });
                }
                if (wrapper.Type == WrapperInfoType.Method)
                {
                    var unwrappingMethodAccess = syntaxGenerator.MemberAccessExpression(sourceAccess, wrapper.UnwrappingMethod.Name);

                    return(new MappingElement()
                    {
                        Expression = (InvocationExpressionSyntax)syntaxGenerator.InvocationExpression(unwrappingMethodAccess),
                        ExpressionType = wrapper.UnwrappingMethod.ReturnType
                    });
                }

                if (targetType.SpecialType == SpecialType.System_String && element.ExpressionType.TypeKind == TypeKind.Enum)
                {
                    var toStringAccess = syntaxGenerator.MemberAccessExpression(element.Expression, "ToString");
                    return(new MappingElement()
                    {
                        Expression = (InvocationExpressionSyntax)syntaxGenerator.InvocationExpression(toStringAccess),
                        ExpressionType = targetType
                    });
                }

                if (element.ExpressionType.SpecialType == SpecialType.System_String && targetType.TypeKind == TypeKind.Enum)
                {
                    var parseEnumAccess = syntaxGenerator.MemberAccessExpression(SyntaxFactory.ParseTypeName("Enum"), "Parse");
                    return(new MappingElement()
                    {
                        Expression = (InvocationExpressionSyntax)syntaxGenerator.InvocationExpression(parseEnumAccess, new[]
                        {
                            syntaxGenerator.TypeOfExpression(SyntaxFactory.ParseTypeName(targetType.Name)),
                            element.Expression,
                            syntaxGenerator.TrueLiteralExpression()
                        }),
                        ExpressionType = targetType
                    });
                }
            }
            else if (conversion.IsExplicit)
            {
                return(new MappingElement()
                {
                    Expression = (ExpressionSyntax)syntaxGenerator.CastExpression(targetType, sourceAccess),
                    ExpressionType = targetType
                });
            }
            return(element);
        }
예제 #13
0
 private bool IsUnwrappingNeeded(ITypeSymbol targetType, MappingElement element)
 {
     return(targetType.Equals(element.ExpressionType) == false && (ObjectHelper.IsSimpleType(targetType) || SymbolHelper.IsNullable(targetType, out _)));
 }
예제 #14
0
 private static bool IsUnrappingNeeded(ITypeSymbol targetType, MappingElement mappingSource)
 {
     return(targetType != mappingSource.ExpressionType && ObjectHelper.IsSimpleType(targetType));
 }