protected override bool ShouldCreateConversionBetweenTypes(ITypeSymbol targetType, ITypeSymbol sourceType)
        {
            if (targetType.Equals(sourceType) && SymbolHelper.IsNullable(targetType, out _))
            {
                return(false);
            }

            return(ObjectHelper.IsSimpleType(targetType) == false && ObjectHelper.IsSimpleType(sourceType) == false);
        }
Exemplo n.º 2
0
        public MappingElement MapExpression(MappingElement source, ITypeSymbol targetType, MappingContext mappingContext, MappingPath mappingPath = null)
        {
            if (source == null)
            {
                return(null);
            }

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

            var sourceType = source.ExpressionType;

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


            if (mappingContext.FindConversion(sourceType, targetType) is {} userDefinedConversion)
            {
                return(new MappingElement()
                {
                    ExpressionType = targetType,
                    Expression = (ExpressionSyntax)syntaxGenerator.InvocationExpression(userDefinedConversion, source.Expression)
                });
            }


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

            if (IsUnwrappingNeeded(targetType, source))
            {
                return(TryToUnwrap(targetType, source, mappingContext));
            }

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

            return(source);
        }
        private SyntaxNode GetDefaultExpression(ITypeSymbol type, MappingContext mappingContext, MappingPath mappingPath)
        {
            if (mappingPath.AddToMapped(type) == false)
            {
                return(syntaxGenerator.DefaultExpression(type)
                       .WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursive mapping */")));
            }

            return(cache.GetOrAdd(type.ToDisplayString().TrimEnd('?'), _ =>
            {
                if (SymbolHelper.IsNullable(type, out var underlyingType))
                {
                    type = underlyingType;
                }


                if (type.TypeKind == TypeKind.Enum && type is INamedTypeSymbol namedTypeSymbol)
                {
                    var enumOption = namedTypeSymbol.MemberNames.Where(x => x != "value__" && x != ".ctor").OrderBy(x => x).FirstOrDefault();
                    if (enumOption != null)
                    {
                        return SyntaxFactoryExtensions.CreateMemberAccessExpression(SyntaxFactory.IdentifierName(namedTypeSymbol.Name), false, enumOption);
                    }
                    return syntaxGenerator.DefaultExpression(type);
                }

                if (type.SpecialType == SpecialType.None)
                {
                    ObjectCreationExpressionSyntax objectCreationExpression = null;

                    if (MappingHelper.IsCollection(type))
                    {
                        var isReadonlyCollection = ObjectHelper.IsReadonlyCollection(type);

                        if (type is IArrayTypeSymbol)
                        {
                            objectCreationExpression = CreateObject(type);
                        }
                        else if (type.TypeKind == TypeKind.Interface || isReadonlyCollection)
                        {
                            if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
                            {
                                var typeArgumentListSyntax = SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(namedType.TypeArguments.Select(x => syntaxGenerator.TypeExpression(x))));
                                var newType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("List"), typeArgumentListSyntax);
                                objectCreationExpression = SyntaxFactory.ObjectCreationExpression(newType, SyntaxFactory.ArgumentList(), default(InitializerExpressionSyntax));
                            }
Exemplo n.º 4
0
        private MappingElement FindSubPropertySource(string targetName, ITypeSymbol containingType, IEnumerable <IObjectField> properties, SyntaxNode currentAccessor, MappingContext mappingContext, bool isCurrentAccessorNullable, string prefix = null)
        {
            if (ObjectHelper.IsSimpleType(containingType))
            {
                return(null);
            }

            var subProperty = properties.Where(x => SanitizeName(targetName).StartsWith(SanitizeName($"{prefix}{x.Name}"), StringComparison.OrdinalIgnoreCase))
                              .FirstOrDefault(p => p.CanBeGet(containingType, mappingContext));

            if (subProperty != null)
            {
                var currentNamePart     = $"{prefix}{subProperty.Name}";
                var subPropertyAccessor = SyntaxFactoryExtensions.CreateMemberAccessExpression((ExpressionSyntax)currentAccessor, isCurrentAccessorNullable, subProperty.Name);
                var expressionCanBeNull = isCurrentAccessorNullable || subProperty.Type.CanBeNull;
                if (SanitizeName(targetName).Equals(SanitizeName(currentNamePart), StringComparison.OrdinalIgnoreCase))
                {
                    //Special Case: x.YValue = z.Y.Value
                    if (subProperty.Name == "Value" && SymbolHelper.IsNullable(containingType, out var _))
                    {
                        return(new MappingElement
                        {
                            Expression = (ExpressionSyntax)currentAccessor,
                            ExpressionType = new AnnotatedType(containingType, true)
                        });
                    }

                    return(new MappingElement
                    {
                        Expression = subPropertyAccessor,
                        ExpressionType = new AnnotatedType(subProperty.Type.Type, expressionCanBeNull)
                    });
                }
                return(FindSubPropertySource(targetName, subProperty.Type.Type, GetFields(subProperty.Type.Type), subPropertyAccessor, mappingContext, expressionCanBeNull, currentNamePart));
            }
            return(null);
        }
Exemplo n.º 5
0
 private bool IsUnwrappingNeeded(ITypeSymbol targetType, MappingElement element)
 {
     return(targetType.Equals(element.ExpressionType) == false && (ObjectHelper.IsSimpleType(targetType) || SymbolHelper.IsNullable(targetType, out _)));
 }
Exemplo n.º 6
0
        public async Task <MappingElement> MapExpression(MappingElement source, AnnotatedType targetType, MappingContext mappingContext, MappingPath mappingPath = null)
        {
            if (source == null)
            {
                return(null);
            }

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

            var sourceType = source.ExpressionType;

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

            if (mappingContext.FindConversion(sourceType, targetType) is {} userDefinedConversion)
            {
                //TODO: Check if conversion accept nullable type
                var invocationExpression  = (ExpressionSyntax)syntaxGenerator.InvocationExpression(userDefinedConversion.Conversion, source.Expression);
                var protectResultFromNull = targetType.CanBeNull == false && userDefinedConversion.ToType.CanBeNull;
                var conversionExpression  = protectResultFromNull ? OrFailWhenExpressionNull(invocationExpression) : invocationExpression;
                return(new MappingElement
                {
                    ExpressionType = targetType,
                    Expression = HandleSafeNull(source, userDefinedConversion.FromType, conversionExpression)
                });
            }


            if (ObjectHelper.IsSimpleType(targetType.Type) && SymbolHelper.IsNullable(sourceType.Type, out var underlyingType))
            {
                return(new MappingElement
                {
                    Expression = OrFailWhenArgumentNull(source.Expression),
                    ExpressionType = new AnnotatedType(underlyingType, false)
                });
            }

            if (IsConversionToSimpleTypeNeeded(targetType.Type, source.ExpressionType.Type))
            {
                var conversion = ConvertToSimpleType(targetType, source, mappingContext);
                if (targetType.CanBeNull == false && conversion.ExpressionType.CanBeNull)
                {
                    return(new MappingElement
                    {
                        ExpressionType = conversion.ExpressionType.AsNotNull(),
                        Expression = OrFailWhenArgumentNull(conversion.Expression)
                    });
                }
                return(conversion);
            }

            if (ShouldCreateConversionBetweenTypes(targetType.Type, sourceType.Type))
            {
                return(await  TryToCreateMappingExpression(source, targetType, mappingPath, mappingContext).ConfigureAwait(false));
            }


            if (source.ExpressionType.Type.Equals(targetType.Type) && source.ExpressionType.CanBeNull && targetType.CanBeNull == false)
            {
                return(new MappingElement
                {
                    Expression = OrFailWhenArgumentNull(source.Expression),
                    ExpressionType = source.ExpressionType.AsNotNull()
                });
            }
            return(source);
        }
Exemplo n.º 7
0
 private bool IsConversionToSimpleTypeNeeded(ITypeSymbol targetType, ITypeSymbol sourceType)
 {
     return(targetType.Equals(sourceType) == false && (ObjectHelper.IsSimpleType(targetType) || SymbolHelper.IsNullable(targetType, out _)));
 }
        private async Task <SyntaxNode> GetDefaultExpression(ITypeSymbol type, MappingContext mappingContext, MappingPath mappingPath)
        {
            if (mappingPath.AddToMapped(type) == false)
            {
                return(syntaxGenerator.DefaultExpression(type)
                       .WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursive mapping */")));
            }

            if (SymbolHelper.IsNullable(type, out var underlyingType))
            {
                type = underlyingType;
            }


            if (type.TypeKind == TypeKind.Enum && type is INamedTypeSymbol namedTypeSymbol)
            {
                var enumOption = namedTypeSymbol.MemberNames.Where(x => x != "value__" && x != ".ctor").OrderBy(x => x).FirstOrDefault();
                if (enumOption != null)
                {
                    return(SyntaxFactoryExtensions.CreateMemberAccessExpression(SyntaxFactory.IdentifierName(namedTypeSymbol.Name), false, enumOption));
                }
                return(syntaxGenerator.DefaultExpression(type));
            }

            if (type.SpecialType == SpecialType.None)
            {
                ObjectCreationExpressionSyntax objectCreationExpression = null;

                if (MappingHelper.IsCollection(type))
                {
                    var isReadonlyCollection = ObjectHelper.IsReadonlyCollection(type);

                    if (type is IArrayTypeSymbol)
                    {
                        objectCreationExpression = CreateObject(type);
                    }
                    else if (type.TypeKind == TypeKind.Interface || isReadonlyCollection)
                    {
                        if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
                        {
                            var typeArgumentListSyntax = SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(namedType.TypeArguments.Select(x => syntaxGenerator.TypeExpression(x))));
                            var newType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("List"), typeArgumentListSyntax);
                            objectCreationExpression = SyntaxFactory.ObjectCreationExpression(newType, SyntaxFactory.ArgumentList(), default(InitializerExpressionSyntax));
                        }
                        else
                        {
                            var newType = SyntaxFactory.ParseTypeName("ArrayList");
                            objectCreationExpression = SyntaxFactory.ObjectCreationExpression(newType, SyntaxFactory.ArgumentList(), default(InitializerExpressionSyntax));
                        }
                    }
                    objectCreationExpression ??= CreateObject(type, Array.Empty <ArgumentSyntax>());

                    var subType = MappingHelper.GetElementType(type);
                    var initializationBlockExpressions = new SeparatedSyntaxList <ExpressionSyntax>();
                    var subTypeDefault = (ExpressionSyntax)(await GetDefaultExpression(subType.Type, mappingContext, mappingPath.Clone()).ConfigureAwait(false));
                    if (subTypeDefault != null)
                    {
                        initializationBlockExpressions = initializationBlockExpressions.Add(subTypeDefault);
                    }

                    var initializerExpressionSyntax = SyntaxFactory.InitializerExpression(SyntaxKind.ObjectInitializerExpression, initializationBlockExpressions).FixInitializerExpressionFormatting(objectCreationExpression);
                    return(objectCreationExpression
                           .WithInitializer(initializerExpressionSyntax)
                           .WrapInReadonlyCollectionIfNecessary(isReadonlyCollection, syntaxGenerator));
                }

                {
                    var nt = type as INamedTypeSymbol;
                    if (nt == null)
                    {
                        var genericTypeConstraints = type.UnwrapGeneric().ToList();
                        if (genericTypeConstraints.Any() == false)
                        {
                            return(GetDefaultForUnknown(type, ObjectType));
                        }
                        nt = genericTypeConstraints.FirstOrDefault(x => x.TypeKind == TypeKind.Class) as INamedTypeSymbol ??
                             genericTypeConstraints.FirstOrDefault(x => x.TypeKind == TypeKind.Interface) as INamedTypeSymbol;
                    }

                    if (nt == null)
                    {
                        return(GetDefaultForUnknownType(type));
                    }

                    if (nt.TypeKind == TypeKind.Interface)
                    {
                        var implementations = await SymbolFinder.FindImplementationsAsync(type, _document.Project.Solution).ConfigureAwait(false);

                        var firstImplementation = implementations.FirstOrDefault();
                        if (firstImplementation is INamedTypeSymbol == false)
                        {
                            return(GetDefaultForUnknownType(type));
                        }

                        nt = firstImplementation as INamedTypeSymbol;
                        objectCreationExpression = CreateObject(nt);
                    }
                    else if (nt.TypeKind == TypeKind.Class && nt.IsAbstract)
                    {
                        var allDerived = await SymbolFinder.FindDerivedClassesAsync(nt, _document.Project.Solution).ConfigureAwait(false);

                        var randomDerived = allDerived.FirstOrDefault(x => x.IsAbstract == false);

                        if (randomDerived != null)
                        {
                            nt = randomDerived;
                            objectCreationExpression = CreateObject(nt);
                        }
                    }
                    else
                    {
                        var publicConstructors    = nt.Constructors.Where(x => mappingContext.AccessibilityHelper.IsSymbolAccessible(x, nt)).ToList();
                        var hasDefaultConstructor = publicConstructors.Any(x => x.Parameters.Length == 0);
                        if (hasDefaultConstructor == false && publicConstructors.Count > 0)
                        {
                            var randomConstructor    = publicConstructors.First();
                            var constructorArguments = await GetConstructorArguments(mappingContext, mappingPath, randomConstructor).ConfigureAwait(false);

                            objectCreationExpression = CreateObject(nt, constructorArguments);
                        }
                    }

                    var fields      = mappingTargetHelper.GetFieldsThaCanBeSetPublicly(nt, mappingContext);
                    var assignments = new List <AssignmentExpressionSyntax>(fields.Count);
                    foreach (var x in fields)
                    {
                        var identifier    = (ExpressionSyntax)(SyntaxFactory.IdentifierName(x.Name));
                        var mappingSource = await this.FindMappingSource(x.Type, mappingContext, mappingPath.Clone()).ConfigureAwait(false);

                        assignments.Add(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, identifier, mappingSource.Expression));
                    }

                    if (objectCreationExpression == null)
                    {
                        objectCreationExpression = CreateObject(type);
                    }

                    return(SyntaxFactoryExtensions.WithMembersInitialization(objectCreationExpression, assignments));
                }
            }
        internal SyntaxNode GetDefaultExpression(ITypeSymbol type, MappingPath mappingPath)
        {
            if (mappingPath.AddToMapped(type) == false)
            {
                return(syntaxGenerator.DefaultExpression(type)
                       .WithTrailingTrivia(SyntaxFactory.Comment(" /* Stop recursive mapping */")));
            }

            if (SymbolHelper.IsNullable(type, out var underlyingType))
            {
                type = underlyingType;
            }


            if (type.TypeKind == TypeKind.Enum && type is INamedTypeSymbol namedTypeSymbol)
            {
                var enumOptions = namedTypeSymbol.MemberNames.Where(x => x != "value__" && x != ".ctor").ToList();
                if (enumOptions.Count > 0)
                {
                    return(syntaxGenerator.MemberAccessExpression(syntaxGenerator.IdentifierName(namedTypeSymbol.Name), syntaxGenerator.IdentifierName(enumOptions[0])));
                }
                return(syntaxGenerator.DefaultExpression(type));
            }

            if (type.SpecialType == SpecialType.None)
            {
                var objectCreationExpression = (ObjectCreationExpressionSyntax)syntaxGenerator.ObjectCreationExpression(type);


                if (MappingHelper.IsCollection(type))
                {
                    var isReadonlyCollection = ObjectHelper.IsReadonlyCollection(type);

                    if (type is IArrayTypeSymbol)
                    {
                        objectCreationExpression = SyntaxFactory.ObjectCreationExpression((TypeSyntax)syntaxGenerator.TypeExpression(type));
                    }
                    else if (type.TypeKind == TypeKind.Interface || isReadonlyCollection)
                    {
                        var namedType = type as INamedTypeSymbol;
                        if (namedType.IsGenericType)
                        {
                            var typeArgumentListSyntax = SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(namedType.TypeArguments.Select(x => syntaxGenerator.TypeExpression(x))));
                            var newType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("List"), typeArgumentListSyntax);
                            objectCreationExpression = SyntaxFactory.ObjectCreationExpression(newType, SyntaxFactory.ArgumentList(), default(InitializerExpressionSyntax));
                        }
                        else
                        {
                            var newType = SyntaxFactory.ParseTypeName("ArrayList");
                            objectCreationExpression = SyntaxFactory.ObjectCreationExpression(newType, SyntaxFactory.ArgumentList(), default(InitializerExpressionSyntax));
                        }
                    }
                    var subType = MappingHelper.GetElementType(type);
                    var initializationBlockExpressions = new SeparatedSyntaxList <ExpressionSyntax>();
                    var subTypeDefault = (ExpressionSyntax)GetDefaultExpression(subType, mappingPath.Clone());
                    if (subTypeDefault != null)
                    {
                        initializationBlockExpressions = initializationBlockExpressions.Add(subTypeDefault);
                    }

                    var initializerExpressionSyntax = SyntaxFactory.InitializerExpression(SyntaxKind.ObjectInitializerExpression, initializationBlockExpressions).FixInitializerExpressionFormatting(objectCreationExpression);
                    return(objectCreationExpression
                           .WithInitializer(initializerExpressionSyntax)
                           .WrapInReadonlyCollectionIfNecessary(isReadonlyCollection, syntaxGenerator));
                }

                {
                    var nt = type as INamedTypeSymbol;

                    if (nt == null)
                    {
                        var genericTypeConstraints = type.UnwrapGeneric().ToList();
                        if (genericTypeConstraints.Any() == false)
                        {
                            return(GetDefaultForUnknown(type, SyntaxFactory.ParseTypeName("object")));
                        }
                        nt = genericTypeConstraints.FirstOrDefault(x => x.TypeKind == TypeKind.Class) as INamedTypeSymbol ??
                             genericTypeConstraints.FirstOrDefault(x => x.TypeKind == TypeKind.Interface) as INamedTypeSymbol;
                    }

                    if (nt == null)
                    {
                        return(GetDefaultForUnknownType(type));
                    }

                    if (nt.TypeKind == TypeKind.Interface)
                    {
                        var implementations     = SymbolFinder.FindImplementationsAsync(type, this._document.Project.Solution).Result;
                        var firstImplementation = implementations.FirstOrDefault();
                        if (firstImplementation is INamedTypeSymbol == false)
                        {
                            return(GetDefaultForUnknownType(type));
                        }

                        nt = firstImplementation as INamedTypeSymbol;
                        objectCreationExpression = (ObjectCreationExpressionSyntax)syntaxGenerator.ObjectCreationExpression(nt);
                    }
                    else if (nt.TypeKind == TypeKind.Class && nt.IsAbstract)
                    {
                        var randomDerived = SymbolFinder.FindDerivedClassesAsync(nt, this._document.Project.Solution).Result
                                            .FirstOrDefault(x => x.IsAbstract == false);

                        if (randomDerived != null)
                        {
                            nt = randomDerived;
                            objectCreationExpression = (ObjectCreationExpressionSyntax)syntaxGenerator.ObjectCreationExpression(nt);
                        }
                    }

                    var publicConstructors = nt.Constructors.Where(x =>
                                                                   x.DeclaredAccessibility == Accessibility.Public ||
                                                                   (x.DeclaredAccessibility == Accessibility.Internal &&
                                                                    x.ContainingAssembly.IsSameAssemblyOrHasFriendAccessTo(_contextAssembly))).ToList();


                    var hasDefaultConstructor = publicConstructors.Any(x => x.Parameters.Length == 0);
                    if (hasDefaultConstructor == false && publicConstructors.Count > 0)
                    {
                        var randomConstructor    = publicConstructors.First();
                        var constructorArguments = randomConstructor.Parameters.Select(p => GetDefaultExpression(p.Type, mappingPath.Clone())).ToList();
                        objectCreationExpression = (ObjectCreationExpressionSyntax)syntaxGenerator.ObjectCreationExpression(nt, constructorArguments);
                    }

                    var fields      = ObjectHelper.GetFieldsThaCanBeSetPublicly(nt, _contextAssembly);
                    var assignments = fields.Select(x =>
                    {
                        var identifier = (ExpressionSyntax)(SyntaxFactory.IdentifierName(x.Name));
                        return((ExpressionSyntax)syntaxGenerator.AssignmentStatement(identifier, this.FindMappingSource(x.Type, mappingPath.Clone()).Expression));
                    }).ToList();

                    if (assignments.Count == 0)
                    {
                        return(objectCreationExpression);
                    }
                    var initializerExpressionSyntax = SyntaxFactory.InitializerExpression(SyntaxKind.ObjectInitializerExpression, new SeparatedSyntaxList <ExpressionSyntax>().AddRange(assignments)).FixInitializerExpressionFormatting(objectCreationExpression);
                    return(objectCreationExpression.WithInitializer(initializerExpressionSyntax));
                }
            }


            return(GetDefaultForSpecialType(type));
        }