internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, IEnumerable<Document> documents, CancellationToken cancellationToken)
            {
                AssertIsForeground();

                using (new SelectionTracking(this))
                {
                    // 1. Undo any previous edits and update the buffer to resulting document after conflict resolution
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    var preMergeSolution = _session._baseSolution;
                    var postMergeSolution = conflictResolution.NewSolution;

                    var diffMergingSession = new LinkedFileDiffMergingSession(preMergeSolution, postMergeSolution, postMergeSolution.GetChanges(preMergeSolution), logSessionInfo: true);
                    var mergeResult = diffMergingSession.MergeDiffsAsync(mergeConflictHandler: null, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

                    var newDocument = mergeResult.MergedSolution.GetDocument(documents.First().Id);
                    var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id);

                    var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken);

                    // TODO: why does the following line hang when uncommented?
                    // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse();

                    _session.UndoManager.CreateConflictResolutionUndoTransaction(_subjectBuffer, () =>
                    {
                        using (var edit = _subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, null, s_propagateSpansEditTag))
                        {
                            foreach (var change in changes)
                            {
                                edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
                            }

                            edit.Apply();
                        }
                    });

                    // 2. We want to update referenceSpanToLinkedRenameSpanMap where spans were affected by conflict resolution.
                    // We also need to add the remaining document edits to conflictResolutionRenameTrackingSpans
                    // so they get classified/tagged correctly in the editor.
                    _conflictResolutionRenameTrackingSpans.Clear();

                    foreach (var document in documents)
                    {
                        var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None);
                        if (!relevantReplacements.Any())
                        {
                            continue;
                        }

                        var bufferContainsLinkedDocuments = documents.Skip(1).Any();
                        var mergedReplacements = bufferContainsLinkedDocuments
                            ? GetMergedReplacementInfos(
                                relevantReplacements,
                                conflictResolution.NewSolution.GetDocument(document.Id),
                                mergeResult.MergedSolution.GetDocument(document.Id),
                                cancellationToken)
                            : relevantReplacements;

                        // Show merge conflicts comments as unresolvable conflicts, and do not 
                        // show any other rename-related spans that overlap a merge conflict comment.
                        var mergeConflictComments = mergeResult.MergeConflictCommentSpans.ContainsKey(document.Id)
                            ? mergeResult.MergeConflictCommentSpans[document.Id]
                            : SpecializedCollections.EmptyEnumerable<TextSpan>();

                        foreach (var conflict in mergeConflictComments)
                        {
                            // TODO: Add these to the unresolvable conflict counts in the dashboard

                            _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(conflict.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                RenameSpanKind.UnresolvedConflict));
                        }

                        foreach (var replacement in mergedReplacements)
                        {
                            var kind = GetRenameSpanKind(replacement.Kind);

                            if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified)
                            {
                                var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan(
                                    new InlineRenameLocation(newDocument, replacement.NewSpan), _session.ReplacementText, cancellationToken);
                                if (linkedRenameSpan.HasValue)
                                {
                                    if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                    {
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                            _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                                                linkedRenameSpan.Value.ToSpan(),
                                                SpanTrackingMode.EdgeInclusive,
                                                TrackingFidelityMode.Forward),
                                            kind);
                                    }
                                }
                                else
                                {
                                    // We might not have a renamable span if an alias conflict completely changed the text
                                    _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan].TrackingSpan,
                                        RenameSpanKind.None);

                                    if (_activeSpan.HasValue && _activeSpan.Value.IntersectsWith(replacement.OriginalSpan))
                                    {
                                        _activeSpan = null;
                                    }
                                }
                            }
                            else
                            {
                                if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                {
                                    _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                        _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(replacement.NewSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                        kind));
                                }
                            }
                        }
                    }

                    UpdateReadOnlyRegions();

                    // 3. Reset the undo state and notify the taggers.
                    this.ApplyReplacementText(updateSelection: false);
                    RaiseSpansChanged();
                }
            }
            internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, LinkedFileMergeSessionResult mergeResult, IEnumerable <Document> documents, CancellationToken cancellationToken)
            {
                AssertIsForeground();

                if (!AreAllReferenceSpansMappable())
                {
                    // don't dynamically update the reference spans for documents with unmappable projections
                    return;
                }

                using (new SelectionTracking(this))
                {
                    // 1. Undo any previous edits and update the buffer to resulting document after conflict resolution
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    var newDocument      = mergeResult.MergedSolution.GetDocument(documents.First().Id);
                    var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id);

                    var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken);

                    // TODO: why does the following line hang when uncommented?
                    // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse();

                    _session.UndoManager.CreateConflictResolutionUndoTransaction(_subjectBuffer, () =>
                    {
                        using (var edit = _subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, null, s_propagateSpansEditTag))
                        {
                            foreach (var change in changes)
                            {
                                edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
                            }

                            edit.ApplyAndLogExceptions();
                        }
                    });

                    // 2. We want to update referenceSpanToLinkedRenameSpanMap where spans were affected by conflict resolution.
                    // We also need to add the remaining document edits to conflictResolutionRenameTrackingSpans
                    // so they get classified/tagged correctly in the editor.
                    _conflictResolutionRenameTrackingSpans.Clear();

                    var documentReplacements = documents
                                               .Select(document => (document, conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None).ToImmutableArray()))
                                               .ToImmutableArray();

                    var firstDocumentReplacements     = documentReplacements.FirstOrDefault(d => !d.Item2.IsEmpty);
                    var bufferContainsLinkedDocuments = documentReplacements.Length > 1 && firstDocumentReplacements.document != null;
                    var linkedDocumentsMightConflict  = bufferContainsLinkedDocuments;
                    if (linkedDocumentsMightConflict)
                    {
                        // When changes are made and linked documents are involved, some of the linked documents may
                        // have changes that differ from others. When these changes conflict (both differ and overlap),
                        // the inline rename UI reveals the conflicts. However, the merge process for finding these
                        // conflicts is slow, so we want to avoid it when possible. This code block attempts to set
                        // linkedDocumentsMightConflict back to false, eliminating the need to merge the changes as part
                        // of the conflict detection process. Currently we only special case one scenario: ignoring
                        // documents that have no changes at all, we check if all linked documents have exactly the same
                        // set of changes.

                        // 1. Check if all documents have the same replacement spans (or no replacements)
                        var spansMatch = true;
                        foreach (var(document, replacements) in documentReplacements)
                        {
                            if (document == firstDocumentReplacements.document || replacements.IsEmpty)
                            {
                                continue;
                            }

                            if (replacements.Length != firstDocumentReplacements.Item2.Length)
                            {
                                spansMatch = false;
                                break;
                            }

                            for (var i = 0; i < replacements.Length; i++)
                            {
                                if (!replacements[i].Equals(firstDocumentReplacements.Item2[i]))
                                {
                                    spansMatch = false;
                                    break;
                                }
                            }

                            if (!spansMatch)
                            {
                                break;
                            }
                        }

                        // 2. If spans match, check content
                        if (spansMatch)
                        {
                            linkedDocumentsMightConflict = false;

                            // Only need to check the new span's content
                            var firstDocumentNewText     = conflictResolution.NewSolution.GetDocument(firstDocumentReplacements.document.Id).GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                            var firstDocumentNewSpanText = firstDocumentReplacements.Item2.SelectAsArray(replacement => firstDocumentNewText.ToString(replacement.NewSpan));
                            foreach (var(document, replacements) in documentReplacements)
                            {
                                if (document == firstDocumentReplacements.document || replacements.IsEmpty)
                                {
                                    continue;
                                }

                                var documentNewText = conflictResolution.NewSolution.GetDocument(document.Id).GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                                for (var i = 0; i < replacements.Length; i++)
                                {
                                    if (documentNewText.ToString(replacements[i].NewSpan) != firstDocumentNewSpanText[i])
                                    {
                                        // Have to use the slower merge process
                                        linkedDocumentsMightConflict = true;
                                        break;
                                    }
                                }

                                if (linkedDocumentsMightConflict)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    foreach (var document in documents)
                    {
                        var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None);
                        if (!relevantReplacements.Any())
                        {
                            continue;
                        }

                        var mergedReplacements = linkedDocumentsMightConflict
                            ? GetMergedReplacementInfos(
                            relevantReplacements,
                            conflictResolution.NewSolution.GetDocument(document.Id),
                            mergeResult.MergedSolution.GetDocument(document.Id),
                            cancellationToken)
                            : relevantReplacements;

                        // Show merge conflicts comments as unresolvable conflicts, and do not
                        // show any other rename-related spans that overlap a merge conflict comment.
                        var mergeConflictComments = mergeResult.MergeConflictCommentSpans.ContainsKey(document.Id)
                            ? mergeResult.MergeConflictCommentSpans[document.Id]
                            : SpecializedCollections.EmptyEnumerable <TextSpan>();

                        foreach (var conflict in mergeConflictComments)
                        {
                            // TODO: Add these to the unresolvable conflict counts in the dashboard

                            _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                           _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(conflict.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                           RenameSpanKind.UnresolvedConflict));
                        }

                        foreach (var replacement in mergedReplacements)
                        {
                            var kind = GetRenameSpanKind(replacement.Kind);

                            if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified)
                            {
                                var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan(
                                    new InlineRenameLocation(newDocument, replacement.NewSpan), GetWithoutAttributeSuffix(_session.ReplacementText, document.GetLanguageService <LanguageServices.ISyntaxFactsService>().IsCaseSensitive), cancellationToken);
                                if (linkedRenameSpan.HasValue)
                                {
                                    if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                    {
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                            _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                                                linkedRenameSpan.Value.ToSpan(),
                                                SpanTrackingMode.EdgeInclusive,
                                                TrackingFidelityMode.Forward),
                                            kind);
                                    }
                                }
                                else
                                {
                                    // We might not have a renameable span if an alias conflict completely changed the text
                                    _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan].TrackingSpan,
                                        RenameSpanKind.None);

                                    if (_activeSpan.HasValue && _activeSpan.Value.IntersectsWith(replacement.OriginalSpan))
                                    {
                                        _activeSpan = null;
                                    }
                                }
                            }
                            else
                            {
                                if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                {
                                    _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                                   _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(replacement.NewSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                                   kind));
                                }
                            }
                        }

                        if (!linkedDocumentsMightConflict)
                        {
                            break;
                        }
                    }

                    UpdateReadOnlyRegions();

                    // 3. Reset the undo state and notify the taggers.
                    this.ApplyReplacementText(updateSelection: false);
                    RaiseSpansChanged();
                }
            }
            internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, IEnumerable <Document> documents, CancellationToken cancellationToken)
            {
                AssertIsForeground();

                if (!AreAllReferenceSpansMappable())
                {
                    // don't dynamically update the reference spans for documents with unmappable projections
                    return;
                }

                using (new SelectionTracking(this))
                {
                    // 1. Undo any previous edits and update the buffer to resulting document after conflict resolution
                    _session.UndoManager.UndoTemporaryEdits(_subjectBuffer, disconnect: false);

                    var preMergeSolution  = _session._baseSolution;
                    var postMergeSolution = conflictResolution.NewSolution;

                    var diffMergingSession = new LinkedFileDiffMergingSession(preMergeSolution, postMergeSolution, postMergeSolution.GetChanges(preMergeSolution), logSessionInfo: true);
                    var mergeResult        = diffMergingSession.MergeDiffsAsync(mergeConflictHandler: null, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

                    var newDocument      = mergeResult.MergedSolution.GetDocument(documents.First().Id);
                    var originalDocument = _baseDocuments.Single(d => d.Id == newDocument.Id);

                    var changes = GetTextChangesFromTextDifferencingServiceAsync(originalDocument, newDocument, cancellationToken).WaitAndGetResult(cancellationToken);

                    // TODO: why does the following line hang when uncommented?
                    // newDocument.GetTextChangesAsync(this.baseDocuments.Single(d => d.Id == newDocument.Id), cancellationToken).WaitAndGetResult(cancellationToken).Reverse();

                    _session.UndoManager.CreateConflictResolutionUndoTransaction(_subjectBuffer, () =>
                    {
                        using (var edit = _subjectBuffer.CreateEdit(EditOptions.DefaultMinimalChange, null, s_propagateSpansEditTag))
                        {
                            foreach (var change in changes)
                            {
                                edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
                            }

                            edit.ApplyAndLogExceptions();
                        }
                    });

                    // 2. We want to update referenceSpanToLinkedRenameSpanMap where spans were affected by conflict resolution.
                    // We also need to add the remaining document edits to conflictResolutionRenameTrackingSpans
                    // so they get classified/tagged correctly in the editor.
                    _conflictResolutionRenameTrackingSpans.Clear();

                    foreach (var document in documents)
                    {
                        var relevantReplacements = conflictResolution.GetReplacements(document.Id).Where(r => GetRenameSpanKind(r.Kind) != RenameSpanKind.None);
                        if (!relevantReplacements.Any())
                        {
                            continue;
                        }

                        var bufferContainsLinkedDocuments = documents.Skip(1).Any();
                        var mergedReplacements            = bufferContainsLinkedDocuments
                            ? GetMergedReplacementInfos(
                            relevantReplacements,
                            conflictResolution.NewSolution.GetDocument(document.Id),
                            mergeResult.MergedSolution.GetDocument(document.Id),
                            cancellationToken)
                            : relevantReplacements;

                        // Show merge conflicts comments as unresolvable conflicts, and do not
                        // show any other rename-related spans that overlap a merge conflict comment.
                        var mergeConflictComments = mergeResult.MergeConflictCommentSpans.ContainsKey(document.Id)
                            ? mergeResult.MergeConflictCommentSpans[document.Id]
                            : SpecializedCollections.EmptyEnumerable <TextSpan>();

                        foreach (var conflict in mergeConflictComments)
                        {
                            // TODO: Add these to the unresolvable conflict counts in the dashboard

                            _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                           _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(conflict.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                           RenameSpanKind.UnresolvedConflict));
                        }

                        foreach (var replacement in mergedReplacements)
                        {
                            var kind = GetRenameSpanKind(replacement.Kind);

                            if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified)
                            {
                                var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan(
                                    new InlineRenameLocation(newDocument, replacement.NewSpan), _session.ReplacementText, cancellationToken);
                                if (linkedRenameSpan.HasValue)
                                {
                                    if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                    {
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                            _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                                                linkedRenameSpan.Value.ToSpan(),
                                                SpanTrackingMode.EdgeInclusive,
                                                TrackingFidelityMode.Forward),
                                            kind);
                                    }
                                }
                                else
                                {
                                    // We might not have a renameable span if an alias conflict completely changed the text
                                    _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan] = new RenameTrackingSpan(
                                        _referenceSpanToLinkedRenameSpanMap[replacement.OriginalSpan].TrackingSpan,
                                        RenameSpanKind.None);

                                    if (_activeSpan.HasValue && _activeSpan.Value.IntersectsWith(replacement.OriginalSpan))
                                    {
                                        _activeSpan = null;
                                    }
                                }
                            }
                            else
                            {
                                if (!mergeConflictComments.Any(s => replacement.NewSpan.IntersectsWith(s)))
                                {
                                    _conflictResolutionRenameTrackingSpans.Add(new RenameTrackingSpan(
                                                                                   _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(replacement.NewSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward),
                                                                                   kind));
                                }
                            }
                        }
                    }

                    UpdateReadOnlyRegions();

                    // 3. Reset the undo state and notify the taggers.
                    this.ApplyReplacementText(updateSelection: false);
                    RaiseSpansChanged();
                }
            }