Ah I see what you're getting at.  I missed that you were aggregating the TextContentChangedEventArg there.  So yeah in general you should be safe from the textBuffer.CurrentSnapshot being ahead of x.After.  And really since x is not TextContentChangedEventArgs but some collection of them you'd have to use x.Last().After.  

This does cause another problem though.  Imagine the following series of edits on an ITextBuffer which has an initial content of "hello " (length is 7) 

- insert "cat" at position 7. y will have NewSpan.Start = 7, NewSpan.End = 10 
- delete 4 characters at position 6: y will have NewSpan.Start 6, NewSpan.End = 6

At this point the content is "hello" and the length is 6.  But the logic inside of the SelectMany  clause will leave you with `acc[0] == 6` and `acc[1] == 10`.  This will cause an exception on line 131 because 10 is past the length of the buffer.  

To be 100% accurate here you need to use ITrackingPoint.  It's the method of mapping a position from one ITextSnapshot to another one.  Based on your comment here I feel like that's a bit heavy weight though since you just want to get a general area to look for changes.  

A simpler approach may be to just track the start / end line of the overarching edit instead of the position inside lines 118 - 122.  I tried writing down an explanation of how this would work a few times and only served to confuse myself.  Decided it would be better to speak in code : ) 

    int?[] acc = new int?[2];
    x.SelectMany(y => y.EventArgs)
     .Foreach(y => {
        var snapshot = y.After;
        foreach (var change in y.Changes) { 
          var startNum = snapshot.GetLineNumberFromPosition(change.NewSpan.Start);
          var endNum = snapshot.GetLineNumberFromPosition(change.NewSpan.End);

          acc[0] = Math.Min(acc[0] ?? Int32.MaxValue, startNum);
          acc[1] = Math.Max(acc[1] ?? Int32.MinValue, endNum);

          // Consider the case where the user edits line 10, then later inserts 
          // 5 lines at line 3.  The last line needs to be 15, not 10.  Account
          // for that possibility here.  This will often over estimate the last
          // line but will never under estimate it
          if (change.LineCountDelta > 0) { 
            acc[1] = acc[1].Value + change.LineCountDelt;
          }
        }
     });

    var after = x.Last(y => y.After);
    acc[1] = Math.Min(acc[1].Value, after.LineCount - 1);

Edit tracking is full of surprises :(