private IEnumerable <TextChange> MergeChangesWithMergeFailComments( IEnumerable <TextChange> mergedChanges, IEnumerable <TextChange> commentChanges, IList <TextSpan> mergeConflictResolutionSpans, LinkedFileGroupSessionInfo groupSessionInfo) { var mergedChangesList = NormalizeChanges(mergedChanges).ToList(); var commentChangesList = NormalizeChanges(commentChanges).ToList(); var combinedChanges = new List <TextChange>(); var insertedMergeConflictCommentsAtAdjustedLocation = 0; var commentChangeIndex = 0; var currentPositionDelta = 0; foreach (var mergedChange in mergedChangesList) { while (commentChangeIndex < commentChangesList.Count && commentChangesList[commentChangeIndex].Span.End <= mergedChange.Span.Start) { // Add a comment change that does not conflict with any merge change combinedChanges.Add(commentChangesList[commentChangeIndex]); mergeConflictResolutionSpans.Add(new TextSpan(commentChangesList[commentChangeIndex].Span.Start + currentPositionDelta, commentChangesList[commentChangeIndex].NewText.Length)); currentPositionDelta += (commentChangesList[commentChangeIndex].NewText.Length - commentChangesList[commentChangeIndex].Span.Length); commentChangeIndex++; } if (commentChangeIndex >= commentChangesList.Count || mergedChange.Span.End <= commentChangesList[commentChangeIndex].Span.Start) { // Add a merge change that does not conflict with any comment change combinedChanges.Add(mergedChange); currentPositionDelta += (mergedChange.NewText.Length - mergedChange.Span.Length); continue; } // The current comment insertion location conflicts with a merge diff location. Add the comment before the diff. var conflictingCommentInsertionLocation = new TextSpan(mergedChange.Span.Start, 0); while (commentChangeIndex < commentChangesList.Count && commentChangesList[commentChangeIndex].Span.Start < mergedChange.Span.End) { combinedChanges.Add(new TextChange(conflictingCommentInsertionLocation, commentChangesList[commentChangeIndex].NewText)); mergeConflictResolutionSpans.Add(new TextSpan(commentChangesList[commentChangeIndex].Span.Start + currentPositionDelta, commentChangesList[commentChangeIndex].NewText.Length)); currentPositionDelta += commentChangesList[commentChangeIndex].NewText.Length; commentChangeIndex++; insertedMergeConflictCommentsAtAdjustedLocation++; } combinedChanges.Add(mergedChange); currentPositionDelta += (mergedChange.NewText.Length - mergedChange.Span.Length); } while (commentChangeIndex < commentChangesList.Count) { // Add a comment change that does not conflict with any merge change combinedChanges.Add(commentChangesList[commentChangeIndex]); mergeConflictResolutionSpans.Add(new TextSpan(commentChangesList[commentChangeIndex].Span.Start + currentPositionDelta, commentChangesList[commentChangeIndex].NewText.Length)); currentPositionDelta += (commentChangesList[commentChangeIndex].NewText.Length - commentChangesList[commentChangeIndex].Span.Length); commentChangeIndex++; } groupSessionInfo.InsertedMergeConflictComments = commentChanges.Count(); groupSessionInfo.InsertedMergeConflictCommentsAtAdjustedLocation = insertedMergeConflictCommentsAtAdjustedLocation; return(NormalizeChanges(combinedChanges)); }
public void LogLinkedFileResult(LinkedFileGroupSessionInfo info) { LinkedFileGroups.Add(info); }
private static async Task <ImmutableArray <TextChange> > AddDocumentMergeChangesAsync( Document oldDocument, Document newDocument, List <TextChange> cumulativeChanges, List <UnmergedDocumentChanges> unmergedChanges, LinkedFileGroupSessionInfo groupSessionInfo, IDocumentTextDifferencingService textDiffService, CancellationToken cancellationToken) { var unmergedDocumentChanges = new List <TextChange>(); var successfullyMergedChanges = ArrayBuilder <TextChange> .GetInstance(); int cumulativeChangeIndex = 0; var textchanges = await textDiffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); foreach (var change in textchanges) { while (cumulativeChangeIndex < cumulativeChanges.Count && cumulativeChanges[cumulativeChangeIndex].Span.End < change.Span.Start) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (cumulativeChangeIndex < cumulativeChanges.Count) { var cumulativeChange = cumulativeChanges[cumulativeChangeIndex]; if (!cumulativeChange.Span.IntersectsWith(change.Span)) { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } else { if (change.Span != cumulativeChange.Span || change.NewText != cumulativeChange.NewText) { // The current change in consideration overlaps an existing change but // the changes are not identical. unmergedDocumentChanges.Add(change); groupSessionInfo.OverlappingDistinctDiffs++; if (change.Span == cumulativeChange.Span) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpan++; if (change.NewText.Contains(cumulativeChange.NewText) || cumulativeChange.NewText.Contains(change.NewText)) { groupSessionInfo.OverlappingDistinctDiffsWithSameSpanAndSubstringRelation++; } } } else { // The current change in consideration is identical to an existing change successfullyMergedChanges.Add(change); cumulativeChangeIndex++; groupSessionInfo.IdenticalDiffs++; } } } else { // The current change in consideration does not intersect with any existing change successfullyMergedChanges.Add(change); groupSessionInfo.IsolatedDiffs++; } } while (cumulativeChangeIndex < cumulativeChanges.Count) { // Existing change that does not overlap with the current change in consideration successfullyMergedChanges.Add(cumulativeChanges[cumulativeChangeIndex]); cumulativeChangeIndex++; groupSessionInfo.IsolatedDiffs++; } if (unmergedDocumentChanges.Any()) { unmergedChanges.Add(new UnmergedDocumentChanges( unmergedDocumentChanges.AsEnumerable(), oldDocument.Project.Name, oldDocument.Id)); } return(successfullyMergedChanges.ToImmutableAndFree()); }