Skip to content

Fix various LastIndexOf bugs when dealing with zero-length target substrings - #34616

Merged
GrabYourPitchforks merged 1 commit into
dotnet:masterfrom
GrabYourPitchforks:lastindexof
Apr 7, 2020
Merged

Fix various LastIndexOf bugs when dealing with zero-length target substrings#34616
GrabYourPitchforks merged 1 commit into
dotnet:masterfrom
GrabYourPitchforks:lastindexof

Conversation

@GrabYourPitchforks

Copy link
Copy Markdown
Member

Fixes#13382.
Fixes#13383.

string.LastIndexOf and MemoryExtensions.LastIndexOf are inconsistent with how they handle zero-length target strings with various StringComparison arguments. In some cases they return string.Length - 1. In some cases they return span.Length. And in some cases they return 0.

This PR normalizes the behavior of all of these APIs so that a zero-length target substring is always found at the end of the search space. Since LastIndexOf's parameters vary significantly from IndexOf's parameters, I also included a code comment right in front of string.IndexOf(string) that explains the concept of "search space" vis-à-vis this particular API.

There's also some small comment cleanup throughout the code paths which deal with these checks.

This PR was extracted from #1514 into its own standalone review. This PR addresses only LastIndexOf and doesn't address the zero-weight code point issue tracked by that PR.

- string.LastIndexOf(string.Empty) shouldn't perform -1 adjustment
- MemoryExtensions.LastIndexOf(ROS<char>, string.Empty) shouldn't return 0
- Tighten up some existing unit tests
@GrabYourPitchforksGrabYourPitchforks added area-System.Runtime breaking-change Issue or PR that represents a breaking API or functional change over a previous release. labels Apr 7, 2020
@GrabYourPitchforks
GrabYourPitchforks requested review from adamsitnik and bartonjs and removed request for ahsonkhanApril 7, 2020 00:36
@GrabYourPitchforks

Copy link
Copy Markdown
MemberAuthor

Note to @tarekgh: This PR doesn't have the "avoid validating CompareOptions if you can early-exit" concerns that you raised in #1514 (comment). But that's because this PR doesn't attempt to solve the zero-weight code point problem. 😉 Once I spin #1514 back up we'll have to deal with the issue at that time since it'll necessarily involve contorting control flow.

@tarekgh

Copy link
Copy Markdown
Member

CC @safern just in case he is touching some of the changed files here.

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the change and now our behavior is more understandable. only one thing, we need to document this as a breaking change. right? if so, can we ensure this is written so we can point users to the doc when anyone complains? Thanks for clearing this area.

@GrabYourPitchforks

Copy link
Copy Markdown
MemberAuthor

This issue is marked with a breaking change tag. In theory it should be caught in any pre-release sweep we do to account for such changes in the docs.

@safern

Copy link
Copy Markdown
Member

CC @safern just in case he is touching some of the changed files here.

Thanks @tarekgh for the heads up. It seems only the file renames will conflict, I'll have to deal with it 😄

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 :shipit:

Comment threadsrc/libraries/Common/tests/Tests/System/StringTests.cs
@@ -4068,8 +4070,8 @@ public static void LastIndexOf_TurkishI_EnglishUSCulture()
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not related to your changes: IMHO this test (IndexOf_AllSubstrings) is very complex and is trying to test too many test cases at the same time. It would be better to split it into few smaller tests with self-describing names

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, it's a bit of a bear. Do you have recommendations for how it might naturally be split?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the two if blocks could become separate tests: value.Length == 0, s.Length == 0

@GrabYourPitchforks
GrabYourPitchforks merged commit c4507d7 into dotnet:masterApr 7, 2020
@GrabYourPitchforks
GrabYourPitchforks deleted the lastindexof branch April 7, 2020 19:16
@ghostghost locked as resolved and limited conversation to collaborators Dec 9, 2020
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Runtimebreaking-changeIssue or PR that represents a breaking API or functional change over a previous release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

string.LastIndexOf(string.Empty, ...) returns wrong index ROS<T>.LastIndexOf(ROS<T> value) returns wrong index when 'value' is empty

4 participants

@GrabYourPitchforks@tarekgh@safern@adamsitnik