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); }
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) }); }
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)); }
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); }
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)); } }
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); }
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); }
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)); } }
private bool IsUnwrappingNeeded(ITypeSymbol targetType, MappingElement element) { return(targetType != element.ExpressionType && ObjectHelper.IsSimpleType(targetType)); }
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); }
private bool IsUnwrappingNeeded(ITypeSymbol targetType, MappingElement element) { return(targetType.Equals(element.ExpressionType) == false && (ObjectHelper.IsSimpleType(targetType) || SymbolHelper.IsNullable(targetType, out _))); }
private static bool IsUnrappingNeeded(ITypeSymbol targetType, MappingElement mappingSource) { return(targetType != mappingSource.ExpressionType && ObjectHelper.IsSimpleType(targetType)); }