public static MethodDeclarationSyntax[] CreateWithMethodsToAdd(
     TypeConstructorDetails typeConstructorDetails,
     INamedTypeSymbol doType,
     string[] existingWithMethodNames)
 {
     return
         (typeConstructorDetails.PropertyAndParameters
          .Select(item => new { item, newMethodName = "With" + item.Property.Name })
          .Where(x => !existingWithMethodNames.Contains(x.newMethodName))
          .Select(x => CreateWithMethod(doType, typeConstructorDetails, x.item))
          .ToArray());
 }
        public static MethodDeclarationSyntax CreateWithMethod(
            INamedTypeSymbol doTypeSymbol,
            TypeConstructorDetails typeConstructorDetails,
            PropertyAndParameter propertyToCreateMethodFor)
        {
            var newMethodName = "With" + propertyToCreateMethodFor.Property.Name;

            var doFullname = Utilities.GetFullName(doTypeSymbol);

            var thisParameterName = "instance";

            var propertyTypeFullName = Utilities.GetFullName(propertyToCreateMethodFor.Property.Type);

            List <SyntaxNodeOrToken> nodes = new List <SyntaxNodeOrToken>();

            foreach (var property in typeConstructorDetails.PropertyAndParameters)
            {
                var propertyName = property.Property.Name;

                var parameterName = Utilities.MakeFirstLetterSmall(property.Parameter.Name);

                if (nodes.Count > 0)
                {
                    nodes.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
                }

                if (property.Property.Equals(propertyToCreateMethodFor.Property))
                {
                    nodes.Add(
                        SyntaxFactory.Argument(
                            SyntaxFactory.IdentifierName("newValue"))
                        .WithNameColon(
                            SyntaxFactory.NameColon(
                                SyntaxFactory.IdentifierName(parameterName))));
                }
                else
                {
                    nodes.Add(
                        SyntaxFactory.Argument(
                            Utilities.CreateSimpleMemberAccessSyntax(thisParameterName, propertyName))
                        .WithNameColon(
                            SyntaxFactory.NameColon(
                                SyntaxFactory.IdentifierName(parameterName))));
                }
            }


            var constructionExpressionSyntax =
                typeConstructorDetails.Constructor
                .Match <ExpressionSyntax>(caseNormalConstructor: () =>
                                          SyntaxFactory.ObjectCreationExpression(
                                              SyntaxFactory.IdentifierName(doFullname))
                                          .WithArgumentList(
                                              SyntaxFactory.ArgumentList(
                                                  SyntaxFactory.SeparatedList <ArgumentSyntax>(
                                                      nodes.ToArray()))),
                                          caseFSharpUnionCaseNewMethod: () =>
                                          SyntaxFactory.CastExpression(
                                              SyntaxFactory.IdentifierName(doFullname),
                                              SyntaxFactory.InvocationExpression(
                                                  Utilities.CreateSimpleMemberAccessSyntax(Utilities.GetFullName(doTypeSymbol.BaseType), "New" + doTypeSymbol.Name))
                                              .WithArgumentList(
                                                  SyntaxFactory.ArgumentList(
                                                      SyntaxFactory.SeparatedList <ArgumentSyntax>(
                                                          nodes.ToArray())))));

            var method =
                SyntaxFactory.MethodDeclaration(
                    SyntaxFactory.IdentifierName(doFullname),
                    SyntaxFactory.Identifier(newMethodName))
                .WithModifiers(
                    SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
                .WithParameterList(
                    SyntaxFactory.ParameterList(
                        SyntaxFactory.SeparatedList <ParameterSyntax>(
                            new SyntaxNodeOrToken[] {
                SyntaxFactory.Parameter(
                    SyntaxFactory.Identifier(thisParameterName))
                .WithModifiers(
                    SyntaxFactory.TokenList(
                        SyntaxFactory.Token(SyntaxKind.ThisKeyword)))
                .WithType(
                    SyntaxFactory.IdentifierName(doFullname)),
                SyntaxFactory.Token(SyntaxKind.CommaToken),
                SyntaxFactory.Parameter(
                    SyntaxFactory.Identifier("newValue"))
                .WithType(
                    SyntaxFactory.IdentifierName(propertyTypeFullName))
            })))
                .WithBody(
                    SyntaxFactory.Block(
                        SyntaxFactory.SingletonList <StatementSyntax>(
                            SyntaxFactory.ReturnStatement(
                                constructionExpressionSyntax))));

            if (doTypeSymbol.IsGenericType)
            {
                var openTypeParams = Utilities.GetOpenTypeParameters(doTypeSymbol);

                if (openTypeParams.Any())
                {
                    method = method.WithTypeParameterList(
                        SyntaxFactory.TypeParameterList(
                            SyntaxFactory.SeparatedList(
                                openTypeParams
                                .Select(x => SyntaxFactory.TypeParameter(SyntaxFactory.Identifier(x.Name))))));
                }
            }

            return(method);
        }