예제 #1
0
        private async Task <Document> GenerateSplatting(Document document, InvocationExpressionSyntax invocationExpression, CancellationToken cancellationToken)
        {
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

            var methodSymbol = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken).CandidateSymbols.OfType <IMethodSymbol>().FirstOrDefault();

            if (methodSymbol == null)
            {
                return(document);
            }

            var root = await document.GetSyntaxRootAsync(cancellationToken);

            var invalidArgument     = invocationExpression.ArgumentList.Arguments.First();
            var sourceType          = semanticModel.GetTypeInfo(invalidArgument.Expression);
            var syntaxGenerator     = SyntaxGenerator.GetGenerator(document);
            var mappingSourceFinder = new MappingSourceFinder(sourceType.Type, invalidArgument.Expression, syntaxGenerator, semanticModel);
            var argumentList        = FindBestArgumentsMatch(methodSymbol, cancellationToken, mappingSourceFinder, semanticModel);

            if (argumentList == null)
            {
                return(document);
            }
            var newRoot = root.ReplaceNode(invocationExpression, invocationExpression.WithArgumentList(argumentList));

            return(document.WithSyntaxRoot(newRoot));
        }
예제 #2
0
 public static ArgumentListSyntax FindBestArgumentsMatch(MappingSourceFinder mappingSourceFinder, IEnumerable <ImmutableArray <IParameterSymbol> > overloadParameterSets)
 {
     return(overloadParameterSets
            .Select(x => FindArgumentsMatch(x, mappingSourceFinder))
            .Where(x => x.Arguments.Count > 0)
            .OrderByDescending(argumentList => argumentList.Arguments.Count)
            .FirstOrDefault());
 }
예제 #3
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));
            }
        }
예제 #4
0
 private static ArgumentListSyntax FindMappingConstructorParameters(ITypeSymbol targetType, ITypeSymbol sourceType, MappingSourceFinder mappingSourceFinder, ExpressionSyntax globalSourceAccessor)
 {
     if (targetType is INamedTypeSymbol namedType)
     {
         var directlyMappingConstructor = namedType.Constructors.FirstOrDefault(c => c.Parameters.Length == 1 && c.Parameters[0].Type == sourceType);
         if (directlyMappingConstructor != null)
         {
             return(SyntaxFactory.ArgumentList().AddArguments(SyntaxFactory.Argument(globalSourceAccessor)));
         }
         var constructorOverloadParameterSets = namedType.Constructors.Select(x => x.Parameters);
         return(MethodHelper.FindBestArgumentsMatch(mappingSourceFinder, constructorOverloadParameterSets));
     }
     return(null);
 }
예제 #5
0
        private static ArgumentListSyntax FindBestArgumentsMatch(IMethodSymbol methodSymbol, CancellationToken cancellationToken, MappingSourceFinder mappingSourceFinder, SemanticModel semanticModel)
        {
            var overloadParameterSets = methodSymbol.DeclaringSyntaxReferences.Select(ds =>
            {
                var overloadDeclaration = (MethodDeclarationSyntax)ds.GetSyntax(cancellationToken);
                var overloadMethod      = semanticModel.GetDeclaredSymbol(overloadDeclaration);
                return(overloadMethod.Parameters);
            });

            return(MethodHelper.FindBestArgumentsMatch(mappingSourceFinder, overloadParameterSets));
        }
예제 #6
0
        private static ArgumentListSyntax FindArgumentsMatch(ImmutableArray <IParameterSymbol> parameters, MappingSourceFinder mappingSourceFinder)
        {
            var argumentList = SyntaxFactory.ArgumentList();

            foreach (var parameter in parameters)
            {
                var mappingSource = mappingSourceFinder.FindMappingSource(parameter.Name, parameter.Type);
                if (mappingSource != null)
                {
                    var argument = SyntaxFactory.Argument(SyntaxFactory.NameColon(parameter.Name), SyntaxFactory.Token(SyntaxKind.None), mappingSource.Expression);
                    argumentList = argumentList.AddArguments(argument);
                }
            }
            return(argumentList);
        }