private static SyntaxNode GetRootWithAnnotatedElements(SyntaxNode root,
                                                               Dictionary <SyntaxNodeOrToken, Diagnostic> elementDiagnosticPairs,
                                                               BidirectionalDictionary <Diagnostic, SyntaxAnnotation> diagnosticAnnotationPairs)
        {
            var nodes  = elementDiagnosticPairs.Keys.Where(k => k.IsNode).Select(k => k.AsNode());
            var tokens = elementDiagnosticPairs.Keys.Where(k => k.IsToken).Select(k => k.AsToken());

            return(root.ReplaceSyntax(
                       nodes,
                       (original, rewritten) =>
            {
                var annotation = diagnosticAnnotationPairs.GetByA(elementDiagnosticPairs[original]);
                return rewritten.WithAdditionalAnnotations(annotation);
            },
                       tokens,
                       (original, rewritten) =>
            {
                var annotation = diagnosticAnnotationPairs.GetByA(elementDiagnosticPairs[original]);
                return rewritten.WithAdditionalAnnotations(annotation);
            },
                       null, null));
        }
        private static async Task <SyntaxNode> GetFixedDocumentAsync(FixAllContext fixAllContext, Document document)
        {
            var annotationKind = Guid.NewGuid().ToString();

            var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false);

            var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);

            var elementDiagnosticPairs = diagnostics
                                         .Select(d => new KeyValuePair <SyntaxNodeOrToken, Diagnostic>(GetReportedElement(d, root), d))
                                         .Where(n => !n.Key.IsMissing)
                                         .ToDictionary(kv => kv.Key, kv => kv.Value);

            var diagnosticAnnotationPairs = new BidirectionalDictionary <Diagnostic, SyntaxAnnotation>();

            CreateAnnotationForDiagnostics(diagnostics, annotationKind, diagnosticAnnotationPairs);
            root = GetRootWithAnnotatedElements(root, elementDiagnosticPairs, diagnosticAnnotationPairs);

            var currentDocument   = document.WithSyntaxRoot(root);
            var annotatedElements = root.GetAnnotatedNodesAndTokens(annotationKind).ToList();

            while (annotatedElements.Any())
            {
                var element    = annotatedElements.First();
                var annotation = element.GetAnnotations(annotationKind).First();
                var diagnostic = diagnosticAnnotationPairs.GetByB(annotation);
                var location   = root.GetAnnotatedNodesAndTokens(annotation).FirstOrDefault().GetLocation();
                if (location == null)
                {
                    //annotation is already removed from the tree
                    continue;
                }

                var newDiagnostic = Diagnostic.Create(
                    diagnostic.Descriptor,
                    location,
                    diagnostic.AdditionalLocations,
                    diagnostic.Properties);

                var fixes   = new List <CodeAction>();
                var context = new CodeFixContext(currentDocument, newDiagnostic, (a, d) =>
                {
                    lock (fixes)
                    {
                        fixes.Add(a);
                    }
                }, fixAllContext.CancellationToken);
                await fixAllContext.CodeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                var action = fixes.FirstOrDefault(fix => fix.EquivalenceKey == fixAllContext.CodeActionEquivalenceKey);
                if (action != null)
                {
                    var operations = await action.GetOperationsAsync(fixAllContext.CancellationToken);

                    var solution = operations.OfType <ApplyChangesOperation>().Single().ChangedSolution;
                    currentDocument = solution.GetDocument(document.Id);
                    root            = await currentDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
                }
                root              = RemoveAnnotationIfExists(root, annotation);
                currentDocument   = document.WithSyntaxRoot(root);
                annotatedElements = root.GetAnnotatedNodesAndTokens(annotationKind).ToList();
            }

            return(await currentDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false));
        }