Document PerformAction(Document document, SemanticModel model, SyntaxNode root, PropertyDeclarationSyntax propertyDeclaration, bool needsSetter)
        {
            AccessorDeclarationSyntax accessor = null;
            PropertyDeclarationSyntax newProp  = null;

            if (needsSetter)
            {
                accessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration);

                var getter = propertyDeclaration.AccessorList.Accessors.FirstOrDefault(m => m.IsKind(SyntaxKind.GetAccessorDeclaration));
                if (getter == null)
                {
                    //get;
                    accessor = accessor.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
                }
                else
                {
                    var getField = ReplacePropertyWithBackingFieldWithAutoPropertyCodeRefactoringProvider.ScanGetter(model, getter);
                    if (getField == null && getter.Body == null)
                    {
                        //get;
                        accessor = accessor.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)).WithTrailingTrivia(getter.GetTrailingTrivia());
                    }
                    else if (getField == null || getField.IsReadOnly)
                    {
                        //readonly or no field can be found
                        accessor = accessor.WithBody(GetNotImplementedBlock());
                    }
                    else
                    {
                        //now we add a 'field = value'.
                        accessor = accessor.WithBody(SyntaxFactory.Block(
                                                         SyntaxFactory.ExpressionStatement(
                                                             SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(getField.Name), SyntaxFactory.IdentifierName("value")))));
                    }
                }
                newProp = propertyDeclaration.WithAccessorList(propertyDeclaration.AccessorList.AddAccessors(accessor));
            }
            else
            {
                accessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration);

                var setter           = propertyDeclaration.AccessorList.Accessors.FirstOrDefault(m => m.IsKind(SyntaxKind.SetAccessorDeclaration));
                var accessorDeclList = new SyntaxList <AccessorDeclarationSyntax>();
                if (setter == null)
                {
                    //set;
                    accessor = accessor.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
                }
                else
                {
                    var setField = ReplacePropertyWithBackingFieldWithAutoPropertyCodeRefactoringProvider.ScanSetter(model, setter);
                    if (setField == null && setter.Body == null)
                    {
                        //set;
                        accessor = accessor.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)).WithTrailingTrivia(setter.GetTrailingTrivia());
                    }
                    else if (setField == null)
                    {
                        //no field can be found
                        accessor = accessor.WithBody(GetNotImplementedBlock());
                    }
                    else
                    {
                        //now we add a 'return field;'.
                        accessor = accessor.WithBody(SyntaxFactory.Block(
                                                         SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(setField.Name))));
                    }
                    accessorDeclList = accessorDeclList.Add(propertyDeclaration.AccessorList.Accessors.First(m => m.IsKind(SyntaxKind.SetAccessorDeclaration)));
                }
                accessorDeclList = accessorDeclList.Insert(0, accessor);
                var accessorList = SyntaxFactory.AccessorList(accessorDeclList);
                newProp = propertyDeclaration.WithAccessorList(accessorList);
            }
            var newRoot = root.ReplaceNode((SyntaxNode)propertyDeclaration, newProp).WithAdditionalAnnotations(Formatter.Annotation);

            return(document.WithSyntaxRoot(newRoot));
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var property = root.FindNode(span) as PropertyDeclarationSyntax;

            if (property == null || !property.Identifier.Span.Contains(span))
            {
                return;
            }

            var field = ReplacePropertyWithBackingFieldWithAutoPropertyCodeRefactoringProvider.GetBackingField(model, property);

            if (field == null)
            {
                return;
            }
            var type = property.Parent as TypeDeclarationSyntax;

            if (type == null)
            {
                return;
            }

            var resolvedType = model.Compilation.GetTypeSymbol("System", "EventHandler", 0, cancellationToken);

            if (resolvedType == null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Create changed event"),
                    t2 =>
            {
                var eventDeclaration  = CreateChangedEventDeclaration(property);
                var methodDeclaration = CreateEventInvocatorCodeRefactoringProvider.CreateEventInvocator(
                    document,
                    type.Identifier.ToString(),
                    type.Modifiers.Any(m => m.IsKind(SyntaxKind.SealedKeyword)),
                    eventDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)),
                    eventDeclaration.Declaration.Variables.First().Identifier.ToString(),
                    resolvedType.GetDelegateInvokeMethod(),
                    false
                    );
                var invocation = SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(
                                                                       SyntaxFactory.IdentifierName(methodDeclaration.Identifier.ToString()),
                                                                       SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList <ArgumentSyntax>(new[] { SyntaxFactory.Argument(SyntaxFactory.ParseExpression("System.EventArgs.Empty")) }))
                                                                       ));

                var marker  = new SyntaxAnnotation();
                var newRoot = root.ReplaceNode(property, property.WithAdditionalAnnotations(marker));

                newRoot = newRoot.InsertNodesAfter(newRoot.GetAnnotatedNodes(marker).First(), new SyntaxNode[] {
                    methodDeclaration.WithAdditionalAnnotations(Formatter.Annotation),
                    eventDeclaration.WithAdditionalAnnotations(Formatter.Annotation)
                });

                newRoot = newRoot.InsertNodesAfter(newRoot.GetAnnotatedNodes(marker).OfType <PropertyDeclarationSyntax>().First().AccessorList.Accessors.First(a => a.IsKind(SyntaxKind.SetAccessorDeclaration)).Body.Statements.Last(),
                                                   new[] { invocation.WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation) }
                                                   );

                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            })
                );
        }