Пример #1
0
        private MappingElement FindSubPropertySource(string targetName, ITypeSymbol containingType, IEnumerable <IPropertySymbol> properties, SyntaxNode currentAccessor, string prefix = null)
        {
            if (ObjectHelper.IsSimpleType(containingType))
            {
                return(null);
            }

            var subProperty = properties.FirstOrDefault(x => targetName.StartsWith($"{prefix}{x.Name}", StringComparison.OrdinalIgnoreCase));

            if (subProperty != null)
            {
                var currentNamePart     = $"{prefix}{subProperty.Name}";
                var subPropertyAccessor = (ExpressionSyntax)generator.MemberAccessExpression(currentAccessor, subProperty.Name);
                if (targetName.Equals(currentNamePart, StringComparison.OrdinalIgnoreCase))
                {
                    return(new MappingElement()
                    {
                        Expression = subPropertyAccessor,
                        ExpressionType = subProperty.Type
                    });
                }
                return(FindSubPropertySource(targetName, subProperty.Type, ObjectHelper.GetPublicPropertySymbols(subProperty.Type), subPropertyAccessor, currentNamePart));
            }
            return(null);
        }
        private static IEnumerable <SyntaxNode> GenerateMappingCode(IMethodSymbol methodSymbol,
                                                                    SyntaxGenerator generator, MappingGenerator mappingGenerator, SemanticModel semanticModel)
        {
            if (SymbolHelper.IsPureMappingFunction(methodSymbol))
            {
                var source     = methodSymbol.Parameters[0];
                var targetType = methodSymbol.ReturnType;
                return(mappingGenerator.MapTypes(source.Type, targetType, generator.IdentifierName(source.Name)));
            }

            var isMappingConstructor = SymbolHelper.IsMappingConstructor(methodSymbol);

            if (SymbolHelper.IsUpdateThisObjectFunction(methodSymbol) || isMappingConstructor)
            {
                var source     = methodSymbol.Parameters[0];
                var targetType = methodSymbol.ContainingType;
                return(mappingGenerator.MapTypes(source.Type, targetType, generator.IdentifierName(source.Name), generator.ThisExpression(), targetExists: true, isConstructorContext: isMappingConstructor));
            }

            if (SymbolHelper.IsUpdateParameterFunction(methodSymbol))
            {
                var source = methodSymbol.Parameters[0];
                var target = methodSymbol.Parameters[1];
                return(mappingGenerator.MapTypes(source.Type, target.Type, generator.IdentifierName(source.Name), generator.IdentifierName(target.Name), targetExists: true));
            }

            var isMultiParameterConstructor = SymbolHelper.IsMultiParameterUpdateThisObjectFunction(methodSymbol);

            if (isMultiParameterConstructor || SymbolHelper.IsMultiParameterMappingConstructor(methodSymbol))
            {
                var sourceFinder = new LocalScopeMappingSourceFinder(semanticModel, methodSymbol.Parameters);
                return(ObjectHelper.GetPublicPropertySymbols(methodSymbol.ContainingType)
                       .Where(property => property.SetMethod != null || (property.CanBeSetOnlyFromConstructor() && isMultiParameterConstructor))
                       .Select(property => new
                {
                    source = sourceFinder.FindMappingSource(property.Name, property.Type),
                    target = new MappingElement()
                    {
                        Expression = SyntaxFactory.IdentifierName(property.Name),
                        ExpressionType = property.Type
                    }
                })
                       .Where(x => x.source != null)
                       .SelectMany(pair => mappingGenerator.Map(pair.source, pair.target)));
            }
            return(Enumerable.Empty <SyntaxNode>());
        }
Пример #3
0
        private async Task <Document> InitizalizeWithLocals(Document document, InitializerExpressionSyntax objectInitializer, CancellationToken cancellationToken)
        {
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

            var objectCreationExpression = objectInitializer.FindContainer <ObjectCreationExpressionSyntax>();
            var createdObjectType        = ModelExtensions.GetTypeInfo(semanticModel, objectCreationExpression).Type;
            var mappingSourceFinder      = new LocalScopeMappingSourceFinder(semanticModel, objectInitializer);
            var propertiesToSet          = ObjectHelper.GetPublicPropertySymbols(createdObjectType).Where(x => x.SetMethod?.DeclaredAccessibility == Accessibility.Public);
            var initExpressions          = propertiesToSet.Aggregate(objectInitializer.Expressions, (expr, property) =>
            {
                var mappingSource = mappingSourceFinder.FindMappingSource(property.Name, property.Type);
                if (mappingSource != null)
                {
                    var assignmentExpression = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(property.Name), mappingSource.Expression);
                    return(expr.Add(assignmentExpression));
                }
                return(expr);
            });

            return(await document.ReplaceNodes(objectInitializer, objectInitializer.WithExpressions(initExpressions), cancellationToken));
        }
