private async Task<Solution> RunLocalSemanticPass(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, ILocalSemanticFormattingRule localSemanticRule, CancellationToken cancellationToken)
        {
            if (_verbose)
            {
                FormatLogger.WriteLine("  {0}", localSemanticRule.GetType().Name);
            }

            var currentSolution = originalSolution;
            foreach (var documentId in documentIds)
            {
                using (var document = new ConfiguredDocument(originalSolution, documentId, this))
                {
                    var syntaxRoot = await GetSyntaxRootAndFilter(localSemanticRule, document.Value, cancellationToken);
                    if (syntaxRoot == null)
                    {
                        continue;
                    }

                    StartDocument();
                    var newRoot = await localSemanticRule.ProcessAsync(document.Value, syntaxRoot, cancellationToken);
                    EndDocument(document.Value);

                    if (syntaxRoot != newRoot)
                    {
                        currentSolution = currentSolution.WithDocumentSyntaxRoot(documentId, newRoot);
                    }
                }
            }

            return currentSolution;
        }
        private async Task<Solution> RunGlobalSemanticPass(Solution solution, IReadOnlyList<DocumentId> documentIds, IGlobalSemanticFormattingRule globalSemanticRule, CancellationToken cancellationToken)
        {
            if (_verbose)
            {
                FormatLogger.WriteLine("  {0}", globalSemanticRule.GetType().Name);
            }

            foreach (var documentId in documentIds)
            {
                using (var document = new ConfiguredDocument(solution, documentId, this))
                {
                    var syntaxRoot = await GetSyntaxRootAndFilter(globalSemanticRule, document.Value, cancellationToken);
                    if (syntaxRoot == null)
                    {
                        continue;
                    }

                    StartDocument();
                    solution = await globalSemanticRule.ProcessAsync(document.Value, syntaxRoot, cancellationToken);
                    EndDocument(document.Value);
                }
            }

            return solution;
        }
        /// <summary>
        /// Semantics is not involved in this pass at all.  It is just a straight modification of the 
        /// parse tree so there are no issues about ensuring the version of <see cref="SemanticModel"/> and
        /// the <see cref="SyntaxNode"/> line up.  Hence we do this by iteraning every <see cref="Document"/> 
        /// and processing all rules against them at once 
        /// </summary>
        private async Task<Solution> RunSyntaxPass(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
        {
            FormatLogger.WriteLine("\tSyntax Pass");

            var currentSolution = originalSolution;
            foreach (var documentId in documentIds)
            {
                using (var document = new ConfiguredDocument(originalSolution, documentId, this))
                {
                    var syntaxRoot = await GetSyntaxRootAndFilter(document.Value, cancellationToken);
                    if (syntaxRoot == null)
                    {
                        continue;
                    }

                    StartDocument();
                    var newRoot = RunSyntaxPass(syntaxRoot, document.Value.Project.Language);
                    EndDocument(document.Value);

                    if (newRoot != syntaxRoot)
                    {
                        currentSolution = currentSolution.WithDocumentSyntaxRoot(document.Value.Id, newRoot);
                    }
                }
            }

            return currentSolution;
        }