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>()); }
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)); }
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)); } }
public static IEnumerable <IPropertySymbol> GetFieldsThaCanBeSetFromConstructor(ITypeSymbol type) { return(ObjectHelper.GetPublicPropertySymbols(type) .Where(property => property.SetMethod != null || property.CanBeSetOnlyFromConstructor())); }
public static IEnumerable <IPropertySymbol> GetFieldsThaCanBeSetPrivately(ITypeSymbol type) { return(ObjectHelper.GetPublicPropertySymbols(type) .Where(property => property.SetMethod != null && property.CanBeSetPrivately())); }
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()); }
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()); }