Пример #4
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));
            }
        }
Пример #5
0
 public static IEnumerable <IPropertySymbol> GetFieldsThaCanBeSetFromConstructor(ITypeSymbol type)
 {
     return(ObjectHelper.GetPublicPropertySymbols(type)
            .Where(property => property.SetMethod != null || property.CanBeSetOnlyFromConstructor()));
 }
Пример #6
0
 public static IEnumerable <IPropertySymbol> GetFieldsThaCanBeSetPrivately(ITypeSymbol type)
 {
     return(ObjectHelper.GetPublicPropertySymbols(type)
            .Where(property => property.SetMethod != null && property.CanBeSetPrivately()));
 }
Пример #7
0
 public ObjectMembersMappingSourceFinder(ITypeSymbol sourceType, SyntaxNode sourceGlobalAccessor, SyntaxGenerator generator)
 {
     this.sourceType           = sourceType;
     this.sourceGlobalAccessor = sourceGlobalAccessor;
     this.generator            = generator;
     this.sourceProperties     = new Lazy <IReadOnlyList <IPropertySymbol> >(() => ObjectHelper.GetPublicPropertySymbols(sourceType)
                                                                             .Where(property => property.GetMethod != null)
                                                                             .ToList());
     this.sourceMethods = new Lazy <IReadOnlyList <IMethodSymbol> >(() => ObjectHelper.GetPublicGetMethods(sourceType).ToList());
 }
Пример #8
0
        public IEnumerable <SyntaxNode> MapTypes(ITypeSymbol sourceType, ITypeSymbol targetType,
                                                 SyntaxNode globalSourceAccessor, SyntaxNode globbalTargetAccessor = null, bool targetExists = false,
                                                 bool generatorContext = 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 MappingSourceFinder(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 (targetProperty.SetMethod.DeclaredAccessibility != Accessibility.Public && globbalTargetAccessor.Kind() != SyntaxKind.ThisExpression)
                {
                    continue;
                }

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

                if (IsMappingBetweenCollections(targetProperty.Type, mappingSource.ExpressionType))
                {
                    var targetAccess      = generator.MemberAccessExpression(localTargetIdentifier, targetProperty.Name);
                    var collectionMapping = MapCollections(mappingSource.Expression, mappingSource.ExpressionType, targetProperty.Type);
                    yield return(generator.CompleteAssignmentStatement(targetAccess, collectionMapping));
                }
                else if (ObjectHelper.IsSimpleType(targetProperty.Type) == false)
                {
                    //TODO: What if both sides has the same type?
                    //TODO: Reverse flattening
                    var targetAccess = generator.MemberAccessExpression(localTargetIdentifier, targetProperty.Name);
                    foreach (var complexPropertyMappingNode in MapTypes(mappingSource.ExpressionType, targetProperty.Type, mappingSource.Expression, targetAccess))
                    {
                        yield return(complexPropertyMappingNode);
                    }
                }
                else
                {
                    var targetAccess = generator.MemberAccessExpression(localTargetIdentifier, targetProperty.Name);
                    yield return(generator.CompleteAssignmentStatement(targetAccess, mappingSource.Expression));
                }
            }

            if (globbalTargetAccessor == null)
            {
                yield return(generator.ContextualReturnStatement(localTargetIdentifier, generatorContext));
            }
            else if (targetExists == false)
            {
                yield return(generator.CompleteAssignmentStatement(globbalTargetAccessor, localTargetIdentifier));
            }
        }
 public MappingSourceFinder(ITypeSymbol sourceType, SyntaxNode sourceGlobalAccessor, SyntaxGenerator generator, SemanticModel semanticModel)
 {
     this.sourceType           = sourceType;
     this.sourceGlobalAccessor = sourceGlobalAccessor;
     this.generator            = generator;
     this.semanticModel        = semanticModel;
     this.sourceProperties     = new Lazy <IReadOnlyList <IPropertySymbol> >(() => ObjectHelper.GetPublicPropertySymbols(sourceType).ToList());
     this.sourceMethods        = new Lazy <IReadOnlyList <IMethodSymbol> >(() => ObjectHelper.GetPublicGetMethods(sourceType).ToList());
 }