You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixing this changes observable behavior: callers that currently catch (ArgumentOutOfRangeException) around LastIndexOf with count = 0 would stop entering their catch block. Any downstream code that relies on the exception (intentionally or via defensive try/catch) will behave differently after the fix.
Summary
StringTextSource.LastIndexOf(char c, int startIndex, int count) throws ArgumentOutOfRangeException when called with startIndex = 0 and count = 0. An empty search range should return -1 (not found), consistent with IndexOf(char, 0, 0) which correctly returns -1.
Returns -1 - an empty search range contains no characters, so nothing can be found.
Actual
System.ArgumentOutOfRangeException: Index was out of range.
Must be non-negative and less than the size of the collection. (Parameter 'startIndex')
at System.String.LastIndexOf(Char value, Int32 startIndex, Int32 count)
at AvaloniaEdit.Document.StringTextSource.LastIndexOf(Char c, Int32 startIndex, Int32 count)
Root cause
ITextSource.LastIndexOf uses forward-range semantics: startIndex is the left edge, count is the range width, and the search proceeds backward within [startIndex, startIndex + count).
string.LastIndexOf uses backward-search semantics: startIndex is the rightmost position to begin searching, and count is how many positions to walk left.
The implementation bridges these two conventions with:
When count = 0, this computes startIndex + 0 - 1 = -1, which string.LastIndexOf rejects.
The same issue exists in the LastIndexOf(string, ...) overload which uses the same arithmetic.
Affected overloads
LastIndexOf(char c, int startIndex, int count)
LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
Inconsistency with IndexOf
Method
Call
Result
IndexOf('H', 0, 0)
Works
-1
LastIndexOf('H', 0, 0)
Throws
ArgumentOutOfRangeException
Both should return -1 for an empty search range.
Inconsistency with BCL
.NET's string.LastIndexOf('H', 0, 0) correctly returns -1. The bug is not in the BCL - it is in StringTextSource's arithmetic translation from ITextSource's forward-range convention to string.LastIndexOf's backward-search convention. The -1 underflow only occurs because of the startIndex + count - 1 bridging formula.
Important
Breaking change
Fixing this changes observable behavior: callers that currently
catch (ArgumentOutOfRangeException)aroundLastIndexOfwithcount = 0would stop entering their catch block. Any downstream code that relies on the exception (intentionally or via defensive try/catch) will behave differently after the fix.Summary
StringTextSource.LastIndexOf(char c, int startIndex, int count)throwsArgumentOutOfRangeExceptionwhen called withstartIndex = 0andcount = 0. An empty search range should return-1(not found), consistent withIndexOf(char, 0, 0)which correctly returns-1.Repro
Expected
Returns
-1- an empty search range contains no characters, so nothing can be found.Actual
Root cause
ITextSource.LastIndexOfuses forward-range semantics:startIndexis the left edge,countis the range width, and the search proceeds backward within[startIndex, startIndex + count).string.LastIndexOfuses backward-search semantics:startIndexis the rightmost position to begin searching, andcountis how many positions to walk left.The implementation bridges these two conventions with:
When
count = 0, this computesstartIndex + 0 - 1 = -1, whichstring.LastIndexOfrejects.The same issue exists in the
LastIndexOf(string, ...)overload which uses the same arithmetic.Affected overloads
LastIndexOf(char c, int startIndex, int count)LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)Inconsistency with IndexOf
IndexOf('H', 0, 0)-1LastIndexOf('H', 0, 0)ArgumentOutOfRangeExceptionBoth should return
-1for an empty search range.Inconsistency with BCL
.NET's
string.LastIndexOf('H', 0, 0)correctly returns-1. The bug is not in the BCL - it is in StringTextSource's arithmetic translation fromITextSource's forward-range convention tostring.LastIndexOf's backward-search convention. The-1underflow only occurs because of thestartIndex + count - 1bridging formula.