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
@GrabYourPitchforks GrabYourPitchforks 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 ahsonkhan April 7, 2020 00:36
@GrabYourPitchforks

Copy link
Copy Markdown
Member Author

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

tarekgh commented Apr 7, 2020

Copy link
Copy Markdown
Member

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

@tarekgh tarekgh 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
Member Author

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

safern commented Apr 7, 2020

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 😄

@adamsitnik adamsitnik 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 thread src/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
Member Author

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:master Apr 7, 2020
@GrabYourPitchforks
GrabYourPitchforks deleted the lastindexof branch April 7, 2020 19:16
@ghost ghost locked as resolved and limited conversation to collaborators Dec 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Runtime breaking-change Issue 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