private static ExpressionSyntax Compare(IFieldSymbol field)
        {
            if (field.Type.SpecialType == SpecialType.System_Boolean ||
                field.Type.SpecialType == SpecialType.System_Char ||
                field.Type.SpecialType == SpecialType.System_SByte ||
                field.Type.SpecialType == SpecialType.System_Byte ||
                field.Type.SpecialType == SpecialType.System_Int16 ||
                field.Type.SpecialType == SpecialType.System_UInt16 ||
                field.Type.SpecialType == SpecialType.System_Int32 ||
                field.Type.SpecialType == SpecialType.System_UInt32 ||
                field.Type.SpecialType == SpecialType.System_Int64 ||
                field.Type.SpecialType == SpecialType.System_UInt64 ||
                field.Type.SpecialType == SpecialType.System_Single ||
                field.Type.SpecialType == SpecialType.System_Double)
            {
                return(BinaryExpression(SyntaxKind.EqualsExpression, field.AsIdentifierName(), "value".AsIdentifierName()));
            }

            return(InvocationExpression(
                       MemberAccessExpression(
                           SyntaxKind.SimpleMemberAccessExpression,
                           PredefinedType(
                               Token(SyntaxKind.ObjectKeyword)),
                           IdentifierName("Equals")))
                   .WithArgumentList(RoslynHelpers.CreateArguments(field.AsIdentifierName(), "value".AsIdentifierName())));
        }
        public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
        {
            var symbol = compilation.GetSemanticModel(node.SyntaxTree).GetDeclaredSymbol(node);

            var backingField = symbol.ContainingType.GetMembers().OfType <IFieldSymbol>()
                               .FirstOrDefault(f => f.AssociatedSymbol?.Equals(symbol) == true);

            if (backingField == null)
            {
                return(node);
            }

            // http://roslynquoter.azurewebsites.net/

            BlockSyntax setterBlock = null;

            if (helperMethod.Parameters.Length == 1)
            {
                // string name
                if (helperMethod.Parameters[0].Type.SpecialType.Equals(SpecialType.System_String))
                {
                    setterBlock = Block()
                                  .If(Compare(backingField), ReturnStatement())
                                  .Assign(backingField, "value")
                                  .CallMethod(helperMethod, node.Identifier.Text.AsStringLiteral());

                    if (dependantProperties.TryGetValue(node.Identifier.Text, out var dps))
                    {
                        setterBlock = setterBlock.AddStatements(dps.Select(dp =>
                                                                           ExpressionStatement(InvocationExpression(helperMethod.Name.AsIdentifierName())
                                                                                               .WithArgumentList(RoslynHelpers.CreateArguments(
                                                                                                                     dp.AsStringLiteral()
                                                                                                                     )))).ToArray());
                    }
                }
            }

            if (helperMethod.Parameters.Length == 3)
            {
                // string name, object before, object after
                if (helperMethod.Parameters[0].Type.SpecialType.Equals(SpecialType.System_String) &&
                    helperMethod.Parameters[1].Type.SpecialType.Equals(SpecialType.System_Object) &&
                    helperMethod.Parameters[2].Type.SpecialType.Equals(SpecialType.System_Object))
                {
                    setterBlock = Block()
                                  .If(Compare(backingField), ReturnStatement())
                                  .DeclareVariable("before", node.Identifier.Text.AsIdentifierName())
                                  .Assign(backingField, "value")
                                  .DeclareVariable("after", node.Identifier.Text.AsIdentifierName())
                                  .CallMethod(helperMethod, node.Identifier.Text.AsStringLiteral(), "before".AsIdentifierName(), "after".AsIdentifierName());

                    if (dependantProperties.TryGetValue(node.Identifier.Text, out var dps))
                    {
                        setterBlock = setterBlock.AddStatements(dps.Select(dp =>
                                                                           ExpressionStatement(InvocationExpression(helperMethod.Name.AsIdentifierName())
                                                                                               .WithArgumentList(RoslynHelpers.CreateArguments(
                                                                                                                     dp.AsStringLiteral(),
                                                                                                                     "before".AsIdentifierName(),
                                                                                                                     "after".AsIdentifierName()
                                                                                                                     )))).ToArray());
                    }
                }
            }

            if (setterBlock != null)
            {
                membersToAdd.Add(backingField.AsFieldDeclaration());
                return(node
                       .WithAccessorList(AccessorList(List(
                                                          new AccessorDeclarationSyntax[] {
                    AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,
                                        Block().Return(backingField.Name.AsIdentifierName())),
                    AccessorDeclaration(SyntaxKind.SetAccessorDeclaration,
                                        setterBlock)
                }))));
            }

            reportDiagnostic(Diagnostic.Create(HelperMethodNotMatchedDescriptor, helperMethod.Locations[0], helperMethod.Name));

            return(node);
        }