private ExpressionSyntax HandleSafeNull(MappingElement source, AnnotatedType targetType, ExpressionSyntax expression) { if (source.ExpressionType.CanBeNull) { var condition = BinaryExpression(SyntaxKind.NotEqualsExpression, source.Expression, LiteralExpression(SyntaxKind.NullLiteralExpression)); var whenNull = targetType.CanBeNull ? (ExpressionSyntax)LiteralExpression(SyntaxKind.NullLiteralExpression) : ThrowNullArgumentException(source.Expression.ToFullString()); return(ConditionalExpression(condition, expression, whenNull)); } return(expression); }
public ExpressionSyntax MapExpression(ExpressionSyntax sourceExpression, AnnotatedType sourceType, AnnotatedType destinationType, MappingContext mappingContext) { var mappingSource = new MappingElement { Expression = sourceExpression, ExpressionType = sourceType }; return(MapExpression(mappingSource, destinationType, mappingContext).Expression); }
public ExpressionSyntax CreateMappingLambda(string lambdaParameterName, AnnotatedType sourceListElementType, AnnotatedType targetListElementType, MappingPath mappingPath, MappingContext mappingContext) { var source = new MappingElement() { ExpressionType = sourceListElementType, Expression = syntaxGenerator.IdentifierName(lambdaParameterName) as ExpressionSyntax, }; var listElementMappingStm = MapExpression(source, targetListElementType, mappingContext, mappingPath); return((ExpressionSyntax)syntaxGenerator.ValueReturningLambdaExpression(lambdaParameterName, listElementMappingStm.Expression)); }
protected override Task <MappingElement> TryToCreateMappingExpression(MappingElement source, AnnotatedType targetType, MappingPath mappingPath, MappingContext mappingContext) { //TODO: check if source is not null (conditional member access) if (mappingPath.Length > 1 && source.ExpressionType.Type.AllInterfaces.Any(x => x.Name == "ICloneable") && source.ExpressionType.Type.SpecialType != SpecialType.System_Array) { var invokeClone = syntaxGenerator.InvocationExpression(syntaxGenerator.MemberAccessExpression(source.Expression, "Clone")); var cloneMethods = targetType.Type.GetMembers("Clone").OfType <IMethodSymbol>().Where(m => mappingContext.AccessibilityHelper.IsSymbolAccessible(m, targetType.Type)).ToList(); if (cloneMethods.Any(IsGenericCloneMethod)) { return(Task.FromResult(new MappingElement() { ExpressionType = targetType, Expression = invokeClone as ExpressionSyntax })); } var objectClone = cloneMethods.FirstOrDefault(x => x.Parameters.Length == 0); if (objectClone != null) { return(Task.FromResult(new MappingElement() { ExpressionType = targetType, Expression = syntaxGenerator.TryCastExpression(invokeClone, targetType.Type) as ExpressionSyntax })); } var implicitClone = targetType.Type.GetMembers("System.ICloneable.Clone").FirstOrDefault(); if (implicitClone != null) { var castedOnICloneable = syntaxGenerator.CastExpression(SyntaxFactory.ParseTypeName("ICloneable"), source.Expression); return(Task.FromResult(new MappingElement() { ExpressionType = targetType, Expression = syntaxGenerator.TryCastExpression(syntaxGenerator.InvocationExpression(syntaxGenerator.MemberAccessExpression(castedOnICloneable, "Clone")), targetType.Type) as ExpressionSyntax })); } } return(base.TryToCreateMappingExpression(source, targetType, mappingPath, mappingContext)); }
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); }
public async Task <ExpressionSyntax> MapExpression(ExpressionSyntax sourceExpression, AnnotatedType sourceType, AnnotatedType destinationType, MappingContext mappingContext) { var mappingSource = new MappingElement { Expression = sourceExpression, ExpressionType = sourceType }; var mappingElement = await MapExpression(mappingSource, destinationType, mappingContext).ConfigureAwait(false); return(mappingElement.Expression); }
private MappingElement ConvertToSimpleType(AnnotatedType targetType, MappingElement source, MappingContext mappingContext) { var conversion = semanticModel.Compilation.ClassifyConversion(source.ExpressionType.Type, targetType.Type); if (conversion.Exists == false) { var wrapper = GetWrappingInfo(source.ExpressionType.Type, targetType.Type, mappingContext); if (wrapper.Type == WrapperInfoType.ObjectField) { return(new MappingElement { Expression = SyntaxFactoryExtensions.CreateMemberAccessExpression(source.Expression, source.ExpressionType.CanBeNull, wrapper.UnwrappingObjectField.Name), ExpressionType = wrapper.UnwrappingObjectField.Type }); } if (wrapper.Type == WrapperInfoType.Method) { return(new MappingElement { Expression = SyntaxFactoryExtensions.CreateMethodAccessExpression(source.Expression, source.ExpressionType.CanBeNull, wrapper.UnwrappingMethod.Name), ExpressionType = new AnnotatedType(wrapper.UnwrappingMethod.ReturnType) }); } if (targetType.Type.SpecialType == SpecialType.System_String && source.ExpressionType.Type.TypeKind == TypeKind.Enum) { var toStringAccess = SyntaxFactoryExtensions.CreateMethodAccessExpression(source.Expression, source.ExpressionType.CanBeNull, "ToString"); return(new MappingElement { Expression = toStringAccess, ExpressionType = targetType }); } if (source.ExpressionType.Type.SpecialType == SpecialType.System_String && targetType.Type.TypeKind == TypeKind.Enum) { var parseEnumAccess = syntaxGenerator.MemberAccessExpression(SyntaxFactory.ParseTypeName("System.Enum"), "Parse"); var enumType = SyntaxFactory.ParseTypeName(targetType.Type.Name); var parseInvocation = (InvocationExpressionSyntax)syntaxGenerator.InvocationExpression(parseEnumAccess, new[] { syntaxGenerator.TypeOfExpression(enumType), source.Expression, syntaxGenerator.TrueLiteralExpression() }); return(new MappingElement() { Expression = (ExpressionSyntax)syntaxGenerator.CastExpression(enumType, parseInvocation), ExpressionType = targetType.AsNotNull() }); } } else if (conversion.IsExplicit) { return(new MappingElement() { Expression = (ExpressionSyntax)syntaxGenerator.CastExpression(targetType.Type, source.Expression), ExpressionType = targetType }); } return(source); }
protected virtual async Task <MappingElement> TryToCreateMappingExpression(MappingElement source, AnnotatedType targetType, MappingPath mappingPath, MappingContext mappingContext) { //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.Type as INamedTypeSymbol; if (namedTargetType != null) { var directlyMappingConstructor = namedTargetType.Constructors.FirstOrDefault(c => c.Parameters.Length == 1 && c.Parameters[0].Type.Equals(source.ExpressionType.Type)); if (directlyMappingConstructor != null) { var creationExpression = CreateObject(targetType.Type, SyntaxFactory.ArgumentList().AddArguments(SyntaxFactory.Argument(source.Expression))); var shouldProtectAgainstNull = directlyMappingConstructor.Parameters[0].Type.CanBeNull() == false && source.ExpressionType.CanBeNull; return(new MappingElement { ExpressionType = targetType, Expression = shouldProtectAgainstNull ? HandleSafeNull(source, targetType, creationExpression) : creationExpression }); } } if (MappingHelper.IsMappingBetweenCollections(targetType.Type, source.ExpressionType.Type)) { var shouldProtectAgainstNull = source.ExpressionType.CanBeNull && targetType.CanBeNull == false; var collectionMapping = (await MapCollectionsAsync(source, targetType, mappingPath.Clone(), mappingContext).ConfigureAwait(false)) as ExpressionSyntax; return(new MappingElement { ExpressionType = targetType, Expression = shouldProtectAgainstNull ? OrFailWhenArgumentNull(collectionMapping, source.Expression.ToFullString()) : collectionMapping, }); } var subMappingSourceFinder = new ObjectMembersMappingSourceFinder(source.ExpressionType.AsNotNull(), source.Expression); if (namedTargetType != null) { //maybe there is constructor that accepts parameter matching source properties var constructorOverloadParameterSets = namedTargetType.Constructors.Select(x => x.Parameters); var matchedOverload = await MethodHelper.FindBestParametersMatch(subMappingSourceFinder, constructorOverloadParameterSets, mappingContext).ConfigureAwait(false); if (matchedOverload != null) { var argumentListSyntaxAsync = await matchedOverload.ToArgumentListSyntaxAsync(this, mappingContext).ConfigureAwait(false); var creationExpression = CreateObject(targetType.Type, argumentListSyntaxAsync); var matchedSources = matchedOverload.GetMatchedSources(); var restSourceFinder = new IgnorableMappingSourceFinder(subMappingSourceFinder, foundElement => { return(matchedSources.Any(x => x.Expression.IsEquivalentTo(foundElement.Expression))); }); var mappingMatcher = new SingleSourceMatcher(restSourceFinder); return(new MappingElement() { ExpressionType = new AnnotatedType(targetType.Type), Expression = await AddInitializerWithMappingAsync(creationExpression, mappingMatcher, targetType.Type, mappingContext, mappingPath).ConfigureAwait(false), }); } } var objectCreationExpressionSyntax = CreateObject(targetType.Type); var subMappingMatcher = new SingleSourceMatcher(subMappingSourceFinder); var objectCreationWithInitializer = await AddInitializerWithMappingAsync(objectCreationExpressionSyntax, subMappingMatcher, targetType.Type, mappingContext, mappingPath).ConfigureAwait(false); return(new MappingElement() { ExpressionType = new AnnotatedType(targetType.Type), Expression = HandleSafeNull(source, targetType, objectCreationWithInitializer) }); }